[Feature] Initial Active Directory / Entra Login (#101)

Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#101
This commit is contained in:
2025-09-10 08:29:27 +12:00
parent 4463bf1bc8
commit e82fe7e87e
13 changed files with 146 additions and 5 deletions

0
epauth/__init__.py Normal file
View File

3
epauth/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
epauth/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class EpauthConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'epauth'

View File

3
epauth/models.py Normal file
View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

3
epauth/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

8
epauth/urls.py Normal file
View File

@ -0,0 +1,8 @@
from django.urls import path
from . import views
urlpatterns = [
path("microsoft/login/", views.microsoft_login, name="microsoft_login"),
path("microsoft/callback/", views.microsoft_callback, name="microsoft_callback"),
]

66
epauth/views.py Normal file
View File

@ -0,0 +1,66 @@
import msal
from django.conf import settings as s
from django.contrib.auth import login
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
from epdb.logic import UserManager
def microsoft_login(request):
msal_app = msal.ConfidentialClientApplication(
client_id=s.MS_ENTRA_CLIENT_ID,
client_credential=s.MS_ENTRA_CLIENT_SECRET,
authority=s.MS_ENTRA_AUTHORITY
)
flow = msal_app.initiate_auth_code_flow(
scopes=s.MS_ENTRA_SCOPES,
redirect_uri=s.MS_ENTRA_REDIRECT_URI
)
request.session["msal_auth_flow"] = flow
return redirect(flow["auth_uri"])
def microsoft_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
)
flow = request.session.pop("msal_auth_flow", None)
if not flow:
return redirect("/")
# Acquire token using the flow and callback request
result = msal_app.acquire_token_by_auth_code_flow(flow, request.GET)
if "access_token" in result:
# Optional: Fetch user info from Microsoft Graph
import requests
resp = requests.get(
"https://graph.microsoft.com/v1.0/me",
headers={"Authorization": f"Bearer {result['access_token']}"}
)
user_info = resp.json()
user_name = user_info["displayName"]
user_email = user_info["mail"]
user_oid = user_info["id"]
# Get implementing class
User = get_user_model()
if User.objects.filter(uuid=user_oid).exists():
login(request, User.objects.get(uuid=user_oid))
else:
u = UserManager.create_user(user_name, user_email, None, uuid=user_oid, is_active=True)
login(request, u)
# TODO Group Sync
return redirect("/")
return redirect("/") # Handle errors