Salesforceを認証プロバイダとしてAmazon CognitoでAWSのAPIを叩く方法を書いていきます! 参考URLは以下。今回のソースやら設定方法は、ほぼこちらのパクリです。 Building an App Using Amazon Cognito and an OpenID Connect Identity Provider
Cognitoの基本的な使い方や考え方に関しては以下が詳しいです。
- [AWS][iOS] Amazon Cognito のモバイルユーザー認証 & データ同期 を iOS で使ってみた
- Amazon Cognitoによる認証はSTSのweb identity federationとどう違うのか!?
1. 接続アプリケーションの作成
こんな感じで作成します。コールバック先は4のコードを実行する場所になります。あとはopenidがscopeに入っていればOKです。
2. IAMでOpenID Connect Providerを作成
IAMでIdentity Providerを作成します。
Provider TypeはOpenID Connect、Provider URLは本番環境であればhttps://login.salesforce.com、Sandboxであればhttps://test.salesforce.com、マイドメインの環境であればhttps://{マイドメイン}を入力します。Audienceには接続アプリケーションのクライアントIDを入力します。 ※現時点ではドメインにハイフンとか入っていると、Cognitoのベリファイ通らなくなるっぽいので、マイドメインにハイフンがある場合は注意して下さい。(利用不可?)
[Next Step]をクリックするとProviderURLのベリファイが行われます。ベリファイが通ったら[Create]ボタンをクリックします。
3. Amazon CognitoでIdentity Poolを作成
CognitoでIdentity Poolを作成します。
Authentication providersではOpenIDのタブを開いて、2で作成したプロバイダを設定します。
作成したRoleにはS3のReadアクセスのポリシーを付与しておきます。
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>
実際の動作
こんな感じでホーム画面が表示されて
[Salesforceでログイン]ボタンをクリックすると、認証・認可画面が表示されて
戻って、[S3 - List Objects]をクリックするとS3のアクセス権限が付与されているので一覧が表示される、という認証あるあるな地味な画面フロー
ちなみに、Cognitoでダッシュボードを表示しても、指定したIdentity Providerに対してログインカウントされていませんでした。何故だろう…。