OpenSAML 使用引导 I : 简介——关于OpenSAML你所需知道的一切

相关阅读SAML2.0入门指南, 此文中已经介绍了SAML协议的基本信息,今天开始将会为大家详解OpenSaml——SAML协议的一种开源实现。

SAML

What's OpenSAML

OpenSAML是一个便于使用SAML消息的依赖库,其提供的主要功能包括:

  1. 创建SAML消息;
  2. 解析SAML对象并导出为XML格式;
  3. 签名和加密;
  4. 对SAML消息进行编码并传输。

目前OpenSAML库提供Java和C++实现的版本,需要注意的是OpenSAML虽然多应用用于SSO(单点登录)的开发中,但是该库本身不提供任何身份识别和授权的功能,其只是实现对于SAML消息的相关操作而已。

SAML

SAML是一种XML框架用来交换安全信息,其中定义了按照安全规范所需要的通信的协议和格式。

SAML是一种中心化的认证机制,其定义了两种实体相互通信:

  • Service Provider(SP): 向用户提供正式商业服务的实体,通常需要认证一个用户的身份;
  • Identity Provider(IDP): 提供用户的身份鉴别,确保用户是其所声明的身份;

SAML的重要用途:

  • 单点登录(SSO Single Sign-ON);
  • 联合认证(Federated Identity);
  • 在其他架构内使用SAML,比如WS-Security。

更多关于SAML的内容,请参看SAML2.0入门指南

SAML相关定义

1. 断言(Assertions) 即信息

断言是在SAML中用来描述认证的对象,其中包括一个用户在什么时间、以什么方式被认证,同时还可以包括一些扩展信息,比如用户的Email地址和电话等等。

下面便是一个断言的实例:


但愿.png

2. 协议(Protocol)即通信

协议规定如何执行不同的行为。这些行为被细化成一些列的Request和Response对象,而在这些请求和相应的对象中包含了行为所特别需要的信息。比如,认证请求协议(AuthnRequest Protocol)就规定了一个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信息如何使用通信协议被传输的。比如,HTTP重定向绑定,即声明SAML信息将通过HTTP重定向消息传输;再比如SAML SOAP绑定,声明了通过SOAP来传递SAML消息。

SAML消息.png

配置(Profiles) 即综合

配置定义了如何组织以上信息,并且在一个更高的层次上描述断言,协议和绑定如何被使用去解决一个具体情况。比如Web浏览器的SSO配置就描述了如何一个用户使用浏览器被认证。

元数据(MetaData)

SAML的元数据是配置数据,其包含关于SAML通信各方的信息,比如通信另一方的ID、Web Service的IP地址、所支持的绑定类型以及通信中实用的密钥等等。

OpenSaml中提供了metadata provider来帮助构建和解读元数据。

SAML通过Web浏览器实现的协议流程

通过HTTP协议绑定来实现SSO:

SAML协议流程.png

1. 用户尝试获得权限

流程首先从一个非认证的用户开始,该用户尝试从一个受保护的SP那里获得访问权限。某种方式的过滤器被设置在访问路径上来检测用户是否被授权(J2ee中servlet类就是一个很好地例子)。这一部分其实并不是SAML协议里的内容,但是却决定了是否要被授权。

2. 用户被重定向到IDP

当访问路径上被设置的过滤器发现用户并非是被认证的,将会自动把用户从定向到IDP,以求验证用户的身份。

3. 用户被认证

在这一步里,用户被认证。注意这里并没任何涉及到SP的交互,在安全方式内,IDP对于认证用户有着全权责任。

4. 已认证的用户被从定向回SP

当用户被认证成功之后,用户会携带着SAML产物(SAML artifact)被从定向回SP。这样的SAML产物也可以说是认证信息的标识,因为认证信息中有敏感的信息不能直接通过浏览器传输,所以这里只是发送标识而已。

5. 要求认证信息

当收到SAML产物之后,SP将其发送回IDP,IDP依据SAML产物找到认证信息,并通过SAML产物响应(SAML Artifact Response)发送回SP

上面提到的SAML产物响应(SAML Artifact Response) 中就包含SAML断言,它就是认证的证据。断言中最重要的数据就该用户什么时候以什么方式被认证的。

OpenSAML 快速上手

说了这么多理论上的流程,现在开始讲讲OpenSAML这个库的构成和使用。

如何添加OpenSAML库

OpenSAML库可以在OpenSAML的主页中获得,对于Maven用户可以直接在如下链接中获得依赖:
https://build.shibboleth.net/nexus/content/repositories/releases/org/opensaml/

OpenSAML3是由Maven组织的多模块库,每个模块的功能各不相同。由于项目功能越来越丰富,对于现在的用户已经不可能通过一个单一的依赖来引用其所有的功能了。每个模块都需要添加自己都得引用。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

用户可以根据自己项目的情况自行添加需要的模块,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实现的正确性

OpenSAML使用JCE来提供密码学的功能模块。由于某些
JCE的实现并不覆盖所有OpenSAML要求的功能,所以推荐使用Bouncy Castle的JCE实现。

为了帮助用户来确认JCE的实现是否正确,可以使用如下函数:

JavaCryptoValidationInitializer javaCryptoValidationInitializer = 
    new JavaCryptoValidationInitializer();
javaCryptoValidationInitializer.init();

这个方法应该在OpenSAML初始化之被调用,来确保当前的环境可以符合要求。

如下方法可以用来打印当前已经被安装的所有JCE的provider:

for (Provider jceProvider : Security.getProviders()) {
    logger.info(jceProvider.getInfo());
}

使用Maven引用OpenSAML时,Bouncy Castle
provider将会被自动引用。如果是手动下载OpenSAML源码依赖,其中也已经包括了Bouncy Castle
provider,但是需要手动添加到class path中。

日志打印

OpenSAML使用SLF4J管理日志信息。虽然SLF4J本身没有任何打印日志的能力,但是其依赖于其他logging的实现来做日志管理。OpenSAML团队选择使用Logback来实现logging功能(其他的实现也可以)。

为了能使用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已经有一个默认的配置,其已经可以满足大多数的使用需求,如果有需要还可以对其修改。

配置文件必须在OpenSAML使用之前被加载,加载默认配置需的方法如下进行:

InitializationService.initialize();

这之后,OpenSAML库才能正常使用;

如果不加载配置文件,OpenSAML的初始化将不能完成,其无法返回某个Obejct,返回NullPointerException。这是一个常见的错误。

创建SAML对象

SAML对象的创建使用了工厂模式和构建者模式,涉及到链式配置和类型准换。

创建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);

实例项目

为了方便读者理解和后续文章的解读,这里提供一个示例项目:一个很简单的网址,其充当SP;同时该项目还包括一个很简单的IDP;
SAML协议的交互将在这二者之间展开。

项目地址:
https://github.com/sunrongxin7666/OpenSAML-ref-project-demo-v3.git

这个项目基于Bitbucket的一个实验项目https://bitbucket.org/srasmusson/webprofile-ref-project-v3
其本身是使用Apache Maveng构建的,启动项目需要执行

mvn tomcat:run

嵌入项目中的Tomcat就会启动,运行成功时会有如下信息:

INFO: Starting Coyote HTTP/1.1 on http-8080

经过本人的修改,该项目可以在IntelliJ Idea以工程模式打开,运行方式设置为mvn,命令是tomcat:run。这就便于读者调试和修改。

Idea配置

项目启动之后,访问如下网址:
http://localhost:8080/webprofile-ref-project/app/appservlet
这是一个SP的模拟,第一次访问该网址时将会跳转到IDP,进行认证流程。

IDP

点击“Authenticate”按钮将通过认证,并重定向回SP,


SP

到此为止整个SAML协议的流程及完成了,相关日志信息会在控制台中输出。

这虽然是一个最简单的实例,但是涉及多个部分的代码,如何使用OpenSAML库实现每一个步的流程,欢迎关注后续文章:

  1. OpenSAML 使用引导 II : Service Provider 的实现之AuthnRequest
  2. OpenSAML 使用引导 III: Service Provider 的实现之Artifact与断言
  3. OpenSAMl 使用引导IV: 安全特性
    原创不易,希望大家支持。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容