Skip to main content

Django authentication against WSO2 Identity Server

Project description

django_wso2is

A Django application that enables authentication against a remote WSO2 Identity Server.

Installation

pip install django-wso2is-auth

Getting started

  1. In your Django project's settings file, change the Django AUTHENTICATION_BACKENDS to:
AUTHENTICATION_BACKENDS = ['django_wso2is.backends.WSO2isAuthenticationBackend',]
  1. If you are using Rest framework and want to authenticate API requests against WSO2 Identity server:
REST_FRAMEWORK = {
    # ... other rest framework settings.
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'django_wso2_is.authentication.BearerAuthentication'
    ],
}
  1. Lastly, you need to provide some settings:
WSO2IS_CONFIG = {
    # The URL of your WSO2 identity server
    "SERVER_URL": "<str>",
    # The "OAuth Client Key" of your service provider
    "OAUTH_CLIENT_ID": "<str>",
    # The "OAuth Client Secret" of your service provider
    "OAUTH_SECRET_KEY": "<str>",
    # The username of the service provider admin
    "ADMIN_USER_USERNAME": "<str>",
    # The password of the service provider admin
    "ADMIN_USER_SECRET_KEY": "<str>",
    # The name of the admin role for the client (e.g. `Application/Administration`)
    "CLIENT_ADMIN_ROLE": "<str>",
    # The group's admin role name
    "GROUP_ADMIN_ROLE": "<str>",
    # Whether the validity of the server's SSL certificate should be validated.
    # default=`False`. WARNING: This should be `True` in production environments.
    "VERIFY_SSL": False,
    # When a user is successfully authenticated with the WSO2 server this user
    # will be created or updated in the local database. This search is based on `DJANGO_USER_LOOKUP_FIELD`. 
    # This field is optional (default=None), and in such cases the lookup is performed based on the `USERNAME` field
    # of the auth user model, which by default corresponds to the `username` field. 
    # For instance, if you want this lookup to be based on email 
    # you can specify `"DJANGO_USER_LOOKUP_FIELD": "email"`
    DJANGO_USER_LOOKUP_FIELD: None,
    # This dictionary makes the mapping between attributes of the local user with attributes of the remote user.
    # This field is optional (default=None), but it is HIGHLY recommended you customize it. By default only `username` get's mapped
    # to WSO2's attribute "userName". A more detailed example of how to customize this field will be presented below.
    ATTRIBUTE_MAPPING: {"username": "userName"} # dict in format 'local_attribute' : 'remote_attribute'
}

You are all set!

Advanced usage

1. Customizing attribute mapping

As previously mentioned, only the mapping between the username field is done. Let's say you have the following django User model:

class MyUser(AbstractBaseUser):
  # first_name, last_name and email exist by default in django.contrib.auth user model
  # Now we specify new custom fields to save the user's organization and phone number from WSO2 identity server
  user_organization = models.CharField(max_length=255,null=True, blank=True)
  phone_number = models.CharField(max_length=255, null=True, blank=True)
  external_id = models.CharField(max_length=255, null=True, blank=True)
  

First we can inspect the JSON response from WSO2 to see the user information that is being returned to django. (This assumes you already configured everything else)

# Inside django's shell (python manage.py shell)
from django_wso2is import Token
from pprint import pprint

token = Token.from_credentials("sample-username", "sample-password")
pprint(token.user_info)

You should get something like this:

{'emails': ['sample-email@gmail.com'],
 'id': '6b15e727-6b52-4d15-a9c9-b166a0439aa1',
 'meta': {'created': '2023-01-19T10:44:51.563609Z',
          'lastModified': '2023-01-19T15:52:48.282703Z',
          'location': 'https://sample-wso2is-server:9443/scim2/Users/6b15e727-6b52-4d15-a9c9-b166a0439aa1',
          'resourceType': 'User'},
 'name': {'familyName': 'John', 'givenName': 'Doe'},
 'phoneNumbers': [{'type': 'mobile', 'value': '914420876'}],
 'roles': [{'type': 'default',
            'value': 'Internal/everyone,Application/Administração'},
           {'$ref': 'https://sample-wso2is-server:9443/scim2/Roles/f0da2c12-f4c5-49dd-81f6-5077dfdd98d1',
            'display': 'Application/Administration',
            'value': 'f0da2c12-f4c5-49dd-81f6-5077dfdd98d1'},
           {'$ref': 'https://sample-wso2is-server:9443/scim2/Roles/75ace894-dc8b-495f-8438-60a066d84966',
            'display': 'everyone',
            'value': '75ace894-dc8b-495f-8438-60a066d84966'}],
 'schemas': ['urn:ietf:params:scim:schemas:core:2.0:User',
             'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User'],
 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User': {'country': 'Portugal',
                                                                'organization': 'My organization'},
 'userName': 'sample-username'}

To accommodate these additional fields the attribute mapping will be:

"ATTRIBUTE_MAPPING": {
    "username": "userName",
    "email": "emails[0]", # [0] because WSO2 returns the key "emails" as a list
    "phone_number": "phoneNumbers[0].value", # [0].value because WSO2 returns the key "phoneNumbers" as a list of objects with key "value"
    "first_name": "name.givenName", # .givenName because WSO2 returns nested "name" object
    "last_name": "name.familyName", # .familyName for the same reason as before
    "external_id": "id", # Simple attribute mapping
},

2. Post authentication signal

If you want to hook additional behaviour after an user has been authenticated, you can simply attach to the user_authenticated signal. For instance, let's say we want to also get/create and associate with the user a Group object based on the user WSO2 roles.

yourapp/signals.py
from django.contrib.auth.models import Group
from django.dispatch import receiver
from django_wso2is.signals import user_authenticated
from django_wso2is import Token

@receiver(user_authenticated)
def wso2_user_authenticated(sender, user, token: Token, **kwargs):
   # Get user roles
   roles: list[str] = [role for role in token.client_roles]
   for role in roles:
      group, _ = Group.objects.get_or_create(name=role)
      user.groups.add(group)
      user.save()
       

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-wso2is-auth-0.0.1.tar.gz (13.7 kB view details)

Uploaded Source

Built Distribution

django_wso2is_auth-0.0.1-py3-none-any.whl (13.8 kB view details)

Uploaded Python 3

File details

Details for the file django-wso2is-auth-0.0.1.tar.gz.

File metadata

  • Download URL: django-wso2is-auth-0.0.1.tar.gz
  • Upload date:
  • Size: 13.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for django-wso2is-auth-0.0.1.tar.gz
Algorithm Hash digest
SHA256 842b3affde2139fbe84cab0f3c80ba565e9a3f768ddaef37c08150f2bb6395ed
MD5 0e7a5cc960c8247acd7dc944518082d4
BLAKE2b-256 db4cb6e4805c367de8ec98db58722b2d04d6446171d76861daa429df21835ee8

See more details on using hashes here.

Provenance

File details

Details for the file django_wso2is_auth-0.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for django_wso2is_auth-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6b533e32b40b1f2847b5c9aead45bc271c26444d69d8a31677bd635be075e883
MD5 1e1812072be8f354436181eb35bff004
BLAKE2b-256 05882ee84dedbb87b5ffb56c6650a7880a43c18b557bf169dfae02137f26d1e6

See more details on using hashes here.

Provenance

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page