~ Windows Phone と 認証 / 認可 技術
日本マイクロソフト株式会社
エバンジェリスト
安納 順一(あんのう じゅんいち)blogs.technet.com/junichia
@junichia
開発者のための アイデンティティ・テクノロジー
2
本日のテーマ1. IdP の役割2. IdP とプロトコル
• SAML 2.0• OAuth 2.0
3. IdP にアクセスするには• Active Directory• Windows Live• Facebook• Windows Azure AppFabric ACS
3
IdP の役割
4
認証と認可
認証:本人であることを確認 認可:アクセス権を与えること
認証 認可
どんなシステムにも「認証」と「認可」はつきまとう
「認可」に関するプロトコルが注目を浴びている
5
登場人物と課題
① 本人確認(認証依頼)
自分のもの
利用者
アプリ
IdP
サービス
② 資格情報
「この資格情報は正しいのだろうか?」
③利用
③ 利 用
④ アクセス
④アクセ
ス
ID パスワード氏名所属 など
この資格情報や個人情報は正しいのだろうか?
このアプリは使いたいけど、個人情報を渡して大丈夫?
④ アクセス
6
④ アクセス
課題を解決するには認可の仕組みが必要
① 本人確認(認証依頼)
自分のもの
利用者
アプリ
IdP
サービス
② 資格情報
「この資格情報は正しいのだろうか?」
③利用
③ 利 用
④ アクセス
④アクセ
ス
ID パスワード氏名所属 など
この資格情報や個人情報は正しいのだろうか?
このアプリは使いたいけど、個人情報を渡して大丈夫?
個人情報へのアクセスを認可
アプリの利用を認可
アプリの利用を認可
7
2 つの課題と解決方法
個人情報へのアクセスを認可
アプリの利用を認可
認可のプロセスに以下の要素を組み込む(プロトコル化する)• 誰が (例)本人• いつ (例)アプリがアクセスするとき• どのように (例)画面にアラートが表示され、 Y/N を選択
• IdP から発行された資格情報を提示する( Kerberos )。• IdP によって署名されたセキュリティトークンを提示する
( SAML 、 WS-* 、 OAuth など)。
8
セキュリティトークン(アサーション)
セキュリティトークン / アサーション
クレーム 1
クレーム 2
クレーム n
署名IdP による
署名
個人情報
• 認証の結果、 IdP によって生成、発行される• ユーザーの各種属性を含めることができる
※セキュリティトークン=個人情報• 認可のレベル(権限の強さ、ロール)を明確にできる• 署名によって正当性が担保されている
name= 安納 順一
title=evangelist
role=admin
署名
9
アプリ / サービスが利用を認可するまでの流れ(例 1 )
① UserID/Password
③ セキュリティトークン
IdP
② 認証
④ 認可
利用者
アプリ
個人情報
信頼
10
アプリ / サービスが利用を認可するまでの流れ(例 2 )
① UserID/Password
③ セキュリティトークン
IdP
② 認証
利用者
アプリ
個人情報
⑥ 認可 信頼
サービス
⑤ セキュリティトークン
④ リダイレクト
11
IdP の役割 と サービスの役割
IdP の役割• ユーザーの身元を保証しセキュリティトークンを発行する
サービス / アプリの役割• セキュリティトークンを受け取り解析する• セキュリティトークンに含まれた個人情報を利用する• ユーザーのロールを決定する
残された課題「セキュリティトークンを発行してもよいかどうかの判断」
12
IdP とプロトコル
13
「認可」が重要視されるシチュエーション
システム間の連携 企業間 企業内
クラウドへの移行 社内 IdP の利用 ソーシャルな IdP の利用
ソーシャルアプリの台頭 個人情報保護のセルフサービス化
SAML/WS-*
OAuth
プロトコル
企業システム
SNS
14
企業内システムとソーシャルアプリの違い
• 企業内システム• 「システム(アプリ) : 人」の「信頼」が担保されてい
る
• SNS および ソーシャルアプリ• いかなる「信頼」も担保されていない
• 特に「人」と「アプリ」の信頼関係は深刻
個人情報をアプリに提供するかどうか||
アプリにセキュリティトークンを発行するかどうか
15
OAuth と WS-*/SAML の違い• いずれも認可をするためのプロトコル• WS-*/SAML :「情報の送出」を「セキュリティポリシー」が認可する• OAuth :「『情報にアクセスする API 』へのアクセス」を「利用者が」認可す
る
要求「情報が欲しい!」応答「氏名、メアド ... 」
アプリケーション
IdP
利用者(情報の持ち主)
OAuth
認可 その都度
ユーザーの情報
SAML 認可
セキュリティポリシー事前に環境設定
16
Facebook ( OAuth 2.0 )の場合
個人情報にアクセスしたい
利用している
使 い た い
自分のもの
サービスに保存されている個人情報
利用者
FB にアクセスするアプリ
IdP
アク
セス
した
いAPI 認可
17
Identity&Service Provider( Twitter/Facebook/Google 等)
“API へのアクセスを認可する” とは?
氏名を閲覧メールアドレスを閲覧
投稿を閲覧
各種特権(例)
つながりを閲覧近況を投稿
API Lv1
アプリ
つながりを編集
外部のアプリケーションに対し、各種情報にアクセスするための API の利用を認可する仕組み
① アプリ登録(信頼関係確立)
③ API にアクセス
② アクセス認可
ユーザー情報
API Lv2
API Lv3
API Lv4
属性の主体(持ち主)
18
利用者 アプリケーション Facebook
アプリ利用開始
認証 / 認可画面へ Redirect
Access Token 要求
認証 / 認可を完了
Access Token 発行
API 呼び出し
認証 / 認可 画面表示
CallBack url に Redirect
API
認可コードを発行
Facebook ( OAuth 2.0 デスクトップアプリ)の場合
19
Windows Phone アプリへの実装
20
Windows Phone と IdP
AD DS
Windows Live
SL.IdentityModelIdentity Developer Training kit
Live SDK 5.0Download Center
Facebook C# SDKCodeplex
SL.Phone.FederationWindows Azure Platform Training Kit
Windows Azure
AppFabric ACS
ライブラリ Identity Provider
OpenID 系
HigLaboCodeplex
OAuth 2.0(draft 16)
AD FS
OAuth Wrap
OAuth 2.0(draft 10)
WS-Trust ( SAML トークン)
OAuth 1.0a
予定
プロトコル
検証中
21
Windows Phone と Active Directory
• System.DirectoryServce がサポートされていない– Active Directory に直接アクセスできない– 何らかのサービスを介して認証の代行を依頼する必要がある
認証
利用 認証
AD DS
認証代行サービス
22
Windows Phone と Active Directory Federation Service
① AD FS にはドメインのユーザー ID とパスワードを渡す(もちろん SSL )② AD 認証は AD FS が代行③ AD DS からユーザーの属性が返される(どんな属性を返すかは AD FS に定義されている)④ AD FS は「属性(クレーム)」に署名をしてセキュリティートークン( SAML アサーショ
ン)を生成⑤ WP アプリにはセキュリティトークンが返される
① UserID/Password ② 認証 AD DS
WS-Trust ( SOAP )
③ 属性⑤ セキュリティトークン
AD FS
④ 属性に署名
23
Windows Phone から AD FS を利用するにはSL.IdentityModel ライブラリ• Identity Developer Training Kit 2010 April に含まれている
http://www.microsoft.com/download/en/details.aspx?id=14347
• PC 用 Silverlight 版なので移植が必要
\Claims├ Claim.cs├ ClaimCollection.cs├ ClaimsIdentity.cs├ ClaimsPrincipal.cs├ ClaimType.cs├ IClaimsIdentity.cs└ IClaimsPrincipal.cs
\Protocols\WSTrust├ IRequestCredentials.cs├ IssueCompletedEventArgs.cs├ IssuedTokenHeader.cs├ IWSTrustContract.cs├ RequestedSecurityToken.cs├ RequestSecurityToken.cs├ RequestSecurityTokenResponse.cs├ UsernameCredentials.cs├ WindowsCredentials.cs├ WSTrust13Constants.cs├ WSTrust13ResponseSerializer.cs├ WSTrustBinding.cs├ WSTrustBindingUsernameMixed.cs├ WSTrustBindingWindows.cs├ WSTrustClient.cs├ WSTrustRequestBodyWriter.cs└ WSTrustSerializationHelper.cs
\Services└ TokenCache.cs
24
SL.IdentityModel ライブラリの移植手順1. プロジェクトを作成
• テンプレート: Windows Phone クラスライブラリ( Visual C# )
• 名前:(例) WP.IdentityModel とか
2. 参照設定の追加• System.Runtime.Serialization• System.ServiceModel• System.Xml.Linq
3. SL.IdentityModel から ソースをひたすらコピペ
移行したライブラリはこちらにありますhttp://blogs.technet.com/b/junichia/p/wp7_and_ad.aspx
25
SL.IdentityModel を使用したアプリの作成1. 必要情報の収集
AD FS のエンドポイント https://<ADFS サーバー >/adfs/services/trust/13/usernamemixed
スコープ( ApplyTo 、業務アプリの識別名) (例) https://www.contoso.com/
2. 参照設定の追加• 移植したライブラリのプロジェクトを選択
3. using の追加• using SL.IdentityModel.Claims;• using SL.IdentityModel.Protocols.WSTrust;• using SL.IdentityModel.Services;
26
WSTrustClient _client;
private void _btnLogin_Click(object sender, RoutedEventArgs e) { RequestST(); }
private void RequestST() {
_client = new WSTrustClient( new WSTrustBindingUsernameMixed(), new EndpointAddress("https://tfadfs.tf.com/adfs/services/trust/13/usernamemixed"), new UsernameCredentials(<ユーザー名 >, <パスワード >));
var rst = new RequestSecurityToken(WSTrust13Constants.KeyTypes.Bearer) {
AppliesTo = new EndpointAddress("https://www.contoso.com/") }; _client.IssueCompleted += client_IssueCompleted; _client.IssueAsync(rst); }
WS-Trust クライアントを作成
セキュリティトークンを非同期で要求
4. 認証&セキュリティトークンの取得
非同期で実行
27
void client_IssueCompleted(object sender, IssueCompletedEventArgs e) { _client.IssueCompleted -= client_IssueCompleted;
if (e.Error == null) { Globals.RSTR = e.Result; MessageBox.Show( e.Result ); } else { MessageBox.Show(e.Error.Message); _btnLogin.IsEnabled = true; } }
28
セキュリティトークン( SAML アサーション)<saml:Assertion MajorVersion="1" MinorVersion="1" AssertionID="_b6d37acb-381c-4160-a712-d3eceee44ef5" Issuer="http://tfadfs.tf.com/adfs/services/trust" IssueInstant="2011-11-28T00:16:18.445Z" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"><saml:Conditions NotBefore="2011-11-28T00:16:18.445Z" NotOnOrAfter="2011-11-28T01:16:18.445Z“><saml:AudienceRestrictionCondition><saml:Audience>https://www.contoso.com/</saml:Audience></saml:AudienceRestrictionCondition></saml:Conditions><saml:AttributeStatement><saml:Subject><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject><saml:Attribute AttributeName="name" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>西城秀樹 </saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="emailaddress" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>[email protected]</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="companyname" AttributeNamespace="http://schemas.tf.com"><saml:AttributeValue> マイクロソフト </saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="department"AttributeNamespace="http://shcemas.tf.com"><saml:AttributeValue> エバンジェリズムグループ </saml:AttributeValue></saml:Attribute></saml:AttributeStatement><saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" AuthenticationInstant="2011-11-28T00:16:18.023Z"><saml:Subject><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject></saml:AuthenticationStatement>
29
つづき<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><ds:Reference URI="#_b6d37acb-381c-4160-a712-d3eceee44ef5"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><ds:DigestValue>mT+IdNIJq6No0jKKX034keFNO+0HZ3dIbnOrDnzfnI4=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>fQ/ju362tt3EGKAMOtlfFwNAa7+dZoLftbNv1wyFjkytnPaD/BlxASXkDf2KeyBG8lxIpPDBTJFczME8A3gpHKBLuFIlURldx4V5ZuVkxzltLqjInHs/ectAzbagSHhDVYlRuo3F8zGoV2YFH4ZHme1snqPk0ArB60W5vh8jnAvmN7VsMovmmwPupMc5d4WLeXKH7/2Piz8Q2gM2sQb818lPhYzP9V80gJPPyDX6gbbn+QUjcnITv8nohZOutophufy54498Ul6EnBfFuEUToaZZCVfh6O5NaO/gXHp4XvNgWkRNbNM1IVYBHiOrQyTPrVrccLpYKMxed1j3yJS/Nw==</ds:SignatureValue><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><X509Data><X509Certificate>MIIC1jCCAb6gAwIBAgIQX4B1j9QgNZ9GI3IsMJ/+vTANBgkqhkiG9w0BAQsFADAnMSUwIwYDVQQDExxBREZTIFNpZ25pbmcgLSB0ZmFkZnMudGYuY29tMB4XDTExMDQxNTA1NDIwM1oXDTEyMDQxNDA1NDIwM1owJzElMCMGA1UEAxMcQURGUyBTaWduaW5nIC0gdGZhZGZzLnRmLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALcp//XyPz6m9F5ok4ebtuz7XsIdesuvlze5OgN2FD4PkAykETXHRgeheAq1TtbTN/nIiTy11kKgEAseyUSfvMGJarf49vui+zNcy37t+tbrBGdx+MRhuncTb7+O8FKJ3Wg/q9h8e10hq3VeEoxhzd4Ghdl1R4DfJYf10PztfFeQPvoD3FJNgca7v1BB1gRtUEEykmJvSoZFt18mhk1l+9Bsk5SJyEZaZc4M99ubqriVzzgDMZBa02+9Y6nmyy0P+sNrPnMSg031IulcGH+Zp8/W2B2ojHx3HisNkhYc8cQPYtLVoYanZ/qLG6hdqphM5TFi67QubdqclAE7MAoOx50CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsU3E1uCieRjMAeVel29h9/oHLXy8hoGiy7iG3cgQBysA3Mlm3BjrLII4ze2JEZ74U8t5dk4K3K04emDuy4JhKpOP/iZXRN56UEuhIidFfsHi/k9PLXPEgG1AJnueK52u71xj8noyPJ1EsYwVWTqm5emN5CVDEpJtPFJmsdrBviChFaOO9XURrz2rcp+TAt56cDJKFqj39aKv5YAYWBiSj0UP5cSnXxI7F3lk7kNS19L2HdhPliXFoXI+doQ6ynOJrVUSqVMIbww7nOehWxI6TyWo9+A6TTl3LmpdNYyFYXJFjNI0JMKBm1U6yEvXEApI15LQ8IfJtSjPHoIPBHfSig==</X509Certificate></X509Data></KeyInfo></ds:Signature></saml:Assertion>
30
(この部分は次ページを参照してください)
var sb = new StringBuilder(128);IClaimsPrincipal n = TokenHandler.Convert(Globals.RSTR);n.ClaimsIdentity.Claims.ToList().ForEach(vc => sb.AppendFormat("{0}\n {1}\n\n", vc.ClaimType, vc.Value));MessageBox.Show(sb.ToString()); public static class TokenHandler{ private static XNamespace ASSERTION_NAMESPACE = "urn:oasis:names:tc:SAML:1.0:assertion"; private const string CLAIM_VALUE_TYPE = "http://www.w3.org/2001/XMLSchema#string"; // bit of a hack
public static IClaimsPrincipal Convert(RequestSecurityTokenResponse rstr) { return new ClaimsPrincipal( GetClaimsIdentity( rstr ) ); }
private static ClaimsIdentity GetClaimsIdentity(RequestSecurityTokenResponse rstr) {
}
}
5. クレームの抽出
31
private static ClaimsIdentity GetClaimsIdentity( RequestSecurityTokenResponse rstr ) { XDocument responseDoc = XDocument.Parse(rstr.RequestedSecurityToken.RawToken); XElement attStatement = responseDoc.Element(ASSERTION_NAMESPACE + "Assertion").Element(ASSERTION_NAMESPACE + "AttributeStatement");
var issuer = responseDoc.Root.Attribute("Issuer").Value; ClaimCollection claims = new ClaimCollection();
foreach (var c in attStatement.Elements(ASSERTION_NAMESPACE + "Attribute")) { string attrName = c.Attribute("AttributeName").Value; string attrNamespace = c.Attribute("AttributeNamespace").Value; string claimType = attrNamespace + "/" + attrName;
foreach (var val in c.Elements(ASSERTION_NAMESPACE + "AttributeValue")) { claims.Add(new Claim(issuer, issuer, claimType, val.Value, CLAIM_VALUE_TYPE)); } }
return new ClaimsIdentity(claims); }
32
サーバー証明書のインポート方法
private void _btnInstallCert_Click(object sender, RoutedEventArgs e) { CertP7BPath = “http://<WEB サーバー >/< 証明書のファイル名>.p7b"; WebBrowserTask webBrowserTask = new WebBrowserTask(); webBrowserTask.Uri = new Uri(CertP7BPath, UriKind.Absolute); webBrowserTask.Show(); }
SSL を要求するサービスの場合、証明書がインストールされていないとエンドポイントを見つけられない( There was no endpoint listening エラー)
33
資格情報の再利用について
ID/Password を送信
認証結果
ID/Password 入力
次回以降は起動したらすぐに認証開始
• 認証のために入力した資格情報( UserID/Password )は分離ストレージに保存して再利用することが可能
• 保存の際には暗号化することが望ましい
34
DPAPI を使用した暗号化 /復号化
using System.Text;using System.Security.Cryptography;
//暗号化byte[] PinByte = Encoding.UTF8.GetBytes(<文字列>);byte[] ProtectedPinByte = ProtectedData.Protect(PinByte, null);
//復号化byte[] PinByte = ProtectedData.Unprotect(ProtectedPinByte, null);n = Encoding.UTF8.GetString(PinByte, 0, PinByte.Length);
いったん Byte型に変換してから暗号化する
35
暗号化した文字列を参照するにはBase64 にエンコード
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();if (store.FileExists(encryptpin.FilePath_username) ) { MessageBox.Show( System.Convert.ToBase64String(encryptpin.ReadPinFromFile(encryptpin.FilePath_username)) ); }else { MessageBox.Show(" 資格情報は保存されていません "); }
36
まとめ
• 企業内システムとソーシャルアプリ系で使用するプロトコルが違います
• OAuth 2.0 の実装は習得必須
• AD FS の実装方法も習得必須
• 必要なライブラリをそろえておきましょう
• Windows Phone を買ってね!
37
リソースはここに!
http://blogs.technet.com/junichia/サンプルプロジェクトもこちらから
アイデンティティ・テクノロジーって超楽しい!
The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation.
MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
© 2011 Microsoft Corporation.
All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.