DBMI Client is an app to provide common functionality needed to integrate a client application with DBMI services. DBMI services offer features like centralized authentication, custom authorizations, user management, and more. Installing this app provides view decorators and API authentication/authorization classes to easily utilize the DBMI services for your Django application.
1. Install django-dbmi-client (not available yet)
pip install django-dbmi-client==0.1.0
2. Add "dbmi_client" to your INSTALLED_APPS setting like this
INSTALLED_APPS = [ ... 'dbmi_client', ]
3a. Configure settings for your application (dev or prod)
# Example 'prod' or 'dev' configuration DBMI_CLIENT_CONFIG = { 'CLIENT': 'my-client', # This string is used to identify your app in DBMI services 'ENVIRONMENT': 'prod|dev', # The environment setting determines the URLs of DBMI services to use 'AUTHZ_ADMIN_GROUP': 'my-client-admin', # This optional setting will give admin permissions to users with this group 'AUTHZ_ADMIN_PERMISSION: 'admin', # This optional setting will grant a user staff/superuser status if this permissions exists for them 'JWT_COOKIE_DOMAIN': '.my-client.hms.harvard.edu', # This setting must be a subdomain of your app's public domain 'AUTH0_CLIENT_ID': 'xxxxxxxxxxxxxxx', # An Auth0 client to authenticate for 'AUTH0_TENANT': 'my-client, # The Auth0 tenant identifier that your Auth0 client is registered in 'AUTHN_TITLE': 'My Client', # A title of your app to be shown on the login screen 'AUTHN_ICON_URL': 'https://authentication.hms.harvard.edu/static/hms_shield.png', # A square image to be shown on the login screen 'DRF_OBJECT_OWNER_KEY': 'user' # If using DBMI Client DRF permissions, specify the lookup attribute by which object ownership should be referenced }
3b. If running a local or test environment, configurations might look as follows
# Example local, testing, etc configuration # You must supply the URLs of the three services. This library will throw an exception if those are not defined. # To enable JWT claims inspection for groups/roles/permissions, you must also define the JWT claims namespace # AUTHN_URL renders the login page so this must be resolvable by the client's browser, e.g. 'localhost:8001' if running in Docker (ensure the port is exposed) # AUTHZ_URL and REG_URL are API only so in a Docker environment, for example, you would use their container name or defined domain name DBMI_CLIENT_CONFIG = { 'CLIENT': 'my-client', # This string is used to identify your app in DBMI services 'ENVIRONMENT': 'local', # The environment setting determines the URLs of DBMI services to use 'AUTHN_URL': 'http://localhost:8001', # Must be resolvable by client browser 'AUTHZ_URL': 'http://dbmiauthz:8002', # Must be resolvable from other services 'REG_URL': 'http://dbmireg:8005', # Must be resolvable from other services 'JWT_AUTHZ_NAMESPACE': 'http://local.authorization.dbmi.hms.harvard.edu', The namespace for JWT claims authorizations 'AUTHZ_ADMIN_GROUP': 'my-client-admin', # This optional setting will give admin permissions to users with this group 'AUTHZ_ADMIN_PERMISSION: 'admin', # This optional setting will grant a user staff/superuser status if this permissions exists for them 'JWT_COOKIE_DOMAIN': '.my-client.hms.harvard.edu', # This setting must be a subdomain of your app's public domain 'AUTH0_CLIENT_ID': 'yyyyyyyyyyyyyyyy', # An Auth0 client to authenticate for 'AUTH0_TENANT': 'my-client, # The Auth0 tenant identifier that your Auth0 client is registered in 'AUTHN_TITLE': 'My Client', # A title of your app to be shown on the login screen 'AUTHN_ICON_URL': 'https://authentication.hms.harvard.edu/static/hms_shield.png', # A square image to be shown on the login screen 'DRF_OBJECT_OWNER_KEY': 'user' # If using DBMI Client DRF permissions, specify the lookup attribute by which object ownership should be referenced }
4. If your site requires the User model for authenticated users, be sure to add the DBMI model backend
AUTHENTICATION_BACKENDS = ['dbmi_client.authn.DBMIModelAuthenticationBackend', ... ]
When a user visits your site, a decorated view will automatically send them to the login service if they have not yet authenticated. To limit a Django view to authenticated users:
from dbmi_client.auth import dbmi_user from dbmi_client.authn import get_jwt_email @dbmi_user def secure_view(self, request, *args, **kwargs): # The current user's email can be retrieved email = get_jwt_email(request) ...
If an authenticated user visits an admin-only view without the proper permissions, a Django PermissionDenied exception is raised. To limit a Django view to admins only
from dbmi_client.auth import dbmi_user from dbmi_client.authn import get_jwt_email @dbmi_admin def ultra_secure_view(self, request, *args, **kwargs): # The current admin user's email can be retrieved admin_email = get_jwt_email(request) ...
To limit a view to users with your a custom app permission
from dbmi_client.auth import dbmi_permission from dbmi_client.authn import get_jwt_email @dbmi_permission('my_permission') def secure_view(self, request, *args, **kwargs): # The current user's email can be retrieved email = get_jwt_email(request) ...
To limit a view to users with a permission on a custom item or subitem
from dbmi_client.auth import dbmi_item_permission from dbmi_client.authn import get_jwt_email @dbmi_item_permission('profile.image', 'my_item_permission') def secure_item_view(self, request, *args, **kwargs): # The current user's email can be retrieved email = get_jwt_email(request) ...
If your application utilizes the Django Rest Framework library for API management, consider the following authentication and permission classes for controlling access.
To protect an Django-rest-framework API, you can use the built-in authentication and permission classes (this example allows users whose email is present in the object being queried or admins and users with MANAGE permission)
from rest_framework import viewsets from dbmi_client.authn import DBMIUser from dbmi_client.authz import DBMIOwnerPermission, DBMIManageOrOwnerPermission class MyAPIViewSet(viewsets.ModelViewSet): """ API View for UserPermission Model. """ authentication_classes = (DBMIUser, ) permission_classes = (DBMIOwnerPermission, DBMIManageOrOwnerPermission ) def list(self, request, *args, **kwargs): # Get user email email = request.user ...
Or, a restricted API where the user model is enabled for authenticated users
from rest_framework import viewsets from dbmi_client.authn import DBMIModelUser from dbmi_client.authz import DBMIOwnerPermission, DBMIManageOrOwnerPermission class MyAPIViewSet(viewsets.ModelViewSet): """ API View for UserPermission Model. """ authentication_classes = (DBMIModelUser, ) permission_classes = (DBMIOwnerPermission, DBMIManageOrOwnerPermission ) def list(self, request, *args, **kwargs): # Get user instance user = request.user # Get their email email = user.email ...
TBD