Commit 65a9f04e authored by Carl Schwan's avatar Carl Schwan 🚴
Browse files

Add OpenID Connect support



Signed-off-by: Carl Schwan's avatarCarl Schwan <carl@carlschwan.eu>
parent 311b7cce
# Generated by Django 3.0.14 on 2022-02-27 19:01
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import martor.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.OAUTH2_PROVIDER_ID_TOKEN_MODEL),
('bid_main', '0045_merge_20210329_1645'),
('oauth2_provider', '0005_auto_20211222_2352'),
]
operations = [
migrations.AddField(
model_name='oauth2accesstoken',
name='id_token',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='access_token', to=settings.OAUTH2_PROVIDER_ID_TOKEN_MODEL),
),
migrations.AddField(
model_name='oauth2application',
name='algorithm',
field=models.CharField(blank=True, choices=[('', 'No OIDC support'), ('RS256', 'RSA with SHA-2 256'), ('HS256', 'HMAC with SHA-2 256')], default='', max_length=5),
),
migrations.AlterField(
model_name='oauth2application',
name='authorization_grant_type',
field=models.CharField(choices=[('authorization-code', 'Authorization code'), ('implicit', 'Implicit'), ('password', 'Resource owner password-based'), ('client-credentials', 'Client credentials'), ('openid-hybrid', 'OpenID connect hybrid')], max_length=32),
),
migrations.AlterField(
model_name='user',
name='bio',
field=martor.models.MartorField(blank=True, help_text='Public information about the user', verbose_name='Description'),
),
migrations.AlterField(
model_name='user',
name='irc_nick',
field=models.CharField(blank=True, max_length=80, verbose_name='IRC/Libera Username'),
),
]
# SPDX-FileCopyrigtText: 2022 Carl Schwan <carl@carlschwan.eu>
# SPDX-License-Identifier: GPL-2.0-or-later
from oauth2_provider.oauth2_validators import OAuth2Validator
class KDEOAuth2Validator(OAuth2Validator):
def get_additional_claims(self, request):
claims = super().get_additional_claims(request)
claims["name"] = request.user.full_name
claims["preferred_username"] = request.user.nickname
claims["email"] = request.user.email
claims["permissions"] = list(request.user.roles.filter(is_public=True))
return claims
def get_userinfo_claims(self, request):
claims = super().get_userinfo_claims(request)
claims["name"] = request.user.full_name
claims["preferred_username"] = request.user.nickname
claims["email"] = request.user.email
claims["permissions"] = list(request.user.roles.filter(is_public=True))
return claims
def get_claim_dict(self, request):
if self._get_additional_claims_is_request_agnostic():
claims = {"sub": lambda r: str(r.user.uuid)}
else:
claims = {"sub": str(request.user.uuid)}
# https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
if self._get_additional_claims_is_request_agnostic():
add = self.get_additional_claims()
else:
add = self.get_additional_claims(request)
claims.update(add)
print(claims)
return claims
......@@ -43,6 +43,8 @@ user.save()
- `./manage.py loaddata blender_cloud_dev_webhook`
- `./manage.py loaddata flatpages`
- Run `./manage.py collectmedia` to collect media from fixtures and place into the media directory.
- openssl genrsa -out oidc.key 4096
- Run `OIDC_RSA_PRIVATE_KEY=`cat oidc.key` ./manage.py runserver`
## Setting up the Blender Store (and other `bid_api` users)
......
# Configuring OpenID Connect
## Example Nextcloud
Discovery endpoint: http://host.docker.internal:8087/oauth/.well-known/openid-configuration/
Scope: openid email
Attribute mapping: keep default
Use unique Id: uncheck
## MyKDE
redirect uri: https://nextcloud.local/index.php/apps/user_oidc/code
client type: confidential
authorization type: authorization code
algorithm: rsa with sha 2 256
......@@ -13,6 +13,7 @@ https://docs.djangoproject.com/en/1.9/ref/settings/
import datetime
import pathlib
import pytz
import os
from django.urls import reverse_lazy
BASE_DIR = pathlib.Path(__file__).absolute().parent.parent
......@@ -30,6 +31,7 @@ DEBUG = False
ALLOWED_HOSTS = []
SITE_ID = 1
# Application definition
INSTALLED_APPS = [
......@@ -173,12 +175,16 @@ BLENDER_ID_ADDON_CLIENT_ID = "-secret-"
OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = "bid_main.OAuth2AccessToken"
OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = "bid_main.OAuth2RefreshToken"
OAUTH2_PROVIDER_APPLICATION_MODEL = "bid_main.OAuth2Application"
OAUTH2_PROVIDER_ID_TOKEN_MODEL = "oauth2_provider.IDToken"
OAUTH2_PROVIDER = {
"SCOPES": {
"email": "Default scope",
"badge": "Read access to the user's badges",
"openid": "OpenID Connect scope",
},
"OIDC_ENABLED": True,
"OIDC_RSA_PRIVATE_KEY": os.environ.get("OIDC_RSA_PRIVATE_KEY"),
"ALLOWED_REDIRECT_URI_SCHEMES": ["https"],
"REQUEST_APPROVAL_PROMPT": "auto",
"ACCESS_TOKEN_EXPIRE_SECONDS": 3600 * 24 * 31, # keep for a month
......@@ -186,6 +192,7 @@ OAUTH2_PROVIDER = {
"ACCESS_TOKEN_MODEL": OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL,
"REFRESH_TOKEN_MODEL": OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL,
"APPLICATION_MODEL": OAUTH2_PROVIDER_APPLICATION_MODEL,
"OAUTH2_VALIDATOR_CLASS": "bid_main.oauth_validator.KDEOAuth2Validator",
}
# This is required for compatibility with Blender Cloud, as it performs
......
......@@ -7,6 +7,7 @@ I've also removed the "management" URLs, as we use the admin interface for that.
# TODO(Sybren): move this file into bid_main, or move OAuth2 views into their own app.
from django.conf.urls import url
from django.urls import re_path
from oauth2_provider import views as default_oauth2_views
from bid_main.views import oauth2
......@@ -20,4 +21,11 @@ urlpatterns = (
default_oauth2_views.RevokeTokenView.as_view(),
name="revoke-token",
),
re_path(
r"^\.well-known/openid-configuration/$",
default_oauth2_views.ConnectDiscoveryInfoView.as_view(),
name="oidc-connect-discovery-info",
),
re_path(r"^\.well-known/jwks.json$", default_oauth2_views.JwksInfoView.as_view(), name="jwks-info"),
re_path(r"^userinfo/$", default_oauth2_views.UserInfoView.as_view(), name="user-info"),
)
This diff is collapsed.
......@@ -9,7 +9,7 @@ python = "^3.8"
Django = {version = "3.2", extras = ["bcrypt"]}
django-braces = "~1.13"
django-debug-toolbar = "~2.2"
django-oauth-toolkit = "~1.2"
django-oauth-toolkit = "1.7"
django-loginas = "~0.3"
mysqlclient = "~1"
python-dateutil = "~2.8"
......@@ -25,10 +25,11 @@ sorl-thumbnail = "~12"
dj-database-url = "^0.5.0"
django-environ = "^0.4.5"
django_extensions = "^2.2.9"
django-two-factor-auth = "^1.11.0"
phonenumbers = "^8.12.2"
django-two-factor-auth = "1.13.2"
ldap3 = "^2.7"
martor = "^1.5.0"
phonenumberslite = "^8.12.44"
phonenumbers = "^8.12.44"
[tool.poetry.dev-dependencies]
pytest = "*"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment