基于 SAML 的 WebSphere Application Server 单点登录的场景设计

来源:http://www.ibm.com/developerworks/cn/websphere/library/techarticles/1012_zhangt_saml/1012_zhangt_saml.html

本文向您介绍了如何在 WebSphere 环境下使用 SAML 实现单点登录的场景设计。在向您介绍了 SAML 的基本概念之后,本文将一步步向您介绍如何搭建 WebSphere Application Server 之间的 SAML 单点登录环境。

引言

随着互联网规模的不断扩大,把一个用户的所有信息全部收集到一个地方,既不可能也不需要。不同个人 和组织在与不同的对象打交道时会使用不同类型的信息,例如用户在线购物并付款、会计师保存财政和税款记录等等。经常性地将此信息移动到一个地点,只能使保 持数据的准确性和及时更新更加困难。同时,移动信息还会增加数据在传输中丢失和被窃的可能性。

单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

SAML 介绍

通 常来说,一个企业在物理或逻辑的范围已经界定了企业的 IT 安全。然而,由于在线合作需要共享更可靠的安全服务环境,因此 IT 安全越来越成为人们关注的重点问题。为了解决单点登录的问题,越来越多的系统通过 Web 服务、门户和集成化应用程序彼此链接,对于保证欲共享的信息安全交换的标准的需求也随之日益显著起来。

SAML(安全性断言标记语 言,Security Assertion Markup Language)正是为解决网络安全性问题而发挥其作用。它允许不同安全系统产生的信息进行交换。提供一个健壮且可扩展的数据格式集,在各种环境下交换 数据和身份识别信息。也就是说可使用独立、受管理的多个信息来源中的信息,从而实现身份严整这样的安全服务。

SAML 是一种基于 XML 语言用于传输认证及授权信息的框架,以与主体相关的断言形式表达。在这里,主体是一个实体 ( 人或计算机 ),这个实体在某个安全域中拥有一个特定身份,断言可传递主体执行的认证信息、属性信息及关于是否允许主体访问其资源的授权决定。SAML 在标准行业传输协议环境里工作,例如 HTTP、SMTP 和 FTP; 同时也服务于各种各样的 XML 文件交换框架,例如 SOAP 和 BizTalk。SAML 具备的一个最突出的好处,是使用户能够通过互联网进行安全证书移动。也就是说,使用 SAML 标准作为安全认证和共享资料的中间语言,能够在多个站点之间实现单点登录。

基于 SMAL 的单点登录的场景设计

我 们希望利用 SAML 实现不同服务器之间的单点登录实现。我们设计一种自定义的单点登录场景。这种场景使用 SAML 令牌 API 以及 WebSphere Application Server 所提供的支持 SAML 的 API 开发。下图展示了客户端通过一个与公司服务器存在信任关系的身份验证提供方 (Identity Provider)鉴别并签发 SAML 令牌后,客户端携带被认证的 SAML 令牌继续访问公司服务器,公司服务器将判断此 SAML 令牌中的用户信息是否存在。如果存在,公司服务器直接同意客户端的访问,而不需要要求用户再次进行身份验证了。

图 1. 自定义设计场景

图 1. 自定义设计场景接 下来,客户端可以通过浏览器利用 HTTP 协议将 SAML 令牌传给应用服务器。服务器端通过建立一个信任联合拦截器 (Trust Association Interceptor:TAI )拦截客户端请求。将 HTTP 请求中的 SAML 令牌信息解析并转换成 Subject,同时得到客户端的用户 ID。如果服务器端验证用户 ID 是合法的,则将为客户端提供服务。具体的流程如下:

图 2. 自定义设计场景的流程图

图 2. 自定义设计场景的流程图整个流程如下:

  1. 用户首先请求 WebSphere Application Server 1 的服务。
  2. 服务器 1 的 TAI 判断用户未授权,而将用户的请求转发到一个自定义的登录页面。
  3. 用户在登录页面上输入自己的认证信息,提交后转到第三方 STS 上做认证。
  4. STS 从外部 Registry 判断用户认证信息是否正确。
  5. 如果用户信息正确,STS 会为用户生成一个 SAML 令牌给 SAML 代理。
  6. SAML 代理是一个 Servlet,它会带着这个 SAML 令牌重新请求服务器 1 的服务。
  7. 服务器 1 的 TAI 从 SAML 令牌中提取出 UserID。
  8. TAI 从 Registry 中验证此 UserID 是否合法。
  9. 如果合法,服务器 1 会在 Cookie 为用户生成一个 LTPA 令牌。
  10. 用户的 Cookie 中存在已认证过的 LTPA 令牌,服务器 1 为用户提供服务。
  11. 生成 LTPA 令牌的同时,在同一个安全域之内的服务器将相互共享 LTPA 令牌。
  12. 当用户继续访问 WebSphere Application Server 2 的时候,可以不用认证直接访问服务。

从而实现两个服务器之间通过 SAML 令牌进行单点登录。

基于 SMAL 的单点登录的场景实现

1,实现客户端直接访问服务器上的应用

图 3. 客户端直接访问服务器设计场景

图 3. 客户端直接访问服务器设计场景在 这里我们使用的 WebSphere Application Server 的版本为 7.0.0.7。因为此版本提供了对 SAML 的支持。测试使用的应用服务为 DefaultApplication 中的 snoop 应用。我们先在 WebSphere Application Server 的管理控制端启动全局安全性中的应用程序安全性,使客户端必须认证才可访问 WebSphere Application Server 上的 snoop 应用。

在 WebSphere Application Server 的控制台,进入 Security > Global security 页面,开启应用安全 (Enable application security)

图 4. 开启应用安全

图 4. 开启应用安全重新启动应用服务器之后,访问 snoop 应用(如 http://localhost:9080/snoop),应用提示需要输入验证信息才能访问:

图 5. 访问 snoop 应用提示验证

图 5. 访问 snoop 应用提示验证编写一个简单的 Servlet,设置认证信息并访问 snoop 应用,测试认证通过后是否可以直接访问 Web 应用:

清单 1. snoop 访问代码
   URL url = new URL("http://localhost:9080/snoop"); 
	 HttpURLConnection urlConnection = 
		 (HttpURLConnection) url.openConnection(); 
	 urlConnection.setRequestMethod("GET"); 
	 String encodedUserPass; 
	 String userpass = "username:password"; 
	 encodedUserPass = 
		 new sun.misc.BASE64Encoder().encode (userpass.getBytes()); 
	 urlConnection.setRequestProperty("Authorization", 
		"Basic " + encodedUserPass);

由于之前服务器端设置过安全性,在程序访问此 url 的时候,服务器会判断客户端是否有权限访问。如果设置的认证合法则程序顺利执行,如果认证不合法或者为空则报告没有权限访问的错误。

图 6. 未输入验证信息,页面无权限访问

图 6. 未输入验证信息,页面无权限访问2,实现客户端自签发 SAML 令牌,并通过 TAI 访问服务器上的应用

图 7. 客户端利用 SAML 通过 TAI 访问服务器设计场景

图 7. 客户端利用 SAML 通过 TAI 访问服务器设计场景此 场景比上一场景增加了一个 SAML TAI,即信任联合拦截器 (Trust Association Interceptor:TAI )。TAI 的功能是拦截 HTTP 的请求,执行相应的操作。WebSphere Application Server 自带两种拦截器 com.ibm.ws.security.spnego.TrustAssociationInterceptorImpl 和 com.ibm.ws.security.web.TAMTrustAssociationInterceptorPlus。这里的 TAI 是我们自定义的,用于拦截请求解析 SAML 令牌使用。

自定义的 TAI 需要实现 com.ibm.wsspi.security.tai.TrustAssociationInterceptor 接口。这个接口有三个方法,即:

  • public int initialize(Properties props)

当 TAI 初始化成功,返回 0,TAI 会继续执行 isTargetIntercept 方法。

  • public boolean isTargetInterceptor(HttpServletRequest req)

判断拦截的请求是否为目标请求,如果是返回 true,TAI 会继续执行 negotiateValidateandEstablishTrust 方法。

  • public TAIResult negotiateValidateandEstablishTrust

(HttpServletRequest req, HttpServletResponse res)

TAI 会在此方法中执行所需要的操作。返回的 TAIResult 将通过 WebSphere 服务器自身的安全机制,验证生成的 Subject 及用户 ID 是否合法。

清单 2. isTargetInterceptor 函数代码
 public boolean isTargetInterceptor(HttpServletRequest req) 
			 throws WebTrustAssociationException { 
 String uri = req.getRequestURI() ; 
	 if (uri.indexOf("snoop") != -1) { 			
		 String token = req.getHeader("SAMLToken") ; 
		 if (token != null) { 
			 return true ; 
		 } 
	 } else { 
		 System.out.println("This is not the snoop application."); 
		 return false ; 
	 } 
	 return false ; 
	 // return true if this is the target interceptor, else return false. 
 }

在清单 2 中:

在第 4 行上 isTargetInterceptor 函数首先判断此次请求是否访问的是 snoop 应用,如果是 snoop 应用,则继续执行清单 3 中的 negotiateValidateandEstablishTrust 函数。

清单 3. negotiateValidateandEstablishTrust 函数代码
public TAIResult negotiateValidateandEstablishTrust(HttpServletRequest req, 
	HttpServletResponse res) throws WebTrustAssociationFailedException { 
// validate the request and establish trust. 
  // create and return the TAIResult 
  TAIResult result = null; 
  try { 
   String token = req.getHeader("SAMLToken") ; 
   if(token!=null&&!token.equals("")) { 
   String decodedSAMLToken = Base64Coder.base64Decode(token); 
   SAMLTokenFactory samlFactory = 
       SAMLTokenFactory.getInstance(SAMLTokenFactory.WssSamlV20Token11); 
   ByteArrayInputStream in =
     new ByteArrayInputStream(decodedSAMLToken.getBytes()); 
   SAMLToken samlToken = samlFactory.newSAMLToken(null, in); 
   Subject subject = samlFactory.newSubject(samlToken); 
   result = 
   TAIResult.create(HttpServletResponse.SC_OK, samlToken.getKeyIdentifier(), subject); 
	 } 
	 else { 
	 try { 
      System.out.println("You don't have SAMLToken, 
	  you will be redirected to: http://localhost:9080/SAMLServlet/login.jsp"); 
	 res.sendRedirect("http:// localhost:9080/SAMLServlet/login.jsp"); 
      } catch (IOException e) { 
	   e.printStackTrace(); 
	} 
  } 
 }catch (WSSException e) { 
	 e.printStackTrace(); 
 } 
	 return result ; 
 }

在清单 3 中:

在第 7 行上首先先获得请求头文件 SAMLToken 中的内容。

如果 SAMLToken 中的内容为空,将直接跳转到第 20 行的 login.jsp 页面进行用户登录。

如果 SAMLToken 中的内容不为空,则将其内容解析成 SAMLToken 对象,并从对象中获得并验证用户信息。

如果用户信息正确,TAI 会允许此次 snoop 请求,用户可直接访问 snoop 应用。

编 写完成 TAI 之后,需要将 TAI 类拷贝到 app_server_root/lib/ext directory 路径下并在 WebSphere Application Server 的控制台声明此 TAI。进入 Global security > Trust association > Interceptors,新建一个 SamlTAIImpl,设置相关配置后重启服务器,此 TAI 即可生效。

图 8. 新建 TAI

图 8. 新建 TAI3,通过 SAML 实现两台 WAS 之间进行单点登录

设置好应用安全和 TAI 之后,我们就可以利用 SAML 实现两台 WebSphere Application Server 之间的单点登录了。

图 9. 两 WebSphere Application Server 之间实现单点登录

图 9. 两 WebSphere Application Server 之间实现单点登录s 当用户持 SAML 令牌访问 WebSphere 服务器 1 的时候,服务器 1 的 TAI 将解析出 SAML 令牌中的用户 ID,通过 Registry 判断用户 ID 是否合法。如果合法,服务器 1 将返回给客户端 Cookie 一个 LTPA 令牌。因为可以在 WebSphere Application Server 中设置安全域,在相同安全域中的服务器将共享 LTPA 令牌从而实现单点登录。所以我们就可以带着刚才返回给客户端的 LTPA 令牌直接访问 WebSphere 服务器 2 的服务,而不需要在进行身份验证了。

4,实现客户端通过 STS 签发 SAML 令牌,并通过 TAI 访问服务器上的应用

经 过上述 3 中场景的设计,我们已经能通过程序生成 SAML 令牌,从而实现两个应用服务器见的单点登录。如果我们将程序生成 SAML 令牌转换为利用第三方安全标记服务(STS:Security Token Service)自动生成 SAML 令牌。我们将完成整个 SAML 自定义单点登录的场景设计。

图 10. 客户端通过 STS 利用 SAML 通过 TAI 访问服务器设计场景

图 10. 客户端通过 STS 利用 SAML 通过 TAI 访问服务器设计场景

结束语

随 着互联网规模的不断扩大,单点登录已成为目前比较流行的企业业务整合的解决方案之一。SAML 提供了一个健壮且可扩展的数据格式集,能够实现异构系统下的单点登录和复杂环境间的认证和授权。同时 SAML 已被众多商家支持,可在规模庞大的环境中实现联邦身份管理。它尽可能详细地指定了绝大部分实际情况,从而提供了出色的交互性。对于独特的需求和未来可能出 现的需求而言,它还是可扩展的。

发表评论