【翻訳】Amazon Cognito Authentication を理解する Part 1

以下の記事を翻訳したものです。
http://mobile.awsblog.com/post/Tx2UQN4KWI6GDJL/Understanding-Amazon-Cognito-Authentication

個人的に訳したものであり所属する企業や団体における公式見解ならびに公式発表ではございません。

***
[Amazon Cognito](http://aws.amazon.com/jp/cognito/) はデバイスやプラットフォームをまたいで一貫性のある一意な identity をエンドユーザに対して提供します。また、AWSの各種リソースを利用するための権限を、一時的もしくは限定的にアプリケーションへ付与します。本日は、 Cognito の認証の基本的な動作を踏まえつつ、 identity pool にある identity のライフサイクルを説明しましょう。

## Basic Authflow

以前に投稿したブログ記事を踏まえると(*1)、 Cognito のユーザ認証は identity を発行するまで 3 つの処理から構成されます。※1:http://mobile.awsblog.com/ Sep. 24, 2014 以前の記事を確認ください

1. GetId
2. GetOpenIdToken
3. AssumeRoleWithWebIdentity

この 3 つの処理を終えると、 role で指定したアクセスポリシーにしたがって、AWSの各種サービスへアクセスできるようになります。

## GetId

GetId API コールは Cognito における新たな identity を生成するために必要な最初のコールです。

### 未認証アクセス

Cognito の特筆すべき点は、アプリケーションに対して未認証のゲストアクセスを許可できる点です。identity pool で、この機能をオンにしておけば、ユーザはいつでも GetID API から新たな identity ID をリクエストできます。アプリケーションはこの identity ID をキャッシュしておいて、Cognito への後続の API コールを実現します。（[AWS SDK for iOS, AWS SDK for Android](http://aws.amazon.com/sdk-for-android/), and [AWS SDK for JavaScript in the Browser](http://aws.amazon.com/sdk-for-browser/) のすべてがこのキャッシュ機構を有しています。）

### 認証済アクセス

パブリックログインプロバイダ（Facebook, Google+, Amazon）をサポートするようにアプリケーションを構成していれば、これらのプロバイダでユーザを識別できる token （ OAuth, OpenID ）を受け取ることができます。 GetID API コールに際して、 Cognito は認証済みの新たな identity を生成できるだけでなく、ある login ですでに関連付けた identity を返却することもできます。 Cognito はプロバイダを通して token をチェックして以下を確認しています。

1. 有効かつプロバイダで構成されたものである。
2. 期限切れでない。
3. プロバイダで生成されたアプリケーションIDが適切である。（ Facebook app ID など）
4. identifier が適切である。

## GetOpenIdToken

GetOpenIdToken API は identity ID の生成が完了した後にコールされます。 もし identity ID がすでにキャッシュされていれば、アプリケーションからこの API が最初にコールされることになります。

### 未認証アクセス

未認証 identity を持っているとすると、その identity に対して token を取得するために必要なものは、identity ID だけです。また、 identity ID が認証済みであれば（もしくは disabled ）、その identity に対する未認証 token は取得できません。

### 認証済アクセス

認証済み identity を持っているとすると、その identity ですでに関連付けされた login にて、少なくともひとつの有効な token で認証をパスしているはずです。GetOpenIdToken コールにて認証をパスした token も、前述と同様のチェックをパスしなければなりません。なお、途中でエラーが発生した場合は、コール全体が失敗します。また、 GetOpenIdToken コールのレスポンスは identity ID を含んでいます。これは、認証をパスしたときに、渡した identity ID と返却される identity ID が異なるかもしれないからです。

#### login の link

identity とまだ関連付けされていない login token で認証できてしまった場合は、この login は既に関連付けされている identity と link されたものと考えられます。おそらくパブリックプロバイダごとに 1つの login を link するだけでしょうけれども、もしひとつ以上のプロバイダへ link しようとするとResourceConflictException が発生します。また、ある login において既に存在している identity と link されていたとすると、 GetOpenIdToken から返却される identity ID は過去に認証したものと同じになります。

#### identity のマージ

与えられた identity とリンクされていないが、他の identity と link されている login token で認証した場合は、ふたつの identity はマージされます。一度マージされると、一方の identity は login に関連付けされたすべての identity の親になり、他方は無効になります。この場合には、親の identity ID が返却されます。もし返却される値がローカルにキャッシュしているものと異なっていれば、キャッシュの値を更新しなくてはなりません。（ [iOS SDK](http://aws.amazon.com/sdk-for-ios/), [Android SDK](http://aws.amazon.com/sdk-for-android/), or [JavaScript SDK](http://aws.amazon.com/sdk-for-browser/) を利用していれば適切に処理されます。 ）

### AssumeRoleWithWebIdentity

OpenID Connect token を一度取得すると、STS における AssumeRoleWithWebIdentity API コールによる 一時的な AWS credentials を通してこれを交換することができます。パブリックプロバイダから受け取る login token のかわりに Cognito token をやりとりするという点を除けば、Facebook, Google+, Amazon を直接的に利用することと差はありません。

生成される identity の数に制限がないため、ユーザに対して付与される権限を理解することが重要です。Cognito チームはふたつの異なる role をアプリケーションに持たせることをおすすめしています。つまり、未認証ユーザに対しての role と、認証ユーザに対しての role です。AWS マネージメントコンソールでは、 identity pool を作成するとデフォルトでこれらの role が設定されます。これらふたつの role に対するアクセスポリシーは同じものです。どちらも Amazon Cognito Sync と [Amazon Mobile Analytics](http://aws.amazon.com/mobileanalytics/) を利用できるように権限が付与されています。みなさんの要件に合わせてこれら role を修正してください。

### Role Trust と Permissions

これらふたつの role の違いは trust relationships です。未認証 role に対する trust policy の例を見てみましょう。

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "cognito-identity.amazonaws.com:aud": "us-east-1:12345678-dead-beef-cafe-123456790ab"
        },
        "ForAnyValue:StringLike": {
          "cognito-identity.amazonaws.com:amr": "unauthenticated"
        }
      }
    }
  ]
}
```

cognito-identity.amazonaws.com （OpenID Connect  token の発行元）から連携されたユーザに対して、この role を許可するためのポリシーです。加えて、 token の "aud" （この場合は identity pool ID ）が identity pool と適合するという条件を設定しています。また、 token の "amr" が "unauthenticated" という値を含んでいるという条件を設定しています。

Cognito が token を生成するとき、 token の "amr" に "unauthenticated" もしくは　"authenticated" のどちらかをセットし、 "authenticated" の場合には認証に利用したプロバイダを含めます。つまり、 以下のように "amr" を変更しさえすれば、 Facebook を通して login したユーザのみを許可するような role を作成できるということです。

```
"ForAnyValue:StringLike": {
  "cognito-identity.amazonaws.com:amr": "graph.facebook.com"
}
```

 role に対して trust relationships を変更するとき、もしくは、 identity pool をまたぐ role を利用しようとするときは、注意が必要です。もし、 identity pool を正しく信頼できるように role を変更しなければ、以下のような STS のエラーを見ることになるでしょう。

```
AccessDenied -- Not authorized to perform sts:AssumeRoleWithWebIdentity
```

このエラーが発生したときは、 identity pool と authentication type に対する適切な role が設定できているか入念にチェックしてください。

## まとめ

みなさん、Cognito 認証の動作、および各SDK内の credentials プロバイダ の処理は、明確になりましたでしょうか？質問などがございましたら、[フォーラム](https://forums.aws.amazon.com/forum.jspa?forumID=173)などでお気軽にお問い合わせください。

## 免責
この記事は個人の見解であり、所属する企業や団体とは関係ございません。