From f126acfa36cfac91a9ed0d680edfca10e9c31b41 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Bedna=C5=99=C3=ADk?= <jan.bednarik@gmail.com>
Date: Tue, 5 May 2020 00:45:49 +0200
Subject: [PATCH] OpenID Connect SSO using Pirates app

---
 majak/settings/base.py                  |  14 +++
 requirements/base.in                    |   2 +-
 requirements/base.txt                   |   2 +-
 users/__init__.py                       |   0
 users/apps.py                           |   5 +
 users/forms.py                          |  12 +++
 users/migrations/0001_initial.py        | 116 ++++++++++++++++++++++++
 users/migrations/__init__.py            |   0
 users/models.py                         |   7 ++
 users/templates/wagtailadmin/login.html |   6 ++
 10 files changed, 162 insertions(+), 2 deletions(-)
 create mode 100644 users/__init__.py
 create mode 100644 users/apps.py
 create mode 100644 users/forms.py
 create mode 100644 users/migrations/0001_initial.py
 create mode 100644 users/migrations/__init__.py
 create mode 100644 users/models.py
 create mode 100644 users/templates/wagtailadmin/login.html

diff --git a/majak/settings/base.py b/majak/settings/base.py
index 3d88cb84..2744e99a 100644
--- a/majak/settings/base.py
+++ b/majak/settings/base.py
@@ -15,6 +15,7 @@ INSTALLED_APPS = [
     "search",
     "senator",
     "pirates",
+    "users",
     "wagtail.contrib.forms",
     "wagtail.contrib.redirects",
     "wagtail.contrib.modeladmin",
@@ -139,6 +140,15 @@ WAGTAIL_ALLOW_UNICODE_SLUGS = False
 
 TAGGIT_CASE_INSENSITIVE = True
 
+AUTH_USER_MODEL = "users.User"
+
+WAGTAIL_USER_EDIT_FORM = "users.forms.UserEditForm"
+WAGTAIL_USER_CREATION_FORM = "users.forms.UserCreationForm"
+WAGTAIL_PASSWORD_MANAGEMENT_ENABLED = False
+WAGTAIL_PASSWORD_RESET_ENABLED = False
+WAGTAILUSERS_PASSWORD_ENABLED = False
+WAGTAILUSERS_PASSWORD_REQUIRED = False
+WAGTAIL_EMAIL_MANAGEMENT_ENABLED = False
 
 AUTHENTICATION_BACKENDS = ["pirates.auth.PiratesOIDCAuthenticationBackend"]
 
@@ -150,3 +160,7 @@ OIDC_OP_JWKS_ENDPOINT = join(OIDC_RP_REALM_URL, "protocol/openid-connect/certs")
 OIDC_OP_AUTHORIZATION_ENDPOINT = join(OIDC_RP_REALM_URL, "protocol/openid-connect/auth")
 OIDC_OP_TOKEN_ENDPOINT = join(OIDC_RP_REALM_URL, "protocol/openid-connect/token")
 OIDC_OP_USER_ENDPOINT = join(OIDC_RP_REALM_URL, "protocol/openid-connect/userinfo")
+
+LOGIN_REDIRECT_URL = "/admin"
+LOGOUT_REDIRECT_URL = "/admin"
+LOGIN_URL = "/admin"
diff --git a/requirements/base.in b/requirements/base.in
index 2d5e0d1b..54fb7179 100644
--- a/requirements/base.in
+++ b/requirements/base.in
@@ -3,4 +3,4 @@ wagtailmenus
 django-environ
 django-extensions
 psycopg2-binary
-git+https://gitlab.pirati.cz/to/pirates@v0.2.0
+git+https://gitlab.pirati.cz/to/pirates@v0.2.1
diff --git a/requirements/base.txt b/requirements/base.txt
index 27d6540d..ed81bff7 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -25,7 +25,7 @@ josepy==1.3.0             # via mozilla-django-oidc
 l18n==2018.5              # via wagtail
 mozilla-django-oidc==1.2.3  # via pirates
 pillow==6.2.2             # via wagtail
-git+https://gitlab.pirati.cz/to/pirates@v0.2.0  # via -r base.in
+git+https://gitlab.pirati.cz/to/pirates@v0.2.1  # via -r base.in
 psycopg2-binary==2.8.5    # via -r base.in
 pyasn1-modules==0.2.8     # via python-ldap
 pyasn1==0.4.8             # via pyasn1-modules, python-ldap
diff --git a/users/__init__.py b/users/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/users/apps.py b/users/apps.py
new file mode 100644
index 00000000..3ef1284a
--- /dev/null
+++ b/users/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class UsersConfig(AppConfig):
+    name = "users"
diff --git a/users/forms.py b/users/forms.py
new file mode 100644
index 00000000..6a8c7478
--- /dev/null
+++ b/users/forms.py
@@ -0,0 +1,12 @@
+from django import forms
+from django.contrib.auth import get_user_model
+
+
+class UserCreationForm(forms.ModelForm):
+    class Meta:
+        model = get_user_model()
+
+
+class UserEditForm(forms.ModelForm):
+    class Meta:
+        model = get_user_model()
diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py
new file mode 100644
index 00000000..f39e0799
--- /dev/null
+++ b/users/migrations/0001_initial.py
@@ -0,0 +1,116 @@
+# Generated by Django 3.0.5 on 2020-05-04 16:02
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ("auth", "0011_update_proxy_permissions"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="User",
+            fields=[
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "is_superuser",
+                    models.BooleanField(
+                        default=False,
+                        help_text="Designates that this user has all permissions without explicitly assigning them.",
+                        verbose_name="superuser status",
+                    ),
+                ),
+                (
+                    "sso_id",
+                    models.CharField(
+                        error_messages={
+                            "unique": "A user with that SSO ID already exists."
+                        },
+                        max_length=150,
+                        unique=True,
+                        verbose_name="SSO ID",
+                    ),
+                ),
+                (
+                    "first_name",
+                    models.CharField(
+                        blank=True, max_length=150, verbose_name="first name"
+                    ),
+                ),
+                (
+                    "last_name",
+                    models.CharField(
+                        blank=True, max_length=150, verbose_name="last name"
+                    ),
+                ),
+                (
+                    "email",
+                    models.EmailField(
+                        blank=True, max_length=254, verbose_name="email address"
+                    ),
+                ),
+                (
+                    "is_staff",
+                    models.BooleanField(
+                        default=False,
+                        help_text="Designates whether the user can log into this admin site.",
+                        verbose_name="staff status",
+                    ),
+                ),
+                (
+                    "is_active",
+                    models.BooleanField(
+                        default=True,
+                        help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
+                        verbose_name="active",
+                    ),
+                ),
+                (
+                    "date_joined",
+                    models.DateTimeField(
+                        default=django.utils.timezone.now, verbose_name="date joined"
+                    ),
+                ),
+                (
+                    "groups",
+                    models.ManyToManyField(
+                        blank=True,
+                        help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
+                        related_name="user_set",
+                        related_query_name="user",
+                        to="auth.Group",
+                        verbose_name="groups",
+                    ),
+                ),
+                (
+                    "user_permissions",
+                    models.ManyToManyField(
+                        blank=True,
+                        help_text="Specific permissions for this user.",
+                        related_name="user_set",
+                        related_query_name="user",
+                        to="auth.Permission",
+                        verbose_name="user permissions",
+                    ),
+                ),
+            ],
+            options={
+                "verbose_name": "user",
+                "verbose_name_plural": "users",
+                "abstract": False,
+            },
+        ),
+    ]
diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/users/models.py b/users/models.py
new file mode 100644
index 00000000..4004fa15
--- /dev/null
+++ b/users/models.py
@@ -0,0 +1,7 @@
+from pirates.models import AbstractUser
+
+
+class User(AbstractUser):
+    def get_username(self):
+        """Used in wagtail templates"""
+        return self.email or self.sso_id
diff --git a/users/templates/wagtailadmin/login.html b/users/templates/wagtailadmin/login.html
new file mode 100644
index 00000000..c7a422ea
--- /dev/null
+++ b/users/templates/wagtailadmin/login.html
@@ -0,0 +1,6 @@
+{% extends "wagtailadmin/login.html" %}
+
+{% block login_form %}
+    <h1>Redakční systém Maják</h1>
+    <a class="button" href="{% url 'oidc_authentication_init' %}">Přihlásit se Pirátskou identitou</a>
+{% endblock %}
-- 
GitLab