2
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?

More than 1 year has passed since last update.

Keycloakを用いたAuthorization Code Grant + PKCE 検証環境構築方法 メモ

Last updated at Posted at 2022-01-21
  • 学習目的でKeycloakを使ったAuthorization Code Grant + PKCE を検証するための環境を構築したためメモとして残しておく。

  • **過去に作成したコード**を修正して構築する。

    • 変更点を主として記述する。
    • docker-composeなどの設定ファイルはそのまま利用する。

main.py修正

  • code_verifier・code_challenge生成処理などを追加する。

    import ast
    import urllib.parse as parse
    import urllib.request as req
    import urllib.error as error
    import os
    import requests
    import uvicorn
    from fastapi import FastAPI
    from starlette.requests import Request
    from starlette.responses import RedirectResponse
    import base64
    import re
    import hashlib
    # 環境変数取得
    # FastAPI アプリ用
    APP_BASE_URL = os.getenv("APP_BASE_URL")
    APP_CLIENT_ID = os.getenv("CLIENT_ID")
    APP_CLIENT_SECRET = os.getenv('CLIENT_SECRET')
    APP_REDIRECT_URI = os.getenv('REDIRECT_URI')
    
    # Keycloak用
    # Authorization Endpoint
    KEYCLOAK_BASE_URL_LOCALHOST = os.getenv("KEYCLOAK_BASE_URL_LOCALHOST")
    # "Master"は対象のレルム名を指定する。
    AUTH_BASE_URL = (
        f"{KEYCLOAK_BASE_URL_LOCALHOST}auth/realms/Master"
        "/protocol/openid-connect/auth"
    )
    # Token Endpoint
    # コンテナ間通信するためコンテナ名を指定
    # "Master"は対象のレルム名を指定する。
    KEYCLOAK_BASE_URL_CONTAINER_NAME = os.getenv(
        "KEYCLOAK_BASE_URL_CONTAINER_NAME")
    TOKEN_URL = (
        f"{KEYCLOAK_BASE_URL_CONTAINER_NAME}auth/realms/master"
        "/protocol/openid-connect/token"
    )
    
    app = FastAPI()
    
    # Keycloak Authorization Endpointへのリダイレクト
    @app.get("/auth/login")
    async def login() -> RedirectResponse:
        # ステート生成
        state = hashlib.sha256(os.urandom(32)).hexdigest()
    
        # 追加:code_verifier生成
        code_verifier = base64.urlsafe_b64encode(os.urandom(40)).decode('utf-8')
        code_verifier = re.sub('[^a-zA-Z0-9]+', '', code_verifier)
        # 追加:code_challenge生成
        code_challenge = hashlib.sha256(code_verifier.encode('utf-8')).digest()
        code_challenge = base64.urlsafe_b64encode(code_challenge).decode('utf-8')
        code_challenge = code_challenge.replace('=', '')
    
        # Authorization Endpointへリダイレクト
        AUTH_URL = AUTH_BASE_URL + '?{}'.format(parse.urlencode({
            'client_id': APP_CLIENT_ID,
            'redirect_uri': APP_REDIRECT_URI,
            'state': state,
            'response_type': 'code',
            'code_challenge':code_challenge, # 追加
            'code_challenge_method':'S256'  # 追加
        }))
        response = RedirectResponse(AUTH_URL)
        # ステート、code_verifier保存 ※保存方法要検討。暫定でcookieに保存。
        response.set_cookie(key="AUTH_STATE", value=state)
        response.set_cookie(key="AUTH_CODE_VERIFIER", value=code_verifier)
        return response
    
    
    # Token Request
    def get_token(code,code_verifier):
    
        params = {
            'client_id': APP_CLIENT_ID,
            'client_secret': APP_CLIENT_SECRET,
            'grant_type': 'authorization_code',
            'redirect_uri': APP_REDIRECT_URI,
            'code': code,
            'code_verifier': code_verifier #追加
        }
        x = requests.post(TOKEN_URL, params, verify=False).content.decode('utf-8')
        return ast.literal_eval(x)
    
    
    # Redirection Endpoint
    # ステートと認可コードを受け取る。
    # ステート検証後、トークンリクエストを実行する。
    @app.get("/auth/callback")
    async def auth(request: Request, code: str, state: str) -> RedirectResponse:
        # State検証
        if state != request.cookies.get("AUTH_STATE"):
            return {"error": "state_verification_failed"}
        # 追加:code_verifier設定
        return get_token(code,  request.cookies.get("AUTH_CODE_VERIFIER"))
    
    if __name__ == "__main__":
        uvicorn.run(app, port=8000, loop="asyncio")
    
    

KeyCloak準備

  • コンテナを起動する

    docker-compose up
    
  • Keycloak Admin コンソールにアクセスする。

    http://localhost:8080
    

    ※ログイン情報はdocker-composeに記載

  • クライアント(Clients)を登録する。

    • 「Advanced Settings」->「Proof Key for Code Exchange Code Challenge Method 」で「S256」を選択する。
    • その他の登録情報は、**Keycloak: Authorization Code Grant Example**を参考に設定する。
  • テストユーザー(Users)を登録する。

  • コンテナを再起動する。

    docker-compose down
    docker-compose build
    docker-compose up
    

動作確認

  • Keycloak Authorization Endpointリダイレクト用エンドポイントにアクセスする。

    http://localhost:8000/auth/login
    
  • ユーザー認証を行う。

  • FastAPI側のリダイレクトURIにリダイレクトされ、ブラウザに以下のようなトークンレスポンスJSONが表示される。

    {    
        "access_token": "...",    
        "expires_in": 60,    
        "refresh_expires_in": 1800,    
        "refresh_token": "...",    
        "token_type": "Bearer",    
        "not-before-policy": 0,    
        "session_state": "...",    
        "scope": "profile email"
    }
    

参考情報

2
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
2
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?