0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ADFS_mozilla_django

Last updated at Posted at 2025-08-18

必須の個別エンドポイント設定

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'

認証フローの概要

  1. ユーザーがログインリンクをクリック
  2. DjangoがADFSの認証エンドポイントにリダイレクト
  3. ユーザーがADFSでログイン
  4. ADFSがDjangoのコールバックURLにリダイレクト(認可コード付き)
  5. Djangoが認可コードをアクセストークンに交換
  6. DjangoがADFSからユーザー情報を取得
  7. カスタム認証バックエンドでユーザー作成/更新
  8. Djangoアプリケーションにログイン完了

詳細な認証フロー

  1. ログイン開始フェーズ
    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にリダイレクトされる

  1. ADFS認証フェーズ
    ユーザー → ADFS認証画面でログイン → 認証成功
    ADFSでの処理:

ユーザーの認証情報を検証
設定されたスコープに基づいてクレームを準備
認可コードを生成

  1. コールバック処理フェーズ
    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
  1. セッション確立・リダイレクトフェーズ
    使われる設定値:
    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ユーザーモデルにマッピングされます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?