必須の個別エンドポイント設定
OIDC_OP_AUTHORIZATION_ENDPOINT = 'https://your-adfs-server/adfs/oauth2/authorize'
OIDC_OP_TOKEN_ENDPOINT = 'https://your-adfs-server/adfs/oauth2/token'
OIDC_OP_USER_ENDPOINT = 'https://your-adfs-server/adfs/oauth2/userinfo'
OIDC_OP_JWKS_ENDPOINT = 'https://your-adfs-server/adfs/discovery/keys'
Discovery Document とは
OpenID Connect Discovery Documentは、OIDCプロバイダーが提供する設定情報をまとめたJSONドキュメントです:
{
"issuer": "https://your-adfs-server/adfs",
"authorization_endpoint": "https://your-adfs-server/adfs/oauth2/authorize",
"token_endpoint": "https://your-adfs-server/adfs/oauth2/token",
"userinfo_endpoint": "https://your-adfs-server/adfs/oauth2/userinfo",
"jwks_uri": "https://your-adfs-server/adfs/discovery/keys",
"response_types_supported": ["code", "id_token", "token"],
"scopes_supported": ["openid", "email", "profile"],
"grant_types_supported": ["authorization_code", "implicit"]
}
mozilla-django-oidc での制約
mozilla-django-oidcライブラリは:
Discovery Documentの自動取得機能がない
各エンドポイントを個別に設定する必要がある
手動でDiscovery Documentを確認してエンドポイントURLを設定する必要がある
実際の設定手順
Discovery Documentを手動で確認:
bashcurl https://your-adfs-server/adfs/.well-known/openid-configuration
レスポンスから各エンドポイントを確認:
json{
"authorization_endpoint": "https://your-adfs-server/adfs/oauth2/authorize",
"token_endpoint": "https://your-adfs-server/adfs/oauth2/token",
"userinfo_endpoint": "https://your-adfs-server/adfs/oauth2/userinfo",
"jwks_uri": "https://your-adfs-server/adfs/discovery/keys"
}
Django設定に個別に記載:
python# settings.py
OIDC_OP_AUTHORIZATION_ENDPOINT = 'https://your-adfs-server/adfs/oauth2/authorize'
OIDC_OP_TOKEN_ENDPOINT = 'https://your-adfs-server/adfs/oauth2/token'
OIDC_OP_USER_ENDPOINT = 'https://your-adfs-server/adfs/oauth2/userinfo'
OIDC_OP_JWKS_ENDPOINT = 'https://your-adfs-server/adfs/discovery/keys'
認証フローの概要
- ユーザーがログインリンクをクリック
- DjangoがADFSの認証エンドポイントにリダイレクト
- ユーザーがADFSでログイン
- ADFSがDjangoのコールバックURLにリダイレクト(認可コード付き)
- Djangoが認可コードをアクセストークンに交換
- DjangoがADFSからユーザー情報を取得
- カスタム認証バックエンドでユーザー作成/更新
- Djangoアプリケーションにログイン完了
詳細な認証フロー
- ログイン開始フェーズ
html
ログイン
使われる設定値:
pythonOIDC_RP_CLIENT_ID = 'your-adfs-client-id'
OIDC_RP_SCOPES = 'openid email profile'
OIDC_OP_AUTHORIZATION_ENDPOINT = 'https://your-adfs-server/adfs/oauth2/authorize'
内部処理:
mozilla_django_oidcのOIDCAuthenticationRequestViewが呼び出される
以下のような認証URLが生成される:
https://your-adfs-server/adfs/oauth2/authorize?
client_id=your-adfs-client-id&
response_type=code&
scope=openid email profile&
redirect_uri=https://your-django-app.com/oidc/callback/&
state=random-state-value&
nonce=random-nonce-value
ユーザーのブラウザがこのURLにリダイレクトされる
- ADFS認証フェーズ
ユーザー → ADFS認証画面でログイン → 認証成功
ADFSでの処理:
ユーザーの認証情報を検証
設定されたスコープに基づいてクレームを準備
認可コードを生成
- コールバック処理フェーズ
ADFSから以下のようなコールバックが来る:
https://your-django-app.com/oidc/callback/?
code=authorization-code&
state=same-state-value
使われる設定値:
pythonOIDC_RP_CLIENT_SECRET = 'your-adfs-client-secret'
OIDC_OP_TOKEN_ENDPOINT = 'https://your-adfs-server/adfs/oauth2/token'
内部処理:
OIDCAuthenticationCallbackViewが処理を開始
stateパラメータの検証
認可コードをアクセストークンに交換するリクエスト:
python# mozilla-django-oidcが内部で実行するリクエスト
POST https://your-adfs-server/adfs/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=authorization-code&
redirect_uri=https://your-django-app.com/oidc/callback/&
client_id=your-adfs-client-id&
client_secret=your-adfs-client-secret
4. ユーザー情報取得フェーズ
使われる設定値:
pythonOIDC_OP_USER_ENDPOINT = 'https://your-adfs-server/adfs/oauth2/userinfo'
OIDC_OP_JWKS_ENDPOINT = 'https://your-adfs-server/adfs/discovery/keys'
OIDC_RP_SIGN_ALGO = 'RS256'
内部処理:
IDトークンのJWT署名を検証(JWKS_ENDPOINTから公開鍵取得)
ユーザー情報エンドポイントからクレーム取得:
python# mozilla-django-oidcが内部で実行するリクエスト
GET https://your-adfs-server/adfs/oauth2/userinfo
Authorization: Bearer access-token
取得されるクレーム例:
json{
"sub": "user-unique-id",
"email": "user@company.com",
"upn": "user@company.com",
"given_name": "太郎",
"family_name": "山田",
"preferred_username": "yamada.taro"
}
5. カスタム認証バックエンド処理フェーズ
使われる設定値:
pythonAUTHENTICATION_BACKENDS = [
'your_app.auth_backends.ADFSOIDCAuthenticationBackend',
'django.contrib.auth.backends.ModelBackend',
]
カスタムバックエンドの各メソッドがどう呼び出されるか:
pythonclass ADFSOIDCAuthenticationBackend(OIDCAuthenticationBackend):
def filter_users_by_claims(self, claims):
"""
1番目に呼び出される - 既存ユーザーの検索
claims = {
"email": "user@company.com",
"given_name": "太郎",
"family_name": "山田",
...
}
"""
email = claims.get('email') or claims.get('upn')
try:
return self.UserModel.objects.filter(email__iexact=email)
except self.UserModel.DoesNotExist:
return self.UserModel.objects.none()
def create_user(self, claims):
"""
既存ユーザーが見つからない場合に呼び出される
"""
email = claims.get('email') or claims.get('upn')
username = claims.get('preferred_username') or email
user = User.objects.create_user(
username=username,
email=email,
first_name=claims.get('given_name', ''),
last_name=claims.get('family_name', ''),
)
return user
def update_user(self, user, claims):
"""
既存ユーザーが見つかった場合、または新規作成後に呼び出される
"""
user.email = claims.get('email', user.email)
user.first_name = claims.get('given_name', user.first_name)
user.last_name = claims.get('family_name', user.last_name)
user.save()
return user
- セッション確立・リダイレクトフェーズ
使われる設定値:
pythonLOGIN_REDIRECT_URL = '/'
OIDC_STORE_ACCESS_TOKEN = True
OIDC_STORE_ID_TOKEN = True
内部処理:
Djangoセッションにユーザー情報を保存
設定に応じてアクセストークン・IDトークンをセッションに保存
LOGIN_REDIRECT_URLにリダイレクト
実際の処理フローの追跡例
python# デバッグ用のカスタムバックエンド例
import logging
logger = logging.getLogger(name)
class DebugADFSOIDCAuthenticationBackend(OIDCAuthenticationBackend):
def filter_users_by_claims(self, claims):
logger.info(f"🔍 ユーザー検索開始: {claims}")
email = claims.get('email') or claims.get('upn')
users = self.UserModel.objects.filter(email__iexact=email)
logger.info(f"🔍 検索結果: {users.count()}件")
return users
def create_user(self, claims):
logger.info(f"👤 新規ユーザー作成: {claims.get('email')}")
user = super().create_user(claims)
logger.info(f"✅ ユーザー作成完了: {user.username}")
return user
def update_user(self, user, claims):
logger.info(f"🔄 ユーザー更新: {user.username}")
user = super().update_user(user, claims)
logger.info(f"✅ ユーザー更新完了")
return user
設定値とエンドポイントの対応関係
python# 認証開始時
OIDC_OP_AUTHORIZATION_ENDPOINT → /adfs/oauth2/authorize
トークン交換時
OIDC_OP_TOKEN_ENDPOINT → /adfs/oauth2/token
ユーザー情報取得時
OIDC_OP_USER_ENDPOINT → /adfs/oauth2/userinfo
JWT署名検証時
OIDC_OP_JWKS_ENDPOINT → /adfs/discovery/keys
または discovery document使用時
OIDC_OP_DISCOVERY_ENDPOINT → /adfs/.well-known/openid-configuration
この一連のフローにより、ADFSでの認証からDjangoアプリケーションへのシームレスなログインが実現されます。各設定値は認証プロセスの特定の段階で使用され、カスタム認証バックエンドによってADFS特有のクレーム情報が適切にDjangoユーザーモデルにマッピングされます。