LoginSignup
7
2

More than 1 year has passed since last update.

ALBの認証に対するログアウト処理(ALB + Cognito + Lambda)

Last updated at Posted at 2021-04-01

はじめに

AWSでは、Webサービスの認証機能は、ALBを使うのが超便利ですね!
ここでは、まず準備段階として認証機能を実装します。(→「準備」の段落)
つぎに、ログアウト処理を追加します。(→「ログアウトの実装」の段落)

ALBに認証させる方法は、いろいろな方が書いてくれています。そちらを参考にしてください。
以下、クラスメソッドさんの記事です。

準備

まず、ALBにCognitoを連携し、ログインの実装まで。
上のリンクのとおりに、ALB、Cognitoユーザープールなどは実装してください。
WebサーバはLambdaでベタ書きします。EC2は面倒なので。ログアウトの処理がやりたいので手抜きです。

Webサーバ

Lambda関数を、Python3.8で実装する。

import json

def lambda_handler(event, context):

    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'text/html; charset=utf-8'
        },
        'body': '''
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>title</title>
  </head>
  <body>
    テスト
  </body>
</html>
'''
    }

ターゲットグループの作成

ターゲットをこのLambda関数にしたターゲットグループを作成します。

Cognitoユーザープールの作成、ALBの作成、ターゲットと認証の登録

上にあるリンク先のとおりに。
ここまでで、認証をもったWebサイトができたとします。

ログアウトの実装

方法

認証からログアウトさせる方法は、以下に記載があります。

認証セッション Cookie の有効期限を -1 に設定し、クライアントを IdP ログアウトエンドポイントにリダイレクトする

① Cookieの有効期限を-1に設定する。

認証セッションのCookieは、ALBで設定しています。
どのCookieを使っているの?
→ 下の、セッションCookieのところにあります。(※ここはCookie名の確認のみ。)
変更していなかったので、デフォルトですね(^_^;)
「AWSELBAuthSessionCookie-0」「AWSELBAuthSessionCookie-1」が使われていました。
これらCookieの有効期限を、プログラムから-1に設定します。
スクリーンショット 2021-04-01 16.44.44.png

② クライアントをIdPログアウトエンドポイントにリダイレクトする。

IdPはCognitoです。Cognitoのログアウトエンドポイントは以下に記載あり。

プログラムから、ログアウトエンドポイントに、クライアントIDとログアウトURLを渡してあげればいいわけです。
例のとおり、こんな感じ。

GET https://mydomain.auth.us-east-1.amazoncognito.com/logout?client_id=ad398u21ijw3s9w3939&logout_uri=https://myclient/logout

クライアントIDは、ALBがヘッダーに渡してくれているので、そこから取り出します。

ユーザークレーム(x-amzn-oidc-data)のJWTヘッダーにクライアントID(client_id)があります。
ログアウトURLは、ログアウト後に遷移するURLのことです。ここではまたログイン画面を出したいと思います。つまり、WebサーバにアクセスするURL(=ALBのエンドポイント)とします。

Lambdaにログアウト処理を追加

パスに"logout"があるときにログアウトをさせます。

import json
import base64
import urllib.parse

def lambda_handler(event, context):
    # print(event)
    headers = event['headers']
    # JwtヘッダをDict型に変換
    encoded_jwt = headers['x-amzn-oidc-data']
    jwt_headers = encoded_jwt.split('.')[0]
    decoded_jwt_headers = base64.urlsafe_b64decode(jwt_headers)
    decoded_jwt_headers = decoded_jwt_headers.decode("utf-8")
    decoded_json = json.loads(decoded_jwt_headers)

    path = event['path']
    # ログアウト処理
    if path.find('logout') > 0:
      logout_uri = 'https://<ELBのドメイン>.ap-northeast-1.elb.amazonaws.com'

      redirect_url = 'https://<ユーザープールのドメインのプレフィックス>.auth.ap-northeast-1.amazoncognito.com/logout?client_id=' \
        + decoded_json['client'] + '&logout_uri=' + urllib.parse.quote(logout_uri, encoding='utf-8')
      return {
        'statusCode': 302,
        'headers': {
          'Set-Cookie': 'AWSELBAuthSessionCookie-0=; max-age=0',
          'Set-CookiE': 'AWSELBAuthSessionCookie-1=; max-age=0',
          'Access-Control-Allow-Origin': logout_uri,
          'Access-Control-Allow-Methods': 'GET',
          'Location': redirect_url
        }
      }

    return {
        'statusCode': 200,
        'headers': {
          'Content-Type': 'text/html; charset=utf-8'
        },
        'body': '''
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>title</title>
  </head>
  <body>
    テスト
  </body>
</html>
'''
    }

<>の箇所は、自分の値を設定します。

ユーザープールへのリダイレクトの追加

ユーザープールのアプリクライアントに、サインアウト(ログアウト)のURLを設定します。上に書いたように、ALBのエンドポイントとしました。

スクリーンショット 2021-04-01 17.49.33.png

動作確認

ELBのDNS名にブラウザでアクセスしてログインからサイトの表示
https://<ELB名>.ap-northeast-1.elb.amazonaws.com
ログアウトするとき → ログイン画面に遷移
https://<ELB名>.ap-northeast-1.elb.amazonaws.com/logout

おわりに

100%理解していないところもありますが、動くので掲載しました!!

  • ユーザークレームの署名の検証は省略しています。本来は、必要に応じて検証を実施すべきです。(コードが長くなったのと、ライブラリのインポートの説明が必要になるので、省略しました。)

  • リダイレクトのステータスコードは302にしていますが、301とか、ちゃんと理解できてないです(^_^;)
  • MacOS+Safariで確認しています。MacOS+Chromeだと、httpsの自己証明書ではALBのドメインにアクセス出来ませんでした。
  • リージョンはTokyo(ap-northeast-1)に固定してしまっています。
7
2
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
7
2