「マイクロソフト系技術情報 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は使えない。
○ emailAddress ○ unspecified ☓ persistent(永続的仮名) ☓ transient(一時的仮名) ☓☓ X509SubjectName ☓☓ WindowsDomainQualifiedName ☓☓ kerberos ☓☓ entity
多くのSPでは使用していない
○ 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 にする。
著名、IdPを使用してテストする。
Technical Overviewから取り出したサンプル・シーケンス
https://idp.example.org/SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token
<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="token" /> ... <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=token
<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=PHNhbW xwOkxvZ291dFJlcXVlc3QgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOj IuMDpwcm90b2NvbCIgG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3Nlc nRpb24iDQogICAgSUQ9ImQyYjdjMzg4Y2VjMzZmYTdjMzljMjhmZDI5ODY0NGE4IiBJc3N 1ZUluc3RhbnQ9IjIwMDQtMDEtMjFUMTk6MDA6NDlaIiBWZXJzaW9uPSIyLjAiPg0KICA gIDxJc3N1ZXI+aHR0cHM6Ly9JZGVudGl0eVByb3ZpZGVyLmNvbS9TQU1MPC9Jc3N1ZXI +DQogICAgPE5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDp uYW1laWQtZm9ybWF0OnBlcnNpc3RlbnQiPjAwNWEwNmUwLWFkODItMTEwZC1hNTU 2LTAwNDAwNWIxM2EyYjwvTmFtZUlEPg0KICAgIDxzYW1scDpTZXNzaW9uSW5kZXg+ MTwvc2FtbHA6U2Vzc2lvbkluZGV4Pg0KPC9zYW1scDpMb2dvdXRSZXF1ZXN0Pg==&Rela yState=0043bfc1bc45110dae17004005b13a2b Content-Type: text/html; charset=iso-8859-1
<?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><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=AAQAADWNEw5VT47w cO4zX%2FiEzMmFQvGknDfws2ZtqSGdkNSbsW1cmVR0bzU%3D&RelayState=0043bfc1bc45 110dae17004005b13a2b Content-Type: text/html; charset=iso-8859-1
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>
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
https://gist.github.com/daisukenishino2/69074e571cf89c23cce6d1522abc67e5
Tags: :IT国際標準, :認証基盤, :クレームベース認証, :SAML