2 Commits

Author SHA1 Message Date
ef733cb7bf SSO Pattern update
All checks were successful
CVE Scan & Docker Build / security-scan (push) Successful in 51s
CVE Scan & Docker Build / build-and-push (push) Successful in 46s
2026-05-13 06:31:00 -04:00
88afd5d307 docs(auth): add SSO signup template docs and update allauth imports 2026-05-13 06:30:59 -04:00

View File

@@ -1,4 +1,4 @@
# SSO with Allauth & Casdoor Pattern v1.0.0
# SSO with Allauth & Casdoor Pattern v1.02
Standardizes OIDC-based Single Sign-On using Django Allauth and Casdoor, covering adapter customization, user provisioning, group mapping, superuser protection, and configurable local-login fallback. Used by the `core` Django application.
@@ -35,6 +35,7 @@ Every SSO implementation following this pattern must provide these files:
| Local account adapter | `<app>/adapters.py` | Disable local signup, authentication logging |
| Management command | `<app>/management/commands/create_sso_groups.py` | Idempotent group + permission creation |
| Login template | `templates/account/login.html` | SSO button + conditional local login form |
| SSO signup template | `templates/socialaccount/signup.html` | Email confirmation step for first-time SSO users |
| Context processor | `<app>/context_processors.py` | Expose `CASDOOR_ENABLED` / `ALLOW_LOCAL_LOGIN` to templates |
| SSL patch (optional) | `<app>/ssl_patch.py` | Development-only SSL bypass |
@@ -194,7 +195,7 @@ The social account adapter is the core of the pattern. It handles user provision
```python
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.exceptions import ImmediateHttpResponse
from allauth.core.exceptions import ImmediateHttpResponse
from django.contrib.auth.models import User, Group
from django.contrib import messages
from django.shortcuts import redirect
@@ -440,6 +441,73 @@ The login template shows an SSO button when Casdoor is enabled and conditionally
---
## SSO Signup Template
When a new SSO user has no existing account, allauth redirects them to `accounts/3rdparty/signup/` to confirm their email before the account is created. Without a custom template this page renders with no styling.
Create `templates/socialaccount/signup.html` extending the project base:
```html
{% extends "<app>/base.html" %}
{% block title %}Complete Sign Up — {{ themis_app_name }}{% endblock %}
{% block content %}
<div class="flex justify-center items-center min-h-[60vh]">
<div class="card bg-base-200 shadow-xl w-full max-w-md">
<div class="card-body">
<h2 class="card-title text-2xl justify-center mb-2">Complete Sign Up</h2>
<p class="text-center text-base-content/70 mb-4">
Confirm your email address to finish signing in with SSO.
</p>
{% if form.errors %}
<div class="alert alert-error mb-4">
<span>Please correct the errors below.</span>
</div>
{% endif %}
<form method="post" action="{{ action_url }}">
{% csrf_token %}
<div class="form-control mb-6">
<label class="label" for="id_email">
<span class="label-text">Email</span>
</label>
<input type="email" name="email" id="id_email"
class="input input-bordered w-full{% if form.email.errors %} input-error{% endif %}"
value="{{ form.email.value|default:'' }}"
autocomplete="email" required>
{% if form.email.errors %}
<label class="label">
<span class="label-text-alt text-error">{{ form.email.errors|join:", " }}</span>
</label>
{% endif %}
</div>
<div class="form-control mt-2">
<button type="submit" class="btn btn-primary w-full">Complete Sign Up</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
```
Key context variables allauth provides to this template:
| Variable | Description |
|----------|-------------|
| `form` | `SignupForm` with a single `email` field pre-populated from the OIDC claim |
| `action_url` | POST target (`/accounts/3rdparty/signup/`) — always use this, not a hard-coded path |
| `sociallogin` | The in-progress social login object (rarely needed in the template) |
> **Why this page exists:** `SOCIALACCOUNT_AUTO_SIGNUP = True` skips it when the IdP provides a valid email. It only appears when allauth cannot confirm the email (e.g. the IdP omitted it or there is a conflict with an existing account).
---
## Context Processor
Exposes SSO settings to every template:
@@ -701,7 +769,7 @@ class CasdoorAdapterTest(TestCase):
def test_superuser_sso_login_blocked(self):
"""pre_social_login must raise ImmediateHttpResponse for superusers."""
from allauth.exceptions import ImmediateHttpResponse
from allauth.core.exceptions import ImmediateHttpResponse
user = User.objects.create_superuser(
'admin@example.com', 'admin@example.com', 'pass'
)