Browse Source

Integrate SurfConext

master
Joshua Rubingh 3 months ago
parent
commit
deb0217fea
  1. 1
      .gitignore
  2. 26
      VRE/VRE/env.example
  3. 54
      VRE/VRE/settings.py
  4. 16
      VRE/VRE/urls.py
  5. 2
      VRE/apps/api/apps.py
  6. 33
      VRE/apps/api/authentication.py
  7. 1
      VRE/apps/api/views.py
  8. 1
      VRE/requirements-dev.txt
  9. 6
      VRE/requirements.txt

1
.gitignore

@ -146,3 +146,4 @@ VRE/db.sqlite3*
VRE/media/*
.idea
docker/project.env
VRE/surfnet_conext_secrets.ini

26
VRE/VRE/env.example

@ -30,6 +30,32 @@ MEDIA_ROOT=
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TIME_ZONE
TIME_ZONE=Europe/Amsterdam
# Authentication settings
# This information can be created in a separate settings.ini file.
# https://mozilla-django-oidc.readthedocs.io/en/stable/installation.html
# The Client ID which is the Entity ID in SurfConext
# OIDC_RP_CLIENT_ID=
# The Client secret that is created with the Entity ID. This will be shown only once
# OIDC_RP_CLIENT_SECRET=
# The encryption algorithm. Default is RS256
# OIDC_RP_SIGN_ALGO=RS256
# The following urls should be loaded automatically when PR039 is merged: https://github.com/mozilla/mozilla-django-oidc/pull/309 For now, we have to manually add those urls
# The source is at: https://connect.surfconext.nl/.well-known/openid-configuration (production)
# The source is at: https://connect.test.surfconext.nl/.well-known/openid-configuration (testing)
# This is the 'authorization_endpoint' url
# OIDC_OP_AUTHORIZATION_ENDPOINT=
# This is the 'token_endpoint' url
# OIDC_OP_TOKEN_ENDPOINT=
# This is the 'userinfo_endpoint' url
# OIDC_OP_USER_ENDPOINT=
# This is the 'jwks_uri' url. Needed due to the `OIDC_RP_SIGN_ALGO` choice
# OIDC_OP_JWKS_ENDPOINT=
# Where to go after valid login.
# LOGIN_REDIRECT_URL=
# Where to go after valid logout.
# LOGOUT_REDIRECT_URL=
# Email settings
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host
# EMAIL_HOST=

54
VRE/VRE/settings.py

@ -15,6 +15,8 @@ from pathlib import Path
from decouple import config, Csv
from dj_database_url import parse as db_url
from django.utils.translation import ugettext_lazy as _
import os
from django.urls import reverse_lazy
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
@ -54,6 +56,9 @@ ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='localhost,127.0.0.1', cast=Csv(
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'mozilla_django_oidc',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
@ -76,19 +81,20 @@ INSTALLED_APPS = [
'drf_yasg',
'hawkrest',
'huey.contrib.djhuey',
'django_extensions',
'corsheaders',
]
if DEBUG:
INSTALLED_APPS.append('django_extensions')
INSTALLED_APPS.append('debug_toolbar')
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
"django.middleware.common.CommonMiddleware",
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
# 'mozilla_django_oidc.middleware.SessionRefresh',
'corsheaders.middleware.CorsPostCsrfMiddleware',
'hawkrest.middleware.HawkResponseMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
@ -222,6 +228,42 @@ HUEY = {
},
}
# Add 'mozilla_django_oidc' authentication backend
AUTHENTICATION_BACKENDS = (
# 'mozilla_django_oidc.auth.OIDCAuthenticationBackend',
'apps.api.authentication.VRE_OIDC_Researcher_Update',
'django.contrib.auth.backends.ModelBackend' # The default https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-AUTHENTICATION_BACKENDS
)
# Dynamic load the Surfconext secrets
surfnet_conext_secrets = Path(f'{BASE_DIR}/surfnet_conext_secrets.ini')
if surfnet_conext_secrets.exists():
with surfnet_conext_secrets.open() as secrets_file:
while True:
line = secrets_file.readline()
if not line:
break
line = line.strip()
if not line.startswith('#') and line.find('='):
pos = line.find('=')
os.environ[line[:pos].strip()] = line[pos + 1:].strip()
# Surfconext settings
# Authentication settings
# https://mozilla-django-oidc.readthedocs.io/en/stable/installation.html
OIDC_RP_CLIENT_ID = config('OIDC_RP_CLIENT_ID')
OIDC_RP_CLIENT_SECRET = config('OIDC_RP_CLIENT_SECRET')
OIDC_RP_SIGN_ALGO = config('OIDC_RP_SIGN_ALGO', default='RS256')
OIDC_OP_AUTHORIZATION_ENDPOINT = config('OIDC_OP_AUTHORIZATION_ENDPOINT')
OIDC_OP_TOKEN_ENDPOINT = config('OIDC_OP_TOKEN_ENDPOINT')
OIDC_OP_USER_ENDPOINT = config('OIDC_OP_USER_ENDPOINT')
OIDC_OP_JWKS_ENDPOINT = config('OIDC_OP_JWKS_ENDPOINT')
# Login/logout after surfconext....
LOGIN_REDIRECT_URL = config('LOGIN_REDIRECT_URL', default=(reverse_lazy('test-login-surfconext') if DEBUG else '/'))
LOGOUT_REDIRECT_URL = config('LOGOUT_REDIRECT_URL', default=(reverse_lazy('test-login-surfconext') if DEBUG else '/'))
# Email settings for sending out upload invitations.
DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', default='Do not reply<no-reply@rug.nl>')
EMAIL_HOST = config('EMAIL_HOST', default='')
@ -273,6 +315,10 @@ CORS_EXPOSE_HEADERS = CORS_ALLOW_HEADERS
# 'class': 'logging.FileHandler',
# 'filename': f'{BASE_DIR}/../log/debug.log',
# },
# 'console': {
# 'class': 'logging.StreamHandler',
# 'stream': 'ext://sys.stdout'
# },
# },
# 'loggers': {
# 'django': {
@ -280,6 +326,10 @@ CORS_EXPOSE_HEADERS = CORS_ALLOW_HEADERS
# 'level': 'DEBUG' if DEBUG else 'INFO',
# 'propagate': True,
# },
# 'mozilla_django_oidc': {
# 'handlers': ['console'],
# 'level': 'DEBUG',
# },
# 'hawkrest': {
# 'handlers': ['file'],

16
VRE/VRE/urls.py

@ -17,12 +17,28 @@ from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
from django.urls.base import reverse_lazy
from django.views.generic.base import RedirectView
from .views import test_login_page
urlpatterns = [
path('api/', include('apps.api.urls')),
path('admin/', admin.site.urls),
path('oidc/', include('mozilla_django_oidc.urls')),
# Redirect alias so we have an easy to remember url for login.
path('auth/login/', RedirectView.as_view(url=reverse_lazy('oidc_authentication_init')), name='api-login-surfconext'),
# Redirect alias so we have an easy to remember url for logout does not work. It needs to be an post action
# TODO: Make this a bit easier? How do we do the logout?
#path('auth/logout/', RedirectView.as_view(url=reverse_lazy('oidc_logout')), name='api-logout-surfconext'),
# For testing only.... should be loaded only when debug is true
path('auth/login/test/', test_login_page, name='test-login-surfconext')
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if settings.DEBUG:
import debug_toolbar
# urlpatterns.append(path('auth/login/test/', test_login_page, name='test-login-surfconext'))
urlpatterns.append(path('__debug__/', include(debug_toolbar.urls)))

2
VRE/apps/api/apps.py

@ -38,6 +38,8 @@ class ApiConfig(AppConfig):
settings.REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'mozilla_django_oidc.contrib.drf.OIDCAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
'apps.api.authentication.APIHawk',
),

33
VRE/apps/api/authentication.py

@ -4,6 +4,8 @@ from hawkrest import HawkAuthentication
from rest_framework import exceptions
import django.utils
import logging
from mozilla_django_oidc.auth import OIDCAuthenticationBackend
# Get an instance of a logger
logger = logging.getLogger(__name__)
@ -71,3 +73,34 @@ class APIHawk(HawkAuthentication):
string: Returns the name of the used authentication mechanism.
"""
return 'Hawk authenticator'
class VRE_OIDC_Researcher_Update(OIDCAuthenticationBackend):
"""Update the logged in user his/her first and last name based on Surfconext login
This is done after each login.
"""
def create_user(self, claims):
user = super().create_user(claims)
user.first_name = claims.get('given_name', '')
user.last_name = claims.get('family_name', '')
user.save()
idnumber = claims.get('eduperson_principal_name', '').split('@')[0].lower()
user.researcher.idnumber = idnumber
user.researcher.save()
return user
def update_user(self, user, claims):
user.first_name = claims.get('given_name', '')
user.last_name = claims.get('family_name', '')
user.save()
idnumber = claims.get('eduperson_principal_name', '').split('@')[0].lower()
user.researcher.idnumber = idnumber
user.researcher.save()
return user

1
VRE/apps/api/views.py

@ -69,7 +69,6 @@ class Info(APIView):
If you used your Hawk credentials, you should see here your account information.
"""
authentication_classes = []
permission_classes = [AllowAny]
def get(self, request, format=None):

1
VRE/requirements-dev.txt

@ -1,2 +1,3 @@
django-extensions==3.1.3 # Is used for: https://django-extensions.readthedocs.io/en/latest/graph_models.html
pygraphviz==1.7
django-debug-toolbar==3.2.2

6
VRE/requirements.txt

@ -27,6 +27,7 @@ python-decouple==3.5
requests==2.26.0
openstacksdk==0.55.0
pycryptodome==3.10.4
mozilla-django-oidc==2.0.0
# Storgage packages
diskcache==5.2.1
@ -37,7 +38,4 @@ python-irodsclient==1.0.0
# Remove:
djoser==2.1.0
django-extensions==3.1.3
dj-database-url==0.5.0
dj-database-url==0.5.0
Loading…
Cancel
Save