More on PES

This commit is contained in:
Tim Lorsbach
2026-04-15 21:14:47 +02:00
parent 349877b5e3
commit ca0508d96a
11 changed files with 544 additions and 34 deletions

View File

@ -1,12 +1,33 @@
import msal
from django.conf import settings as s
from django.contrib.auth import get_user_model
from django.contrib.auth import login
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
from epdb.logic import UserManager, GroupManager
from epdb.models import Group
def get_msal_app_with_cache(request):
"""
Create MSAL app with session-based token cache.
"""
cache = msal.SerializableTokenCache()
# Load cache from session if it exists
if request.session.get("msal_token_cache"):
cache.deserialize(request.session["msal_token_cache"])
msal_app = msal.ConfidentialClientApplication(
client_id=s.MS_ENTRA_CLIENT_ID,
client_credential=s.MS_ENTRA_CLIENT_SECRET,
authority=s.MS_ENTRA_AUTHORITY,
token_cache=cache
)
return msal_app, cache
def entra_login(request):
msal_app = msal.ConfidentialClientApplication(
client_id=s.MS_ENTRA_CLIENT_ID,
@ -23,11 +44,7 @@ def entra_login(request):
def entra_callback(request):
msal_app = msal.ConfidentialClientApplication(
client_id=s.MS_ENTRA_CLIENT_ID,
client_credential=s.MS_ENTRA_CLIENT_SECRET,
authority=s.MS_ENTRA_AUTHORITY,
)
msal_app, cache = get_msal_app_with_cache(request)
flow = request.session.pop("msal_auth_flow", None)
if not flow:
@ -35,24 +52,10 @@ def entra_callback(request):
# Acquire token using the flow and callback request
result = msal_app.acquire_token_by_auth_code_flow(flow, request.GET)
print(result)
# if "error" in result:
# {'correlation_id': '626f511b-5230-4d06-9ffd-d89a764082c6',
# 'error': 'invalid_client',
# 'error_codes': [7000222],
# 'error_description': 'AADSTS7000222: The provided client secret keys for app '
# "'35c75dfb-bd15-493d-b4e9-af847f2df894' are expired. "
# 'Visit the Azure portal to create new keys for your app: '
# 'https://aka.ms/NewClientSecret, or consider using '
# 'certificate credentials for added security: '
# 'https://aka.ms/certCreds. Trace ID: '
# '30ba1c58-c949-4432-9ed6-3b6136856700 Correlation ID: '
# '626f511b-5230-4d06-9ffd-d89a764082c6 Timestamp: '
# '2026-04-15 08:21:15Z',
# 'error_uri': 'https://login.microsoftonline.com/error?code=7000222',
# 'timestamp': '2026-04-15 08:21:15Z',
# 'trace_id': '30ba1c58-c949-4432-9ed6-3b6136856700'}
# return redirect("/")
# Save the token cache to session
if cache.has_state_changed:
request.session["msal_token_cache"] = cache.serialize()
claims = result["id_token_claims"]
@ -79,7 +82,8 @@ def entra_callback(request):
# Ensure groups exists in eP
for id, name in s.ENTRA_SECRET_GROUPS.items():
if not Group.objects.filter(uuid=id).exists():
g = GroupManager.create_group(User.objects.get(username="admin"), name, f"Synced Entra Group {name} ", uuid=id)
g = GroupManager.create_group(User.objects.get(username="admin"), name, f"Synced Entra Group {name} ",
uuid=id)
else:
g = Group.objects.get(uuid=id)
# Ensure its secret
@ -88,7 +92,8 @@ def entra_callback(request):
for id, name in s.ENTRA_GROUPS.items():
if not Group.objects.filter(uuid=id).exists():
g = GroupManager.create_group(User.objects.get(username="admin"), name, f"Synced Entra Group {name} ", uuid=id)
g = GroupManager.create_group(User.objects.get(username="admin"), name, f"Synced Entra Group {name} ",
uuid=id)
else:
g = Group.objects.get(uuid=id)
@ -100,3 +105,53 @@ def entra_callback(request):
# EDIT END
return redirect(s.SERVER_URL) # Handle errors
def get_access_token_from_request(request, scopes=None):
"""
Get an access token from the request using MSAL token cache.
"""
if scopes is None:
scopes = s.MS_ENTRA_SCOPES
# Get user from request (must be authenticated)
if not request.user.is_authenticated:
return None
# Create MSAL app with persistent cache
msal_app, cache = get_msal_app_with_cache(request)
# Try to get accounts from cache
accounts = msal_app.get_accounts()
if not accounts:
return None
# Find the account that matches the current user
user_account = None
for account in accounts:
if account.get("local_account_id") == str(request.user.uuid):
user_account = account
break
# If no matching account found, use the first available account
if not user_account and accounts:
user_account = accounts[0]
if not user_account:
return None
# Try to acquire token silently from cache
result = msal_app.acquire_token_silent(
scopes=scopes,
account=user_account
)
# Save cache changes back to session
if cache.has_state_changed:
request.session["msal_token_cache"] = cache.serialize()
if result and "access_token" in result:
return result
return None