简介
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协定是怎么解决的。
- 用户通过User Agent申请Service Provider,比方:
http://sp.flydean.com/myresource
SP将会对该资源进行相应的安全检查,如果发现曾经有一个无效的平安上下文的话,SP将会跳过2-7步,间接进入第8步。
- 如果在第一步的时候,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来进行签名。
- User agent将会发送一个get申请到IdP的SSO server :
GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token HTTP/1.1Host: idp.flydean.com
IdP收到这个AuthnRequest申请之后,将会进行平安验证,如果是非法的AuthnRequest,那么将会展现登录界面。
- 用户能够输出用户名明码进行登录。登录胜利之后,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信息。
- user agent 收到XHTML form之后将会提交该form给SP。
- SP中的assertion consumer service将会解决这个申请,创立相干的平安上下文,并将user agent重定向到要拜访的资源页面。
- user agent再次申请SP资源。
- 因为平安上下文曾经创立结束,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的博客
欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!