SAML 模板使用指南

一、概述

IDaaS平台支持基于标准SAML协议的SSO(Single Sign On 单点登录),IDaaS作为SAML协议中的IDP(Identity Provider身份提供方)角色,提供用户的身份认证服务,用户可以登录一次就直接使用多个SP(Service Provider 业务提供方)的服务,免去了每个应用都要登录的烦恼。

二、IDP发起和SP发起

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

作为一种流行的SSO协议, SAML同时支持IDP发起和SP发起, 也就是可以在登录门户后,跳转到任意一个应用, 也可以从一个应用发起,跳转到IDP, 登录认证后,再跳转回这个应用, 继续SSO。 二者都是SSO, 流程的前半部分参数不同, 后半部分是很相似的。

2.1、SAML的流程

2.1.1、SP发起SSO

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

具体流程如下:

2.1.1.1、用户请求目标资源

用户向SP请求目标资源,例如目标资源为:

https://sp.example.com/myresource

SP会进行安全检查,如果SP已经存在有效的IDP安全会话上下文,则认为已经登录过, 跳过步骤2~8。

2.1.1.2、重定向到IDP的SSO服务

SP会生成SAMLRequest,同时会把SP当前发起的URL生成一个随机数opaque, 临时存放, 同时把它作为RelayState,然后使用标准的HTTP 302重定向redirect到IDP的SSO服务,例如:

302 Redirect

Location: http://idp4/enduser/api/application/plugin_saml//sp_sso?SAMLRequest=xxx&RelayState=opaque

RelayState是SP的发起URL的不透明引用,SAMLRequest是Base64编码以后的<samlp:AuthnRequest>元素,<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>

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

2.1.1.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

2.1.1.4、IDP解析SAML请求

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

2.1.1.5、认证用户

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

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

IDP认证用户身份以后会返回SAMLResponse响应,响应中包含如下表单:

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

表单中的RelayState参数值就是步骤2中生成的RelayState,IDP会将其原封不动的返回。表单中的SAMLResponse是Base64编码以后的<samlp:Response>元素,<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>

这里重要的是Assertion部分, 包含有用户的Subject 身份信息。 默认一般用IDP的私钥对整个SAMLResponse 签名, 也可以是对Assertion 签名, 或是二者兼而有之, 取决于IDP和SP的协商。

2.1.1.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

2.1.1.8、SP解析验证SAML响应

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

2.1.1.9、用户获取目标资源

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

2.1.2、IDP发起SSO

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

具体的流程如下:

2.1.2.1、用户访问IDP

用户打开IDP的登录页面。

2.1.2.2、用户登录IDP

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

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

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

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

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

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

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

2.1.2.6、SP解析验证SAML响应

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

注: 可以看到, 这一步和SP发起中的第8步非常类似, 包括下一步。

2.1.2.7、用户获取目标资源

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

2.1.2.8、显示目标资源

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

2.2、SAML的Metadata

SAML协议中规定,IDP或SP的配置信息通过元数据(Metadata)信息实现,配置过程只要交换IDP和SP的元数据配置信息就可以快速实现SSO配置。

2.2.1、IDP的Metadata

IDP的Metada是<md:EntityDescriptor>元素,示例如下:

  <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>

主要元素信息为:

标签

说明

entityID

IDP的唯一标识。

validUtil

元数据的过期时间。

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提供的断言的属性。

2.2.2、SP的Metadata

SP的Metada是<md:EntityDescriptor>元素,示例如下:

  <md:EntityDescriptor entityID="https://sp.example.com/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:SPSSODescriptor element (see below) -->
    <md:Organization>
      <md:OrganizationName xml:lang="en">Some Commercial Vendor of California</md:OrganizationName>
      <md:OrganizationDisplayName xml:lang="en">Some Commercial Vendor</md:OrganizationDisplayName>
      <md:OrganizationURL xml:lang="en">https://www.example.com/</md:OrganizationURL>
    </md:Organization>
    <md:ContactPerson contactType="technical">
      <md:SurName>SAML Technical Support</md:SurName>
      <md:EmailAddress>mailto:saml-support@example.com</md:EmailAddress>
    </md:ContactPerson>
  </md:EntityDescriptor>

主要元素信息为:

标签

说明

entityID

SP的唯一标识。

validUtil

元数据的过期时间。

ds:Signature

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

md:Organization

组织信息。

md:ContactPerson

联系人信息。

SP的ACS相关Metadata是<md:SPSSODescriptor>元素,示例如下:

  <md:SPSSODescriptor
    protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <md:KeyDescriptor use="signing">
      <ds:KeyInfo>...</ds:KeyInfo>
    </md:KeyDescriptor>
    <md:KeyDescriptor use="encryption">
      <ds:KeyInfo>...</ds:KeyInfo>
    </md:KeyDescriptor>
    <md:ArtifactResolutionService isDefault="true" index="0"
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
      Location="https://sp.example.com/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:AssertionConsumerService isDefault="true" index="0"
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
      Location="https://sp.example.com/SAML2/SSO/POST"/>
    <md:AssertionConsumerService index="1"
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
      Location="https://sp.example.com/SAML2/Artifact"/>
    <md:AttributeConsumingService isDefault="true" index="1">
      <md:ServiceName xml:lang="en">Service Provider Portal</md:ServiceName>
      <md:RequestedAttribute
        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">
      </md:RequestedAttribute>
    </md:AttributeConsumingService>
  </md:SPSSODescriptor>

标签

说明

<md:KeyDescriptor use="signing">

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

<md:KeyDescriptor use="encryption">

SP公共SAML加密密钥。

<md:AssertionConsumerService>下的index

<samlp:AuthnRequest>元素中的AssertionConsumerServiceIndex属性的值。

<md:AssertionConsumerService>下的Binding

SAML的绑定信息。

<md:AttributeConsumingService>

IDP用来构造一个<saml:AttributeStatement>元素,该元素与Web浏览器SSO一起推送到SP。

<md:AttributeConsumingService>下的index

SP在SSO时生成<samlp:AuthnRequest>元素中AttributeConsumingServiceIndex属性的值。

三、IDaaS中配置SAML应用示例

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

3.1、获取SP的元数据信息

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

image

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

image.png

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

3.2、IDaaS中配置SP的元数据信息

3.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

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

3.2.2、启用应用并且授权

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

image.png

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

image.png

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

3.2.3、IDP新建子账户(非必须步骤)

一个系统要SSO到另外一个系统,需要使用对方能够识别的子账号进行认证,往往登录到IDP的主账户和应用SP的子账户是不一样的,可以使用账号同步(两套系统中的账号信息相同)或者新建子账户进行账号映射的方法。账号映射是指给IDP的账户建立一个SP中已经存在的账户作为子账户,身份认证的时候通过子账户进行认证。例如SP系统中有个账户“demo”,我们想用IDP系统中的“zhangsan”账号SSO到SP,则需要给账号“zhangsan”新建一个对应的子账户“demo”。这里以阿里云RAM演示新建子账户的功能,如下图,阿里云RAM中有账户demo@117yyyyyyyyyyy63.onaliyun.com

image.png

IDaaS中新建子账户有两种方式,操作如下:

3.2.3.1、授权账号新建子账户

登录授权账户,点击左侧导航栏 主导航 > 应用子账户 添加应用子账户功能中提交新建子账户申请。由于上一步阿里云RAM中的账户是demo@117yyyyyyyyyyy63.onaliyun.com,所以这里子账户的名称应该填demo。IDaaS在SSO的时候,会将子账户(demo)和步骤3.2.1中配置的阿里云个人域名(117yyyyyyyyyyy63.onaliyun.com)进行拼接映射到阿里云RAM的账户。

image.png

登录管理员账户,点击左侧导航栏 其它管理 > 审批中心 审核通过该应用子账户的添加。

image.png

image.png

3.2.3.2、管理员新建子账户

管理员新建子账户不需要审核过程,具体操作为:

登录管理员账户,点击左侧导航栏 应用 > 应用列表 找到添加的应用,点击详情中的查看应用子账户。

image.png

点击添加账户关联,添加子账户。

image.png

输入授权账户(主账户)和子账户,点击保存完成子账户添加。

image.png

3.3、SP中配置IDaaS的元数据信息

3.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>

3.3.2、SP中配置元数据信息

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

image.png

3.4、功能演示

3.4.1、IDP发起SSO

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

image.png

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

image.png

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

image.png

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

image.png

3.4.2、SP发起SSO

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

image.png

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

image.png

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

image.png

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

四、FAQ

4.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>