Cognito+SpringBoot+SpringSecurityでOAuth2認証する時の設定

# Cognito+SpringBoot+SpringSecurityでOAuth2認証する時の設定
散々嵌りまくったので設定方法や踏んだ地雷についてのメモ

## ユーザープールを作る
単純なOAuth2認証がしたいだけの場合はユーザープールを作成。

## 「属性」の設定
### ユーザー名かEmail/電話番号か
* 任意のユーザー名を付けたい場合はユーザー名側を選ぶ必要あり
* Email/電話番号を選ぶと、内部的なユーザー名はランダムな文字列になる

### カスタム属性
カスタム属性はPrincipalから取れる

``` java
//custom属性roleがADMINか確かめたい場合
	@RequestMapping("/")
	public String index(Principal principal) {
		if(principal instanceof OAuth2AuthenticationToken) {
			OAuth2AuthenticationToken token = (OAuth2AuthenticationToken)principal;
			return token.getPrincipal().getAttributes().entrySet().stream().anyMatch(e -> {
				return e.getKey().equals("custom:role") && e.getValue().equals("ADMIN");
			});
		}
　　　　　　　　　///省略
	}
```
なお、カスタム属性はCognitoの設定画面からは設定できないので、
AdminUpdateUserAttributesRequestなどを使って登録する必要がある

## ポリシー
一般的な設定でかつ嵌りどころもないので省略。
唯一気を付けるべきは仮パスワードであってもここの制限に引っかかることか。

## MFA
### 多要素認証の設定は一度設定すると取り返しがつかなくなるものもあるので注意。
例えば、MFA用のSMSロールを紐づけると解除できなくなる。(ロールも多要素認証も）

### SMSを利用する場合はSMSの利用上限に注意する
[こちらの記事](https://qiita.com/aki/items/e35e1bea8c27cfab5e9e)でも紹介されているが
SMSの上限がデフォルトだと極めて低。15通程度で上限に達するので事前に上限解放申請をしておくべき。
(ユーザーサポートへの問合せが必要なので即時反映を期待してはいけない)

### ワンタイムパスワード利用認証は独自認証画面を作っている時のみ
Google 認証システムに読み込ませるQRコードを生成するライブラリは用意されているものの、
デフォルトのログイン画面では表示してくれない。

## アプリクライアント
プール作成時は名前を決めるだけ。
プール作成後に戻ってきて設定を行う必要アリ。

## トリガー
最小構成では不要。
独自の認証を差し込みたい場合に。

## プールの作成
ここでプールIDが付与される。
プールIDは作成完了画面の他、サイドメニューの全般設定をクリックすると表示される。
(若干分かりにくい)

## アプリクライアント(再び)
戻っているとクライアントIDとクライアントシークレットが生成されているので控えておく
普通にOAuth2でつなぐだけならチェックボックスは無視してOK

## アプリクライアントの設定
* 有効なIDプロバイダ：Cognito User Pool
* コールバックURL:springの設定におけるredirect-uriの部分。``https://{自サービスのドメイン}/login/oauth2/code/cognito``https限定だが、localhostの場合のみhttpでも可能。
* サインアウトURL:任意のサインアウトURL
* フロー/スコープ Authorization code grant/openid

## ドメイン名の選択
使える文字列なら何でもOK
反映に少々時間(10～20分程度)かかる(なぜか削除画面側にのみ反映に時間がかかるという警告が出る)


## spring側の設定 
### application.ymlの設定

```yaml
spring:
  security:
    oauth2:
      client:
        registration:
          {アプリクライアント名}:
            client-id: {クライアントID}
            client-secret: {クライアントシークレット}
            client-name: {任意の文字列}
            provider: cognito
            scope: openid
            redirect-uri: {コールバックURI}
            authorization-grant-type: authorization_code
        provider:
          cognito:
            authorization-uri: https://{ドメイン名}.auth.ap-northeast-1.amazoncognito.com/oauth2/authorize
            token-uri: https://{ドメイン名}.auth.ap-northeast-1.amazoncognito.com/oauth2/token
            user-info-uri: https://{ドメイン名}.auth.ap-northeast-1.amazoncognito.com/oauth2/userInfo
            user-name-attribute: cognito:username
            jwk-set-uri: https://cognito-idp.ap-northeast-1.amazonaws.com/{プールID}/.well-known/jwks.json


```

### WebSecurityConfig
```
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    //とりあえず全部ログイン要求
	@Override
	public void configure(HttpSecurity http) throws Exception {
		http.oauth2Login().and().authorizeRequests().antMatchers("/**").authenticated().and().csrf()
				.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
	}

```

### リバプロを通す場合の注意点
https://qiita.com/xx2xyyy/items/5c6edf816894769c4b2d

## ユーザー作成時の注意点
### 招待をメールで送る場合にはSESの設定が必要
デフォルトではSESがSandboxモードになっており、
SESで認証したメールアドレスにしか招待メールを送ることができない。
こちらもSMSの設定と同じくサポートセンターに連絡しないと変更できない設定なので早めに対応しておく必要がある。