SAML

最后更新:2021-12-06

1. 应用介绍

SAML(Security Assertion Markup Language 安全断言标记语言)是一个基于XML的开源标准数据格式,为在安全域间交换身份认证和授权数据,尤其是在IDP(Identity Provider身份提供方)和SP(Service Provider 服务提供方)之间。SAML是OASIS(Organization for the Advancement of Structured Information Standards 安全服务技术委员会)制定的标准,始于2001年,其最新主要版本SAML 2.0于2005年发布。SAML解决的最主要的需求是基于Web的单点登录(SSO)。

SAML出现早,内容比较全,应用很广泛,但是缺点也比较明显。首先SAML只支持Web的SSO,不支持移动端;其次内容太广,如果要做一个比较全的SAML,需要实现协议中规定的所有项目,包括大量的可选项目,工程量比较大;再次SAML是基于XML的协议,这样又需要基于更多的协议进行开发。 SAML协议中定义了三种角色:

User Agent:用户代理,一般指自然人用户通过浏览器进行服务访问或者向其他服务提供者请求资源的的系统主体;

IDP(Identity Provider):一种服务提供者,它创建、维护和管理主体的身份信息,并向联邦内的其他服务提供者提供主体身份验证;

SP(Service Provider):一种服务提供者,通过解析IDP发出的身份认证断言,验证主体身份认证信息后,给主体或联邦内其他系统提供服务。

SAML分为SP发起SSO和IDP发起SSO两种流程

1.1. SP发起SSO

用户请求SP资源,SP生成SAML请求,IDP接收并解析SAML请求并进行用户认证后返回SAML响应,SP接收并解析SAML响应后,提起其中的令牌Assertion, 提供被请求的资源给用户使用。

这是SAML的SP发起SSO流程图

具体流程如下

1、用户请求目标资源

用户向SP请求目标资源,例如目标资源为: https://sp.example.com/myresource SP会进行安全检查,如果SP已经存在有效的IDP安全会话上下文,则认为已经登录过, 跳过步骤2~8。

2、重定向到IDP的SSO服务

SP会生成SAMLRequest,同时会把SP当前发起的URL生成一个随机数opaque, 临时存放, 同时把它作为RelayState,然后使用标准的HTTP 302重定向redirect到IDP的SSO服务,例如: 302 Redirect Location: http://idp4/enduser/api/application/plugin_saml/<application_id>/sp_sso?SAMLRequest=xxx&RelayState=opaque RelayState是SP的发起URL的不透明引用,SAMLRequest是Base64编码以后的samlp:AuthnRequest元素。如果需要的话,SAMLRequest还可以使用SigningKey进行签名。

3、浏览器转发SAML请求,重定向到IDP的SSO服务

浏览器将SP的SAMLRequest和RelayState通过一个GET请求转发到IDP的SSO服务: GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=opaque HTTP/1.1 Host: idp.example.org

4、IDP解析SAML请求

IDP解析SAML请求,通过Base64解码得到samlp:AuthnRequest元素。IDP会验证用户是否已经登录,如果已经登录则跳过步骤5。

5、认证用户

IDP认证用户身份,常用的方法是IDP返回登录页面给用户,IDP可以配置自己需要的认证方式, 比如用户使用账号和密码进行登录认证。

6、用户认证成功后返回SAML响应

IDP认证用户身份以后会返回SAMLResponse响应,包含有用户的Subject 身份信息。

7、浏览器将SAML响应转发到SP的ACS

浏览器将SAMLResponse和RelayState以POST的方式转发到SP的ACS URL, SP继续解析令牌。 POST /SAML2/SSO/POST HTTP/1.1 Host: sp.example.com Content-Type: application/x-www-form-urlencoded Content-Length: nnn SAMLResponse=response&RelayState=opaque

8、SP解析验证SAML响应

SP处理SAMLResponse响应,Base64解码得到samlp:Response元素,最重要的是要用SP中的公钥, 来检查签名的合法性, 如果合法 ,则抽取其中包含的用户信息Subject,找到对应的SP应用子账户, 生成SP安全会话上下文。

9、用户获取目标资源

用户成功获取SP提供的目标资源。如果SP发现RelayState中有对应的URL, 则提取这个URL, 跳转到对应的URL。

1.2. IDP发起SSO

同上面的SP发起SSO不同, IDP发起可以实现用户登录IDP,在IDP中选择某个SP应用,IDP跳转到SP,用户使用SP的资源。

这是SAML的IDP发起SSO流程图

1、用户访问IDP

用户打开IDP的登录页面。

2、用户登录IDP

使用配置好的如账号密码等方式登录到IDP。

3、用户选择需要的SP应用

用户在IDP中选择需要使用的SP应用, 背后会触发http://idp4/api/bff/v1.2/enduser/portal/sso/go_0fbd26xxx?access_token=9a2e8d41-cde9-4ba9-b09b-yyyy,继续流程。

4、IDP返回用户选择的SP应用的SAML响应

IDP生成用户选择的SP应用的SAMLResponse响应(前文已介绍),返回给用户的浏览器。

5、浏览器将SAML响应转发到SP的ACS

浏览器将SAMLResponse和RelayState以POST的方式转发到SP的ACS URL。

6、SP解析验证SAML响应

SP处理SAMLResponse响应,Base64解码得到samlp:Response元素,最重要的是要用SP中的公钥, 来检查签名的合法性, 如果合法 ,则抽取其中包含的用户信息Subject,找到对应的SP应用子账户, 生成SP安全会话上下文。 注: 可以看到, 这一步和SP发起中的第8步非常类似, 包括下一步。

7、用户获取目标资源

自此,SSO结束,用户成功获取SP提供的目标资源。如果SP发现RelayState中有对应的URL, 则提取这个URL, 跳转到对应的URL。

8、显示目标资源

用户看到对应的应用目标资源。

2. Metadata

SAML协议规定,要让IDP和SP实现SSO,需要在IDP和SP进行参数配置,主要是交换IDP和SP的Metadata(元数据)信息,IDP的Metadata示例如下:

  <md:EntityDescriptor entityID="https://idp.example.org/SAML2" validUntil="2013-03-22T23:00:00Z"
    xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <!-- insert ds:Signature element (omitted) -->
    <!-- insert md:IDPSSODescriptor element (below) -->
    <md:Organization>
      <md:OrganizationName xml:lang="en">Some Non-profit Organization of New York</md:OrganizationName>
      <md:OrganizationDisplayName xml:lang="en">Some Non-profit Organization</md:OrganizationDisplayName>
      <md:OrganizationURL xml:lang="en">https://www.example.org/</md:OrganizationURL>
    </md:Organization>
    <md:ContactPerson contactType="technical">
      <md:SurName>SAML Technical Support</md:SurName>
      <md:EmailAddress>mailto:saml-support@example.org</md:EmailAddress>
    </md:ContactPerson>
  </md:EntityDescriptor>

主要元素信息为:

标签

说明

md:EntityDescriptor下的entityID

IDP的唯一标识。

md:EntityDescriptor下的validUntil

元数据的过期时间。

ds:Signature

包含数字签名,以确保元数据的真实性和完整性。

md:Organization

组织信息。

md:ContactPerson

联系人信息。

IDP的SSO相关Metadata是md:IDPSSODescriptor元素,示例如下:

  <md:IDPSSODescriptor
    protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <md:KeyDescriptor use="signing">
      <ds:KeyInfo>...</ds:KeyInfo>
    </md:KeyDescriptor>
    <md:ArtifactResolutionService isDefault="true" index="0"
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
      Location="https://idp.example.org/SAML2/ArtifactResolution"/>
    <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
    <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
    <md:SingleSignOnService
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
      Location="https://idp.example.org/SAML2/SSO/Redirect"/>
    <md:SingleSignOnService
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
      Location="https://idp.example.org/SAML2/SSO/POST"/>
    <md:SingleSignOnService
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
      Location="https://idp.example.org/SAML2/Artifact"/>
    <saml:Attribute
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
      Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1"
      FriendlyName="eduPersonAffiliation">
      <saml:AttributeValue>member</saml:AttributeValue>
      <saml:AttributeValue>student</saml:AttributeValue>
      <saml:AttributeValue>faculty</saml:AttributeValue>
      <saml:AttributeValue>employee</saml:AttributeValue>
      <saml:AttributeValue>staff</saml:AttributeValue>
    </saml:Attribute>
  </md:IDPSSODescriptor>

主要元素信息为:

标签

说明

<md:KeyDescriptor use=“signing”>

IDP配置的一个私有SAML签名密钥和/或一个私有后端通道TLS密钥。

md:ArtifactResolutionService下的Binding

SAML绑定信息。

md:NameIDFormat

SSO支持的SAML名称标识格式。

md:SingleSignOnService

单点登录信息。

saml:Attribute

IDP提供的断言的属性。

SP的Metadata与IDP的类似。从上面的示例中我们看到交换IDP和SP的Metadata,主要就是交换两部分信息,一部分是实体的唯一标识、签名信息等,让IDP和SP能够唯一识别对方的身份;另一部分是绑定信息、名称标识格式等SSO相关信息,让IDP和SP能够进行SSO。更详细的Metadata信息可以查看《SAML 模板使用指南》

3. SAMLRequest

SP在请求IDP进行身份认证时会发送一个SAMLRequest,它是Base64编码以后的samlp:AuthnRequest元素,示例如下:

  <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="0">
    <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>

主要元素信息为:

标签

说明

samlp:AuthnRequest下的IssueInstant

消息签发时间。

saml:Issuer

消息签发者。

samlp:NameIDPolicy

向IDP请求身份认证。

如果需要的话,SAMLRequest还可以使用SigningKey进行签名。

4. SAMLResponse

IDP接收到SP的SAMLRequest后,进行用户身份认证,生成主会话,然后返回一个XHTML表单:

  <form method="post" action="https://sp.example.com/SAML2/SSO/POST" ...>
    <input type="hidden" name="SAMLResponse" value="response" />
    ...
    <input type="submit" value="Submit" />
  </form>

其中SAMLResponse的值是Base64编码以后的samlp:Response元素,示例如下:

 <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"
            Recipient="https://sp.example.com/SAML2/SSO/POST"
            NotOnOrAfter="2004-12-05T09:27:05Z"/>
        </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>

主要元素信息为:

标签

说明

samlp:Response下的IssueInstant

消息签发时间。

samlp:Response下的Destination

消息发送目的地,即请求身份认证的SP地址。

saml:Issuer

消息签发者。

saml:Assertion

SAML断言信息。

saml:Subject

主体身份信息。

saml:SubjectConfirmationData

主体身份确认信息。

saml:Conditions

条件信息,主体身份信息在这个条件下有效。

saml:AuthnStatement

SAML认证状态。

一般情况下IDP会用自己的私钥对SAMLResponse进行签名,SP接收到SAMLResponse以后,先Base64解码得到samlp:Response元素,然后用公钥检查签名,验证完以后提取主体身份信息,找到对应的子账户信息,生成子会话。SAMLResponse中重要的是Assertion部分, 包含有用户的Subject 身份信息。 默认一般用IDP的私钥对整个SAMLResponse 签名, 也可以是对Assertion 签名, 或是二者兼而有之, 取决于IDP和SP的协商。

5. SAMLBinding

SAML协议中一共规定了如下几种Binding方式:

  • SAML SOAP Binding

  • Reverse SOAP (PAOS) Binding

  • HTTP Redirect Binding

  • HTTP POST Binding

  • HTTP Artifact Binding

  • SAML URI Binding

不同的Binding方式使用不同的通信方式和消息体,使用最多的是HTTP Redirect Binding和HTTP POST Binding方式,其次是HTTP Artifact Binding。常用方式是SP使用HTTP Redirect Binding通过浏览器将SAMLRequest转发到IDP的SSO地址,IDP使用HTTP POST Binding方式将用SAMLResponse返回到SP的ACS地址。

6. 如何配置

IDaaS平台支持基于标准SAML协议的SSO,并提供来一系列的应用模版来方便配置,这里以阿里云RAM为例演示如何配置。

6.1. 获取SP的元数据信息

SP会提供自己的元数据信息,以阿里云RAM为例,登录控制台后找到元数据URL。

image.png

浏览器访问该URL得到元数据信息,显示如下:

image.png

将上述内容可以导出, 放在下一步使用。

6.2. IDaaS中配置SP的元数据信息

6.2.1. 添加SP应用

准备好后, 接下来, 在IDaaS 中添加一个RAM应用。 以IT管理员账号登录云盾IDaaS管理平台,具体操作请参考 IT管理员指南-登录 。 点击左侧导航栏 应用 > **添加应用 **在右侧选择一个SAML应用,点击添加应用。IDaaS支持多种SAML应用,这里以添加阿里云RAM-用户SSO为例进行展示。

image.png

点击添加SigningKey按钮,输入名称等信息,系统会据此生成应用的证书,私钥保留在IDP,公钥导出到SP, 用于IDP和SP通信的签名验签。

image.png

如果没有现成的证书可以选择, 则填写以下信息生成一个,其中的名称信息最好是和这个应用比如RAM关联的, 方便将来识别。

image.png

无论是选择已有的还是刚添加的,找到对应的SigningKey,选择它。

image.png

接下来要填写更多的应用信息,名称等信息可以自定义,EntityId、ACS URL等信息从步骤1中的到的SP的元数据中复制过来,需要填写的主要信息如下:

参数名称

说明

应用名称

所添加应用的名称,可以为任意值,但最好和应用相关。

应用类型

引用的类型,只有选中的应用类型才会在用户对应客户端中显示。

IDaaS EntityId

在IDaaS中设置的认证参数,需要将此参数配置到SP中,在IDaaS导出的 metadata 里可以获取,例如 https://signin.aliyun.com/117xxxxxxxxxxx63/saml/SSO。

SP Entity ID

在SP中设置的Entity ID,需要复制到IDaaS的配置中, 可以在RAM的metadata中获取, 例如https://signin.aliyun.com/117yyyyyyyyyyy63/saml/SSO。

SP ACS URL(SSO Location)

单点登录地址,这里以阿里云RAM为例:https://signin.aliyun.com/saml/SSO。

NameldFormat

名称标识格式类型,这里以阿里云RAM为例,选择urn:oasis:names:tc:SAML:2.0:nameid-format:persistent。

image.png

填写完成后提交保存, 如果应用是禁用状态, 可以继续修改重新提交。

6.2.2. 启用应用并且授权

应用配置好以后需要先启用应用,并且将服务授权给一个账户,点击左侧导航栏 应用 > **应用列表 **启用该应用并授权给账户。

image.png

IDaaS支持多种方式进行授权,这里以按应用授权账户为例。

image.png

保存后, 这个用户登录就可以看到这个应用了。

6.3. SP中配置IDaaS的元数据信息

6.3.1. 获取IDaaS的元数据信息

以IT管理员账号登录云盾IDaaS管理平台,点击左侧导航栏 应用 > 应用列表 选择刚才添加的应用,点击查看详情,如下图:

image.png

点击导出SAML元配置文件,将IDaaS的元数据文件保存到本地电脑。

image.png

IDaaS元配置文件示例如下:

<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://signin.aliyun.com/117xxxxxxxxxxx63/saml/SSO">
<md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>TIIC4jCCAcqgAwIBAgIIDmXMktHMYX8wDQYJKoZIhvcNAQEFBQAwMTELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAkJKMRUwEwYDVQQDDAzor5XnlKjlhazlj7gwHhcNMjAxMjA3MDMwNTU3WhcNMjExMjA3MDMwNTU3WjAxMQswCQYDVQQGEwJDTjELMAkGA1UECBMCQkoxFTATBgNVBAMMDOivleeUqOWFrOWPuDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALiuwcn+sbMaVRT2Byb3GzBV1P0eOoK326fQS9rdeaGaIykSMqCMMKOZ+/QfdMWh+9Fr59A5pIEbCN7aP3P+cV1ClqhfKD4DTbsmGikSiUYgYf4tWztZx9NFWyuoucm8LOKKpKlPbjUyLudzLlQGOCrX/4Be0md4mIVZMK96J41jRuJXUTxFepE0cTEi15SXbEsXrnJ1wueFylNKl9JerbCJ1EDayktAYvkMrmn2d2R2etiVR4Una9pBqtPvCElPKCNesWAE/3AcWTgSj+u8ocnTgnknIfVO65QRxaNrDAyTOpkquXFshs+DtlILEdk2p9UUxkUCNySbIIM/gVgL0TkCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAeDdH7BYcalDYfpNKvJrHA9rKZ2vBTi4uy2WoXclE0EdzBGUC41oPL5g3ictNA+4S8tnCkzl8aQr79tjUmcL/0Uzv4sdOggwglmkgw3kek9Yq44i/ycMN8HVeF/vtyVxhlvqBeXU2P5n6jFqatG+VkeVGyiJQHwuP1UHokXWwyukcjr35CQQX5WALFNJ+F68ICKT9Ulqb5GtQgrd1JoRQB1Eb//IjxlZJAvZ6CxLnVCgVUSOI4xYEb8ATZPbzLIMIyXN4U6r6VxvBJuW/eMcqogYSYssbngSgpHmZFV9+MrDSjJLLtsVRuzmF+cBisojvo53z3EiNu/c4FGlUuKozPA==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>TIIC4jCCAcqgAwIBAgIIDmXMktHMYX8wDQYJKoZIhvcNAQEFBQAwMTELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAkJKMRUwEwYDVQQDDAzor5XnlKjlhazlj7gwHhcNMjAxMjA3MDMwNTU3WhcNMjExMjA3MDMwNTU3WjAxMQswCQYDVQQGEwJDTjELMAkGA1UECBMCQkoxFTATBgNVBAMMDOivleeUqOWFrOWPuDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALiuwcn+sbMaVRT2Byb3GzBV1P0eOoK326fQS9rdeaGaIykSMqCMMKOZ+/QfdMWh+9Fr59A5pIEbCN7aP3P+cV1ClqhfKD4DTbsmGikSiUYgYf4tWztZx9NFWyuoucm8LOKKpKlPbjUyLudzLlQGOCrX/4Be0md4mIVZMK96J41jRuJXUTxFepE0cTEi15SXbEsXrnJ1wueFylNKl9JerbCJ1EDayktAYvkMrmn2d2R2etiVR4Una9pBqtPvCElPKCNesWAE/3AcWTgSj+u8ocnTgnknIfVO65QRxaNrDAyTOpkquXFshs+DtlILEdk2p9UUxkUCNySbIIM/gVgL0TkCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAeDdH7BYcalDYfpNKvJrHA9rKZ2vBTi4uy2WoXclE0EdzBGUC41oPL5g3ictNA+4S8tnCkzl8aQr79tjUmcL/0Uzv4sdOggwglmkgw3kek9Yq44i/ycMN8HVeF/vtyVxhlvqBeXU2P5n6jFqatG+VkeVGyiJQHwuP1UHokXWwyukcjr35CQQX5WALFNJ+F68ICKT9Ulqb5GtQgrd1JoRQB1Eb//IjxlZJAvZ6CxLnVCgVUSOI4xYEb8ATZPbzLIMIyXN4U6r6VxvBJuW/eMcqogYSYssbngSgpHmZFV9+MrDSjJLLtsVRuzmF+cBisojvo53z3EiNu/c4FGlUuKozPA==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://lidcfkpjfb.login.aliyunidaas.com/enduser/api/application/plugin_aliyun/idaas-cn-hangzhou-vr533mky3c3plugin_aliyun/sp_sso"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://lidcfkpjfb.login.aliyunidaas.com/enduser/api/application/plugin_aliyun/idaas-cn-hangzhou-vr533mky3c3plugin_aliyun/sp_sso_post"/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>

6.3.2. SP中配置元数据信息

不同的SP配置IDP的元数据方式不同,有的需要填入参数,有的可以直接上传元数据文件。以阿里云RAM为例,在阿里云RAM选择开启SSO功能,并且上传刚刚下载的元配置文件,完成SP中的IDP元数据信息配置。

image.png

6.4. 功能演示

6.4.1. IDP发起SSO

配置完成后, 就可以检查结果了。 授权用户登录IDaaS,点击左侧导航栏 **主导航 **> **首页 **在我的应用中点击该应用进行单点登录,点击应用的图标进行单点登录。

image.png

选择子账户demo进行单点登录。

image.png

成功登录阿里云RAM控制台,然后就可以看到阿里云作为SP提供的资源了。

image.png

如果账号配置错误或者选择的登录账号不是阿里云RAM中的账户,则会提示账户不存在。

image.png

6.4.2. SP发起SSO

同样, 正确配置后, 也支持SP发起, 首先找到阿里云RAM子账户登录地址。

image.png

贴到浏览器跳转后, 登录界面上可以看到“主账号登录”和“使用企业账号登录”两种选择。主账号登录是使用阿里云RAM自己的账号和密码进行登录,点击使用企业账号登录,则开始进行IDaaS的SSO过程。

image.png

浏览器会自动跳转到IDP的登录界面,登录IDaaS授权账号,例如zhangsan,然后IDaaS认证完成以后,找到对应的子账号,生成SAMLResponse, 就会跳转到阿里云RAM控制台。

自此, IDP发起和SP发起全部工作正常!

7. 常见QA

7.1. 代码中如何解析SAMLRequest

SP发起SSO的时候会生成SAMLRequest,SAMLRequest是Base64编码后的内容,我们需要解析以后才能得到需要的内容,如下代码可以解析SAMLRequest,然后就可以拿到AuthnRequest进行认证。

import java.io.*;
import org.opensaml.xml.util.Base64;
import java.util.zip.InflaterInputStream;
import java.util.zip.Inflater;
public class SamlRequestTest {
    public static void main(String[] args) throws Exception {
        // 接收到的原始SAMLRequest
        String samlRequest = "fZJNT%2BMwEIbv%2Bysi3%2FNhd9umVhPUXYQWiRUVCRy4IMedFIMzzmacavvvCQll4bAcfLD0fnjm8frsb2ODA3RkHGaMRwkLALXbGdxn7La8CFN2ln9bk2qsaOWm9494A396IB9siKDzg%2B%2BnQ%2Bob6AroDkbD7c1Vxh69b0nGMZk9GoyUNcceI%2B2a%2BDUqLoprFpwPKQaVH6tPBmyttmiPhyqybv9uNTulaPQD7vqhOFatGU5rjR4T4tb2g%2FxhksejPtQYVmCehmHC2h3h%2BETPz%2B3yk5LH1D4QORZcuE7DOGHGamUJWHB5njElaljCTOxTriuuVlzVS6iTNIVK8F01iGiriMwB%2FtmIerhE8gp9xkQikpCLMElLzuV8JvkqWqTf71mw7Zx32tkfBqeF9x1Kp8iQRNUASa9lsfl9JUWUyGoSkfxVlttwe12ULLg7gROv4AaUSHJC9XVW%2B1bM8omsHF%2FcfUz4OkCd2LP8%2F6R5ukgWq8V8NpsnKyEW7%2BjX8cfW%2FO36%2BXvlLw%3D%3D&RelayState=https%3A%2F%2Fhomenew.console.aliyun.com%2Fhome%2Fscene%2FOperation";
        // base64解码
        byte[] decodedBytes = Base64.decode(java.net.URLDecoder.decode(samlRequest, "utf-8"));
        // 获取输入流
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decodedBytes);
        InflaterInputStream inflaterInputStream = new InflaterInputStream(byteArrayInputStream, new Inflater(true));
        byte[] buffer = new byte[decodedBytes.length];
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        // 信息写到输出流
        for (int i = 0; i != -1; i = inflaterInputStream.read(buffer)) {
            byteArrayOutputStream.write(buffer, 0, i);
        }
        String result = new String(byteArrayOutputStream.toByteArray(), "UTF-8");
        // 输出解析后结果
        System.out.println(result);
    }
}

解析后的结果为

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest AssertionConsumerServiceURL="https://signin.aliyun.com/saml/SSO" Destination="https://nplclnlyvb.login.aliyunidaas.com/enduser/api/application/plugin_aliyun/idaas-cn-beijing-foyeyjskkp7plugin_aliyun1/sp_sso" ForceAuthn="false" ID="a2fe7e32g81cb1a91af7ef088eb21db" IsPassive="false" IssueInstant="2020-12-08T11:53:19.684Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://signin.aliyun.com/1860696533509226/saml/SSO</saml2:Issuer></saml2p:AuthnRequest>