From a612239083d6403ffaae57fdb7c0a6fecdec239d Mon Sep 17 00:00:00 2001 From: Tom Irgang Date: Sun, 23 Apr 2023 17:40:19 +0200 Subject: [PATCH] Keycloak login --- rc_hip/rc_hip/settings.py | 26 +++++++++- rc_hip/rc_hip/urls.py | 1 + rc_hip/repapp/templates/repapp/base.html | 9 ++++ .../repapp/templates/repapp/member_login.html | 26 ++++++++++ rc_hip/repapp/urls.py | 2 + rc_hip/repapp/views.py | 8 ++- rc_hip/repapp_users/backends.py | 50 +++++++++++++++++++ requirements_dev.txt | 2 + requirements_prod.txt | 1 + 9 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 rc_hip/repapp/templates/repapp/member_login.html diff --git a/rc_hip/rc_hip/settings.py b/rc_hip/rc_hip/settings.py index 54412c7..b3baec8 100644 --- a/rc_hip/rc_hip/settings.py +++ b/rc_hip/rc_hip/settings.py @@ -41,16 +41,17 @@ ALLOWED_HOSTS = [ # Application definition INSTALLED_APPS = [ - 'repapp_users.apps.RepappUsersConfig', 'repapp.apps.RepappConfig', 'django.contrib.admin', 'django.contrib.auth', + 'mozilla_django_oidc', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'crispy_forms', 'crispy_bootstrap4', + 'repapp_users.apps.RepappUsersConfig', ] CRISPY_ALLOWED_TEMPLATE_PACKS = 'bootstrap4' @@ -154,6 +155,27 @@ EMAIL_USE_TLS = os.getenv("DJANGO_EMAIL_USE_TLS", 'true') in ('true', '1', 't') AUTH_USER_MODEL = "repapp_users.CustomUser" AUTHENTICATION_BACKENDS = [ - "repapp_users.backends.EmailBackend", "django.contrib.auth.backends.ModelBackend"] + "repapp_users.backends.EmailBackend", + "django.contrib.auth.backends.ModelBackend", + # 'mozilla_django_oidc.auth.OIDCAuthenticationBackend', + 'repapp_users.backends.KeycloakOIDCAB' +] LOGIN_REDIRECT_URL = '/guest/profile/' + +OIDC_RP_CLIENT_ID = "repapp" +OIDC_RP_CLIENT_SECRET = os.getenv("DJANGO_OIDC_RP_CLIENT_SECRET", None) + +OIDC_RP_SIGN_ALGO = "RS256" +OIDC_OP_JWKS_ENDPOINT = "https://sso.makes-hacks-hip.de/realms/Makes-Hacks-Hip/protocol/openid-connect/certs" + +OIDC_OP_AUTHORIZATION_ENDPOINT = "https://sso.makes-hacks-hip.de/realms/Makes-Hacks-Hip/protocol/openid-connect/auth" +OIDC_OP_TOKEN_ENDPOINT = "https://sso.makes-hacks-hip.de/realms/Makes-Hacks-Hip/protocol/openid-connect/token" +OIDC_OP_USER_ENDPOINT = "https://sso.makes-hacks-hip.de/realms/Makes-Hacks-Hip/protocol/openid-connect/userinfo" + +if DEBUG: + LOGIN_REDIRECT_URL = "http://127.0.0.1:8000/" + LOGOUT_REDIRECT_URL = "http://127.0.0.1:8000/" +else: + LOGIN_REDIRECT_URL = "https://repapp.rc-hip.de/" + LOGOUT_REDIRECT_URL = "https://repapp.rc-hip.de/" diff --git a/rc_hip/rc_hip/urls.py b/rc_hip/rc_hip/urls.py index b0ce1c6..9cd3412 100644 --- a/rc_hip/rc_hip/urls.py +++ b/rc_hip/rc_hip/urls.py @@ -22,6 +22,7 @@ from django.conf.urls.static import static urlpatterns = [ path("", include("repapp.urls")), + path('oidc/', include('mozilla_django_oidc.urls')), path('accounts/', include('django.contrib.auth.urls')), path('admin/', admin.site.urls), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/rc_hip/repapp/templates/repapp/base.html b/rc_hip/repapp/templates/repapp/base.html index acb2fa5..1e78f2b 100644 --- a/rc_hip/repapp/templates/repapp/base.html +++ b/rc_hip/repapp/templates/repapp/base.html @@ -34,5 +34,14 @@ + diff --git a/rc_hip/repapp/templates/repapp/member_login.html b/rc_hip/repapp/templates/repapp/member_login.html new file mode 100644 index 0000000..c93b392 --- /dev/null +++ b/rc_hip/repapp/templates/repapp/member_login.html @@ -0,0 +1,26 @@ +{% extends "repapp/base.html" %} +{% block title %} + - Mitarbeiter Login +{% endblock title %} +{% block content %} +

+ Mitarbeiter + {% if user.is_authenticated %} + Logout + {% else %} + Login + {% endif %} +

+
+
+ {% if user.is_authenticated %} +

Angemeldeter Benutzer: {{ user.email }}

+
+ {% csrf_token %} + +
+ {% else %} + Anmelden mit Makes-Hacks-Hip + {% endif %} +
+{% endblock content %} diff --git a/rc_hip/repapp/urls.py b/rc_hip/repapp/urls.py index 5cddc8e..24277d5 100644 --- a/rc_hip/repapp/urls.py +++ b/rc_hip/repapp/urls.py @@ -23,4 +23,6 @@ urlpatterns = [ views.device_view, name="view_device"), path("guest/profile/", views.profile, name="guest_profile"), + path("member/login/", + views.member_login, name="member_login"), ] diff --git a/rc_hip/repapp/views.py b/rc_hip/repapp/views.py index 209e7fb..2f04e8d 100644 --- a/rc_hip/repapp/views.py +++ b/rc_hip/repapp/views.py @@ -257,7 +257,13 @@ def profile(request): request, "repapp/guest_profile.html", { - 'user': user, 'guest': guest } ) + + +def member_login(request): + return render( + request, + "repapp/member_login.html" + ) diff --git a/rc_hip/repapp_users/backends.py b/rc_hip/repapp_users/backends.py index 169d764..1ee9555 100644 --- a/rc_hip/repapp_users/backends.py +++ b/rc_hip/repapp_users/backends.py @@ -1,5 +1,8 @@ +import unicodedata from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend +from mozilla_django_oidc.auth import OIDCAuthenticationBackend +from repapp.models import Organisator, Reparateur class EmailBackend(ModelBackend): @@ -13,3 +16,50 @@ class EmailBackend(ModelBackend): if user.check_password(password): return user return None + + +def generate_username(email): + # Using Python 3 and Django 1.11+, usernames can contain alphanumeric + # (ascii and unicode), _, @, +, . and - characters. So we normalize + # it and slice at 150 characters. + return unicodedata.normalize('NFKC', email)[:150] + + +def create_repapp_user(user): + organisator = Organisator.objects.filter(mail=user.email).first() + if not organisator: + reparateur = Reparateur.objects.filter(mail=user.email).first() + if not reparateur: + reparateur = Reparateur( + name=user.username, + mail=user.email, + ) + reparateur.save() + else: + reparateur.name = user.username + reparateur.save() + else: + organisator.name = user.username + organisator.save() + + +class KeycloakOIDCAB(OIDCAuthenticationBackend): + def create_user(self, claims): + user = super(KeycloakOIDCAB, self).create_user(claims) + + user.username = claims.get( + 'preferred_username', generate_username(user.email)) + user.save() + + create_repapp_user(user) + + return user + + def update_user(self, user, claims): + user.username = claims.get( + 'preferred_username', generate_username(user.email)) + user.save() + + create_repapp_user(user) + + return user diff --git a/requirements_dev.txt b/requirements_dev.txt index f8fb2e1..dc77789 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -6,3 +6,5 @@ pylint-django==2.5.3 pylint-plugin-utils==0.7 django-crispy-forms==2.0 crispy-bootstrap4==2022.1 +mozilla-django-oidc==3.0.0 +djlint==1.23.3 diff --git a/requirements_prod.txt b/requirements_prod.txt index 28faded..231eaca 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -2,3 +2,4 @@ Django==4.2 gunicorn==20.1.0 django-crispy-forms==2.0 crispy-bootstrap4==2022.1 +mozilla-django-oidc==3.0.0