Welcome to django-helmholtz-aai’s documentation!
A generic Django app to login via Helmholtz AAI
Features
Features include
ready-to-use views for authentification against the Helmholtz AAI
a new
HelmholtzUser
class based upon djangosUser
model and derived from the Helmholtz AAIa new
HelmholtzVirtualOrganization
class based upon djangosGroup
model and derived from the Helmholtz AAIseveral signals to handle the login of Helmholtz AAI user for your specific application
automated synchronization of VOs of on user authentification
Get started by following the installation instructions and have a look into the Configuration options.
Installation
To install the django-helmholtz-aai package for your Django project, you need to follow three steps:
Installation from PyPi
The recommended way to install this package is via pip and PyPi via:
pip install django-helmholtz-aai
or, if you are using pipenv, via:
pipenv install django-helmholtz-aai
Or install it directly from the source code repository on Gitlab via:
pip install git+https://codebase.helmholtz.cloud/hcdc/django/django-helmholtz-aai.git
The latter should however only be done if you want to access the development versions (see Installation for development).
Register your OAuth-Client at the Helmholtz AAI
To install this app in your Django application, you first need to register an OAuth client for the Helmholtz AAI. In short, this works the following way
head over to https://login.helmholtz.de
make sure that you are logged out at the Helmholtz AAI
click No Acccount? Sign up on the top-right on , and then by
click on Oauth2/OIDC client Registration
register your client. For more information on the necessary fields, see [client-registration] in the Helmholtz AAI docs.
Note
Make sure that you enter the correct return URL which should be something like
https://<link-to-your-django-website>/helmholtz-aai/auth/
.The
/helmholtz-aai/
part is determined by the settings in your URL configuration down below. But you can also change this URL or add more once your client has been approved at https://login.helmholtz.de/oauthhome/
Install the Django App for your project
To use the django-helmholtz-aai package in your Django project,
you need to add the app to your INSTALLED_APPS
, configure your urls.py
, run
the migration, add a login button in your templates. Here are the step-by-step
instructions:
Add the
django_helmholtz_aai
app to yourINSTALLED_APPS
in your projects urlconf (see
ROOT_URLCONF
), add includedjango_helmholtz_aai.urls
via:from django.urls import include, path urlpatterns += [ path("helmholtz-aai/", include("django_helmholtz_aai.urls")), ]
Note that the
helmholtz-aai/
-part has to match what you entered when you registered your client (see above).Run
python manage.py migrate
to add models to your databaseAdd the link to the login view in one of your templates (e.g. in the login.html template from your
LOGIN_URL
), e.g. via{% load helmholtz_aai %} <a href="{% helmholtz_login_url %}"> login via Helmholtz AAI </a>
Note
To tell the user why he or should could not login, we are also using djangos
messaging
framework. Seedjango.contrib.messages
. To display these messages, you should add something in your django template, e.g. something like{% if messages %} <ul class="messages"> {% for message in messages %} <li{% if message.tags %} class="{{ message.tags }}"{% endif %}> {{ message }} </li> {% endfor %} </ul> {% endif %}
Make sure to set the
HELMHOLTZ_CLIENT_ID
andHELMHOLTZ_CLIENT_SECRET
settings in your settings.py with the username and password you specified during the client registration.
That’s it! For further adaption to you Django project, please head over to the
Configuration options. You can also have a look into the testproject
in the source code repository for a possible implementation.
Installation for development
Please head over to our contributing guide for installation instruction for development.
References
Configuration options
Configuration settings
Most important settings
A string of lists specifying which VOs are allowed to log into the website. |
|
Client id for the Helmholtz AAI |
|
Client secret for the Helmholtz AAI |
Two settings are necessary to use this package, this is the
HELMHOLTZ_CLIENT_ID
and the HELMHOLTZ_CLIENT_SECRET
that
you specified during the OAuth-Client registration (see Register your OAuth-Client at the Helmholtz AAI).
By default, the website allows all users to login and create an account via the
Helmholtz AAI. This if often not desired and you can modify this with the
HELMHOLTZ_ALLOWED_VOS
setting, e.g. something like:
HELMHOLTZ_ALLOWED_VOS = [
"urn:geant:helmholtz.de:group:hereon#login.helmholtz.de",
]
in your settings.py
.
Other settings
Further settings can be used to specify how to connect to the helmholtz AAI and how to interpret the userinfo of the Helmholtz AAI.
openid configuration url of the Helmholtz AAI |
|
Regular expressions for VOs that are allowed to login to the website. |
|
Keyword argument for the oauth client to connect with the helmholtz AAI. |
|
Flag to enable/disable user account creation via the Helmholtz AAI. |
|
Allow duplicated emails for users in the website |
|
Flag whether existing user accounts should be mapped |
|
Flag whether usernames should be updated from the Helmholtz AAI |
|
Username fields in the userinfo |
|
The backend that is used to login the user. |
|
Root url for the django application |
Customizing the login
If you are using the Helmholtz AAI, you likely want to combine it with the permission system of your Django project. You may want to set the is_staff attribute for users of a specific VO, or perform additional actions when a user logged in for the first time (e.g. send a welcome mail), enters or leaves a VO.
To perfectly adjust the django-helmholtz-aai framework to your projects need, you have two choices:
connect to the signals of the
signals
module, see Configuration via Signalssubclass the
HelmholtzAuthentificationView
view, see Customization via the HelmholtzAuthentificationView
The signals are the recommended way as they provide a more stable interface.
As the django-helmholtz-aai is very new, we cannot guarantee that there
won’t be breaking changes in the
HelmholtzAuthentificationView
.
Configuration via Signals
The signals
module defines various signal that are
fired on different events:
Signal that is fired when a user has been created via the Helmholtz AAI |
|
Signal that is fired when a user logs in via the Helmholtz AAI |
|
Signal that is fired when a user receives an update via the Helmholtz AAI |
|
Signal that is fired if a new Virtual Organization has been created |
|
Signal that is fired if a Helmholtz AAI user enteres a VO |
|
Signal that is fired if a Helmholtz AAI user left a VO |
The purpose of these signals should be pretty much self-explanatory.
Examples
Suppose you want users of a specific VO to become superusers. Then you can do
something like this using the aai_vo_entered
and
aai_vo_left
signals:
from django.dispatch import receiver
from django_helmholtz_aai import models, signals
@receiver(signals.aai_vo_entered)
def on_vo_enter(
sender,
vo: models.HelmholtzVirtualOrganization,
user: models.HelmholtzUser,
**kwargs,
):
vo_id = "urn:geant:helmholtz.de:group:hereon#login.helmholtz.de"
if vo.eduperson_entitlement == vo_id:
user.is_superuser = True
user.save()
@receiver(signals.aai_vo_left)
def on_vo_leave(
sender,
vo: models.HelmholtzVirtualOrganization,
user: models.HelmholtzUser,
**kwargs,
):
vo_id = "urn:geant:helmholtz.de:group:hereon#login.helmholtz.de"
if vo.eduperson_entitlement == vo_id:
user.is_superuser = False
user.save()
Let’s say you want to display a message in the frontend when a user logged in
for the first time. Here you can use the aai_user_created
signal:
from django.contrib import messages
from django_helmholtz_aai import models, signals
@receiver(signals.aai_user_created)
def created_user(
sender,
user: models.HelmholtzUser,
request,
**kwargs,
):
messages.add_message(
request, messages.success, f"Welcome on board {user}!"
)
Customization via the HelmholtzAuthentificationView
Warning
Please bear in mind that this python package is still very new and we
cannot guarantee that there won’t be breaking changes in the
HelmholtzAuthentificationView
class.
Another way to customize the login is via the
HelmholtzAuthentificationView
. Your
starting point should be the following two methods, one for checking the
permissions and one for performing the request:
|
Login the Helmholtz AAI user and update the data. |
Check if the user has permission to login. |
For a more fine-grained control of the authentification (such as user creation or update), you can make use of the following methods and reimplement to your needs.
|
Create a Django user for a Helmholtz AAI User. |
|
Login the Helmholtz AAI user to the Django Application. |
Synchronize the memberships in the virtual organizations. |
|
Update the user from the userinfo provided by the Helmholtz AAI. |
Example
Let’s say you want to approve users before you let them login to the website.
One possibility is, to create a custom model with reference to a user and
reimplement the
django_helmholtz_aai.views.HelmholtzAuthentificationView.login_user()
.
Your custom app that reimplements this view then might look like
models.py
from django.db import models from django_helmholtz_aai.models import HelmholtzUser class HelmholtzUserReview(models.Model): """A review of a helmholtz user""" class ReviewStatus(models.TextChoices): accepted = "accepted" rejected = "rejected" user = models.OneToOneField(HelmholtzUser, on_delete=models.CASCADE) review_status = models.CharField( choices=ReviewStatus.choices, blank=True, null=True )
views.py
from django.contrib import messages from django_helmholtz_aai.views import HelmholtzAuthentificationView from django_helmholtz_aai.models import HelmholtzUser from .models import HelmholtzUserReview class CustomHelmholtzAuthentificationView(HelmholtzAuthentificationView): def login_user(self, user: HelmholtzUser): review = HelmholtzUserReview.objects.get_or_create(user=user)[0] if ( review.review_status == HelmholtzUserReview.ReviewStatus.accepted ): super().login_user(user) elif ( review.review_status == HelmholtzUserReview.ReviewStatus.rejected ): messages.add_message( self.request, messages.error, f"Your account creation request has been rejected.", ) else: messages.add_message( self.request, messages.success, f"Your account creation request is currently under review.", )
urls.py
from django.urls import include, path from .views import CustomHelmholtzAuthentificationView urlpatterns = [ path( "helmholtz-aai/auth/", CustomHelmholtzAuthentificationView.as_view(), ), path("helmholtz-aai/", include("django_helmholtz_aai.urls")), ]
Common problems
In this document, we collect common problems and questions. If you cannot find your issue documented in here, you should create an issue at the source code repository and we’ll try to find a solution and update this document with your problem.
Mapping to existing accounts
When you add this app to an existing django project, you might already have
accounts in your database. If this is the case, you should have a look into
the HELMHOLTZ_MAP_ACCOUNTS
configuration variable.
Mapping of multiple accounts
One user can have multiple accounts in the Helmholtz AAI. You can, for instance create an account via GitHub and through your home institution. Both accounts can have the same email address. The Helmholtz AAI however treats them as separate accounts and both have different unique IDs and belong to different VOs. As we use the ID for mapping a user in the Helmholtz AAI to a user in Django, and we synchronize the VOs of the user in the Helmholtz AAI, we have to distinguish the two accounts as well.
As an example: One user can register two accounts in the Helmholtz AAI:
one via Google
one via GitHub but with the same Google-Mail
Then the user logs in to your project via the Helmholtz AAI and his Google account. If the user then logs in to your project via GitHub, this creates a new account, independent from the first one.
Usually you do not want to have this behaviour as both user-accounts will
then have the same email-address. Therefore this is disabled by default.
However, you can allow the creation of multiple user accounts using the
HELMHOLTZ_EMAIL_DUPLICATES_ALLOWED
configuration variable.
Too many VOs
Each time a user account is created, we create the VOs that the user
participates in. These VOs remain, even if one deletes the user account. To
remove these empty VOs, we therefore added the
remove_empty_vos
management
command that you can use via python manage.py remove_empty_vos
. Or you call
it directly from python, e.g. via:
from django_helmholtz_aai import models
models.HelmholtzVirtualOrganization.objects.remove_empty_vos()
API Reference
App settings
This module defines the settings options for the django_helmholtz_aai
app.
Data:
openid configuration url of the Helmholtz AAI |
|
A string of lists specifying which VOs are allowed to log into the website. |
|
Regular expressions for VOs that are allowed to login to the website. |
|
Client id for the Helmholtz AAI |
|
Keyword argument for the oauth client to connect with the helmholtz AAI. |
|
Client secret for the Helmholtz AAI |
|
Flag to enable/disable user account creation via the Helmholtz AAI. |
|
Allow duplicated emails for users in the website |
|
Flag whether existing user accounts should be mapped |
|
Flag whether usernames should be updated from the Helmholtz AAI |
|
Username fields in the userinfo |
|
The backend that is used to login the user. |
|
Root url for the django application |
- django_helmholtz_aai.app_settings.HELMHOLTZ_AAI_CONF_URL: str = 'https://login.helmholtz.de/oauth2/.well-known/openid-configuration'
openid configuration url of the Helmholtz AAI
Can also be overwritten using the
HELMHOLTZ_CLIENT_KWS
setting.
- django_helmholtz_aai.app_settings.HELMHOLTZ_ALLOWED_VOS: list[str] = []
A string of lists specifying which VOs are allowed to log into the website.
By default, this is an empty list meaning that each and every user is allowed to login via the Helmholtz AAI. Each string in this list will be interpreted as a regular expression and added to
HELMHOLTZ_ALLOWED_VOS_REGEXP
Examples
Assume you only want to allow people from the Hereon VO to login to the website. Then you can add the following to your
settings.py
:HELMHOLTZ_ALLOWED_VOS = [ "urn:geant:helmholtz.de:group:hereon#login.helmholtz.de", ]
or use a regex, e.g. something like:
HELMHOLTZ_ALLOWED_VOS = [ r".*helmholtz.de:group:hereon#login.helmholtz.de", ]
[]
- django_helmholtz_aai.app_settings.HELMHOLTZ_ALLOWED_VOS_REGEXP: list[Pattern] = []
Regular expressions for VOs that are allowed to login to the website.
This attribute is created from the
HELMHOLTZ_ALLOWED_VOS
setting.[]
- django_helmholtz_aai.app_settings.HELMHOLTZ_CLIENT_ID: str = None
Client id for the Helmholtz AAI
This is the username you use to login at https://login.helmholtz.de/oauthhome/, see [client-registration] for how to create a client
See also
- django_helmholtz_aai.app_settings.HELMHOLTZ_CLIENT_KWS = {'client_id': None, 'client_kwargs': {'scope': 'profile email eduperson_unique_id'}, 'client_secret': None, 'server_metadata_url': 'https://login.helmholtz.de/oauth2/.well-known/openid-configuration'}
Keyword argument for the oauth client to connect with the helmholtz AAI.
Can also be overwritten using the
HELMHOLTZ_CLIENT_KWS
setting.{ 'client_id': None, 'client_kwargs': {'scope': 'profile email eduperson_unique_id'}, 'client_secret': None, 'server_metadata_url': 'https://login.helmholtz.de/oauth2/.well-known/openid-configuration', }
- django_helmholtz_aai.app_settings.HELMHOLTZ_CLIENT_SECRET: str = None
Client secret for the Helmholtz AAI
This is the password you use to login at https://login.helmholtz.de/oauthhome/, see[client-registration]_ for how to create a client
See also
- django_helmholtz_aai.app_settings.HELMHOLTZ_CREATE_USERS: bool = True
Flag to enable/disable user account creation via the Helmholtz AAI.
Use this flag if you want the Helmholtz AAI to create users when they login for the first time. This is enabled by default.
If you disable this setting, you should enable the
HELMHOLTZ_MAP_ACCOUNTS
, otherwise nobody will be allowed to login via the Helmholtz AAI.
- django_helmholtz_aai.app_settings.HELMHOLTZ_EMAIL_DUPLICATES_ALLOWED: bool = False
Allow duplicated emails for users in the website
This setting controls if a user can register with multiple accounts from the Helmholtz AAI. An email is not unique in the AAI, but this might be desired in the Django application. This option prevents a user to create an account if the email has already been taken by some other user from the Helmholtz AAI
- django_helmholtz_aai.app_settings.HELMHOLTZ_MAP_ACCOUNTS: bool = False
Flag whether existing user accounts should be mapped
Use this flag, if you want to map existing user accounts by their email address.
Examples
Suppose you just install django-helmholtz-aai to your already existing Django project and there exists already a user with the mail
user@example.com
. If this user now logs into your project, it would create a newHelmholtzUser
which is probably not desired. To overcome this, you can set theHELMHOLTZ_MAP_ACCOUNTS
configuration variable toTrue
and theHelmholtzUser
will be mapped to the already existingUser
- django_helmholtz_aai.app_settings.HELMHOLTZ_UPDATE_USERNAME: bool = True
Flag whether usernames should be updated from the Helmholtz AAI
Use this setting to control, whether the usernames are updated automatically on every login. If this is true, we will check the fields specified in the
HELMHOLTZ_USERNAME_FIELDS
setting variable on every login and update the username accordingly. If the user, for instance, changes his or herpreferred_username
on https://login.helmholtz.de/, we will update the username of the django user as well (ifpreferred_username
is in theHELMHOLTZ_USERNAME_FIELDS
).
- django_helmholtz_aai.app_settings.HELMHOLTZ_USERNAME_FIELDS: list[str] = ['preferred_username', 'eduperson_unique_id']
Username fields in the userinfo
This setting determines how to get the username. By default, we use the
preferred_username
that the user can configure at https://login.helmholtz.de/oauthhome. If this is already taken, we use the uniqueeduperson_unique_id
from the Helmholtz AAI. You can add more variables to this list but you should always include theeduperson_unique_id
to make sure you do not end up with duplicated usernames.Examples
You can use the email instead of the
preferred_username
via:HELMHOLTZ_USERNAME_FIELDS = ["email", "eduperson_unique_id"]
['preferred_username', 'eduperson_unique_id']
- django_helmholtz_aai.app_settings.HELMHOLTZ_USER_BACKEND: str = 'django.contrib.auth.backends.ModelBackend'
The backend that is used to login the user. By default, we use the Django default, i.e.
django.contrib.auth.backends.ModelBackend
- django_helmholtz_aai.app_settings.ROOT_URL: str | None = None
Root url for the django application
The login requires a redirect url that is derived from the view with the name
"django_helmholtz_aai:auth"
and the protocoll and host name of your application. In case your application is behind a reverse proxy that does not forward correct host or protocoll, you can use this setting to set the URL manually.Examples
If this app is included via
path("helmholtz-aai/", include("django_helmholtz_aai.urls"))
in your url-config and available athttps://example.com/helmholtz-aai/
, then theROOT_URL
in yoursettings.py
should behttps://example.com
Signals
This module defines the signals that are fired by the views in
django_helmholtz_aai.views
module.
- django_helmholtz_aai.signals.aai_user_created = <django.dispatch.dispatcher.Signal object>
Signal that is fired when a user has been created via the Helmholtz AAI
This signal is called by the
HelmholtzAuthentificationView
when a new user has been created. Subscribers to this signal can accept the following parameters.- Parameters:
sender (Type[django_helmholtz_aai.models.HelmholtzUser]) – The type who sent the signal (implemented for reasons of convention)
user (django_helmholtz_aai.models.HelmholtzUser) – The new user that has been created
request (Request) – The request holding the session of the user.
userinfo (Dict[str, Any]) – The userinfo as obtained from the Helmholtz AAI
- django_helmholtz_aai.signals.aai_user_logged_in = <django.dispatch.dispatcher.Signal object>
Signal that is fired when a user logs in via the Helmholtz AAI
This signal is called by the
HelmholtzAuthentificationView
when a user logged in via the Helmholtz AAI. Subscribers to this signal can accept the following parameters.- Parameters:
sender (Type[django_helmholtz_aai.models.HelmholtzUser]) – The type who sent the signal (implemented for reasons of convention)
user (django_helmholtz_aai.models.HelmholtzUser) – The user who just logged in
request (Request) – The request holding the session of the user.
userinfo (Dict[str, Any]) – The userinfo as obtained from the Helmholtz AAI
- django_helmholtz_aai.signals.aai_user_updated = <django.dispatch.dispatcher.Signal object>
Signal that is fired when a user receives an update via the Helmholtz AAI
This signal is called by the
HelmholtzAuthentificationView
when a user who does already have an account gets updated, e.g. because the email of thepreferred_username
changed in the Helmholtz AAI. Subscribers to this signal can accept the following parameters.- Parameters:
sender (Type[django_helmholtz_aai.models.HelmholtzUser]) – The type who sent the signal (implemented for reasons of convention)
user (django_helmholtz_aai.models.HelmholtzUser) – The user that is supposed to be updated
request (Request) – The request holding the session of the user.
userinfo (Dict[str, Any]) – The userinfo as obtained from the Helmholtz AAI
- django_helmholtz_aai.signals.aai_vo_created = <django.dispatch.dispatcher.Signal object>
Signal that is fired if a new Virtual Organization has been created
This signal is called by the
HelmholtzAuthentificationView
when a new virtual organization has been created from the Helmholtz AAI because a of this VO registered on the website. Subscribers to this signal can accept the following parameters.- Parameters:
sender (Type[django_helmholtz_aai.models.HelmholtzUser]) – The type who sent the signal (implemented for reasons of convention)
user (django_helmholtz_aai.models.HelmholtzUser) – The user that is about to become a member of the new VO
vo (django_helmholtz_aai.models.HelmholtzVirtualOrganization) – The VO that has just been created
request (Request) – The request holding the session of the user.
userinfo (Dict[str, Any]) – The userinfo as obtained from the Helmholtz AAI
to_update (Dict[str, Any]) – A mapping from field name to value for the fields that have changed during the update.
- django_helmholtz_aai.signals.aai_vo_entered = <django.dispatch.dispatcher.Signal object>
Signal that is fired if a Helmholtz AAI user enteres a VO
This signal is called by the
HelmholtzAuthentificationView
when a user enters a virtual organization as the user is a member in the Helmholtz AAI. Subscribers to this signal can accept the following parameters.- Parameters:
sender (Type[django_helmholtz_aai.models.HelmholtzUser]) – The type who sent the signal (implemented for reasons of convention)
user (django_helmholtz_aai.models.HelmholtzUser) – The user that entered the VO.
vo (django_helmholtz_aai.models.HelmholtzVirtualOrganization) – The VO that the user has just entered
request (Request) – The request holding the session of the user.
userinfo (Dict[str, Any]) – The userinfo as obtained from the Helmholtz AAI
- django_helmholtz_aai.signals.aai_vo_left = <django.dispatch.dispatcher.Signal object>
Signal that is fired if a Helmholtz AAI user left a VO
This signal is called by the
HelmholtzAuthentificationView
when a user leaves a virtual organization as the user is not anymore a member in the Helmholtz AAI. Subscribers to this signal can accept the following parameters.- Parameters:
sender (Type[django_helmholtz_aai.models.HelmholtzUser]) – The type who sent the signal (implemented for reasons of convention)
user (django_helmholtz_aai.models.HelmholtzUser) – The user that entered the VO.
vo (django_helmholtz_aai.models.HelmholtzVirtualOrganization) – The VO that the user has just entered
request (Request) – The request holding the session of the user.
userinfo (Dict[str, Any]) – The userinfo as obtained from the Helmholtz AAI
URL config
URL patterns of the django-helmholtz-aai to be included via:
from django.urls import include, path
urlpatters = [
path("helmholtz-aai/", include("django_helmholtz_aai.urls")),
]
Data:
App name for the django-helmholtz-aai to be used in calls to |
|
urlpattern for the Helmholtz AAI . |
- django_helmholtz_aai.urls.app_name = 'django_helmholtz_aai'
App name for the django-helmholtz-aai to be used in calls to
django.urls.reverse()
- django_helmholtz_aai.urls.urlpatterns: List[Any] = [<URLPattern 'login/' [name='login']>, <URLPattern 'auth/' [name='auth']>]
urlpattern for the Helmholtz AAI .. code-block:: JavaScript
[<URLPattern ‘login/’ [name=’login’]>, <URLPattern ‘auth/’ [name=’auth’]>]
Models
Models to mimic users and virtual organizations of the Helmholtz AAI in Django.
Models:
|
A User in the in the Helmholtz AAI. |
|
A VO in the Helmholtz AAI. |
Classes:
|
A manager for the helmholtz User. |
|
Database manager for the |
A queryset with an extra command to remove empty VOs. |
- class django_helmholtz_aai.models.HelmholtzUser(*args, **kwargs)
Bases:
User
A User in the in the Helmholtz AAI.
- Parameters:
id (AutoField) – Primary key: ID
password (CharField) – Password
last_login (DateTimeField) – Last login
is_superuser (BooleanField) – Superuser status. Designates that this user has all permissions without explicitly assigning them.
username (CharField) – Username. Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.
first_name (CharField) – First name
last_name (CharField) – Last name
email (EmailField) – Email address
is_staff (BooleanField) – Staff status. Designates whether the user can log into this admin site.
is_active (BooleanField) – Active. Designates whether this user should be treated as active. Unselect this instead of deleting accounts.
date_joined (DateTimeField) – Date joined
eduperson_unique_id (CharField) – Eduperson unique id
Relationship fields:
- Parameters:
groups (
ManyToManyField
toGroup
) – Groups. The groups this user belongs to. A user will get all permissions granted to each of their groups. (related name:user_set
)user_permissions (
ManyToManyField
toPermission
) – User permissions. Specific permissions for this user. (related name:user_set
)user_ptr (
OneToOneField
toUser
) – Primary key: User ptr (related name:helmholtzuser
)
Reverse relationships:
- Parameters:
logentry (Reverse
ForeignKey
fromLogEntry
) – All log entries of this user (related name ofuser
)
Miscellaneous:
Model Fields:
Type:
CharField
Type:
OneToOneField
toUser
Attributes:
Internal field, use
user_ptr
instead.- exception DoesNotExist
Bases:
DoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- eduperson_unique_id
Type:
CharField
Eduperson unique id
A wrapper for a deferred-loading field. When the value is read from this
- objects = <django_helmholtz_aai.models.HelmholtzUserManager object>
- user_ptr
Type:
OneToOneField
toUser
Primary key: User ptr (related name:
helmholtzuser
)Accessor to the related object on the forward side of a one-to-one relation.
In the example:
class Restaurant(Model): place = OneToOneField(Place, related_name='restaurant')
- class django_helmholtz_aai.models.HelmholtzUserManager(*args, **kwargs)
Bases:
UserManager
A manager for the helmholtz User.
Methods:
create_aai_user
(userinfo)Create a user from the Helmholtz AAI userinfo.
- create_aai_user(userinfo)
Create a user from the Helmholtz AAI userinfo.
- class django_helmholtz_aai.models.HelmholtzVirtualOrganization(*args, **kwargs)
Bases:
Group
A VO in the Helmholtz AAI.
- Parameters:
Relationship fields:
- Parameters:
permissions (
ManyToManyField
toPermission
) – Permissions (related name:group
)group_ptr (
OneToOneField
toGroup
) – Primary key: Group ptr (related name:helmholtzvirtualorganization
)
Reverse relationships:
- Parameters:
user (Reverse
ManyToManyField
fromUser
) – All user set of this group (related name ofgroups
)
Miscellaneous:
Attributes:
Internal field, use
group_ptr
instead.Model Fields:
Type:
CharField
Type:
OneToOneField
toGroup
- exception DoesNotExist
Bases:
DoesNotExist
- exception MultipleObjectsReturned
Bases:
MultipleObjectsReturned
- eduperson_entitlement
Type:
CharField
Eduperson entitlement
A wrapper for a deferred-loading field. When the value is read from this
- group_ptr
Type:
OneToOneField
toGroup
Primary key: Group ptr (related name:
helmholtzvirtualorganization
)Accessor to the related object on the forward side of a one-to-one relation.
In the example:
class Restaurant(Model): place = OneToOneField(Place, related_name='restaurant')
- objects = <django_helmholtz_aai.models.HelmholtzVirtualOrganizationManager object>
- class django_helmholtz_aai.models.HelmholtzVirtualOrganizationManager(*args, **kwargs)
Bases:
GroupManagerFromHelmholtzVirtualOrganizationQuerySet
Database manager for the
HelmholtzVirtualOrganization
model.
- class django_helmholtz_aai.models.HelmholtzVirtualOrganizationQuerySet(model=None, query=None, using=None, hints=None)
Bases:
QuerySet
A queryset with an extra command to remove empty VOs.
Methods:
remove_empty_vos
([exclude, without_confirmation])Remove empty virtual organizations.
- remove_empty_vos(exclude: list[str] = [], without_confirmation: bool = True) list[HelmholtzVirtualOrganization]
Remove empty virtual organizations.
This method filters for virtual organizations in the queryset and removes them.
- Parameters:
exclude (list[str]) – A list of strings that will be interpreted as regular expressions. If a
eduperson_entitlement
matches any of these strings, it will not be removed.without_confirmation (bool) – If True (default), remove the VO without asking for confirmation using python’s built-in
input()
from the command-line.
- Returns:
The list of virtual organizations that have been removed
- Return type:
Views
Views of the django_helmholtz_aai app to be imported via the url config (see
django_helmholtz_aai.urls
). We define two views here: The
HelmholtzLoginView
that redirects to the Helmholtz AAI, and the
HelmholtzAuthentificationView
that handles the user login after
successful login at the Helmholtz AAI.
Classes:
|
Authentification view for the Helmholtz AAI. |
|
A login view for the Helmholtz AAI that forwards to the OAuth login. |
- class django_helmholtz_aai.views.HelmholtzAuthentificationView(**kwargs)
Bases:
PermissionRequiredMixin
,View
Authentification view for the Helmholtz AAI.
Classes:
PermissionDeniedReasons
(value)Reasons why permissions are denied to login.
Attributes:
Message templates that explain why a user is not allowed to login.
The reason why the user cannot login.
The userinfo as obtained from the Helmholtz AAI.
Methods:
apply_updates
(to_update)Apply the update to the user and send the signal.
create_user
(userinfo)Create a Django user for a Helmholtz AAI User.
create_vo
(vo_name)Create a new VO with the given name.
get
(request)Login the Helmholtz AAI user and update the data.
Get the permission denied message for a specific reason.
Return the URL to redirect to after processing a valid form.
get_user_from_email
(email)Get a user from the email
Handle the response if the permission has been denied.
Check if the user has permission to login.
join_vo
(vo)Join the given VO.
leave_vo
(vo)Leave the given VO.
login_user
(user)Login the Helmholtz AAI user to the Django Application.
Synchronize the memberships in the virtual organizations.
Update the user from the userinfo provided by the Helmholtz AAI.
- class PermissionDeniedReasons(value)
-
Reasons why permissions are denied to login.
Attributes:
the user is new and user creation is disabled by
the virtual organization is not part of
- cannot_find_user = 'cannot_find_user'
- email_changed_and_taken = 'email_changed_and_taken'
- email_exists = 'email_exists'
- email_not_verified = 'email_not_verified'
- new_user = 'new_user'
the user is new and user creation is disabled by
- vo_not_allowed = 'vo_not_allowed'
the virtual organization is not part of
- aai_user: models.HelmholtzUser
- create_user(userinfo: Dict[str, Any]) HelmholtzUser
Create a Django user for a Helmholtz AAI User.
This method uses the
create_aai_user()
to create a new user.Notes
Emits the
aai_user_created
signal
- create_vo(vo_name: str) HelmholtzVirtualOrganization
Create a new VO with the given name.
- get(request)
Login the Helmholtz AAI user and update the data.
This method logs in the aai user (or creates one if it does not exist already). Afterwards we update the user info from the information on the Helmholtz AAI using the
update_user()
andsynchronize_vos()
methods.
- get_permission_denied_message()
Get the permission denied message for a specific reason.
This method is called by the super-classes
handle_no_permission()
method.
- handle_no_permission()
Handle the response if the permission has been denied.
This reimplemented method adds the
permission_denied_message
to the messages of the request using djangos messaging framework.
- has_permission() bool
Check if the user has permission to login.
This method checks, if the user belongs to the specified
HELMHOLTZ_ALLOWED_VOS
and verifies that the email does not exist (if this is desired, seeHELMHOLTZ_EMAIL_DUPLICATES_ALLOWED
setting).
- is_new_user
- join_vo(vo: HelmholtzVirtualOrganization)
Join the given VO.
- leave_vo(vo: HelmholtzVirtualOrganization)
Leave the given VO.
- login_user(user: HelmholtzUser)
Login the Helmholtz AAI user to the Django Application.
Login is done via the top-level
django_helmholtz_aai.login()
function.Notes
Emits the
aai_user_logged_in
signal
- permission_denied_message_templates: dict[PermissionDeniedReasons, str] = {PermissionDeniedReasons.cannot_find_user: 'A user with the email {email} is not available on this website and the account creation is disabled. Please sign up or contact the website administrators.', PermissionDeniedReasons.email_changed_and_taken: 'You email in the Helmholtz AAI changed to {email}. A user with this email already exists and on this website. Please contact the website administrators.', PermissionDeniedReasons.email_exists: 'A user with the email {email} already exists.', PermissionDeniedReasons.email_not_verified: 'Your email has not been verified.', PermissionDeniedReasons.new_user: 'Your email {email} does not yet have a user account on this website and the account creation is disabled. Please sign up or contact the website administrators.', PermissionDeniedReasons.vo_not_allowed: 'Your virtual organizations are not allowed to log into this website.'}
Message templates that explain why a user is not allowed to login.
via the Helmholtz AAI. Use in the
get_permission_denied_message()
- permission_denied_reason: PermissionDeniedReasons
The reason why the user cannot login.
- synchronize_vos()
Synchronize the memberships in the virtual organizations.
This method checks the
eduperson_entitlement
of the AAI userinfo andcreates the missing virtual organizations
removes the user from virtual organizations that he or she does not belong to anymore
adds the user to the virtual organizations that are new.
Notes
As we remove users from virtual organizations, this might end up in a lot of VOs without any users. One can remove these VOs via:
python manage.py remove_empty_vos
Notes
Emits the
aai_vo_created
,aai_vo_entered
andaai_vo_left
signals.
- update_user()
Update the user from the userinfo provided by the Helmholtz AAI.
Notes
Emits the
aai_user_updated
signal
- class django_helmholtz_aai.views.HelmholtzLoginView(**kwargs)
Bases:
LoginView
A login view for the Helmholtz AAI that forwards to the OAuth login.
Methods:
get
(request)Get the redirect URL to the Helmholtz AAI.
post
(request)Reimplemented post method to call
get()
.- get(request)
Get the redirect URL to the Helmholtz AAI.
django_helmholtz_aai.management.commands package
Submodules
Remove empty virtual organizations
This command can be used to automatically remove empty virtual organizations.
usage: python manage.py remove_empty_vos [-h] [-e EXCLUDE] [-y] [-db DATABASE]
Named Arguments
- -e, --exclude
Exclude VOs that match the following pattern. This argument can be specified multiple times.
Default: []
- -y, --yes
Remove the VOs without asking for confirmation.
Default: False
- -db, --database
The Django database identifier (see settings.py), default: “default”
Default: “default”
Classes:
|
Django command to migrate the database. |
- class django_helmholtz_aai.management.commands.remove_empty_vos.Command(stdout=None, stderr=None, no_color=False, force_color=False)
Bases:
BaseCommand
Django command to migrate the database.
Methods:
add_arguments
(parser)Add connection arguments to the parser.
handle
(*args[, database, exclude, ...])Migrate the database.
Attributes:
- add_arguments(parser)
Add connection arguments to the parser.
- handle(*args, database: str = 'default', exclude: list[str] = [], without_confirmation: bool = False, **options)
Migrate the database.
- help = 'Remove virtual organization of the helmholtz AAI without users.'
django_helmholtz_aai package
Helmholtz AAI Django App
A generic Django app to login via Helmholtz AAI
Functions:
|
Login the helmholtz user into django. |
- django_helmholtz_aai.login(request, user: HelmholtzUser, userinfo: dict[str, Any])
Login the helmholtz user into django.
Notes
Emits the
aai_user_logged_in
signal
Subpackages
django_helmholtz_aai.management package
Subpackages
django_helmholtz_aai.tests package
Tests for the django_helmholtz_aai
app.
Submodules
Submodules
Admin interfaces
This module defines the django Helmholtz AAI Admin interfaces, based upon the
interfaces from django.contrib.auth.admin
.
Classes:
|
|
|
- class django_helmholtz_aai.admin.HelmholtzAAIUserAdmin(model, admin_site)
Bases:
UserAdmin
Attributes:
- list_display = ('username', 'first_name', 'last_name', 'email', 'eduperson_unique_id', 'is_staff')
- property media
- class django_helmholtz_aai.admin.HelmholtzVirtualOrganizationAdmin(model, admin_site)
Bases:
GroupAdmin
Attributes:
Methods:
users
(obj)- list_display = ('name', 'eduperson_entitlement', 'users')
- property media
- search_fields = ['name', 'eduperson_entitlement']
- users(obj: HelmholtzVirtualOrganization)
App config
App config for the django_helmholtz_aai app.
Classes:
|
Contribution and development hints
The django-helmholtz-aai project is developed by the Helmholtz Coastal Data Center (HCDC) of the Helmholtz-Zentrum Hereon. It is open-source as we believe that this package can be helpful for multiple other django applications, and we are looking forward for your feedback, questions and especially for your contributions.
If you want to ask a question, are missing a feature or have comments on the docs, please open an issue at the source code repository
If you have suggestions for improvement, please let us know in an issue, or fork the repository and create a merge request. See also Contributing in the development.
Contributing in the development
Thanks for your wish to contribute to this project!! The source code of the django-helmholtz-aai package is hosted at https://codebase.helmholtz.cloud/hcdc/django/django-helmholtz-aai.
This is an open gitlab where you can register via the Helmholtz AAI. If your home institution is not listed in the Helmholtz AAI, please use one of the social login providers, such as Google, GitHub or OrcID.
Once you created an account in this gitlab, you can fork this repository to your own user account and implement the changes.
Afterwards, please make a merge request into the main repository. If you have any questions, please do not hesitate to create an issue on gitlab and contact the maintainers of this package.
Once you created you fork, you can clone it via
git clone https://codebase.helmholtz.cloud/<your-user>/django-helmholtz-aai.git
we recommend that you change into the directory and create a virtual environment via:
cd django-helmholtz-aai
python -m venv venv
source venv/bin/activate # (or venv/Scripts/Activate.bat on windows)
and install it in development mode with the [dev]
option via:
pip install -e ./django-helmholtz-aai/[dev]
cd django-helmholtz-aai/
python manage.py migrate
which will create an sqlite-database for you.
Helpers
Shortcuts with make
There are several shortcuts available with the Makefile
in the root of
the repository. On Linux, you can execute make help
to get an overview.
Annotating licenses
If you want to create new files, you need to set license and copyright
statements correctly. We use reuse
to check that the licenses are
correctly encoded. As a helper script, you can use the script at
.reuse/add_license.py
that provides several shortcuts from
.reuse/shortcuts.yaml
. Please select the correct shortcut, namely
If you create a new python file, you should run:
python .reuse/add_license.py code <file-you-created>.py
If you created a new file for the docs, you should run:
python .reuse/add_license.py docs <file-you-created>.py
If you created any other non-code file, you should run:
python .reuse/add_license.py supp <file-you-created>.py
If you have any questions on how licenses are handled, please do not hesitate to contact the maintainers of django-helmholtz-aai.
Fixing the docs
The documentation for this package is written in restructured Text and built with sphinx and deployed on readthedocs.
If you found something in the docs that you want to fix, head over to the
docs
folder, install the necessary requirements via
pip install -r requirements.txt ../[docs]
and build the docs with
make html
(or make.bat
on windows).
The docs are then available in docs/_build/html/index.html
that you can
open with your local browser.
Implement your fixes in the corresponding .rst
-file and push them to your
fork on gitlab.
Contributing to the code
We use automated formatters (see their config in pyproject.toml
), namely
Black for standardized code formatting
blackdoc for standardized code formatting in documentation
Flake8 for general code quality
isort for standardized order in imports.
mypy for static type checking on type hints
reuse for handling of licenses
cffconvert for validating the
CITATION.cff
file.
We highly recommend that you setup pre-commit hooks to automatically run all the above tools every time you make a git commit. This can be done by running:
pre-commit install
from the root of the repository. You can skip the pre-commit checks with
git commit --no-verify
but note that the CI will fail if it
encounters any formatting errors.
You can also run the pre-commit
step manually by invoking:
pre-commit run --all-files
Updating the skeleton for this package
This package has been generated from the template `https://codebase.helmholtz.cloud/hcdc/software-templates/django-app-template.git`__.
See the template repository for instructions on how to update the skeleton for this package.
How to cite this software
Philipp S. P.S., Housam H., Hatef H. Helmholtz AAI Django App URL: https://codebase.helmholtz.cloud/hcdc/django/django-helmholtz-aai
@misc{YourReferenceHere,
author = {Philipp S., Philipp S. and Housam, Housam and Hatef, Hatef},
title = {Helmholtz AAI Django App},
url = {https://codebase.helmholtz.cloud/hcdc/django/django-helmholtz-aai}
}
TY - GEN
AB - A generic Django app to login via Helmholtz AAI
AU - Philipp S., Philipp S.
AU - Housam, Housam
AU - Hatef, Hatef
KW - Helmholtz AAI
KW - authlib
KW - oauth
KW - hifis
KW - login
KW - hgf
TI - Helmholtz AAI Django App
UR - https://codebase.helmholtz.cloud/hcdc/django/django-helmholtz-aai
ER
%0 Generic
%A Philipp S., Philipp S.
%A Housam, Housam
%A Hatef, Hatef
%K Helmholtz AAI
%K authlib
%K oauth
%K hifis
%K login
%K hgf
%T Helmholtz AAI Django App
%U https://codebase.helmholtz.cloud/hcdc/django/django-helmholtz-aai
# SPDX-FileCopyrightText: 2022-2023 Helmholtz-Zentrum hereon GmbH
#
# SPDX-License-Identifier: CC0-1.0
authors:
# list author information. see
# https://github.com/citation-file-format/citation-file-format/blob/main/schema-guide.md#definitionsperson
# for metadata
- family-names: "Philipp S."
given-names: "Philipp S."
affiliation: "Helmholtz-Zentrum Hereon"
# orcid: null
email: "philipp.sommer@hereon.de"
- family-names: "Housam"
given-names: "Housam"
affiliation: "Helmholtz-Zentrum Hereon"
# orcid: null
email: "hcdc_support@hereon.de"
- family-names: "Hatef"
given-names: "Hatef"
affiliation: "Helmholtz-Zentrum Hereon"
# orcid: null
email: "hcdc_support@hereon.de"
cff-version: 1.2.0
message: "If you use this software, please cite it using these metadata."
title: "Helmholtz AAI Django App"
keywords:
- "Helmholtz AAI"
- "authlib"
- "oauth"
- "hifis"
- "login"
- "hgf"
license: 'EUPL-1.2'
repository-code: "https://codebase.helmholtz.cloud/hcdc/django/django-helmholtz-aai"
url: "https://codebase.helmholtz.cloud/hcdc/django/django-helmholtz-aai"
contact:
# list maintainer information. see
# https://github.com/citation-file-format/citation-file-format/blob/main/schema-guide.md#definitionsperson
# for metadata
- family-names: "Philipp S."
given-names: "Philipp S."
affiliation: "Helmholtz-Zentrum Hereon"
# orcid: null
email: "philipp.sommer@hereon.de"
abstract: |
A generic Django app to login via Helmholtz AAI
License information
Copyright © 2022-2023 Helmholtz-Zentrum hereon GmbH
The source code of django-helmholtz-aai is licensed under EUPL-1.2.
If not stated otherwise, the contents of this documentation is licensed under CC-BY-4.0.