我眼中的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

相關文章
相關標籤/搜索