diff --git a/.env.example b/.env.example index 5af7515..429e03b 100644 --- a/.env.example +++ b/.env.example @@ -4,8 +4,14 @@ DATABASE_URL= DEBUG=no SECRET_KEY= +# for Keycloak, see https://{your keycloak host}/realms/{your realm}/.well-known/openid-configuration OIDC_OP_AUTHORIZATION_ENDPOINT= +OIDC_OP_JWKS_ENDPOINT= OIDC_OP_TOKEN_ENDPOINT= OIDC_OP_USER_ENDPOINT= + OIDC_RP_CLIENT_ID= OIDC_RP_CLIENT_SECRET= + +# defaults to RS256 +OIDC_RP_SIGN_ALGO= diff --git a/ljg/core/auth.py b/ljg/core/auth.py index 9614739..4ad8b71 100644 --- a/ljg/core/auth.py +++ b/ljg/core/auth.py @@ -9,6 +9,10 @@ from .models import OIDCUser def get_permissions(claims): + roles = claims.get("resource_access") + if roles is None or settings.OIDC_RP_CLIENT_ID not in roles: + return Permission.objects.none() + return Permission.objects.filter( codename__in=claims.get("resource_access")[settings.OIDC_RP_CLIENT_ID]["roles"] ) @@ -20,8 +24,8 @@ class OIDCAuthenticationBackend(BaseOIDCAuthenticationBackend): user = self.UserModel.objects.create_user( claims.get("preferred_username"), claims.get("email") ) - user.first_name = claims.get("given_name") - user.last_name = claims.get("family_name") + user.first_name = claims.get("given_name", "") + user.last_name = claims.get("family_name", "") user.user_permissions.set(get_permissions(claims)) user.save() @@ -30,6 +34,7 @@ class OIDCAuthenticationBackend(BaseOIDCAuthenticationBackend): return user def update_user(self, user, claims): + user.email = claims.get("email") or user.email user.user_permissions.set(get_permissions(claims)) user.save() @@ -41,10 +46,11 @@ class OIDCAuthenticationBackend(BaseOIDCAuthenticationBackend): return self.UserModel.objects.none() try: - oidc_user = OIDCUser.object.get(uuid=uuid) + oidc_user = OIDCUser.objects.get(uuid=uuid) return [oidc_user.user] except OIDCUser.DoesNotExist: return self.UserModel.objects.none() def verify_claims(self, claims): - return settings.OIDC_RP_CLIENT_ID in claims.get("resource_access") + roles = claims.get("resource_access") + return roles is not None and settings.OIDC_RP_CLIENT_ID in roles diff --git a/ljg/core/migrations/0001_initial.py b/ljg/core/migrations/0001_initial.py new file mode 100644 index 0000000..34f64c7 --- /dev/null +++ b/ljg/core/migrations/0001_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.4 on 2023-10-11 14:47 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="OIDCUser", + fields=[ + ("uuid", models.UUIDField(primary_key=True, serialize=False)), + ( + "user", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/ljg/settings.py b/ljg/settings.py index eca3be8..9c4609e 100644 --- a/ljg/settings.py +++ b/ljg/settings.py @@ -137,9 +137,14 @@ AUTHENTICATION_BACKENDS = ( "ljg.core.auth.OIDCAuthenticationBackend", ) +LOGIN_REDIRECT_URL = "/" +LOGOUT_REDIRECT_URL = "/" + OIDC_OP_AUTHORIZATION_ENDPOINT = env.str("OIDC_OP_AUTHORIZATION_ENDPOINT", "") +OIDC_OP_JWKS_ENDPOINT = env.str("OIDC_OP_JWKS_ENDPOINT", "") OIDC_OP_TOKEN_ENDPOINT = env.str("OIDC_OP_TOKEN_ENDPOINT", "") OIDC_OP_USER_ENDPOINT = env.str("OIDC_OP_USER_ENDPOINT", "") OIDC_RP_CLIENT_ID = env.str("OIDC_RP_CLIENT_ID", "") OIDC_RP_CLIENT_SECRET = env.str("OIDC_RP_CLIENT_SECRET", "") +OIDC_RP_SIGN_ALGO = env.str("OIDC_RP_SIGN_ALGO", "RS256")