
【Auth0】SAML + AWS SDK for JavaScriptを使って静的HTMLからS3へファイルアップロードを試してみた
はじめに
こんにちは植木和樹@上越妙高オフィスです。本日はGmailで認証したユーザーがS3にファイルアップロードできるスタティックHTMLなアプリケーションを作成してみました。
以前のブログではAWSが公開しているFacebook認証による静的HTMLのサンプルを写経しました。今回はそれをベースにしつつ、Gmailでの認証にはAuth0を利用してみました。
参考ページ
今回は下記のページを参考にページを作成しました。
GoogleでAuth0 AWS JavaScriptで検索するとたくさんのページが表示されます。しかし情報が古いページがいくつかあり、そのまま試してもうまくいかないケースが見つけられました。
- getProfileはAuth0 API v8以降obsoleteなので、getUserProfileを使う
- 上記に関連してidTokenの取得方法が変わっている(lock.on("authenticated")のイベントハンドラを利用する)
- getDelegationToken の引数としてRole ARN, ID Provider ARNを指定するのではなく、ClientのAWS Addonsを有効にして、RulesでARNを指定する
が主に異なる点です。
また上記 Amazon API Gateway Tutorial Introduction ではページ作成にAngularJS(v1.3.0)を利用しており、動作確認のサンプルとしてやや難解でした。そのため今回は2ファイル(HTML本体+設定用JavaScriptファイル)で動作確認できるページを用意しました。
設定とサンプルコード
動作には下記のものが必要になります
- Auth0の設定(Client, Connection, Rule)
- AWSのリソース(IAM Role, ID Provider, ファイルアップロード先のS3バケット)
- AWS SDK for JavaScriptを組み込んだHTMLファイル
まずは前回のAWS SDK for JavaScriptのGetting Startedを写経して静的HTMLからS3へファイルアップロードを試してみた | Developers.IOと共通点も多いため、前回のブログを参考にS3バケット等を用意しておくと良いでしょう。
1. Auth0の設定
Amazon API Gateway Tutorial - Step 2 - Adding Security and Deployingを参考にClients、Connections、Rulesを作成します。
Client設定はほぼ初期設定のままです。Allowed Callback URLsにはS3にアップロードしたsample.htmlのURLを設定してください。
ページで紹介されている通りAmazon Web Services Addonを有効にしておきましょう。これによりAuth0LockインスタンスのgetDelegationTokenメソッドで、idTokenからAWSのアクセスキー、シークレットアクセスキー、セッショントークンへの変換を行ってくれます。
Connectionsは認証に利用するID Providerを指定します。今回はGoogle Appsを指定しました。
Ruleでは利用するAWS側のIAM RoleとID Providerのマッピングを設定します。コードはこの後にご紹介します。
2. AWSのリソース
Setup AWS for Delegated Authentication with APIs を参考にIAM RoleとID Provider設定を行います。
3. AWS SDK for JavaScriptを組み込んだHTMLファイル
サンプルコードは gist にあげました。
auth0_ruleに記載したJavaScriptコードはAuth0のRuleに貼り付けます。。AUTH0_CLIENT_IDには作成したClientのClient IDを入力し、特定Clientでのみ適用されるようにします。またprincipalとroleのARNを作成したID ProviderとIAM RoleのARNに修正してください。修正したら適当な名前で保存します。
アプリケーションの各種設定値は config.js にまとめていますので環境にあわせて修正してください。
function (user, context, callback) { | |
if (context.clientID === 'AUTH0_CLIENT_ID') { | |
// set AWS settings | |
context.addonConfiguration = context.addonConfiguration || {}; | |
context.addonConfiguration.aws = context.addonConfiguration.aws || {}; | |
context.addonConfiguration.aws.principal = 'arn:aws:iam::123456789012:saml-provider/auth0-test'; | |
context.addonConfiguration.aws.role = 'arn:aws:iam::123456789012:role/cm-js-sample-role@auth0'; | |
} | |
callback(null, user, context); | |
} |
window.config = { | |
client_id: 'AUTH0_CLIENT_ID', | |
domain: 'YOUR_DOMAIN.auth0.com', | |
bucket: 'YOUR_UPLOAD_BUCKET', | |
region: 'ap-northeast-1' | |
}; |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>AWS SDK for JavaScript - Sample Application</title> | |
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js "></script> | |
<script src="https://cdn.auth0.com/js/lock/10.8/lock.min.js"></script> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> | |
<script src="./config.js"></script> | |
</head> | |
<body> | |
<input type="file" id="file-chooser" /> | |
<button id="upload-button" style="display:none">Upload to S3</button> | |
<div id="results"></div> | |
<div id="fb-root"></div> | |
<script type="text/javascript"> | |
var lock = new Auth0Lock(window.config.client_id, window.config.domain); | |
var bucketName = window.config.bucket; | |
AWS.config.region = window.config.region; | |
var auth0UserId; | |
var bucket = new AWS.S3({ | |
params: { | |
Bucket: bucketName | |
} | |
}); | |
var fileChooser = document.getElementById('file-chooser'); | |
var button = document.getElementById('upload-button'); | |
var results = document.getElementById('results'); | |
button.addEventListener('click', function () { | |
var file = fileChooser.files[0]; | |
if (file) { | |
results.innerHTML = ''; | |
//Object key will be auth0-USERID#/FILE_NAME | |
var objKey = 'auth0-' + auth0UserId + '/' + file.name; | |
var params = { | |
Key: objKey, | |
ContentType: file.type, | |
Body: file, | |
ACL: 'public-read' | |
}; | |
bucket.putObject(params, function (err, data) { | |
if (err) { | |
results.innerHTML = 'ERROR: ' + err; | |
} else { | |
listObjs(); | |
} | |
}); | |
} else { | |
results.innerHTML = 'Nothing to upload.'; | |
} | |
}, false); | |
function listObjs() { | |
var prefix = 'auth0-' + auth0UserId; | |
bucket.listObjects({ | |
Prefix: prefix | |
}, function (err, data) { | |
if (err) { | |
results.innerHTML = 'ERROR: ' + err; | |
} else { | |
var objKeys = ""; | |
data.Contents.forEach(function (obj) { | |
objKeys += obj.Key + "<br>"; | |
}); | |
results.innerHTML = objKeys; | |
} | |
}); | |
}; | |
lock.on("authenticated", function(authResult) { | |
console.log("authResult: " + JSON.stringify(authResult)); | |
lock.getUserInfo(authResult.accessToken, function(error, profile) { | |
if (error) { | |
console.log('Error loading the Profile', error) | |
return; | |
} | |
console.log("Profile:" + JSON.stringify(profile)); | |
auth0UserId = profile.nickname; | |
var auth0 = new Auth0({ | |
clientID: window.config.client_id, | |
domain: window.config.domain, | |
callbackURL: 'dummy' | |
}); | |
var aws_creds; | |
var options = { | |
id_token: authResult.idToken, | |
api: 'aws' | |
}; | |
auth0.getDelegationToken(options, function(err, result) { | |
if (err) { | |
console.log(err); | |
return; | |
} | |
aws_creds = result.Credentials; // AWS temp credentials | |
console.log("aws_creds: " + JSON.stringify(aws_creds)); | |
bucket.config.credentials = new AWS.Credentials({ | |
accessKeyId: aws_creds.AccessKeyId, | |
secretAccessKey: aws_creds.SecretAccessKey, | |
sessionToken: aws_creds.SessionToken}); | |
}); | |
button.style.display = 'block'; | |
}); | |
}); | |
(function () { | |
if (location.hash == '') { | |
lock.show(); | |
} | |
}()); | |
</script> | |
</body> | |
</html> | |
sample.htmlとconfig.jsの2つのファイルをStatic Webhosting設定したS3バケットにアップロードしブラウザでアクセスしてください。Auth0による認証画面が表示されます。
認証後に、適当なファイルをアップロードしファイル名が画面に表示されれば成功です。
まとめ
今回はAWS SDK for JavaScriptを使ってS3バケットへのアップロードを行いました。Gmailで認証+静的HTMLなアプリケーションだとこんな点でうれしいことがあります。
- AWS利用者毎にIAMユーザーを作成する必要がない
- ユーザー認証をGmail(GSuite)に任せることができる(会社ドメインのメールアドレスを持っていれば利用可能など)
- 静的HTMLなのでEC2等でサーバーを用意する必要がない
- AWSに不慣れな人にも機能を限定した画面を用意して簡単に操作してもらえる
つまりAWSに詳しくない管理部の人でも簡単にS3へファイルをアップロードできるアプリケーションが作れます。また応用すればAPIが公開されている各種サービスについても静的HTMLだけでカスタム管理画面が作れそうですね。
なによりHTML + JavaScriptファイルだけで作れるのでサーバーを用意しなくて良く、運用の手間が減るのがうれしいです。Auth0のようなIdPサービスを使うことで、認証まで含めたアプリケーションを簡単にサーバーレスで利用するのが主流になりそうですね。