LoginSignup
80
83

More than 3 years have passed since last update.

SAMLを使ったSSOの挙動とSAML Response、SAML Requestの概要

Last updated at Posted at 2021-06-17

自己紹介

現在はエンジニアとして株式会社メタップスでSaaS一元管理ツールであるメタップスクラウドの開発やSAMLを使ったSSOを簡単に導入できるようなライブラリ(sp-rails-saml)の開発を行っています。

その中でSAMLに関して勉強を行ったので、現状理解している範囲でSAMLの仕組みや、SAMLを使って認証を行う際のフローを関してまとめてみました。

特にSAMLによってやりとりされるSAML ResponseやSAML Requestの中身に関して結構複雑だと思ったので、そこに重点を置いて書いてみました。

SAMLとは

SAMLは「Security Assertion Markup Language」のことで、セキュリティ情報の伝達を目的としてOASISが定義したXMLベースの認証情報の仕様のことです。
電子署名を行うことで異なるインターネットドメイン間でも信頼できる情報のやりとりを行うことができます。
現在は2005年に定義されたSAML2.0が最新版として使用されています。

認証情報を管理するサービスにログインすることで連携されているSaaSへのシングルサインオンを実現する際にSAMLが使われたりします。

SAMLに関してよく出てくる用語

  • SSO
    • シングルサインオンの略で、一つのサーバーにログインすることで連携されているサービス全てへのログインが行える様な仕組みのことを指します。
  • SLO
    • シングルログアウトの略で、一つのサーバーをログアウトすることで連携されている全てのサービスからログアウトが行えるような仕組みのことを指します。
  • プロビジョニング
    • シングルサインオン時にユーザーがいなければユーザーを作成する様な機能のことを指します。
  • SP
    • Service Providerの略でシングルサインオンを使用してログインしたいSaaSのことを指します。
    • 例: Slack、SmartHR、Zoom
  • IdP
  • アサーション
    • SAMLにおけるシングルサインオンを行う際の認証情報の部分のことです。
  • Metadata
    • SAML連携において必要になるSP、IdPそれぞれの情報をまとめたデータになります。
    • 例外があるかもしれないですが、ほとんどの場合IdP側、SP側それぞれがMetadataを返すURLを用意しています。

SAMLを使ったSSOの流れ

SAMLを使ったSSOの流れですが、「SP Initiated」というSPが起点となる場合と「IdP Initiated」というIdPが起点となる場合の2つがあります。

SP Initiatedの場合

SP InitiatedはSPが起点となったSAML認証フローになり

1. SPのログイン画面を表示し、ログインボタンを押す
2. SPが「SAML Request」という認証リクエストをIdPに送る
3. IdPは受け取ったSAML RequestとIdPにログインしているユーザー情報を元に「SAML Response」を生成しSPに送る
4. SPは受け取ったSAML Responseを検証し、問題なければSAML Responseに記載されているユーザー情報を元にログイン処理を行う

この様な順番で処理が行われます。

図に表すと下記の様な形になり、ブラウザを通してSAML RequestとSAML Responseのやりとりが行われる形になります。

spp.jpg

IdP Initiatedの場合

IdP InitiatedはIdPが起点となったSAML認証フローになり

1. IdPの画面に用意されているSPへのログインボタンを押す
2. ログインしているユーザー情報を元にSAML Responseを生成してSPに送る
3. SPは受け取ったSAML Responseを検証し、問題なければSAML Responseに記載されているユーザー情報を元にログイン処理を行う

この様な順番で処理が行われます。

図に表すと下記の様な形になり、ブラウザを通してIdPからSPへSAML Responseが送られます。
SP Initiatedと異なり、SPがSAML RequestをIdPに送るフローが省かれる形になります。

ll.jpg

IdP Initiatedの場合、SP側から送られてくるSAML Requestが無いので、SP側でどのような方法でSAML Responseを返して欲しいかわかりません。
そのため、IdP Initiatedを行う場合はSP側へどの様な形でSAML Responseを返すのかの情報を持っておく必要があります。

SSOにてやりとりされるSAMLのデータの中身

SSOの中でSAML RequestとSAML Responseというデータのやりとりが行われ、それを元にSSOを行うのですがこのSAML RequestとSAML Responseの中身に関して解説した記事が少ないので現状理解している範囲で説明したいと思います。

SAML Request

SAML Requestのデータは下記の様な形で渡されることになります。

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="Request ID" Version="2.0" IssueInstant="2004-12-05T09:21:59Z" AssertionConsumerServiceIndex="1">
  <saml:Issuer>https://sp.saas.com</saml:Issuer>
  <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" />
  <samlp:RequestedAuthnContext Comparison="exact">
    <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
  </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>

上記の場合はAuthnRequest、Issuer、NameIDPolicy、RequestedAuthnContextタグによって構成されていますが、署名が行われる場合は上記の加えてSignatureタグが追加されることになります。

それぞれのタグの役割と中身に関しては下記の様な形になります。

AuthnRequest

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="Request ID" Version="2.0" IssueInstant="2004-12-05T09:21:59Z" AssertionConsumerServiceIndex="1">
タグ/属性 内容 備考
ID RequestのユニークなIDが振られます。 SAML ResponseのInResponseTo属性にこのIDが振られる形になります。 SAML Requestに対するSAML Responseであるかを検証したい場合はここを見る形になると思います。
Version SAMLはバージョンが入ります
AssertionConsumerServiceURL SP側でSAML Responseを受けるURLになります
ProtocolBinding SAML Responseの受ける際の方法が記載されています。 HTTP POSTにてSAML Responseを受け取る場合やメッセージングプロトコルであるSOAPを使用する場合があります。
Destination SAML Requestを送る先のURLが入ります
IssueInstant SAML Requestが作られたタイミングの時刻が入ります。

Issuer

<saml:Issuer>https://sp.saas.com/</saml:Issuer>
タグ/属性 内容 備考
Issuer URL形式のSP側のIDみたいなもの? 基本的にmetadataを返すURLが設定されます。 SAML RequestのIssuerはSP側のEntityIDが設定され、 SAML ResponseのIssuerにはIdP側のEntityIDが設定される形になります。

NameIDPolicy

<samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" />
タグ/属性 内容 備考
Format SAML Responseで受け取るNameIDの形式が入ります。

RequestedAuthnContext

<samlp:RequestedAuthnContext Comparison="exact">
  <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
</samlp:RequestedAuthnContext>
タグ/属性 内容 備考
RequestedAuthnContext/Comparison AuthnContextClassRefの比較方法になります。 exactの場合は完全一致するものを検索する形になります。
AuthnContextClassRef IdP側でユーザーをどのように認証して欲しいかを指定 ID/Passwordでの認証を行って欲しい場合はurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportを指定する形になります。

SAML Response

SAML Responseのデータは下記の様な形で渡されることになります。

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfx64932347-5370-fea3-61bf-486ba519c861" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="https://sp.saas.com/acs" InResponseTo="4fee3b046395c4e751011e97f8900b5273d56685">
  <saml:Issuer>http://idp.service.com/metadata</saml:Issuer>
  <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/2000/09/xmldsig#rsa-sha1" />
      <ds:Reference URI="#pfx64932347-5370-fea3-61bf-486ba519c861">
        <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/2000/09/xmldsig#sha1" />
        <ds:DigestValue>VzCbNSpQ/1iWYTsFTlWMbB9xx+ttOuIuEOpiBBOlc9I=</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>HzmAJ2vPPjUHSXJczYb6Tnjx2iVwcmYc0TdyrSeoXYbMx17XEzzFRnSx03nZEsc+xbHmN++Mal7CwwvlFkSp9js3ubFRtLP70cJ7zNaQA83gfhHPu5roFRHqGoyKFvkJVIWnjnYrL/fvOUNC0osFNll85a6geoJGvTrNK9i+LEQtkATuO5/NqrtqPLqFzJc3veC74ChreMXd/1FBZO8w6nfo74yPDk9taJ/QFYRQikZd4PhMtx0PtArsVmpoYZWjJ5Drcdyq1ELshWRQrVXgsY/iGwo8CAhTumWB89SnuraUR23B4vD4wiapsoQzzun6hXiTXgRo4nDrPlUXvM/v3A==</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>MIIDVjCCAj6gAwIBAgIBATANBgkqhkiG9w0BAQsFADA8MRQwEgYDVQQKDAttZXRhcHMgSW5jLjETMBEGA1UECwwKbWNsb3VkIElkcDEPMA0GA1UEAwwGbWNsb3VkMB4XDTIxMDUyMTA1MjQyMVoXDTI2MDUyMDA1MjQyMVowPDEUMBIGA1UECgwLbWV0YXBzIEluYy4xEzARBgNVBAsMCm1jbG91ZCBJZHAxDzANBgNVBAMMBm1jbG91ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOldNOBsT8bmI3CqSIy3E76+6o4jFBSjRlU4DXLKKLUvTdqAl82FBCZFlSKOn6zNmihKpRwn0loHED+2Trla5zLN++vgRm5WsMkQBUqv/uq20EB0LG4cosMYseDABUrAy6PF+RkNlLDDViw7/POFgQgtRomNm6Yn3nUEmh6QHlX25A83nvUwUzV5R76jVe6elRXviB/U7WkzZHJVeLUTaxFMK/u0xL7eE/Fu/hXM115Jhx6wMyWg10IhnwYGJwExK8FfWlLNtvkGK8wfVjUcHC6N0rXMWUxTEKtor9+d48Q8IhW2QJYIjWsDlFjQc9EHurWeaT02eoYeCKPMXFovm80CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJp32suFwe3KUkxJQ6PL6eTTCqm0MB8GA1UdIwQYMBaAFJp32suFwe3KUkxJQ6PL6eTTCqm0MA0GCSqGSIb3DQEBCwUAA4IBAQBBvnn6f4pUKdzo3AqnrOSam315n4efdMwKPM3YsRogffeCJL1a9MDBaQ2FLTimjT/bJS7B9cfpBfoIG/ix/AQMRGoy8imUrFnoxCHhIWSWy80XAxQkGqErI59xzgqUTU3rNurq7WCazq9IyCQ3VJrg55v6UDfNkTag+nEEPbRSpHjJgZKdAKISihIdwkwSwvXFVTNDnScO++wgy4VuAJGL3ouAbQvx2iF/ge8uNqEP7Zz3GtN6o6Uy8Hfrxi7rla10ZxQ3HGJTQ0ixHA1DOQ9IHg3rQQzUR1dyCpfhfjsZ1T4aqhXbwLq5/FW8Tl38BU0d8V3Eu0WWeY+DbUdg5rUF</ds:X509Certificate>
      </ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
  </samlp:Status>
  <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfx566beda3-0c5f-f472-bdcb-2b09e9653270" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
    <saml:Issuer>http://idp.service.com/metadata</saml:Issuer>
    <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/2000/09/xmldsig#rsa-sha1" />
        <ds:Reference URI="#pfx566beda3-0c5f-f472-bdcb-2b09e9653270">
          <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/2000/09/xmldsig#sha1" />
          <ds:DigestValue>VzCbNSpQ/1iWYTsFTlWMbB9xx+ttOuIuEOpiBBOlc9I=</ds:DigestValue>
        </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue>HzmAJ2vPPjUHSXJczYb6Tnjx2iVwcmYc0TdyrSeoXYbMx17XEzzFRnSx03nZEsc+xbHmN++Mal7CwwvlFkSp9js3ubFRtLP70cJ7zNaQA83gfhHPu5roFRHqGoyKFvkJVIWnjnYrL/fvOUNC0osFNll85a6geoJGvTrNK9i+LEQtkATuO5/NqrtqPLqFzJc3veC74ChreMXd/1FBZO8w6nfo74yPDk9taJ/QFYRQikZd4PhMtx0PtArsVmpoYZWjJ5Drcdyq1ELshWRQrVXgsY/iGwo8CAhTumWB89SnuraUR23B4vD4wiapsoQzzun6hXiTXgRo4nDrPlUXvM/v3A==</ds:SignatureValue>
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>MIIDVjCCAj6gAwIBAgIBATANBgkqhkiG9w0BAQsFADA8MRQwEgYDVQQKDAttZXRhcHMgSW5jLjETMBEGA1UECwwKbWNsb3VkIElkcDEPMA0GA1UEAwwGbWNsb3VkMB4XDTIxMDUyMTA1MjQyMVoXDTI2MDUyMDA1MjQyMVowPDEUMBIGA1UECgwLbWV0YXBzIEluYy4xEzARBgNVBAsMCm1jbG91ZCBJZHAxDzANBgNVBAMMBm1jbG91ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOldNOBsT8bmI3CqSIy3E76+6o4jFBSjRlU4DXLKKLUvTdqAl82FBCZFlSKOn6zNmihKpRwn0loHED+2Trla5zLN++vgRm5WsMkQBUqv/uq20EB0LG4cosMYseDABUrAy6PF+RkNlLDDViw7/POFgQgtRomNm6Yn3nUEmh6QHlX25A83nvUwUzV5R76jVe6elRXviB/U7WkzZHJVeLUTaxFMK/u0xL7eE/Fu/hXM115Jhx6wMyWg10IhnwYGJwExK8FfWlLNtvkGK8wfVjUcHC6N0rXMWUxTEKtor9+d48Q8IhW2QJYIjWsDlFjQc9EHurWeaT02eoYeCKPMXFovm80CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJp32suFwe3KUkxJQ6PL6eTTCqm0MB8GA1UdIwQYMBaAFJp32suFwe3KUkxJQ6PL6eTTCqm0MA0GCSqGSIb3DQEBCwUAA4IBAQBBvnn6f4pUKdzo3AqnrOSam315n4efdMwKPM3YsRogffeCJL1a9MDBaQ2FLTimjT/bJS7B9cfpBfoIG/ix/AQMRGoy8imUrFnoxCHhIWSWy80XAxQkGqErI59xzgqUTU3rNurq7WCazq9IyCQ3VJrg55v6UDfNkTag+nEEPbRSpHjJgZKdAKISihIdwkwSwvXFVTNDnScO++wgy4VuAJGL3ouAbQvx2iF/ge8uNqEP7Zz3GtN6o6Uy8Hfrxi7rla10ZxQ3HGJTQ0ixHA1DOQ9IHg3rQQzUR1dyCpfhfjsZ1T4aqhXbwLq5/FW8Tl38BU0d8V3Eu0WWeY+DbUdg5rUF</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </ds:Signature>
    <saml:Subject>
      <saml:NameID SPNameQualifier="https://sp.saas.com/metadata" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="https://sp.saas.com/acs" InResponseTo="4fee3b046395c4e751011e97f8900b5273d56685" />
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
      <saml:AudienceRestriction>
        <saml:Audience>https://sp.saas.com/metadata</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
    <saml:AttributeStatement>
      <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">test@example.com</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue>
        <saml:AttributeValue xsi:type="xs:string">role</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>

大まかに分けると Responseタグ、Issuerタグ、Singatureタグ、Statusタグ、Assertionタグがある構成になります。

Responseタグ

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfx64932347-5370-fea3-61bf-486ba519c861" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="https://sp.saas.com/acs" InResponseTo="4fee3b046395c4e751011e97f8900b5273d56685">
タグ/属性 内容 備考
ID 一意のID
Version SAMLのVersion
IssueInstant SAML Responseが作成された時刻
Destination SP側でSAML Responseを受け取るURL SAML RequestのAssertionConsumerServiceURLと同一の値が入る形になるはずです
InResponseTo SAML RequestのID SP側が送ったSAML Requestに対するSAML Responseであるかを検証する際にこの値を参照します。IdP Initiatedの場合はSAML Requestを受け取るフローが無いのでここに値は入らない形になると思います。

Issuerダグ

<saml:Issuer>http://idp.service.com/metadata</saml:Issuer>
タグ/属性 内容 備考
Issuer URL形式のIdP側のIDみたいなもの? 基本的にmetadataを返すURLが設定されます。 SAML RequestのIssuerはSP側のEntityIDが設定され、 SAML ResponseのIssuerにはIdP側のEntityIDが設定される形になります。

Signatureタグ

  <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/2000/09/xmldsig#rsa-sha1" />
      <ds:Reference URI="#pfx64932347-5370-fea3-61bf-486ba519c861">
        <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/2000/09/xmldsig#sha1" />
        <ds:DigestValue>VzCbNSpQ/1iWYTsFTlWMbB9xx+ttOuIuEOpiBBOlc9I=</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>HzmAJ2vPPjUHSXJczYb6Tnjx2iVwcmYc0TdyrSeoXYbMx17XEzzFRnSx03nZEsc+xbHmN++Mal7CwwvlFkSp9js3ubFRtLP70cJ7zNaQA83gfhHPu5roFRHqGoyKFvkJVIWnjnYrL/fvOUNC0osFNll85a6geoJGvTrNK9i+LEQtkATuO5/NqrtqPLqFzJc3veC74ChreMXd/1FBZO8w6nfo74yPDk9taJ/QFYRQikZd4PhMtx0PtArsVmpoYZWjJ5Drcdyq1ELshWRQrVXgsY/iGwo8CAhTumWB89SnuraUR23B4vD4wiapsoQzzun6hXiTXgRo4nDrPlUXvM/v3A==</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>MIIDVjCCAj6gAwIBAgIBATANBgkqhkiG9w0BAQsFADA8MRQwEgYDVQQKDAttZXRhcHMgSW5jLjETMBEGA1UECwwKbWNsb3VkIElkcDEPMA0GA1UEAwwGbWNsb3VkMB4XDTIxMDUyMTA1MjQyMVoXDTI2MDUyMDA1MjQyMVowPDEUMBIGA1UECgwLbWV0YXBzIEluYy4xEzARBgNVBAsMCm1jbG91ZCBJZHAxDzANBgNVBAMMBm1jbG91ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOldNOBsT8bmI3CqSIy3E76+6o4jFBSjRlU4DXLKKLUvTdqAl82FBCZFlSKOn6zNmihKpRwn0loHED+2Trla5zLN++vgRm5WsMkQBUqv/uq20EB0LG4cosMYseDABUrAy6PF+RkNlLDDViw7/POFgQgtRomNm6Yn3nUEmh6QHlX25A83nvUwUzV5R76jVe6elRXviB/U7WkzZHJVeLUTaxFMK/u0xL7eE/Fu/hXM115Jhx6wMyWg10IhnwYGJwExK8FfWlLNtvkGK8wfVjUcHC6N0rXMWUxTEKtor9+d48Q8IhW2QJYIjWsDlFjQc9EHurWeaT02eoYeCKPMXFovm80CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJp32suFwe3KUkxJQ6PL6eTTCqm0MB8GA1UdIwQYMBaAFJp32suFwe3KUkxJQ6PL6eTTCqm0MA0GCSqGSIb3DQEBCwUAA4IBAQBBvnn6f4pUKdzo3AqnrOSam315n4efdMwKPM3YsRogffeCJL1a9MDBaQ2FLTimjT/bJS7B9cfpBfoIG/ix/AQMRGoy8imUrFnoxCHhIWSWy80XAxQkGqErI59xzgqUTU3rNurq7WCazq9IyCQ3VJrg55v6UDfNkTag+nEEPbRSpHjJgZKdAKISihIdwkwSwvXFVTNDnScO++wgy4VuAJGL3ouAbQvx2iF/ge8uNqEP7Zz3GtN6o6Uy8Hfrxi7rla10ZxQ3HGJTQ0ixHA1DOQ9IHg3rQQzUR1dyCpfhfjsZ1T4aqhXbwLq5/FW8Tl38BU0d8V3Eu0WWeY+DbUdg5rUF</ds:X509Certificate>
      </ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>

こちらは署名の情報が入っています。

タグ/属性 内容 備考
SignatureValue 署名の値
X509Certificate 署名の検証に使用する証明書の値 おそらくこのSAML Responseに記載されている証明書を読み取って使用する形は取らず、SP側に証明書の情報をアップロードさせ、その情報を元に検証する形が一般的な様です。

Statusタグ

<samlp:Status>
  <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
</samlp:Status>
タグ/属性 内容 備考
StatusCode SAML Requestに対するStatusを返します。 StatusCodeの種類に関しては「StatusCodeのCode一覧」にて記載します。

StatusCodeのCode一覧(前半のurn:oasis:names:tc:SAML:2.0:statusは省略して表示)

StatusCode 内容 備考
Success 成功
Requester SAML Reuestを出した側の問題で失敗 例えば SAML Requestに記載されているbindingの方法に対応していなかった場合など
Responder SAML Responseを作る側の問題で失敗 IdP側の設定不足の場合など?
VersionMismatch SAML の Versionに対応していない SAML Requestに記載されているVersionがIdP側で対応しているVersionではなかった場合

上記の内容は第一階層のStatusCodeになります。
StatusCodeは下記の様にStatusCodeの中にStatusCodeを置けます。

<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Requester">
  <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported" />
</samlp:StatusCode>

この内側に記載するStatusCodeは結構たくさん種類があるため全ての解説は行いませんが種類としては下記の様な種類があります。

  • urn:oasis:names:tc:SAML:2.0:status:AuthnFailed
  • urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue
  • urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy
  • urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext
  • urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP
  • urn:oasis:names:tc:SAML:2.0:status:NoPassive
  • urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP
  • urn:oasis:names:tc:SAML:2.0:status:PartialLogout
  • urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded
  • urn:oasis:names:tc:SAML:2.0:status:RequestDenied
  • urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported
  • urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated
  • urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh
  • urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow
  • urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized
  • urn:oasis:names:tc:SAML:2.0:status:TooManyResponses
  • urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile
  • urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal
  • urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding

また、StatusMessageタグやStatusDetailタグを使用することでエラーメッセージ内容も指定することができます。

アサーションタグ

<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfx566beda3-0c5f-f472-bdcb-2b09e9653270" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
タグ/属性 内容 備考
ID 一意のID
Version SAMLのVersion
IssueInstant SAML Responseが生成されたタイミング

Issuerタグ

<saml:Issuer>http://idp.service.com/metadata</saml:Issuer>
タグ/属性 内容 備考
Issuer IdPのEntityID

Signatureタグ

アサーション内の署名になり、中身としてはResponseの署名と同様です。

Subjectタグ

<saml:Subject>
  <saml:NameID SPNameQualifier="https://sp.saas.com/metadata" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
  <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
    <saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="https://sp.saas.com/acs" InResponseTo="_4fee3b046395c4e751011e97f8900b5273d56685" />
  </saml:SubjectConfirmation>
</saml:Subject>
タグ/属性 内容 備考
NameID/SPNameQualifier SPのEntityID 信頼するSAMLリライングパーティ(SAML依拠当事者)を指定する?
NameID/Format NameIDの形式 NameIDの形式の種類に関しては下記に記載
NameID ログインを行うユーザーを識別するデータ(例: メールアドレス)
SubjectConfirmation/NotOnOrAfter SAML Responseの検証時にこの時刻を過ぎている場合は検証を失敗させる
SubjectConfirmation/InResponseTo SAML RequestのID
SubjectConfirmation/Recipient Assertionの検証を行うエンドポイント

Formatの形式の種類

Format 内容 備考
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress メールアドレス
urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName ds:X509SubjectNameタグ内に記載されたものを参照?
urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName Windowsのdomain付きのユーザー名?
urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos Kerberos プリンシパル
urn:oasis:names:tc:SAML:2.0:nameid-format:entity Issuerの値を使用

Conditionsタグ

<saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
  <saml:AudienceRestriction>
    <saml:Audience>https://sp.saas.com/metadata</saml:Audience>
  </saml:AudienceRestriction>
</saml:Conditions>
タグ/属性 内容 備考
NotBefore 現在がこの時刻より前の時間の場合は無効とする
NotOnOrAfter 現在がこの時刻以降の場合は無効とする SubjectConfirmationにも同じ情報を持っているので、なぜ二つの箇所で持てるようにしているのかは不明
AudienceRestriction Assertionを送る対象のSPの情報?
Audience 対象のSPのEntityIDを指定

AuthnStatementタグ

<saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
  <saml:AuthnContext>
    <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
  </saml:AuthnContext>
</saml:AuthnStatement>
タグ/属性 内容 備考
AuthnInstant 認証が開始される時刻
SessionIndex IdP側で管理しているSessionのIndex それぞれのSPに対して特定のIDをIdPが発行している様な形?
SessionNotOnOrAfter セッションが切れる時刻
AuthnContext/AuthnContextClassRef IdPにてユーザーを認証した方法 AuthnContextClassRefの種類は下記に記載

AuthnContextClassRefの種類

  • urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol
  • urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocolPassword
  • urn:oasis:names:tc:SAML:2.0:ac:classes:Kerberos
  • urn:oasis:names:tc:SAML:2.0:ac:classes:MobileOneFactorUnregistered
  • urn:oasis:names:tc:SAML:2.0:ac:classes:MobileTwoFactorUnregistered
  • urn:oasis:names:tc:SAML:2.0:ac:classes:MobileOneFactorContract
  • urn:oasis:names:tc:SAML:2.0:ac:classes:MobileTwoFactorContract
  • urn:oasis:names:tc:SAML:2.0:ac:classes:Password
  • urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
  • urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession
  • urn:oasis:names:tc:SAML:2.0:ac:classes:X509
  • urn:oasis:names:tc:SAML:2.0:ac:classes:PGP
  • urn:oasis:names:tc:SAML:2.0:ac:classes:SPKI
  • urn:oasis:names:tc:SAML:2.0:ac:classes:XMLDSig
  • urn:oasis:names:tc:SAML:2.0:ac:classes:Smartcard
  • urn:oasis:names:tc:SAML:2.0:ac:classes:SmartcardPKI
  • urn:oasis:names:tc:SAML:2.0:ac:classes:SoftwarePKI
  • urn:oasis:names:tc:SAML:2.0:ac:classes:Telephony
  • urn:oasis:names:tc:SAML:2.0:ac:classes:NomadTelephony
  • urn:oasis:names:tc:SAML:2.0:ac:classes:PersonalTelephony
  • urn:oasis:names:tc:SAML:2.0:ac:classes:AuthenticatedTelephony
  • urn:oasis:names:tc:SAML:2.0:ac:classes:SecureRemotePassword
  • urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient
  • urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken
  • urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified

かなり大量にあるのですが、ほとんどの場合ID/Passwordを使用してIdPにログインすると思うのでSAML Responseではurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportが選択されている形になると思います。
SP側でユーザーのIdPへの認証方法を指定したい場合はSAML RequestAuthnContextClassRefを指定することでIdP側で実装が行われていれば指定した方法でユーザーをログインさせる形になると思います。

AttributeStatementタグ

<saml:AttributeStatement>
  <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
    <saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
  </saml:Attribute>
  <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
    <saml:AttributeValue xsi:type="xs:string">test@example.com</saml:AttributeValue>
  </saml:Attribute>
  <saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
    <saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue>
    <saml:AttributeValue xsi:type="xs:string">role</saml:AttributeValue>
  </saml:Attribute>
</saml:AttributeStatement>
タグ/属性 内容 備考
Attribute/Name Attribute名を指定 これといって決まった記載の方法はなく、SPごとで値の指定の仕方は異なる様です。
Attribute/NameFormat AttributeのNameの形式 URI形式で指定する場合などNameの指定方法に関しては種類があるようで、その方法を指定する形になる様です。
Attribute/AttributeValue Attributeの値が入ります。 ユーザーのプロビジョニングで使用する場合はSPによってはSSO時にEmailの情報を必須入力させるなど使用用途は色々ありそうです。

Attribute/NameFormatは下記の三種類がある様です。

  • urn:oasis:names:tc:SAML:2.0:attrname-format:uri
  • urn:oasis:names:tc:SAML:2.0:attrname-format:basic
  • urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified

SAMLの実装で詰まるところ

同じ目的の値がいろんな箇所にあるため、なぜその値がそのタグに必要なのか不明なものがちょくちょくあります。
例えばNotOnOrAfterSubjectタグにもConditionタグにもありますし、署名に関してはResponseに署名を行う場合もあればAssertionに署名を行う場合、両方に署名を行う場合など様々です。
そのため、まず仕様に関して何が正しいのか、どこを参照してどんな検証を行えば良いかわかりづらい気がしています。

また、仕様が複雑でAuthnContextClassRefの内容だけで4000行近いドキュメントがあります。
この内容を全て理解するのは厳しく、かつ英語なためさらに理解が大変そうです。

仕様が複雑であることから、例えばAuthnContextClassRefの値が送られてきても、この値をみて挙動を変える様なところまで実装できていないため無視していたり、InResponseToを検証するSaaSもあればしないSaaSもあったりみたいな感じになっていると思います。

こういった仕様の複雑さからくるIdP SP側の実装の差異が発生してどのような動きが正しいかわからない箇所があるため実装に困る場面があるのでは無いかなと思っています。

SSOだけでこんなに複雑なので、これに合わせてSLOやプロビジョニングも入ってくると実装と仕様の把握に結構な時間がかかってくるのでは無いかなと思いました。

SAML関係で参考になるサイトのリンク

SAML連携を行うためのOSSを作っています

メタップスでは現在SaaS一元管理ツールである「メタップスクラウド」の開発を行っています。
ただ、現状としてSaaSがSAMLに対応していない場合があり、SaaSの一元管理を行う際にSAMLを使ったSSOが実現できないSaaSが少なからずあります。

SaaS事業者がSAMLを導入しない理由としては実装コストが高かったり、優先順位が低いといった理由があり、そういった状況を踏まえ、SaaS事業者が簡単にSAML連携を導入できる様にするためのライブラリがあったら良い思い、現在はSAML連携を既存のアプリに導入するためのOSS開発を行っています。

内容としては、設定ファイルを用意することで細かい実装はしなくてもSSOが実装できる様なライブラリの開発を行っています。

興味ある方は是非見てみてください。

80
83
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
80
83