「マイクロソフト系技術情報 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。
汎用認証サイトにSAML2.0を実装するため作成中。
SAMLの仕様は膨大だが、使われていないものも多い。
以下の範囲に絞れば、実装は割とスリムになる。
前述のトラストサークルの慣例から、リクエスト・レスポンス共に署名を行う。
SAMLは、Web Browser SSO Profile以外で使われていない。
IdM実験室によると...。
昔はデータサイズの問題で、Artifact Binding を使っていたが
最近は通信速度や端末性能の向上により、使われることは減ってきているらしい。
SPとIdPの間で直接通信をさせなければならないので、
クラウドサービスと社内IdPを連携させる場合など面倒なため。
ただ、今でも稀にArtifact Binding しか使えないSPが
存在するので、仕方なく(IdP側に)実装することがある。
なお、AD FSではArtifact Binding をサポートしている。
Azure ADはPOST BindingのみでArtifact Binding は使えない。
○ unspecified ○ entity ○ emailAddress ☓ persistent(永続的仮名) ☓ transient(一時的仮名) ☓☓ X509SubjectName ☓☓ WindowsDomainQualifiedName ☓☓ kerberos
○ exact ☓ minimum ☓ maximum ☓ better
○ unspecified(不特定の方法で) ○ PasswordProtectedTransport(パスワード) ☓ Password(PasswordProtectedTransportとの違いが?) ☓ PreviousSession(既存のセッションを利用) ☓ X509 ☓ SecureRemotePassword ☓ TimeSyncToken ☓ Smartcard ☓ SmartcardPKI ☓ MobileOneFactorContract ☓ MobileOneFactorUnregistered ☓ MobileTwoFactorContract ☓ MobileTwoFactorUnregistered ☓ PGP ☓ SPKI ☓ XMLDSig ☓ TLSClient ☓ Kerberos ☓ Telephony ☓ NomadTelephony ☓ AuthenticatedTelephony ☓ SoftwarePKI ☓ InternetProtocol ☓ PersonalTelephony ☓ InternetProtocolPassword
例を参考にする。
例を参考にする。
下記のsamltool.ioからアサーションを取得し、SAMLTool.comで確認するなど。
SignedXml?クラスの実装に問題があり、
ネストした複数のXML署名が Verify できないという問題があるらしい。
※ 外側だけ検証すればイイ気がする。
コチラが、SignedXml?によるネストしたXML署名・検証結果。
XmlDocuement? を利用する際に PreserveWhitespace? を単に true にする。
以下を用いて、SAMLを検証する。
しかし、結局XPathで検証していたりする。
(適切な、ミニマムのXSDをオンラインで発見できないため)
既定値
メアド
様々なクレームを、
に指定できる。
この設定は、Custom Claim Rule(要求規則)に設定するらしい
(samlp:AuthnRequest?に要求を設定するという方式では無さそう)。
テスト用SPを使用してテストすると良い。
著名、IdPを使用してテストすると良い。
Technical Overviewから取り出したサンプル・シーケンス
HTTP/1.1 302 Object Moved Date: 21 Jan 2004 07:00:49 GMT Location:https://idp.example.org/SAML2/SSO/Redirect?SAMLRequest=request&RelayState=... Content-Type: text/html; charset=iso-8859-1
GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=... HTTP/1.1 Host: idp.example.org
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="identifier_1" Version="2.0" IssueInstant="2004-12-05T09:21:59Z" AssertionConsumerServiceIndex="1"> <saml:Issuer> https://sp.example.com/SAML2 </saml:Issuer> <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/> </samlp:AuthnRequest>
<form method="post" action="https://sp.example.com/SAML2/SSO/POST" ...> <input type="hidden" name="SAMLResponse" value="response" /> <input type="hidden" name="RelayState" value="value" /> ... <input type="submit" value="Submit" /> </form>
POST /SAML2/SSO/POST HTTP/1.1 Host: sp.example.com Content-Type: application/x-www-form-urlencoded Content-Length: nnnn SAMLResponse=response&RelayState=value
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="identifier_2" InResponseTo="identifier_1" Version="2.0" IssueInstant="2004-12-05T09:22:05Z" Destination="https://sp.example.com/SAML2/SSO/POST"> <saml:Issuer> https://idp.example.org/SAML2 </saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="identifier_3" Version="2.0" IssueInstant="2004-12-05T09:22:05Z"> <saml:Issuer> https://idp.example.org/SAML2 </saml:Issuer> <!-- a POSTed assertion MUST be signed --> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> ... </ds:Signature> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"> 3f7b3dcf-1674-4ecd-92c8-1544f346baf8 </saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="identifier_1" NotOnOrAfter="2004-12-05T09:27:05Z" Recipient="https://sp.example.com/SAML2/SSO/POST"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2004-12-05T09:17:05Z" NotOnOrAfter="2004-12-05T09:27:05Z"> <saml:AudienceRestriction> <saml:Audience> https://sp.example.com/SAML2 </saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2004-12-05T09:22:00Z" SessionIndex="identifier_3"> <saml:AuthnContext> <saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport </saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response>
医療分野共通認証基盤整備コンソーシアムのドキュメントから取り出したサンプル・シーケンス
HTTP/1.1 302 Object Moved Date: 21 Jan 2004 07:00:49 GMT Location:https://auth.pki.med.or.jp/sso/SSORedirect/metaAlias/idp?SAMLRequest=... Content-Type: text/html; charset=iso-8859-1
GET /sso/SSORedirect/metaAlias/idp?SAMLRequest=... HTTP/1.1 Host: auth.pki.med.or.jp
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN“ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <body onload="document.forms[0].submit()"> <noscript> <p> <strong>Note:</strong> Since your browser does not support JavaScript、you must press the Continue button once to proceed. </p> </noscript> <form action=https://ServiceProvider.com/SAML/SLO/Browser method="post"> <div> <input type="hidden" name="RelayState“ value="0043bfc1bc45110dae17004005b13a2b"/> <input type="hidden" name="SAMLRequest“ value="PHNhbWxwOkxvZ291dFJlcXVlc3QgeG1sbnM6c2FtbHA9InVybjpvYX NpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgG1sbnM9InVybjpvYXN pczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iDQogICAgSUQ9ImQyYjdj Mzg4Y2VjMzZmYTdjMzljMjhmZDI5ODY0NGE4IiBJc3N1ZUluc3RhbnQ9IjIwM DQtMDEtMjFUMTk6MDA6NDlaIiBWZXJzaW9uPSIyLjAiPg0KICAgIDxJc3N1 ZXI+aHR0cHM6Ly9JZGVudGl0eVByb3ZpZGVyLmNvbS9TQU1MPC9Jc3N1ZXI +DQogICAgPE5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1 MOjIuMDpuYW1laWQtZm9ybWF0OnBlcnNpc3RlbnQiPjAwNWEwNmUwLWF kODItMTEwZC1hNTU2LTAwNDAwNWIxM2EyYjwvTmFtZUlEPg0KICAgIDxz YW1scDpTZXNzaW9uSW5kZXg+MTwvc2FtbHA6U2Vzc2lvbkluZGV4Pg0KPC9 zYW1scDpMb2dvdXRSZXF1ZXN0Pg=="/> </div> <noscript> <div> <input type="submit" value="Continue"/> </div> </noscript> </form> </body> </html>
POST /sso/SSOPost/... HTTP/1.1 Host: auth.pki.med.or.jp Content-Type: application/x-www-form-urlencoded Content-Length: nnnn SAMLRequest=request&RelayState=value
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="s2cee63177ff33bcacd5263caa4af9da101837de24" Version="2.0" IssueInstant="2011-06-28T05:08:41Z" Destination="https://auth.pki.med.or.jp/sso/SSORedirect/metaAlias/idp" ForceAuthn="false" IsPassive="false" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" AssertionConsumerServiceURL="https://ServiceProvider.com/SAML/Consumer/metaAlias/sp"> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> sso-sp </saml:Issuer> <samlp:NameIDPolicy xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" SPNameQualifier="openam-sp" AllowCreate="true"> </samlp:NameIDPolicy> <samlp:RequestedAuthnContext xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Comparison="exact"> <saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> urn:oasis:names:tc:SAML:2.0:ac:classes:X509 </saml:AuthnContextClassRef> </samlp:RequestedAuthnContext> </samlp:AuthnRequest>
HTTP/1.1 302 Object Moved Date: 21 Jan 2004 07:00:49 GMT Location:https://ServiceProvider.com/SAML/SLO/Browser?SAMLart=...&RelayState=... Content-Type: text/html; charset=iso-8859-1
GET /SAML/SLO/Browser?SAMLart=...&RelayState=... HTTP/1.1 Host: ServiceProvider.com
Artifact Binding
POST /SAML/Artifact/Resolve HTTP/1.1 HOST: IdentityProvider.com Content-Type: text/xml Content-Length: nnn SOAPAction: http://www.oasis-open.org/committees/security <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <samlp:ArtifactResolve xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="_6c3a4f8b9c2d" Version="2.0" IssueInstant="2004-01-21T19:00:49Z"> <Issuer>https://ServiceProvider.com/SAML/</Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...Signature...</ds:Signature> <Artifact>...artifact...</Artifact> </samlp:ArtifactResolve> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Artifact Binding
HTTP/1.1 200 OK Date: 21 Jan 2004 07:00:49 GMT Content-Type: application/soap+xml Content-Length: nnnn <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <samlp:ArtifactResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="identifier_3" InResponseTo="identifier_2" Version="2.0" IssueInstant="2004-12-05T09:22:05Z"> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="identifier_4" InResponseTo="identifier_1" Version="2.0" IssueInstant="2004-12-05T09:22:05Z" Destination="https://ServiceProvider.com/SAML/SSO/Artifact"> <saml:Issuer> medical-doctor-sso-idp </saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ... </saml:Assertion> </samlp:Response> </samlp:ArtifactResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" ID="s2ead62f287a9e36c31b3a693974582fdae20c5351" IssueInstant="2011-06-28T05:08:41Z"> <saml:Issuer> medical-doctor-sso-idp </saml:Issuer> <saml:Subject> <saml:NameID NameQualifier="medical-doctor-sso-idp" SPNameQualifier="sso-sp" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"> 1234567890 </saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="s2cee63177ff33bcacd5263caa4af9da101837de24" NotOnOrAfter="2011-06-28T05:18:41Z" Recipient="https://ServiceProvider.com/SAML/Consumer/metaAlias/sp"> </saml:SubjectConfirmationData> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2011-06-28T04:58:41Z" NotOnOrAfter="2011-06-28T05:18:41Z"> <saml:AudienceRestriction> <saml:Audience> sso-sp </saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2011-06-28T05:08:41Z" SessionIndex="xxxxx"> <saml:AuthnContext> <saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:X509 </saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> <saml:AttributeStatement> <saml:Attribute Name="HCROLE "> <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string"> Medical Doctor </saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> </saml:Assertion>
<samlp:AuthnRequest xmlns="urn:oasis:names:tc:SAML:2.0:metadata" ID="id6c1c178c166d486687be4aaf5e482730" Version="2.0" IssueInstant="2013-03-18T03:28:54.1839884Z" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">https://www.contoso.com</Issuer> <NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/> </samlp:AuthnRequest>
<samlp:Response ID="_a4958bfd-e107-4e67-b06d-0d85ade2e76a" Version="2.0" IssueInstant="2013-03-18T07:38:15.144Z" Destination="https://contoso.com/identity/inboundsso.aspx" InResponseTo="id758d0ef385634593a77bdf7e632984b6" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion"> https://login.microsoftonline.com/82869000-6ad1-48f0-8171-272ed18796e9/ </Issuer> <ds:Signature xmlns:ds="https://www.w3.org/2000/09/xmldsig#"> ... </ds:Signature> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /> </samlp:Status> <Assertion ... </Assertion> </samlp:Response>
<Assertion ID="_bf9c623d-cc20-407a-9a59-c2d0aee84d12" Version="2.0" IssueInstant="2013-03-18T07:38:15.144Z" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"> <Issuer>https://login.microsoftonline.com/82869000-6ad1-48f0-8171-272ed18796e9/</Issuer> <ds:Signature xmlns:ds="https://www.w3.org/2000/09/xmldsig#"> ... </ds:Signature> <Subject> <NameID>Uz2Pqz1X7pxe4XLWxV9KJQ+n59d573SepSAkuYKSde8=</NameID> <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <SubjectConfirmationData InResponseTo="id758d0ef385634593a77bdf7e632984b6" NotOnOrAfter="2013-03-18T07:43:15.144Z" Recipient="https://contoso.com/identity/inboundsso.aspx" /> </SubjectConfirmation> </Subject> <Conditions NotBefore="2013-03-18T07:38:15.128Z" NotOnOrAfter="2013-03-18T08:48:15.128Z"> <AudienceRestriction> <Audience>https://www.contoso.com</Audience> </AudienceRestriction> </Conditions> <AttributeStatement> <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"> <AttributeValue>testuser@contoso.com</AttributeValue> </Attribute> <Attribute Name="http://schemas.microsoft.com/identity/claims/objectidentifier"> <AttributeValue>3F2504E0-4F89-11D3-9A0C-0305E82C3301</AttributeValue> </Attribute> ... </AttributeStatement> <AuthnStatement AuthnInstant="2013-03-18T07:33:56.000Z" SessionIndex="_bf9c623d-cc20-407a-9a59-c2d0aee84d12"> <AuthnContext> <AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:Password </AuthnContextClassRef> </AuthnContext> </AuthnStatement> </Assertion>
<samlp:AuthnRequest AssertionConsumerServiceURL="https://(sub_domain).cybozu.com/saml/acs" ID="szqd0c3d0u3vpz5jwna4p24iso42opc4" IssueInstant="2013-04-01T00:00:00Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> https://(sub_domain).cybozu.com </saml:Issuer> <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" /> </samlp:AuthnRequest>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="s2b39863179da0358f10bb499d6ac0e64062e89e1d" InResponseTo="szqd0c3d0u3vpz5jwna4p24iso42opc4" Version="2.0" IssueInstant="2013-04-01T00:30:00Z" Destination="https://(sub_domain).cybozu.com/saml/acs"> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> http://(idp_host) </saml:Issuer> <samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <samlp:StatusCode xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ... </saml:Assertion> </samlp:Response>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="s2822cac48e7b7ec82ff36710996423e7baec43a00" IssueInstant="2013-04-01T00:30:00Z" Version="2.0"> <saml:Issuer> https://(idp_host) </saml:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> ...アサーションの署名の内容... </ds:Signature> <saml:Subject> <saml:NameID NameQualifier="https://(idp_host)" SPNameQualifier="https://(sub_domain).cybozu.com" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"> watanabe </saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="szqd0c3d0u3vpz5jwna4p24iso42opc4" NotOnOrAfter="2013-04-01T00:40:00Z" Recipient="https://(sub_domain).cybozu.com/saml/acs" /> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2013-04-01T00:20:00Z" NotOnOrAfter="2013-04-01T00:40:00Z"> <saml:AudienceRestriction> <saml:Audience>https://(sub_domain).cybozu.com </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2013-04-01T00:29:30Z" SessionIndex="s2901e6c0e0cc0c8f1aa1075215125b2676774dd01"> <saml:AuthnContext> <saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport </saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion>
https://github.com/Sustainsys/Saml2/blob/master/Sustainsys.Saml2/XmlHelpers.cs#L368
Tags: :IT国際標準, :認証基盤, :クレームベース認証, :SAML