简介

SAML的全称是Security Assertion Markup Language, 是由OASIS制订的一套基于XML格局的凋谢规范,用在身份提供者(IdP)和服务提供者 (SP)之间替换身份验证和受权数据。

SAML的一个十分重要的利用就是基于Web的单点登录(SSO)。

接下来咱们一起来看看SAML是怎么工作的。

SAML的形成

在SAML协定中定义了三个角色,别离是principal:代表主体通常示意人类用户。identity provider (IdP)身份提供者和service provider (SP)服务提供者。

IdP的作用就是进行身份认证,并且将用户的认证信息和受权信息传递给服务提供者。

SP的作用就是进行用户认证信息的验证,并且受权用户拜访指定的资源信息。

SAML的劣势

为什么要应用SAML呢?

第一能够晋升用户体验,如果零碎应用SAML,那么能够在登录一次的状况下,拜访多个不同的零碎服务。这实际上也是SSO的劣势,用户不须要别离记住多个零碎的用户名和明码,只用一个就够了。

第二能够晋升零碎的安全性,应用SAML,咱们只须要向IdP提供用户名明码即可,

第三用户的认证信息不须要保留在所有的资源服务器下面,只须要在在IdP中存储一份就够了。

SAML是怎么工作的

接下来,咱们通过一个用SAML进行SSO认证的流程图,来剖析一下SAML是怎么工作的。

依据申请形式有redirect和post的不同,应用SAML来进行SSO认证有通常有三种形式,咱们一一道来。

SP redirect request; IdP POST response

上图中User Agent就是web浏览器,咱们看一下如果用户想申请Service Provider的资源的时候,SAML协定是怎么解决的。

  1. 用户通过User Agent申请Service Provider,比方:
http://sp.flydean.com/myresource

SP将会对该资源进行相应的安全检查,如果发现曾经有一个无效的平安上下文的话,SP将会跳过2-7步,间接进入第8步。

  1. 如果在第一步的时候,SP并没有找到相应的无效平安上下文的话,则会生成对应的SAMLRequest,并将User Agent重定向到IdP:
302 RedirectLocation: https://idp.flydean.com/SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token

RelayState是SP保护的一个状态信息,次要用来避免CSRF攻打。

其中这个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="aaf23196-1773-2113-474a-fe114412ab72"    Version="2.0"    IssueInstant="2020-09-05T09:21:59Z"    AssertionConsumerServiceIndex="0"    AttributeConsumingServiceIndex="0">    <saml:Issuer>https://sp.flydean.com/SAML2</saml:Issuer>    <samlp:NameIDPolicy      AllowCreate="true"      Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>  </samlp:AuthnRequest>

为了平安起见,SAMLRequest还能够应用SP提供的签名key来进行签名。

  1. User agent将会发送一个get申请到IdP的SSO server :
GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token HTTP/1.1Host: idp.flydean.com

IdP收到这个AuthnRequest申请之后,将会进行平安验证,如果是非法的AuthnRequest,那么将会展现登录界面。

  1. 用户能够输出用户名明码进行登录。登录胜利之后,IdP将会返回一个XHTML form:
  <form method="post" action="https://sp.flydean.com/SAML2/SSO/POST" ...>    <input type="hidden" name="SAMLResponse" value="response" />    <input type="hidden" name="RelayState" value="token" />    ...    <input type="submit" value="Submit" />  </form>

这个form中蕴含了SAMLResponse信息,SAMLResponse中蕴含了用户相干的信息。

同样的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="2020-09-05T09:22:05Z"    Destination="https://sp.flydean.com/SAML2/SSO/POST">    <saml:Issuer>https://idp.flydean.com/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="2020-09-05T09:22:05Z">      <saml:Issuer>https://idp.flydean.com/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.flydean.com/SAML2/SSO/POST"            NotOnOrAfter="2020-09-05T09:27:05Z"/>        </saml:SubjectConfirmation>      </saml:Subject>      <saml:Conditions        NotBefore="2020-09-05T09:17:05Z"        NotOnOrAfter="2020-09-05T09:27:05Z">        <saml:AudienceRestriction>          <saml:Audience>https://sp.flydean.com/SAML2</saml:Audience>        </saml:AudienceRestriction>      </saml:Conditions>      <saml:AuthnStatement        AuthnInstant="2020-09-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中蕴含有saml:Assertion信息。

  1. user agent 收到XHTML form之后将会提交该form给SP。
  2. SP中的assertion consumer service将会解决这个申请,创立相干的平安上下文,并将user agent重定向到要拜访的资源页面。
  3. user agent再次申请SP资源。
  4. 因为平安上下文曾经创立结束,SP能够间接返回相应的资源,不必再次到IdP进行认证。

咱们能够看到下面的所有的信息替换都是由前端浏览器来实现的,在SP和IdP之间不存在间接的通信。

这种全副由前端来实现信息替换的形式益处就是协定流非常简单,所有的音讯都是简略的GET或者POST申请。

如果为了进步安全性,也能够应用援用音讯。也就是说IdP返回的不是间接的SAML assertion,而是一个SAML assertion的援用。SP收到这个援用之后,能够从后盾再去查问实在的SAML assertion,从而进步了安全性。

SP POST Request; IdP POST Response

刚刚讲的是SP redirect Request,这里咱们看一下SP POST request是怎么做的:

和第一种形式的不同之处在于第二步和第三步。

第二步:SP不再进行redirect了,而是返回一个XHTML form给User agent:

  <form method="post" action="https://idp.flydean.com/SAML2/SSO/POST" ...>    <input type="hidden" name="SAMLRequest" value="request" />    <input type="hidden" name="RelayState" value="token" />    ...    <input type="submit" value="Submit" />  </form>

第三步:拿到第二步的XHTML form之后,User agent将该form post到IdP SSO server。

从第四步开始就和第一种形式是一样的了。

SP redirect artifact; IdP redirect artifact

第三种形式,SP和IdP都用的是redirect,然而redirect的内容都是artifact。

之前咱们讲了SAML message能够以值的形式也能够以援用的形式来进行传递。

而这种以援用的传递形式就是artifact。

收到artifact的receiver会发送一个<samlp:ArtifactResolve> 给issuer,从而取得真正的message。

上面是一个向IdP申请message的例子:

  <samlp:ArtifactResolve    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"    ID="_cce4ee769ed970b501d680f697989d14"    Version="2.0"    IssueInstant="2020-09-05T09:21:58Z">    <saml:Issuer>https://idp.flydean.com/SAML2</saml:Issuer>    <!-- an ArtifactResolve message SHOULD be signed -->    <ds:Signature      xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>    <samlp:Artifact>AAQAAMh48/1oXIM+sDo7Dh2qMp1HM4IF5DaRNmDj6RdUmllwn9jJHyEgIi8=</samlp:Artifact>  </samlp:ArtifactResolve>

相应的server会返回一个蕴含<samlp:AuthnRequest>的<samlp:ArtifactResponse>:

<samlp:ArtifactResponse    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"    ID="_d84a49e5958803dedcff4c984c2b0d95"    InResponseTo="_cce4ee769ed970b501d680f697989d14"    Version="2.0"    IssueInstant="2020-09-05T09:21:59Z">    <!-- an ArtifactResponse message SHOULD be signed -->    <ds:Signature      xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>    <samlp:Status>      <samlp:StatusCode        Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>    </samlp:Status>    <samlp:AuthnRequest      xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"      xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"      ID="_306f8ec5b618f361c70b6ffb1480eade"      Version="2.0"      IssueInstant="2020-09-05T09:21:59Z"      Destination="https://idp.flydean.com/SAML2/SSO/Artifact"      ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"      AssertionConsumerServiceURL="https://sp.flydean.com/SAML2/SSO/Artifact">      <saml:Issuer>https://sp.flydean.com/SAML2</saml:Issuer>      <samlp:NameIDPolicy        AllowCreate="false"        Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>    </samlp:AuthnRequest>  </samlp:ArtifactResponse>

看下第三种形式的流程图:

能够看到这种形式和后面两种形式的区别就是多了一个申请实在message的步骤。

以第三,四,五步为例:

第三步user agent申请IdP的SSO server:

 https://idp.example.org/SAML2/SSO/Artifact?SAMLart=artifact_1&RelayState=token

留神这里申请的参数变成了SAMLart。

第四步,IdP须要发送一个<samlp:ArtifactResolve>到SP来申请真正的samlp:AuthnRequest。

第五步,SP返回一个<samlp:ArtifactResponse> 蕴含samlp:AuthnRequest。

总结

SAML协定和它的根本用法就是下面这样。上面的文章咱们会举一个具体的例子,来解说如何利用SAML协定。

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/saml-startup/

本文起源:flydean的博客

欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!