Giter Site home page Giter Site logo

django-keycloak-auth's People

Contributors

chmoder avatar leelith avatar marcelo225 avatar olhybrius avatar singlerider avatar syawarassima avatar timursungatullin avatar turicas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

django-keycloak-auth's Issues

Increasing the Usefulness of the Library

I am using this library with Django Rest Framework. If I were able to integrate the Keycloak authentication mechanisms found in this library in the built-in API explorer, it would make developing with authenticated endpoints much easier.

I would like to advocate for a pluggable way to "Log In" to the default Django Rest Framework API Explorer. It should be documented, as this seems like a great entry-level use-case.

Access other clients's roles

Hi there ! Thanks for your amazing work on this lib first.
We have a project and we have to use following keycloak configuration :

  1. a keycloak client for Angular web-app (let's call it keycloak-front)
  2. a keycloak bearer-only client for Django Rest API (let's call it keycloak-back)

It is for us impossible to use realms roles (too many users) and to duplicate keycloak-front's roles to keycloak-back's roles (technical reason coming from our system team - no discussion).

Would it be ok for you if I set up a modification for a PR, changing this :

client_access = resource_access.get(self.client_id, None) if resource_access is not None else None

to this ?

client_access = resource_access.get(settings.KEYCLOAK_CONFIG['KEYCLOAK_CLIENT_FRONT_ID'], None) if resource_access is not None else None

KEYCLOAK_CLIENT_FRONT_ID must be added in project's settings.py.

Modification done in "keycloak.py", line 134

Best regards !

Edit : sorry if it's not clear, the goal is to take a list of supported clients, not a single one.

Add Keycloak user UUID to request object

Hi,

I know it is slightly out of the scope of this library, but since the information is already there, I think it could be useful to include the Keycloak user UUID in the request object along with the roles. The information is available in the 'sub' attribute of the decoded token.

I can make a PR if you're interested.

Use actions based authorization instead of request method

Hi,

Using actions instead of request methods to authorize resources would allow support for custom actions and more fined-grained control (multiple actions can use the same request method).

Updating line 87 of middleware.py like below would do the trick :

require_view_role = view_roles.get(self.action, [None]) 

I can make a PR if you want, and update the README accordingly.

Authorization based on oAuth2 scopes

Is there the possibility to perform the authorization based on oauth2 scopes instead of keycloak roles?
Would you consider implementing this possibility or merging a PR that implements the feature?

`aud` is using `client_id` by default

Hello, we are implementing keycloak at my job, and we decided to use your awesome library.

I have an issue/question.
I created a client called django-client in keycloak and left all the default configurations as is.
When setting LOCAL_DECODE=True the JWT authorization fails because the keycloak sends aud=['account'] however,
you have

if audience is None:
    audience = self.client_id # "django-client" in my case
....
payload = jwt.decode(token, key=key, algorithms=['RS256'], audience=audience, options=options)

This results in an error because the django-client is not in the intended aud coming from keycloak

I was able to add a custom Dedicated Scope to my Client with the same name (django-client), following the answers here. making aud=['account', 'django-client'] which makes it pass the JWT check.
but I think this is not a real solution.

from my research all created Clients have aud='account' by default from here
and you can remove this aud if you want and assign custom scopes instead.

I think that using audience = self.client_id by default is not correct here.

if audience is None:
    audience = self.client_id
  • It should be either skipped if None
if audience is None:
    audience = None
  • OR should use "account"
`aud` should be either skipped if None 
```python 
if audience is None:
    audience = 'account'
  • OR we can add LOCAL_DECODE_AUD in the config that should indicate that the developer wants to enforce a specific aud, which could be anything "account", CLIENT_ID, "www.supersecretwebapp.com", etc..

I am not sure if my issue is very coherent and up to code. please reach out if you need more info about this.

P.S. A useful resource about JWT aud vs client-id here

Feature Request: Decorator to control specific permissions on view functions

So your config currently works great for REST style API, where you control the permissions on the request method.
One of the API classes I work with exposes the functions as endpoints, so there can be many functions that act as endpoint, and they can all be POST. I created a decorator to control permissions in this circumstance, which works well for me. Was wondering if you see value in adding something like this to your code base.

decorator:

def valid_roles(access_roles):
    def decorator(func):
        @wraps(func)
        def wrapped_func(self, request, *args, **kwargs):
            if len(set(request.roles) & set(access_roles)) == 0:
                raise exceptions.PermissionDenied(exceptions.PermissionDenied.default_detail)
            return func(self, request, *args, **kwargs)
        return wrapped_func
    return decorator

Example use:

class ExternalDemandActionAPI(ActionAPIView):
    permission_classes = []
    authentication_classes = []

    keycloak_roles = {
        'GET': ['api:get'],
        'POST': ['api:add', 'api:get', 'api:mod'],
        'UPDATE': ['api:mod', ],
        'DELETE': ['api:del', ],
        'PATCH': ['api:mod'],
    }

    @valid_roles(['api:demand:add'])
    def add_demand(self, request, params, *args, **kwargs):

        logger.debug(f'{params}')
        return params

Assigning keycloak_roles to ModelViewSet prevents unauthenticated requests

My Django Rest Framework application is still integrating auth. I wanted to test this library a bit before diving deep.

There is a docstring in the example APIView from the documentation that suggests that "Other HTTP methods will be allowed."

However, once that keycloak_roles attribute is assigned (at least in a ModelViewSet), it prevents other methods from being accessed.


Example APIView:

class JudgementView(views.APIView):
    """
    Judgement endpoint
    This endpoint has configured keycloak roles only GET method.
    Other HTTP methods will be allowed.
    """
    keycloak_roles = {
        'GET': ['judge'],
    }

The following are from my project:

settings.py:

# Exempt URIS
KEYCLOAK_EXEMPT_URIS = [
    '/schema/swagger', '/schema/redoc', '/schema/spectacular'
]
KEYCLOAK_CONFIG = {
    'KEYCLOAK_SERVER_URL': 'http://localhost:8080/auth',
    'KEYCLOAK_REALM': 'master',
    'KEYCLOAK_CLIENT_ID': 'client-backend',
    'KEYCLOAK_CLIENT_SECRET_KEY': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
}

views.py:

class ApplicationViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows applications to be viewed or edited.
    """
    queryset = Application.objects.all()
    permission_classes = [permissions.AllowAny]
    serializer_class = ApplicationSerializer
    keycloak_roles = {
        # 'GET': ['director', 'judge', 'employee'],
        'POST': ['director', 'judge', ],
        # 'UPDATE': ['director', 'judge', ],
        # 'DELETE': ['director', 'judge', ],
        # 'PATCH': ['director', 'judge', 'employee'],
    }

I make no effort to properly authenticate, yet, but I would expect this /applications route to be able to see the list view (GET). Here is the result of attempting to perform a request with any method on the /applications route.

{"detail": "Authentication credentials were not provided."}

Am I misunderstanding how to properly exempt specific methods? My application would support unauthenticated requests for some shared routes with specific methods (such as being able to submit an "Application" without having an account with POST).

Realm roles support

Hi,

First of all, thanks for this library !

It could be useful to support realm roles as well instead of just client roles.

It shoudn't be too difficult to implement, my guess is slightly modifying keycloak.py like below would do the trick (lines 131 - 134) :

if not (self.client_id in token_decoded['resource_access'] or self.client_id in token_decoded['realm_access']) : 
       return None
resource_access = token_decoded['resource_access'].get(self.client_id, None)   
realm_access = token_decoded['realm_access']      
return resource_access.get('roles', None) or realm_access.get('roles', None)

I can make a PR for this if you want.

Assistance using the library

I am trying to use the library, have set everything as described in the documentation. I get the JWT from a keycloak server I have set up and use with java clients.

However, at my django app, request.roles is empty, and request.userinfo does not exist. The APIs are all as they would be without any authentication

Maybe some DEFAULT_AUTHENTICATION_CLASSES or AUTH_USER_MODEL or something similar is needed in the configuration ?

Currently the only thing I have used is as in README MIDDLEWARE entry

Thank you

Pass userinfo into views

Hi,

I'd like my backend to get some userinfo from keycloak via the bearer token.

is there a way to pass userinfo to the view ?

I've added

request.userinfo = self.keycloak.userinfo(token)

at the end of the middleware.py and works perfectly. Is it ok or there is a better way ?

best regards

/admin AttributeError

Adding "django_keycloak_auth.middleware.KeycloakMiddleware", to the settings MIDDLEWARE array causes the below error when accessing /admin:

Traceback (most recent call last):
  File "/Users/thomasfex/development/github/ItkBackend/env/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/Users/thomasfex/development/github/ItkBackend/env/lib/python3.8/site-packages/django/core/handlers/base.py", line 171, in _get_response
    response = middleware_method(request, callback, callback_args, callback_kwargs)
  File "/Users/thomasfex/development/github/ItkBackend/env/lib/python3.8/site-packages/django_keycloak_auth/middleware.py", line 91, in process_view
    is_api_view = True if str(view_func.cls.__qualname__) == "WrappedAPIView" else False
AttributeError: 'function' object has no attribute 'cls'
[03-11-23 13:38:09] django.server 500 "GET /admin/ HTTP/1.1" 500 95736

I think we can fix it on line 90 of middleware.py like so:

try:      
    is_api_view = True if str(view_func.cls.__qualname__) == "WrappedAPIView" else False
except AttributeError as e:
    is_api_view = False

Is this a logical fix? I can open a pr if that looks right.

Returns "detail": "Authentication credentials were not provided."

I have all the setup done. I can introspect using Postman. But when I try to access an API endpoint from my DRF, I get "detail": "Authentication credentials were not provided."

Does Django need to authenticate with Keycloak to introspect tokens? I am not sure what I am missing and any help is greatly appreciated.

I am running both the API endpoint and keycloak via docker-compose.

Thanks.

Issue with Exempting Admin Path in New Module Versions

Hi everyone,

I hope this message finds you well. I've come across an issue while working with the latest versions of the module, specifically when attempting to exempt the admin path, as I used to do in older versions.

Here's a snippet of my code:
KEYCLOAK_EXEMPT_URIS = ["admin/"]

However, upon implementing this, I encountered the following error:
AttributeError: 'function' object has no attribute 'cls'
if hasattr(view_func.cls, "keycloak_roles") and request.method not in view_func.cls.keycloak_roles:
"GET /admin/ HTTP/1.1" 500 145

Interestingly, removing the "admin/" part from KEYCLOAK_EXEMPT_URIS resolved the issue for me. I would appreciate some guidance or clarification on whether this behavior is considered an issue in the current module versions.

Thank you for your time and assistance.

Logging doesn't work for keyclock requests

I found the problem is that you are trying to get an error from method raise_for_status. But this method does not return an error, but raised does.

I created a PR that solves this problem. #23

Netbox django-keycloak-auth integration

So I am attempting to use this application to allow Netbox to use the Keycloak API for Authentication. I was wondering if anyone has had any success in this area. I have also attempted to use a basic project app as well and have had little success. Any help is appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.