共计 6967 个字符,预计需要花费 18 分钟才能阅读完成。
简介
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 Redirect
Location: 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.1
Host: 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 的博客
欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!