Files
konova/konova/views/oauth.py
T
mpeltriaux e3d5ee82ee # OAuth2 update
* integrates authlib into project
* adds authlib package to requirements.txt
* refactors internal konova/utils/generators/generate_token method to use authlib's generate_token method and act as wrapper for backwards compatibility
* refactors OAuth views to be based on authlib's oauth client implementation
* refactors oauth model to work with authlib's oauth2 tokens
2026-10-06 11:27:50 +02:00

112 lines
3.3 KiB
Python

"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 26.04.24
"""
import base64
import hashlib
from authlib.common.security import generate_token
from authlib.integrations.base_client import OAuthError
from authlib.integrations.django_client import OAuth
from django.contrib.auth import login
from django.http import HttpRequest, HttpResponse
from django.shortcuts import redirect
from django.urls import reverse
from django.views import View
from api.models import OAuthToken
from konova.sub_settings.django_settings import BASE_URL
from konova.sub_settings.sso_settings import SSO_SERVER_BASE, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET
_OAUTH = OAuth()
_OAUTH.register(
name="sso",
client_id=OAUTH_CLIENT_ID,
client_secret=OAUTH_CLIENT_SECRET,
authorize_url=f"{SSO_SERVER_BASE}o/authorize/",
access_token_url=f"{SSO_SERVER_BASE}o/token/",
code_challenge_method="S256",
client_kwargs={},
)
class OAuthLoginView(View):
""" View for OAuth2 login step
"""
def get(self, request: HttpRequest, *args, **kwargs):
redirect_uri = f'{BASE_URL}{reverse("oauth-callback")}'
# create new PKCE-Verifier
code_verifier, code_challenge = self.__create_code_challenge()
# keep verifier in session, so it can be read out for callback
request.session["oauth_code_verifier"] = code_verifier
return _OAUTH.sso.authorize_redirect(
request,
redirect_uri,
code_verifier=code_verifier,
)
def __create_code_challenge(self):
"""
Creates a code verifier and code challenge for extra security.
See https://django-oauth-toolkit.readthedocs.io/en/latest/getting_started.html#authorization-code for further
information
Returns:
"""
code_verifier = generate_token(128)
code_challenge = hashlib.sha256(code_verifier.encode('utf-8')).digest()
code_challenge = base64.urlsafe_b64encode(code_challenge).decode('utf-8').replace('=', '')
return code_verifier, code_challenge
class OAuthCallbackView(View):
""" View for OAuth2 callback step
"""
def get(self, request: HttpRequest, *args, **kwargs):
# Get code verifier (created on oatuh-login step) from session
code_verifier = request.session.pop(
"oauth_code_verifier",
None,
)
if not code_verifier:
return HttpResponse(
"PKCE code_verifier missing or is invalid.",
status=400,
)
try:
token = _OAUTH.sso.authorize_access_token(
request
)
except OAuthError as e:
print(e)
return HttpResponse(
"OAuth-Login failed while authorizing with OAuth.",
status=400,
)
try:
oauth_token = OAuthToken.create_from_oauth2_token(token)
except AssertionError:
return HttpResponse(
"OAuth-Login failed due to unexpected token content.",
status=400,
)
oauth_token.save()
user = oauth_token.update_and_get_user()
user.oauth_replace_token(oauth_token)
login(request, user)
return redirect("home")