diff --git a/ljg/core/auth.py b/ljg/core/auth.py new file mode 100644 index 0000000..6c5873e --- /dev/null +++ b/ljg/core/auth.py @@ -0,0 +1,49 @@ +from django.conf import settings +from django.contrib.auth.models import Permission +from django.db import transaction +from mozilla_django_oidc.auth import \ + OIDCAuthenticationBackend as BaseOIDCAuthenticationBackend + +from .models import OIDCUser + + +def get_permissions(claims): + return Permission.objects.filter( + codename__in=claims.get("resource_access")[settings.OIDC_RP_CLIENT_ID]["roles"] + ) + + +class OIDCAuthenticationBackend(BaseOIDCAuthenticationBackend): + @transaction.atomic + def create_user(self, claims): + 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.user_permissions.set(get_permissions(claims)) + user.save() + + OIDCUser.objects.create(uuid=claims.get("sub"), user=user) + + return user + + def update_user(self, user, claims): + user.user_permissions.set(get_permissions(claims)) + user.save() + + return user + + def filter_users_by_claims(self, claims): + uuid = claims.get("sub") + if not uuid: + return self.UserModel.objects.none() + + try: + oidc_user = OIDCUser.object.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") diff --git a/ljg/core/models.py b/ljg/core/models.py deleted file mode 100644 index 71a8362..0000000 --- a/ljg/core/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/ljg/core/models/__init__.py b/ljg/core/models/__init__.py new file mode 100644 index 0000000..6a2c37f --- /dev/null +++ b/ljg/core/models/__init__.py @@ -0,0 +1,3 @@ +from .auth import OIDCUser + +__all__ = ("OIDCUser",) diff --git a/ljg/core/models/auth.py b/ljg/core/models/auth.py new file mode 100644 index 0000000..c4015fc --- /dev/null +++ b/ljg/core/models/auth.py @@ -0,0 +1,7 @@ +from django.contrib.auth.models import User +from django.db import models + + +class OIDCUser(models.Model): + uuid = models.UUIDField(primary_key=True) + user = models.OneToOneField(User, on_delete=models.CASCADE) diff --git a/ljg/settings.py b/ljg/settings.py index 21be993..66d7576 100644 --- a/ljg/settings.py +++ b/ljg/settings.py @@ -42,6 +42,7 @@ INSTALLED_APPS = [ "django.contrib.messages", "django.contrib.staticfiles", "ljg.core.apps.CoreConfig", + "mozilla_django_oidc", ] MIDDLEWARE = [ @@ -52,6 +53,7 @@ MIDDLEWARE = [ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", + "mozilla_django_oidc.middleware.SessionRefresh", ] ROOT_URLCONF = "ljg.urls" @@ -134,3 +136,15 @@ STATIC_URL = "static/" DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" APP_TITLE = getenv("APP_TITLE", "ljg.sh") + +AUTHENTICATION_BACKENDS = ( + "django.contrib.auth.backends.ModelBackend", + "ljg.core.auth.OIDCAuthenticationBackend", +) + +OIDC_OP_AUTHORIZATION_ENDPOINT = getenv("OIDC_OP_AUTHORIZATION_ENDPOINT", "") +OIDC_OP_TOKEN_ENDPOINT = getenv("OIDC_OP_TOKEN_ENDPOINT", "") +OIDC_OP_USER_ENDPOINT = getenv("OIDC_OP_USER_ENDPOINT", "") + +OIDC_RP_CLIENT_ID = getenv("OIDC_RP_CLIENT_ID", "") +OIDC_RP_CLIENT_SECRET = getenv("OIDC_RP_CLIENT_SECRET", "") diff --git a/ljg/urls.py b/ljg/urls.py index fedb661..327ca2e 100644 --- a/ljg/urls.py +++ b/ljg/urls.py @@ -15,8 +15,9 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import include, path urlpatterns = [ path("admin/", admin.site.urls), + path("oidc/", include("mozilla_django_oidc.urls")), ]