drf-keycloak-auth


Namedrf-keycloak-auth JSON
Version 0.3.1 PyPI version JSON
download
home_pagehttps://gitlab.com/ecocommons-australia/lib/drf-keycloak-auth
SummaryA convenience libary for authenticating users from Keycloak access tokens
upload_time2024-01-15 06:08:22
maintainer
docs_urlNone
authorEcoCommons Australia
requires_python>=3
licenseMIT
keywords drf django rest_framework djangorestframework authentication python3 keycloak
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # DRF Keycloak Auth

## Requirements


* Python >= 3.4
* Django
* Django Rest Framework
* Python Keycloak


## Installation

```
$ pip install drf-keycloak-auth
```

Add the application to your project's `INSTALLED_APPS` in `settings.py`.

```
INSTALLED_APPS = [
    ...
    'drf_keycloak_auth',
]
```

In your project's `settings.py`, add this to the `REST_FRAMEWORK` configuration. Note that if you want to retain access to the browsable API for locally created users, then you will probably want to keep `rest_framework.authentication.SessionAuthentication` too.

```
REST_FRAMEWORK = {
  ...
  'DEFAULT_AUTHENTICATION_CLASSES': [
    ...
    'rest_framework.authentication.SessionAuthentication',
    'drf_keycloak_auth.authentication.KeycloakAuthentication',
  ]
}
```

The `drf_keycloak_auth` application comes with the following settings as default, which can be overridden in your project's `settings.py` file. Make sure to nest them within `DRF_KEYCLOAK_AUTH` as below:


```python
# should be comma separated string
KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF = \
    os.getenv('KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF')

DEFAULTS = {
    'KEYCLOAK_SERVER_URL': os.getenv('KEYCLOAK_SERVER_URL'),
    'KEYCLOAK_REALM': os.getenv('KEYCLOAK_REALM'),
    'KEYCLOAK_CLIENT_ID': os.getenv('KEYCLOAK_CLIENT_ID'),
    'KEYCLOAK_CLIENT_SECRET_KEY': os.getenv('KEYCLOAK_CLIENT_SECRET_KEY'),
    'KEYCLOAK_AUTH_HEADER_PREFIX':
        os.getenv('KEYCLOAK_AUTH_HEADER_PREFIX', 'Bearer'),
    'KEYCLOAK_ROLE_SET_PREFIX':
        os.getenv('KEYCLOAK_ROLE_SET_PREFIX', 'role:'),
    'KEYCLOAK_MANAGE_LOCAL_USER':
        os.getenv('KEYCLOAK_MANAGE_LOCAL_USER', True),
    'KEYCLOAK_MANAGE_LOCAL_GROUPS':
        os.getenv('KEYCLOAK_MANAGE_LOCAL_GROUPS', False),
    'KEYCLOAK_DJANGO_USER_UUID_FIELD':
        os.getenv('KEYCLOAK_DJANGO_USER_UUID_FIELD', 'pk'),
    'KEYCLOAK_FIELD_AS_DJANGO_USERNAME':
        os.getenv('KEYCLOAK_FIELD_AS_DJANGO_USERNAME', 'preferred_username'),
    'KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF': (
        [x.strip() for x in KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF.split(',')]
        if KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF
        else ['admin']  # can be list, tuple or set
    )
}
```

All you need to do now is have your client code handle the Keycloak authentication flow, retrieve the access_token for the user, and then use the access_token for the user in an `Authorization` header in requests to your API.

```
Bearer <token>
```

Roles will be present in `request.roles` with a `KEYCLOAK_ROLE_SET_PREFIX` prefix (only if succesfully authenticated), e.g.:

```
['role:admin', 'a4a9be6e-bd04-42f8-9377-27d9db82216f']
```

except for the authenticated user's pk field, e.g. for a user model using uuid's as primary key:

```
['role:user', 'a4a9be6e-bd04-42f8-9377-27d9db82216f']
```

where the pk can be used for checking object ownership.

If you wish to create your own role permissions:

https://www.django-rest-framework.org/api-guide/permissions/#custom-permissions

simply import and use the prefix helper:

```python
from .keycloak import prefix_role

ROLE_USER = prefix_role('user')
ROLE_SERVICE = prefix_role('service')
ROLE_ADMIN = prefix_role('admin')
```

request.user.is_staff will be modified based upon roles in `KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF`.
These roles can be hard coded as a list, tuple or set, or from a comma-separated env var.
Functionality ignored if KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF is None or empty.

If your user model doesn't / can't have a UUID primary key, override the `KEYCLOAK_DJANGO_USER_UUID_FIELD` setting to indicate a unique `UUIDField` on your model, e.g.:

```
KEYCLOAK_DJANGO_USER_UUID_FIELD = 'uuid'
```

Voila!


## Multi tenancy support

An application can be configured for multiple tenancies by using different Keycloak Realms on the same or seperate Keycloak instances by using the environment var `KEYCLOAK_MULTI_OIDC_JSON`

The client OIDC adaptor json file can be downloaded from Keycloak.

```
KEYCLOAK_MULTI_OIDC_JSON=
{
"hostname1": { OIDC adaptor },
"hostname2": { OIDC adaptor },
}
```

KeycloakMultiAuthentication should be configured as the authentication class. 

```
REST_FRAMEWORK = {
  ...
  'DEFAULT_AUTHENTICATION_CLASSES': [
    ...
    'rest_framework.authentication.SessionAuthentication',
    'drf_keycloak_auth.authentication.KeycloakMultiAuthentication',
  ]
}
```
___
NOTE: This will ignore `DEFAULTS` parameters for hostname, realm and client credentials.  All other parameters are still shared accross tenancies.
NOTE2: `KeycloakAuthentication` can still be present as a fallback for simpler cases like local dev.
___


## Contributing

* Please raise an issue/feature and name your branch 'feature-n' or 'issue-n', where 'n' is the issue number.

            

Raw data

            {
    "_id": null,
    "home_page": "https://gitlab.com/ecocommons-australia/lib/drf-keycloak-auth",
    "name": "drf-keycloak-auth",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3",
    "maintainer_email": "",
    "keywords": "drf,django,rest_framework,djangorestframework,authentication,python3,keycloak",
    "author": "EcoCommons Australia",
    "author_email": "ecocommons@griffith.edu.au",
    "download_url": "https://files.pythonhosted.org/packages/4b/54/08fee74a38ca76265833bb7b6ae5b53a19b955bce15d214129e594c8f08b/drf_keycloak_auth-0.3.1.tar.gz",
    "platform": null,
    "description": "# DRF Keycloak Auth\n\n## Requirements\n\n\n* Python >= 3.4\n* Django\n* Django Rest Framework\n* Python Keycloak\n\n\n## Installation\n\n```\n$ pip install drf-keycloak-auth\n```\n\nAdd the application to your project's `INSTALLED_APPS` in `settings.py`.\n\n```\nINSTALLED_APPS = [\n    ...\n    'drf_keycloak_auth',\n]\n```\n\nIn your project's `settings.py`, add this to the `REST_FRAMEWORK` configuration. Note that if you want to retain access to the browsable API for locally created users, then you will probably want to keep `rest_framework.authentication.SessionAuthentication` too.\n\n```\nREST_FRAMEWORK = {\n  ...\n  'DEFAULT_AUTHENTICATION_CLASSES': [\n    ...\n    'rest_framework.authentication.SessionAuthentication',\n    'drf_keycloak_auth.authentication.KeycloakAuthentication',\n  ]\n}\n```\n\nThe `drf_keycloak_auth` application comes with the following settings as default, which can be overridden in your project's `settings.py` file. Make sure to nest them within `DRF_KEYCLOAK_AUTH` as below:\n\n\n```python\n# should be comma separated string\nKEYCLOAK_ROLES_TO_DJANGO_IS_STAFF = \\\n    os.getenv('KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF')\n\nDEFAULTS = {\n    'KEYCLOAK_SERVER_URL': os.getenv('KEYCLOAK_SERVER_URL'),\n    'KEYCLOAK_REALM': os.getenv('KEYCLOAK_REALM'),\n    'KEYCLOAK_CLIENT_ID': os.getenv('KEYCLOAK_CLIENT_ID'),\n    'KEYCLOAK_CLIENT_SECRET_KEY': os.getenv('KEYCLOAK_CLIENT_SECRET_KEY'),\n    'KEYCLOAK_AUTH_HEADER_PREFIX':\n        os.getenv('KEYCLOAK_AUTH_HEADER_PREFIX', 'Bearer'),\n    'KEYCLOAK_ROLE_SET_PREFIX':\n        os.getenv('KEYCLOAK_ROLE_SET_PREFIX', 'role:'),\n    'KEYCLOAK_MANAGE_LOCAL_USER':\n        os.getenv('KEYCLOAK_MANAGE_LOCAL_USER', True),\n    'KEYCLOAK_MANAGE_LOCAL_GROUPS':\n        os.getenv('KEYCLOAK_MANAGE_LOCAL_GROUPS', False),\n    'KEYCLOAK_DJANGO_USER_UUID_FIELD':\n        os.getenv('KEYCLOAK_DJANGO_USER_UUID_FIELD', 'pk'),\n    'KEYCLOAK_FIELD_AS_DJANGO_USERNAME':\n        os.getenv('KEYCLOAK_FIELD_AS_DJANGO_USERNAME', 'preferred_username'),\n    'KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF': (\n        [x.strip() for x in KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF.split(',')]\n        if KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF\n        else ['admin']  # can be list, tuple or set\n    )\n}\n```\n\nAll you need to do now is have your client code handle the Keycloak authentication flow, retrieve the access_token for the user, and then use the access_token for the user in an `Authorization` header in requests to your API.\n\n```\nBearer <token>\n```\n\nRoles will be present in `request.roles` with a `KEYCLOAK_ROLE_SET_PREFIX` prefix (only if succesfully authenticated), e.g.:\n\n```\n['role:admin', 'a4a9be6e-bd04-42f8-9377-27d9db82216f']\n```\n\nexcept for the authenticated user's pk field, e.g. for a user model using uuid's as primary key:\n\n```\n['role:user', 'a4a9be6e-bd04-42f8-9377-27d9db82216f']\n```\n\nwhere the pk can be used for checking object ownership.\n\nIf you wish to create your own role permissions:\n\nhttps://www.django-rest-framework.org/api-guide/permissions/#custom-permissions\n\nsimply import and use the prefix helper:\n\n```python\nfrom .keycloak import prefix_role\n\nROLE_USER = prefix_role('user')\nROLE_SERVICE = prefix_role('service')\nROLE_ADMIN = prefix_role('admin')\n```\n\nrequest.user.is_staff will be modified based upon roles in `KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF`.\nThese roles can be hard coded as a list, tuple or set, or from a comma-separated env var.\nFunctionality ignored if KEYCLOAK_ROLES_TO_DJANGO_IS_STAFF is None or empty.\n\nIf your user model doesn't / can't have a UUID primary key, override the `KEYCLOAK_DJANGO_USER_UUID_FIELD` setting to indicate a unique `UUIDField` on your model, e.g.:\n\n```\nKEYCLOAK_DJANGO_USER_UUID_FIELD = 'uuid'\n```\n\nVoila!\n\n\n## Multi tenancy support\n\nAn application can be configured for multiple tenancies by using different Keycloak Realms on the same or seperate Keycloak instances by using the environment var `KEYCLOAK_MULTI_OIDC_JSON`\n\nThe client OIDC adaptor json file can be downloaded from Keycloak.\n\n```\nKEYCLOAK_MULTI_OIDC_JSON=\n{\n\"hostname1\": { OIDC adaptor },\n\"hostname2\": { OIDC adaptor },\n}\n```\n\nKeycloakMultiAuthentication should be configured as the authentication class. \n\n```\nREST_FRAMEWORK = {\n  ...\n  'DEFAULT_AUTHENTICATION_CLASSES': [\n    ...\n    'rest_framework.authentication.SessionAuthentication',\n    'drf_keycloak_auth.authentication.KeycloakMultiAuthentication',\n  ]\n}\n```\n___\nNOTE: This will ignore `DEFAULTS` parameters for hostname, realm and client credentials.  All other parameters are still shared accross tenancies.\nNOTE2: `KeycloakAuthentication` can still be present as a fallback for simpler cases like local dev.\n___\n\n\n## Contributing\n\n* Please raise an issue/feature and name your branch 'feature-n' or 'issue-n', where 'n' is the issue number.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A convenience libary for authenticating users from Keycloak access tokens",
    "version": "0.3.1",
    "project_urls": {
        "Homepage": "https://gitlab.com/ecocommons-australia/lib/drf-keycloak-auth"
    },
    "split_keywords": [
        "drf",
        "django",
        "rest_framework",
        "djangorestframework",
        "authentication",
        "python3",
        "keycloak"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "50dfb7ec2e4e2cf8a13ee1b9f2bfa0b239053f97ba093e96dc68396b1791eea7",
                "md5": "5a4b680e958476c5013d2302e83ef652",
                "sha256": "3d30e4fb7815a826749a9289aeed888b0c2e6a14229d714f479d1e4786cb3f20"
            },
            "downloads": -1,
            "filename": "drf_keycloak_auth-0.3.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5a4b680e958476c5013d2302e83ef652",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3",
            "size": 13345,
            "upload_time": "2024-01-15T06:08:21",
            "upload_time_iso_8601": "2024-01-15T06:08:21.279851Z",
            "url": "https://files.pythonhosted.org/packages/50/df/b7ec2e4e2cf8a13ee1b9f2bfa0b239053f97ba093e96dc68396b1791eea7/drf_keycloak_auth-0.3.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4b5408fee74a38ca76265833bb7b6ae5b53a19b955bce15d214129e594c8f08b",
                "md5": "d6c6471921f2752e1593373e81cda4e6",
                "sha256": "f5856f947da39e4a6e858492abeca2d1da24360265029d2f1850e19e615b1ad9"
            },
            "downloads": -1,
            "filename": "drf_keycloak_auth-0.3.1.tar.gz",
            "has_sig": false,
            "md5_digest": "d6c6471921f2752e1593373e81cda4e6",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3",
            "size": 12004,
            "upload_time": "2024-01-15T06:08:22",
            "upload_time_iso_8601": "2024-01-15T06:08:22.961692Z",
            "url": "https://files.pythonhosted.org/packages/4b/54/08fee74a38ca76265833bb7b6ae5b53a19b955bce15d214129e594c8f08b/drf_keycloak_auth-0.3.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-01-15 06:08:22",
    "github": false,
    "gitlab": true,
    "bitbucket": false,
    "codeberg": false,
    "gitlab_user": "ecocommons-australia",
    "gitlab_project": "lib",
    "lcname": "drf-keycloak-auth"
}
        
Elapsed time: 0.20402s