我眼中的SAML (Security Assertion Markup Language)

提到SAML (Security Assertion Markup Language), 不少人都会联想到单点登陆SSO。那么Saml究竟是什么,它跟sso到底有什么联系?这里给你们分享一下我在读完了saml差很少所有规范以后的一些心得。但愿给saml入门者一些帮助。 我并不想详细介绍每一个xml节点怎么写。你们能够参考标准规范。 看了这篇随笔,相信若是万一哪天你要作saml, 你也不会惧怕了。 javascript

Saml是什么

首先,saml是一种xml格式的语言。 翻译过来大概叫 安全断言(标记)语言。  这里有两个点: 第一是“安全”, 第二是“断言(assertion)”。  用人话翻译saml就是 用安全的方式表达断言一种语言。 php

先看它的核心概念“断言”。  断言是什么?  就是作出判断的语言。好比一句话: 小明是超级管理员。 这就是一个断言。再来一个例子:小红没有权限读取根目录。这也是一个断言。  这种“作出判断的语句”咱们在不少场合都须要用到。  好比你在网上尝试登录一个服务的时候, 这个服务须要知道你是否是合法的用户。 这个时候若是你能提供一个“安全,可靠,可信任”的断言:“小明有权登录XX服务”, 那么这个服务就知道你合法了, 因而就能为你提供服务了。  这个例子比较抽象,但基本上能表达断言在实际用例中的做用了。 实际上saml的大部分用例就在于证实你是谁,你拥有什么权限等等了。 saml中大部分主要内容也都是相似于:你是谁, 你有什么。。等等这些简单的语句。 详细内容后面会介绍。html

接下来第二个概念就是“安全”了。  你能提供一个断言, 别人能不能假冒你提供一个断言从而骗取服务端的信任呢? 另外服务端为何会信任你给的断言呢? 这就涉及到安全的问题了。为了防止断言被假冒,篡改。saml中加入了安全措施。 固然现今能抵御假冒,篡改,重放攻击的利器就是公钥-私钥系统了。  经过给断言加上签名和加密,再结合数字证书系统就确保了saml不受攻击。java

 

在不少sso的场合中, 都支持saml登录。 这就是saml最多的一个应用场景。  做用至关于你们熟知的OpenID,和Oauth等等。程序员

 

好了,说完了大致的概念,就来程序员最喜欢的硬菜了。  windows

 

从技术的角度看saml。

saml迄今为止有两个普遍应用的标准, Saml 1.1 和Saml 2.0浏览器

为了尝鲜,你们先看两个saml的例子, 看个样子便可,不用阅读内容,给你1分钟, 看完赶忙回来接着看这里哦:安全

http://en.wikipedia.org/wiki/SAML_1.1ide

http://en.wikipedia.org/wiki/SAML_2.0post

 

恩,很好, 你已经知道saml大概长什么样了。   saml1.1和saml2.0 是同一个标准的两个版本, 他们在逻辑概念或者对象结构上大体至关, 只是在一些细节上有所差别。 这两个版本不兼容。 另外1.1比2.0要简单许多。  因此下面在讲逻辑结构的时候通常不区分这两个版本,除非特别说明的地方。

我猜你必定喜欢下面这种图:

这张图取自:  https://www.oasis-open.org/committees/download.php/11511/sstc-saml-tech-overview-2.0-draft-03.pdf

这是saml2.0的一个极其简单的应用场景.  若是你不嫌烦的话,我来解释一下这个图:

图上共有三个角色, 1,SP, 服务提供者。 2, Idp,认证用户并生成断言。 3,就是用户你了, client。

首先, 你(client)是idp的注册用户, 它有你的用户名和密码,它能够认证你就是你。 其次, SP和Idp二者会被各自的域管理员设置为相互信任对方。而且双方都持有对方的公钥。这是配置好的。第三,有一天,你须要访问sp提供的某个服务,可是sp并不认识你,也没有你的用户名和密码所以不能认证你。 因而就发生了上图所示的8个步骤:

1. 你去访问sp的某个受保护资源,好比浏览器打开: http://www.apc.com/resource1.aspx.

2. sp发现你是新来的,没有认证信息。固然不能给你这个页面内容了。 他就会生成一个 saml的认证请求数据包(固然是saml格式的)。把这个请求放在一个html的form的一个隐藏的域中,把这个html form返回给你。 这个form后面有一句javascript自动提交这个form。 二而form的action地址就是 提早配置好的 idp上的一个地址。 

saml认证请求的数据包多是这个样子的:

==========

<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="2004-12-05T09:21:59"
    AssertionConsumerServiceIndex="0"
    AttributeConsumingServiceIndex="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>

==========

而返回的html from内容大概设这个样子的:它包含了上面的数据包做为其中一个hidden的值。

=============================

<form method="post" action="https://idp.example.org/SAML2/SSO/POST" ...>
    <input type="hidden" name="SAMLRequest" value="<samlp:AuthnRequest>.......... </samlp:authnreques>" />
    ... other input parameter....
    <input type="submit" value="Submit" />

</form>

<javascript>
document.form[0].submit();// 后面紧跟一句相似这样的提交代码.
</javascript>

=============================

这些代码一部分是复制过来的, 有些是我现写的, 你们领会意思便可,不要在乎那些细节。

 

3. 上面的form会被javascript自动提交到idp的某个地址。

4. idp也须要认证你, 因而返回给你一个认证的页面, 可能使用用户名密码认证,也可使用ntlm认证等等一切能够认证你的方式。 由于idp保存有你的用户名和密码。

5. 同上一步,也是认证你的一个过程。

6. idp在认证你以后。以为你合法, 因而就为你生成一些断言, 证实你是谁,你有什么权限等等。 并用本身的私钥签名。 而后包装成一个response格式,放在form里返回给你。

断言的格式大概以下:

=============

<saml:Assertion
   xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   ID="b07b804c-7c29-ea16-7300-4f3d6f7928ac"
   Version="2.0"
   IssueInstant="2004-12-05T09:22:05">
   <saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
   <ds:Signature
     xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>
   <saml:Subject>
..........
   </saml:Subject>
   <saml:Conditions
.........
   </saml:Conditions>
   <saml:AuthnStatement
     AuthnInstant="2004-12-05T09:22:00"
     SessionIndex="b07b804c-7c29-ea16-7300-4f3d6f7928ac">
     <saml:AuthnContext>
       <saml:AuthnContextClassRef>
         urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
      </saml:AuthnContextClassRef>
     </saml:AuthnContext>
   </saml:AuthnStatement>
   <saml:AttributeStatement>
     <saml:Attribute
       xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
       x500:Encoding="LDAP"
       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
         xsi:type="xs:string">member</saml:AttributeValue>
       <saml:AttributeValue
         xsi:type="xs:string">staff</saml:AttributeValue>
     </saml:Attribute>
   </saml:AttributeStatement>
 </saml:Assertion>

=============

其中authnstatement认证语句表示你认证成功了。subject表示你是谁。而attributestatement表示你有哪些属性。 还有一个受权语句上面例子中没有。

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:05"
    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:05">
      <saml:Issuer>https://idp.example.org/SAML2</saml:Issuer>
      <!-- a POSTed assertion MUST be signed -->
     ....................
    </saml:Assertion>
  </samlp:Response>

============================

正如上面第2步同样,它也会把response包装在一个form里面返回给你,并自动提交给 sp的某个地址。

===========

 <form method="post" action="https://sp.example.com/SAML2/SSO/POST" ...>
    <input type="hidden" name="SAMLResponse" value="<samlp:Response>.........</samlp:respons>" />
    <input type="hidden" name="RelayState" value="''token''" />
    ...
    <input type="submit" value="Submit" />
  </form>
<javascript>
document.form[0].submit();// 后面紧跟一句相似这样的提交代码.
</javascript>
 

===========

 

7. 因而就到了第7步, 这个form被javascript自动提交到sp了。 

8. sp读到form提交上来的 断言。 并经过idp的公钥验证了断言的签名。 因而信任了断言。 知道你是idp的合法用户了。 因此就最终给你返回了你最初请求的页面了。  http://www.apc.com/resource1.aspx.

 

好了一个最简单的saml用例就讲完了。 你能够看到其中几乎全部的步骤均可以自动完成,用户在第一步访问资源以后,就看到浏览器再自动跳转,本身不须要操做什么,几秒钟事后,资源就访问成功了。

 

到这里, 相信saml在你心目中的形象必定跟家立体了。  若是你还有兴趣就继续往下看吧.

上面是“远观”, 下面咱们走近。

先看saml标准的结构:

 

此图出自: https://www.oasis-open.org/committees/download.php/11511/sstc-saml-tech-overview-2.0-draft-03.pdf  

saml标准从内到外 能够分为上图的4个层次:

1. Assertion。 断言。 规定了断言的xml结构, 例如:

==============

<saml:Assertion>

..............

</saml:Assertion?

==============

它规定了,这个assertion节点到底该怎么写, 其实就是这个节点的schema。 按照这个规定写出来的assertion别人才能认识。

2. Protocols。协议。它规定了如何请求(samlrequest)和回复(samlresponse )saml消息,其中固然包含assertion的消息。好比:

===============

<samlp:AuthnRequest>

............

</samlp:AuthnRequest>

 

还有:

 <samlp:Response> 

..............

</samlp:Response>

 

===============

它规定了怎么发送这些请求消息,和回复消息的结构。 这样sp,idp之间才能通讯。

 

3. 绑定。  上面两点都是规定了静态结构。 具体这些消息怎么发送呢。 就是用什么协议来承载这些smal消息呢。就是绑定出马了。 最经常使用的就是http或者soap消息。  把上面的saml消息经过http或者soap消息来传输。 这样sp和idp就能通讯了。  saml1.1只支持 http的soap绑定。 而saml2.0支持更多的绑定。 有兴趣本身阅读标准。   这里须要强调的是, 你可能已经想到了,那就是这个绑定其实不重要。 只要saml消息自己是完整的可靠的,下层用什么协议传输不重要。  对。 saml标准规定的绑定只是一种标准实现。  saml的消息能够绑定到任何协议上, 只要sp和idp实现协商好就好了。  这里面应用最普遍的恐怕要算saml的wss绑定了。 用在微软的一系列产品里面。 包括sharepoint online的登录受权, windows azure登录,以及windows store的登录受权等等。  微软本身在ws-trust和ws-secure协议上传输了saml消息。  这恐怕是saml标准之外用的最多的绑定了。

4. Profile, 这个单词我实在不知道翻译成啥好,因此就写原文把。 我我的喜欢把它叫作一套配置,或者叫解决方案。 它规定了某些场景下一整套saml认证的细节和步骤。 好比, 它规定了比较著名的SSO方案。 就是如何用saml实现sso的一整套配置和详细步骤。  概念就是这样。  同上, 上面的绑定都不肯定,因此这个profile就更自由了。 你可使用任何本身定义的profile,只要大家本身协商好就好了。

 

恩好吧, 先到这吧。大致结构已经出来了。 后续我可能会再分享一下有趣或者有坑的地方。 欢迎你们访问个人我的独立博客交流学习: http://byNeil.com

附上saml协议标准地址:

https://www.oasis-open.org/committees/download.php/3406/oasis-sstc-saml-core-1.1.pdf

http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

相关文章
相关标签/搜索