Java EE和Domino系统间跨域SSO的实现

(转自http://my.donews.com/chenyf97/2007/06/25/j2ee%e5%92%8cdomino%e7%b3%bb%e7%bb%9f%e9%97%b4%e8%b7%
a8%e5%9f%9fsso%e7%9a%84%e5%ae%9e%e7%8e%b0%ef%bc%88%e4%b8%80%ef%bc%89/)

1. SSO需求

单点登录(Single Sign On, SSO)是企业应用集成中最常见的需求。异构系统间往往都有各自的用户管理和身份验证机制,为

避免用户在进行系统切换时频繁输入用户名和密码,因此必须要实现单点登录。

2. SSO原理

说到SSO的原理,先得说一般Web应用的身份验证原理。Web身份验证之所以能成为问题主要在于HTTP协议的无状态性,这导

致了每次HTTP的请求和响应的无关性。而应用的状态保持是大部分应用系统的一般性需求,因此必须借助其他机制,这就是Cookie。

2.1. Cookie的原理

一个Cookie由name、value、domain、path、expires组成。可以给HTTP响应添加Cookie,然后Cookie就作为HTTP响应的

Headers返回给浏览器,例如Domino的登录成功后的Cookie响应头为:

Set-Cookie: DomAuthSessId=1AD479C4D11CD10278A4C523320A6918; path=/

没有设置expires就表示仅在当前浏览器进程生命期内有效,不保存到客户机上;若expires时间大于当前时间,则浏览器在收到

这个 Cookie以后将其写入到客户机文件中,一般是保存在C:/Documents and Settings/Administrator/Cookies/下。

没有设置domain就表示只在当前域内有效。

当客户机再次请求该域内的其他资源时,浏览器会自动将该域内的Cookie附在请求的Headers一起发送给Web服务器,形如:

Cookie: DomAuthSessId=1AD479C4D11CD10278A4C523320A6918

如此Web应用就能够通过读取HTTP请求Headers里面的Cookie值来判断用户身份,这样也就间接实现了HTTP的状态保持需

求。

2.2. SSO原理

了解的Cookie的原理以后就不难理解SSO的原理了。SSO的目的是为了实现两个或多个应用系统间的单点登录,其实现手段无
非是在登录A系统的 同时自动登录到B系统、C系统……,结合Cookie也就是说在SSO登录时同时去A系统、B系统、C系统进行验证,并将来自各系统的Cookie返回给 浏览器,就是这么简单。

一般情况下,做SSO要统一登录界面,这可以通过将各应用系统的登录界面重定向到指定的登录页来实现。

2.3. Cookie的局限

如果仅仅如上所说这么简单,那也就不会创造什么SSO的概念了。问题出在Cookie的domain上。出于浏览器安全的考虑,HTTP响应 Headers中的Cookie的domain只有与HTTP请求域(a.abc.com)一致或为上级域(abc.com)时,Cookie才能生效。

也就是说:

若A、B系统域名分别为a.abc.com和b.abc.com,登录系统A,同时写来自两个系统的Cookie到浏览器,且Cookie的domain设为.abc.com,那么浏览器是可以接受的,SSO成功。

若A、B系统域名分别为a.abc.com和b.xyz.com,登录系统A,同时写来自两个系统的Cookie到浏览器,其中A Cookie的domain设为.abc.com,B Cookie的domain设为.xyz.com,那么浏览器是不可以接受B Cookie的,因为该HTTP请求是来自.abc.com,因此不能写.xyz.com域中的Cookie。

这也就是跨域SSO难题的原因所在。

2.4. 跨域SSO

了解了Cookie的局限和跨域SSO难题所在,也就不难找到解决跨域问题的办法了:由各应用系统中创建各自域的Cookie并返回给浏览器。不要幻想在一个应用中创建所有域的Cookie,这是徒劳的。

至于如何一次性在各应用系统中创建各自域的Cookie并返回给浏览器,这就仁者见仁智者见智了,一般常见的做法是:

在SSO验证成功的返回页中利用JS脚本动态创建隐藏的IFRAME,并将验证信息通过IFRAME的SRC属性的URL参数传递给各应用系统的某 个资源,这些资源可以是动态程序也可以是JS脚本,由各应用系统的动态程序或JS脚本根据传入的参数来完成该应用的验证过程并返回验证通过的 Cookie。

下文说的做法与上略有不同,我的想法是:只在请求哪个应用系统时才进行哪个应用系统的身份验证,而不是一次性全将所有身份都验证完毕。

3. Domino SSO 实现

Domino 的用户信息和身份验证是通过目录( NAMES.NSF )来实现的; J2EE 系统也往往有自己开发的用户管理和身份验证机制。要实现二者的 SSO ,可以通过部署统一的身份认证应用来完成。

要部署唯一的 SSO 应用有三个选择:

l 扩展 Domino 的身份认证功能,提供 SSO 服务;

l 扩展 J2EE 系统的身份认证功能,提供 SSO 服务;

l 部署单独的 SSO 应用,提供 SSO 服务;

Domino 的身份认证在 names.nsf 中进行,登录界面在 domcfg.nsf 中,通过提交包含用户名( username )和密码( password )的请求到路径 /names.nsf?Login 即可完成验证过程。但 Domino 验证是通过其内在机制实现的,没有给开发者提供任何显示的程序代码(如何进行用户名和口令校验的代码),因此无法对 Domino 的验证过程直接进行扩展。

J2EE 系统本身的用户管理和身份认证往往都由我们自行设计的,因此可以在此基础上扩展实现单点登录,我们这里采用的即是这种方案。

此外,也可以开发单独的 SSO 应用,集成 Domino J2EE 系统登录过程,本质上与在 J2EE 系统基础上扩展没有区别,这里不再赘述。

3.1. Domino Cookie

前面已经提过 SSO 的原理就是 Cookie ,所以有必要了解 Domino 系统的 Cookie

Domino 系统根据服务器配置的不同有两种 Cookie 来进行会话状态的维持。


l 单服务器,服务器返回给浏览器的 Cookie 名是: DomAuthSessId

l 多个服务器( SSO ),服务器返回给浏览器的 Cookie 名是: LtpaToken ,这是 IBM 一套轻量级第三方认证标准,自动支持 Websphere Lotus 之间的 SSO

3.2. Domino 系统设置

1. 配置 Domino 的登录页

Notes 打开 domcfg.nsf 数据库,打开” Sign In Form Mapping “配置文档,设置登录页为 domcfg.nsf 里的 SSOLoginForm 表单。


2. Domino 登录页重定向到 J2EE

Designer 打开 domcfg.nsf/SSOLoginForm ,通过脚本将其重定向到 SSO 登录页:

 

js 代码
 
  1. <script language=”javascript”>  
  2. parent.location.href = “http://www.j2ee.com/loginAction.do?method=login&redirectTo=< 计算文本>”;   
  3. </script>  

 

其中该计算文本为 RedirectTo 值,记录用户原始请求的 DominoURL

3.3. J2EE 系统 SSO 开发

3.3.1. SSO 登录界面

SSO 登录表单中,除了必要的用户名和口令输入框之外,还应有一个属性 redirectTo 来记录登录后的重定向路径。当用户访问某个受限资源时,系统自动重定向到该登录界面,同时记录该受限资源的路径,当输入用户名和口令并验证成功以后,系统自动将用户重定向到该受限资源处,而不是简单的返回到缺省首页。

3.3.2. SSO 验证程序

J2EE 系统自身的验证还是才有传统的用户名和口令校验方式。当检查来自客户端的访问请求是去往 Domino 系统时,将自动进行 Domino 的验证并重定向到相应的 Domino 页面。自动 Domino 验证分为两个步骤:

1. 程序自动从服务器后台通过 Http URLConnection 访问 Domino 系统并登录,若验证通过则读取相应的 Cookie 值;

单服务器的 form-based 方式验证获取 Cookie 及重定向 URL 代码如下:

java 代码
 
  1. URL url =  new  URL(httpHost + “names.nsf?Login”);  
  2.   
  3. HttpURLConnection.setFollowRedirects(false );  
  4.   
  5. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();  
  6.   
  7. urlConnection.setDoOutput(true );  
  8.   
  9. OutputStreamWriter wr = new  OutputStreamWriter(urlConnection.getOutputStream());  
  10.   
  11. wr.write(”username=” + userName + “&password=” + password);  
  12.   
  13. wr.flush();  
  14.   
  15. wr.close();  
  16.   
  17. urlConnection.connect();  
  18.   
  19. Map
  20.   
  21. for  (Iterator<string> it = headerFields.keySet().iterator(); it.hasNext(); ) {  </string>
  22.   
  23. String key = it.next();  
  24.   
  25. if  (key !=  null  && key.equals(”Set-Cookie”)) {  
  26.   
  27. String value = urlConnection.getHeaderField(key);  
  28.   
  29. String[] cookies = value.split(”;//s*”);  
  30.   
  31. for  ( int  i =  0 ; i < cookies.length; i++) {  
  32.   
  33. String[] cookie = cookies[i].trim().split(”=”);  
  34.   
  35. if  (cookie[ 0 ].equals(”DomAuthSessId”)) {  
  36.   
  37. successful = true ;  
  38.   
  39. loginURL = httpHost + “domcfg.nsf/SSOLoginAction?OpenAgent”;  
  40.   
  41. loginURL += “&cookeName=DomAuthSessId”;  
  42.   
  43. loginURL += “&cookeValue=” + cookie[1 ];  
  44.   
  45. break ;  
  46.   
  47. }  
  48.   
  49. }  
  50.   
  51. }  
  52.   
  53. }  
  54.   
  55. urlConnection.disconnect();  

多服务器( SSO )方式获取 Cookie 及重定向 URL 代码如下:

java 代码
 
  1. Session session = NotesFactory.createSession(serverName, userName, password);  
  2.   
  3. if  (session !=  null  && session.isValid()) {  
  4.   
  5. successful = true ;  
  6.   
  7. loginURL = httpHost + “domcfg.nsf/SSOLoginAction?OpenAgent”;  
  8.   
  9. loginURL += “&cookeName=LtpaToken”;  
  10.   
  11. loginURL += “&cookeValue=” + URLEncoder.encode(session.getSessionToken(), “UTF-8 ″);  
  12.   
  13. }  

2. 程序将获取的 Cookie 名称、 Cookie 值以及目的资源地址通过 URL 参数的方式传给一个 Domino 的代理(也即上述代码中的变量 loginURL ),由 Domino 代理写 Cookie 并重定到向目的资源地址。 Domino 代理 SSOLoginAction 也非常简单,代码示意如下:

Domino 代码
  1. cookieName$ = request.GetParameter(”cookeName”)  
  2.   
  3. cookieValue$ = request.GetParameter(”cookeValue”)  
  4.   
  5. redirectTo$ = request.GetParameter(”redirectTo”)  
  6.   
  7. Print {Set-Cookie:} + cookieName$ + {=} + cookieValue$ + {; path=/}  
  8.   
  9. Print {Location: } + redirectTo$ + {}  

其中 request.GetParameter 是自定义类方法,用以获取 URL 中的参数值。

如此, J2EE Domino 系统间的跨域 SSO 就顺利实现 J

你可能感兴趣的:(java,浏览器,服务器,SSO,domain,websphere)