Amazon API GatewayでAzure ADのトークンを処理してみた

2021.09.16

いわさです。

Amazon API GatewayとAzure ADを連携させようと色々と試しております。
ユーザー操作をはさんでリダイレクトを使ってトークンを返す部分があるのですが、本日はAPI Gatewayを使って、このフローを処理しAzure ADへのサインインとトークンの取得を行ってみました。

API Gatewayにリダイレクトさせる部分とトークンを受け取る部分をそれぞれ用意する

以下のように処理リソースを2つ用意し、処理1ではAzure AD認証画面へのリダイレクトをさせて、RedirectURIに処理2を指定するようにします。
ユーザーの操作による認証/承認処理のあとに処理2でトークンを受け取ります。

API Gateway + Lambdaの作成

2つAPIリソースを作成しました。

処理1はリダイレクトさせるだけです。
処理2はPOSTでフォームデータを受信します。

リダイレクト処理

単純にHTTPのGETリクエストに対してリダイレクトさせるだけです。
実際はパラメータを動的にすべきと思いますが、今回はハードコードしてますのでご注意を。
リダイレクト先にはAzure AD認証後のRedirectURIパラメータを含む必要があり、ここで処理2を指定します。

処理1

exports.handler = async (event) => {
    const response = {
        statusCode: 301,
        headers: {
            Location: 'https://login.microsoftonline.com/9b9e2fc6-dc1a-4d7f-97ff-e86600ac5b48/oauth2/v2.0/authorize?client_id=a69a8b7c-236f-4b11-8256-c734a884c2df&response_type=token+id_token&scope=user.read+openid+profile+email&response_mode=form_post&state=12345&nonce=678910&redirect_uri=https%3A%2F%2F1bdqc3iioc.execute-api.ap-northeast-1.amazonaws.com%2Fhoge%2Fsyori2'
        }
    };
    return response;
};

トークン受信処理

処理2

exports.handler = async (event) => {
    // TODO implement
    const response = {
        statusCode: 200,
        body: JSON.stringify(event),
    };
    return response;
};

Content-Typeはx-www-form-urlencodedで、フォームデータにJson形式でトークンやら何やらが渡されてきます。
よって、マッピングテンプレートでbodyでJson設定をしてやる必要があります。
といってもデフォルトのパススルーテンプレートでとりあえず受信は出来ますので今回はこちらを使いました。

マッピングテンプレート

##  See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
##  This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload
#set($allParams = $input.params())
{
"body-json" : $input.json('$'),
"params" : {
#foreach($type in $allParams.keySet())
    #set($params = $allParams.get($type))
"$type" : {
    #foreach($paramName in $params.keySet())
    "$paramName" : "$util.escapeJavaScript($params.get($paramName))"
        #if($foreach.hasNext),#end
    #end
}
    #if($foreach.hasNext),#end
#end
},
"stage-variables" : {
#foreach($key in $stageVariables.keySet())
"$key" : "$util.escapeJavaScript($stageVariables.get($key))"
    #if($foreach.hasNext),#end
#end
},
"context" : {
    "account-id" : "$context.identity.accountId",
    "api-id" : "$context.apiId",
    "api-key" : "$context.identity.apiKey",
    "authorizer-principal-id" : "$context.authorizer.principalId",
    "caller" : "$context.identity.caller",
    "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider",
    "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType",
    "cognito-identity-id" : "$context.identity.cognitoIdentityId",
    "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId",
    "http-method" : "$context.httpMethod",
    "stage" : "$context.stage",
    "source-ip" : "$context.identity.sourceIp",
    "user" : "$context.identity.user",
    "user-agent" : "$context.identity.userAgent",
    "user-arn" : "$context.identity.userArn",
    "request-id" : "$context.requestId",
    "resource-id" : "$context.resourceId",
    "resource-path" : "$context.resourcePath"
    }
}

こちらを参考にさせて頂きました。

Azure AD側にリダイレクトURIを追加する

認証URL内のRedirectURIに指定出来るのはAzure AD側に事前に登録されたURIのみです。
API Gatewayに作成した処理2のURLを追加します。

動作確認

処理1にブラウザでアクセスします。

https://1bdqc3iioc.execute-api.ap-northeast-1.amazonaws.com/hoge/syori1

Azure ADの認証画面に遷移しますね。
認証を行います。

処理2に遷移し、画面にトークンが表示されました。

まとめ

Azure ADに関わらず、リダイレクトURIを指定してトークンを受け取るシーンは多いと思いますので試してみました。
Azure ADの場合だと、リダイレクトURIを事前登録しておく必要があるという点が注意点でしょうか。