2015-08-27

Salesforceを認証プロバイダとしてCognitoを使ってみる

Salesforceを認証プロバイダとしてAmazon CognitoでAWSのAPIを叩く方法を書いていきます! 参考URLは以下。今回のソースやら設定方法は、ほぼこちらのパクリです。 Building an App Using Amazon Cognito and an OpenID Connect Identity Provider

Cognitoの基本的な使い方や考え方に関しては以下が詳しいです。

1. 接続アプリケーションの作成

こんな感じで作成します。コールバック先は4のコードを実行する場所になります。あとはopenidがscopeに入っていればOKです。

sfdc-cognito-connectionapp

2. IAMでOpenID Connect Providerを作成

IAMでIdentity Providerを作成します。

sfdc-cognito-create-provider1

Provider TypeはOpenID Connect、Provider URLは本番環境であればhttps://login.salesforce.com、Sandboxであればhttps://test.salesforce.com、マイドメインの環境であればhttps://{マイドメイン}を入力します。Audienceには接続アプリケーションのクライアントIDを入力します。 ※現時点ではドメインにハイフンとか入っていると、Cognitoのベリファイ通らなくなるっぽいので、マイドメインにハイフンがある場合は注意して下さい。(利用不可?)

sfdc-cognito-create-provider2

[Next Step]をクリックするとProviderURLのベリファイが行われます。ベリファイが通ったら[Create]ボタンをクリックします。

sfdc-cognito-create-provider3

3. Amazon CognitoでIdentity Poolを作成

CognitoでIdentity Poolを作成します。

sfdc-cognito-identitypool1

Authentication providersではOpenIDのタブを開いて、2で作成したプロバイダを設定します。

作成したRoleにはS3のReadアクセスのポリシーを付与しておきます。

sfdc-cognito-attach-policy

4. コードを作成

以下のHTMLを作成します。基本的にはOpenID Connectのid_tokenをAWS.CognitoIdentityCredentialsのパラメータとしてセットするだけでOK。あとはCognitoがid_tokenのベリファイをして、通ったらAWSの一時的なクレデンシャルを発行してくれます。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf8"/>
    <script src="//sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
    <script>
      var IDENTITY_POOL_ID = '{Identity Pool Id}';
      var AWS_REGION = 'us-east-1';
      var SFDC_CLIENT_ID = '{Salesforce Client ID}';
      var REDIRECT_URI = '{Redirect URL}';
      var S3_BUCKETNAME = '{S3 Bucket Name';

      // Initialize the Amazon Cognito credentials provider
      AWS.config.region = AWS_REGION;

      function listObjs() {
        var s3 = new AWS.S3({ params: {Bucket: S3_BUCKETNAME} });
        s3.listObjects(function(error,data) {
          if (error === null) {
            var html_keys = '';

            jQuery.each(data.Contents, function(index, obj) {
               html_keys += (index + ': ' + obj.Key + '<br />');
            });
            jQuery("#objKeys").html(html_keys);
          } else {
            console.log(error);
          }
        });
      }

      function loginWithSalesforce() {
        var url =
          'https://login.salesforce.com/services/oauth2/authorize'
          + '?response_type=token id_token'
          + '&scope=openid'
          + '&nonce=abc'
          + '&client_id=' + SFDC_CLIENT_ID
          + '&redirect_uri=' + REDIRECT_URI;
        location.href = url;
      }

      (function(){
        // Capture the redirected URL
        var url = window.location.href;

        // Check if there was an error parameter
        var error = url.match('error=([^&]*)')
        if (error) {
            // If so, extract the error description and display it
            var description = url.match('error_description=([^&]*)')
            console.log('Error: ' + error[1] + '<br>Description: ' + description[1] + '</br>');
            return;
        }

        // Extract id token from the id_token parameter
        var match = url.match('id_token=([^&]*)');
        if (match) {
          var id_token = match[1]; // String captured by ([^&]*)

          // Make AWS request using the id token
          if (id_token) {
            makeCognitoRequest(id_token);
          } else {
            console.log('Error: Could not retrieve id token from the URL');
          }
        }

        // Make AWS request using Cognito
        function makeCognitoRequest(id_token) {
          // **** REPLACE account_id, role_arn, pool_id, and table_name WITH YOUR OWN VALUES ****
          // Initialize CognitoIdentityCredentials
          AWS.config.credentials = new AWS.CognitoIdentityCredentials({
            IdentityPoolId: IDENTITY_POOL_ID,
            Logins: { // optional tokens, used for authenticated login
              '{Your Identity Provider Name}': id_token
            },
            RoleSessionName: 'web' // optional name, defaults to web-identity
          });
          console.log(id_token);

          // Cognito credentials
          AWS.config.credentials.get(function (err) {
            if (err) {
              console.log(err);
            } else {
              console.log('login successful with salesforce. identity id is ' + AWS.config.credentials.identityId);
            }
          });
        }
      })();


    </script>
  </head>
  <body>
    <button onclick="listObjs()">S3 - List Objects</button>
    <div id="objKeys"></div>
    <input type="button" value="Salesforceでログイン" onclick="loginWithSalesforce();"/>
  </body>
</html>

実際の動作

こんな感じでホーム画面が表示されて

cognito-sample-flow1

[Salesforceでログイン]ボタンをクリックすると、認証・認可画面が表示されて

cognito-sample-flow2

戻って、[S3 - List Objects]をクリックするとS3のアクセス権限が付与されているので一覧が表示される、という認証あるあるな地味な画面フロー

cognito-sample-flow3

ちなみに、Cognitoでダッシュボードを表示しても、指定したIdentity Providerに対してログインカウントされていませんでした。何故だろう…。

cognito-dashboard

このエントリーをはてなブックマークに追加