相關(guān)閱讀SAML2.0入門指南, 此文中已經(jīng)介紹了SAML協(xié)議的基本信息媒怯,今天開始將會為大家詳解OpenSaml——SAML協(xié)議的一種開源實現(xiàn)岛琼。
What's OpenSAML
OpenSAML是一個便于使用SAML消息的依賴庫,其提供的主要功能包括:
- 創(chuàng)建SAML消息季研;
- 解析SAML對象并導出為XML格式剃盾;
- 簽名和加密坏逢;
- 對SAML消息進行編碼并傳輸。
目前OpenSAML庫提供Java和C++實現(xiàn)的版本妙黍,需要注意的是OpenSAML雖然多應(yīng)用用于SSO(單點登錄)的開發(fā)中悴侵,但是該庫本身不提供任何身份識別和授權(quán)的功能,其只是實現(xiàn)對于SAML消息的相關(guān)操作而已拭嫁。
SAML
SAML是一種XML框架用來交換安全信息可免,其中定義了按照安全規(guī)范所需要的通信的協(xié)議和格式。
SAML是一種中心化的認證機制做粤,其定義了兩種實體相互通信:
- Service Provider(SP): 向用戶提供正式商業(yè)服務(wù)的實體浇借,通常需要認證一個用戶的身份;
- Identity Provider(IDP): 提供用戶的身份鑒別怕品,確保用戶是其所聲明的身份妇垢;
SAML的重要用途:
- 單點登錄(SSO Single Sign-ON);
- 聯(lián)合認證(Federated Identity)肉康;
- 在其他架構(gòu)內(nèi)使用SAML闯估,比如WS-Security。
更多關(guān)于SAML的內(nèi)容吼和,請參看SAML2.0入門指南
SAML相關(guān)定義
1. 斷言(Assertions) 即信息
斷言是在SAML中用來描述認證的對象涨薪,其中包括一個用戶在什么時間、以什么方式被認證纹安,同時還可以包括一些擴展信息尤辱,比如用戶的Email地址和電話等等砂豌。
下面便是一個斷言的實例:
2. 協(xié)議(Protocol)即通信
協(xié)議規(guī)定如何執(zhí)行不同的行為。這些行為被細化成一些列的Request和Response對象光督,而在這些請求和相應(yīng)的對象中包含了行為所特別需要的信息阳距。比如,認證請求協(xié)議(AuthnRequest Protocol)就規(guī)定了一個SP如何請求去獲得一個被認證的與用戶结借。
<saml2p:AuthnRequest
AssertionConsumerServiceURL=http://localhost:8080/webprofile-refproject/sp/consumer
Destination="http://localhost:8080/webprofile-refproject/idp/singleSignOnService"
ID="_52c9839568ff2e5a10456dfefaad0555"
IssueInstant="2014-05-13T17:34:37.810Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTPArtifact"
Version="2.0">
<saml2:Issuer>
TestSP
</saml2:Issuer>
<saml2p:NameID
PolicyAllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
<saml2p:RequestedAuthnContext Comparison="minimum">
<saml2:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:Password
</saml2:AuthnContextClassRef>
</saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>
3. 綁定(Binding)即傳輸
綁定定義了SAML信息如何使用通信協(xié)議被傳輸?shù)目鹫1热纾琀TTP重定向綁定船老,即聲明SAML信息將通過HTTP重定向消息傳輸咖熟;再比如SAML SOAP綁定,聲明了通過SOAP來傳遞SAML消息柳畔。
配置(Profiles) 即綜合
配置定義了如何組織以上信息馍管,并且在一個更高的層次上描述斷言,協(xié)議和綁定如何被使用去解決一個具體情況薪韩。比如Web瀏覽器的SSO配置就描述了如何一個用戶使用瀏覽器被認證确沸。
元數(shù)據(jù)(MetaData)
SAML的元數(shù)據(jù)是配置數(shù)據(jù),其包含關(guān)于SAML通信各方的信息俘陷,比如通信另一方的ID罗捎、Web Service的IP地址、所支持的綁定類型以及通信中實用的密鑰等等拉盾。
OpenSaml中提供了metadata provider來幫助構(gòu)建和解讀元數(shù)據(jù)桨菜。
SAML通過Web瀏覽器實現(xiàn)的協(xié)議流程
通過HTTP協(xié)議綁定來實現(xiàn)SSO:
1. 用戶嘗試獲得權(quán)限
流程首先從一個非認證的用戶開始,該用戶嘗試從一個受保護的SP那里獲得訪問權(quán)限捉偏。某種方式的過濾器被設(shè)置在訪問路徑上來檢測用戶是否被授權(quán)(J2ee中servlet類就是一個很好地例子)倒得。這一部分其實并不是SAML協(xié)議里的內(nèi)容,但是卻決定了是否要被授權(quán)告私。
2. 用戶被重定向到IDP
當訪問路徑上被設(shè)置的過濾器發(fā)現(xiàn)用戶并非是被認證的屎暇,將會自動把用戶從定向到IDP,以求驗證用戶的身份驻粟。
3. 用戶被認證
在這一步里根悼,用戶被認證。注意這里并沒任何涉及到SP的交互蜀撑,在安全方式內(nèi)挤巡,IDP對于認證用戶有著全權(quán)責任。
4. 已認證的用戶被從定向回SP
當用戶被認證成功之后酷麦,用戶會攜帶著SAML產(chǎn)物(SAML artifact)被從定向回SP矿卑。這樣的SAML產(chǎn)物也可以說是認證信息的標識,因為認證信息中有敏感的信息不能直接通過瀏覽器傳輸沃饶,所以這里只是發(fā)送標識而已母廷。
5. 要求認證信息
當收到SAML產(chǎn)物之后轻黑,SP將其發(fā)送回IDP,IDP依據(jù)SAML產(chǎn)物找到認證信息琴昆,并通過SAML產(chǎn)物響應(yīng)(SAML Artifact Response)發(fā)送回SP
上面提到的SAML產(chǎn)物響應(yīng)(SAML Artifact Response) 中就包含SAML斷言氓鄙,它就是認證的證據(jù)。斷言中最重要的數(shù)據(jù)就該用戶什么時候以什么方式被認證的业舍。
OpenSAML 快速上手
說了這么多理論上的流程抖拦,現(xiàn)在開始講講OpenSAML這個庫的構(gòu)成和使用。
如何添加OpenSAML庫
OpenSAML庫可以在OpenSAML的主頁中獲得舷暮,對于Maven用戶可以直接在如下鏈接中獲得依賴:
https://build.shibboleth.net/nexus/content/repositories/releases/org/opensaml/
OpenSAML3是由Maven組織的多模塊庫态罪,每個模塊的功能各不相同。由于項目功能越來越豐富下面,對于現(xiàn)在的用戶已經(jīng)不可能通過一個單一的依賴來引用其所有的功能了复颈。每個模塊都需要添加自己都得引用。OpenSAML最新版的模塊列表如下:
? opensaml-core
? opensaml-profile-api
? opensaml-profile-impl
? opensaml-soap-api
? opensaml-soap-impl
? opensaml-saml-api
? opensaml-saml-impl
? opensaml-xacml-api
? opensaml-xacml-impl
? opensaml-xacml-saml-api
? opensaml-xacml-saml-impl
? opensaml-messaging-api
? opensaml-messaging-impl
? opensaml-storage-api
? opensaml-storage-impl
? opensaml-security-api
? opensaml-security-impl
? opensaml-xmlsec-api
? opensaml-xmlsec-impl
用戶可以根據(jù)自己項目的情況自行添加需要的模塊沥割,Maven中具體引用的信息如下:
<dependencies>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-core</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-saml-api</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-saml-impl</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-messaging-api</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-messaging-impl</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-soap-api</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml-soap-impl</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>Shibboleth repo</id>
<url>
https://build.shibboleth.net/nexus/content/repositories/releases
</url>
</repository>
</repositories>
保證JCE實現(xiàn)的正確性
OpenSAML使用JCE來提供密碼學的功能模塊券膀。由于某些
JCE的實現(xiàn)并不覆蓋所有OpenSAML要求的功能,所以推薦使用Bouncy Castle的JCE實現(xiàn)驯遇。
為了幫助用戶來確認JCE的實現(xiàn)是否正確,可以使用如下函數(shù):
JavaCryptoValidationInitializer javaCryptoValidationInitializer =
new JavaCryptoValidationInitializer();
javaCryptoValidationInitializer.init();
這個方法應(yīng)該在OpenSAML初始化之被調(diào)用蓄髓,來確保當前的環(huán)境可以符合要求叉庐。
如下方法可以用來打印當前已經(jīng)被安裝的所有JCE的provider:
for (Provider jceProvider : Security.getProviders()) {
logger.info(jceProvider.getInfo());
}
使用Maven引用OpenSAML時,Bouncy Castle
provider將會被自動引用会喝。如果是手動下載OpenSAML源碼依賴陡叠,其中也已經(jīng)包括了Bouncy Castle
provider,但是需要手動添加到class path中肢执。
日志打印
OpenSAML使用SLF4J管理日志信息枉阵。雖然SLF4J本身沒有任何打印日志的能力,但是其依賴于其他logging的實現(xiàn)來做日志管理预茄。OpenSAML團隊選擇使用Logback來實現(xiàn)logging功能(其他的實現(xiàn)也可以)兴溜。
為了能使用LogBack,需要添加依賴包:
- logback-core
- logback-classic
- apache commons logging
其下載鏈接如下:
http://logback.qos.ch/download.html,
https://commons.apache.org/proper/commons-logging/
或者直接添加Maven依賴:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
OpenSAML初始化過程
OpenSAML的初始化依賴于一些列配置文件耻陕。OpenSAML已經(jīng)有一個默認的配置拙徽,其已經(jīng)可以滿足大多數(shù)的使用需求,如果有需要還可以對其修改诗宣。
配置文件必須在OpenSAML使用之前被加載膘怕,加載默認配置需的方法如下進行:
InitializationService.initialize();
這之后,OpenSAML庫才能正常使用召庞;
如果不加載配置文件岛心,OpenSAML的初始化將不能完成来破,其無法返回某個Obejct,返回NullPointerException忘古。這是一個常見的錯誤徘禁。
創(chuàng)建SAML對象
SAML對象的創(chuàng)建使用了工廠模式和構(gòu)建者模式,涉及到鏈式配置和類型準換存皂。
創(chuàng)建SAML斷言對象的方法如下:
XMLObjectBuilderFactory builderFactory =
XMLObjectProviderRegistrySupport.getBuilderFactory();
Assertion assertion = (Assertion) builderFactory
.getBuilder(Assertion.DEFAULT_ELEMENT_NAME)
.buildObject(Assertion.DEFAULT_ELEMENT_NAME);
為了避免大量不需要的代碼晌坤,使用泛型的工具方法是一個好主意〉┐可以通過如下方法生成不同類型的對象:
public static <T> T buildSAMLObject(final Class<T> clazz) {
XMLObjectBuilderFactory builderFactory =
XMLObjectProviderRegistrySupport.getBuilderFactory();
QName defaultElementName = (QName) clazz.getDeclaredField(
"DEFAULT_ELEMENT_NAME").get(null);
T object = (T) builderFactory.getBuilder(defaultElementName)
.buildObject(defaultElementName);
return object;
}
通過使用上面的方法骤菠,就可以將生成斷言對象的代碼簡化為一行;
OpenSAMLUtils.buildSAMLObject(Assertion.class);
實例項目
為了方便讀者理解和后續(xù)文章的解讀疤孕,這里提供一個示例項目:一個很簡單的網(wǎng)址商乎,其充當SP;同時該項目還包括一個很簡單的IDP祭阀;
SAML協(xié)議的交互將在這二者之間展開鹉戚。
項目地址:
https://github.com/sunrongxin7666/OpenSAML-ref-project-demo-v3.git
這個項目基于Bitbucket的一個實驗項目https://bitbucket.org/srasmusson/webprofile-ref-project-v3
其本身是使用Apache Maveng構(gòu)建的,啟動項目需要執(zhí)行
mvn tomcat:run
嵌入項目中的Tomcat就會啟動专控,運行成功時會有如下信息:
INFO: Starting Coyote HTTP/1.1 on http-8080
經(jīng)過本人的修改抹凳,該項目可以在IntelliJ Idea以工程模式打開,運行方式設(shè)置為mvn伦腐,命令是tomcat:run赢底。這就便于讀者調(diào)試和修改。
項目啟動之后柏蘑,訪問如下網(wǎng)址:
http://localhost:8080/webprofile-ref-project/app/appservlet
這是一個SP的模擬幸冻,第一次訪問該網(wǎng)址時將會跳轉(zhuǎn)到IDP,進行認證流程咳焚。
點擊“Authenticate”按鈕將通過認證洽损,并重定向回SP,
到此為止整個SAML協(xié)議的流程及完成了,相關(guān)日志信息會在控制臺中輸出革半。
這雖然是一個最簡單的實例碑定,但是涉及多個部分的代碼,如何使用OpenSAML庫實現(xiàn)每一個步的流程又官,歡迎關(guān)注后續(xù)文章: