AWS で運用している API サービスに対して、特定のクライアントからのアクセスを許可したい。
こんな時、AWS Cognito を利用すれば、利用者ごとに一意な ID を割り振ることができます。
今回は既に Cognito で以下が設定されている前提で、Java 版の AWS SDK を使って認証を通してみましょう。
・ユーザプール
・ユーザ
・アプリクライアント
・クレデンシャル(IAM)
今回のケースでは、ユーザプールから取得した ID トークンをリクエストヘッダの Authorization に Bearer で指定させ、AWS の Web サービスとの認証が可能にすることを目的としています。
利用するライブラリ
AWS SDK の中から Cognito に特化したライブラリを利用してみましょう。
com.amazonaws:aws-java-sdk-cognitoidp
以下が SDK の Maven リポジトリ。
以下が SDK の GitHub になります。
2022 年 3 月時点での最新バージョンは 1.12.x になります。
Kotlin DSL の gradle の場合は以下のように定義すれば問題ありません。
implementation(“com.amazonaws:aws-java-sdk-cognitoidp:1.12.180”)
AWSCognitoIdentityProviderの取得
まずは AWS のクレデンシャルを使って、AWSCognitoIdentityProvider オブジェクトの作成をしてみましょう。
クレデンシャルはプロファイル(aws configure で生成した profile)でもいいですし、以下のキー値を直接指定することもできます。
・AWS_ACCESS_KEY_ID
・AWS_SECRET_ACCESS_KEY
プロファイルを使う
プロファイルを使う場合は、ProfileCredentialsProvider の引数にプロファイル名を指定します。
1 2 3 4 5 6 | AWSCredentialsProvider credentialsProvider = new ProfileCredentialsProvider("profileName"); AWSCognitoIdentityProvider cognitoIdentityProvider = AWSCognitoIdentityProviderClientBuilder.standard() .withCredentials(credentialsProvider) .withRegion(Regions.AP_NORTHEAST_1) .build(); |
キー値を使う
「AWS_ACCESS_KEY_ID」と「AWS_SECRET_ACCESS_KEY」を使う場合は BasicAWSCredentials を利用します。
これで AWSCredentials オブジェクトが生成されるので、AWSStaticCredentialsProvider を利用して AWSCredentialsProvider を作ります。
1 2 3 4 5 6 7 8 | AWSCredentials credentials = new BasicAWSCredentials("AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"); AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials); AWSCognitoIdentityProvider cognitoIdentityProvider = AWSCognitoIdentityProviderClientBuilder.standard() .withCredentials(credentialsProvider) .withRegion(Regions.AP_NORTHEAST_1) .build(); |
AWS のアカウントで STS を利用した一時認証を使っている場合はセッショントークンの指定も必要になるので注意が必要です。詳しくは AWS のドキュメントを参照してください。
セッショントークンを利用する場合は BasicAWSCredentials ではなく BasicSessionCredentials になります。
1 2 3 4 5 6 7 8 | AWSCredentials credentials = new BasicSessionCredentials("AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"); AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials); AWSCognitoIdentityProvider cognitoIdentityProvider = AWSCognitoIdentityProviderClientBuilder.standard() .withCredentials(credentialsProvider) .withRegion(Regions.AP_NORTHEAST_1) .build(); |
AssumeRoleを使う
いやいや、IAM ロールを使って Assume Role を利用したいという場面もありますよね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest() .withRoleArn("IAMロールのARN") .withRoleSessionName("任意の文字列"); AWSCredentialsProvider credentialsProvider = new InstanceProfileCredentialsProvider(true); AWSSecurityTokenService sts = AWSSecurityTokenServiceClientBuilder .standard() .withCredentials(credentialsProvider) .withRegion(Regions.AP_NORTHEAST_1) .build(); AssumeRoleResult assumeRoleResult = sts.assumeRole(assumeRoleRequest); Credentials credentials = assumeRoleResult.getCredentials(); |
credentials に以下の情報が入っているので、
・AWS_ACCESS_KEY_ID
・AWS_SECRET_ACCESS_KEY
・AWS_SESSION_TOKEN
あとは上で書いた BasicSessionCredentials を利用すれば OK です。
1 2 3 4 5 6 7 8 9 10 11 12 | AWSCredentials credentials = new BasicSessionCredentials( credentials.getAccessKeyId(), credentials.getSecretAccessKey(), credentials.getSessionToken() ); AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials); AWSCognitoIdentityProvider cognitoIdentityProvider = AWSCognitoIdentityProviderClientBuilder.standard() .withCredentials(credentialsProvider) .withRegion(Regions.AP_NORTHEAST_1) .build(); |
AssumeRole を利用する場合は、別途「aws-java-sdk-sts」のライブラリが必要になります。
IDトークンを取得する
冒頭でも書きましたが、既に Cognito のユーザプールやユーザは作成されているとします。
ID トークンの取得に必要は情報は以下の通り。
・ユーザ名
・パスワード
・ユーザプールID
・クライアントID
先ほど取得した AWSCognitoIdentityProvider(cognitoIdentityProvider)と上記の情報を合わせて認証してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 | Map<String, String> authParam = new HashMap<>(); authParam.put("USERNAME", "ユーザ名"); authParam.put("PASSWORD", "パスワード"); AdminInitiateAuthRequest request = new AdminInitiateAuthRequest(); request .withAuthFlow(AuthFlowType.ADMIN_NO_SRP_AUTH) .withUserPoolId("ユーザプールID") .withClientId("クライアントID") .withAuthParameters(authParam); AdminInitiateAuthResult authResult = cognitoIdentityProvider.adminInitiateAuth(request); |
ID トークンは以下のように取得できます。
authResult.getAuthenticationResult().getIdToken()
まとめ
AWS の Java SDK を使って、Cognito の認証を行ってみました。
必要な情報が揃っていれば、それほど大変な作業ではありませんね。
ちなみに ID トークンは JWT(JSON Web Token)形式となっています。
さらにヘッダ部分やペイロード部分を検証してあげることで、トークンが意図したものかどうか確認ができます。
