- OpenSSO 的网站: https://opensso.dev.java.net
- 在java应用中使用掩码的密码提示:http://java.sun.com/developer/technicalArticles/Security/pwordmask/
- Kerberos的资源网站:http://web.mit.edu/kerberos/
- Sun的Java&Kerberos教程:http://java.sun.com/j2se/1.5.0/docs/guide/security/jgss/tutorials/index.html
- Apache社区提供的HttpClient工具包网址:http://jakarta.apache.org/commons/index.html)
- Filter的使用教程文章:http://www.javaworld.com/javaworld/jw-06-2001/jw-0622-filters.html
- CAS单点登录与登出演示
http://blog.csdn.net/jaytse/archive/2008/07/25/2710041.aspx
CAS单点登出原理
http://www.blogjava.net/xmatthew/archive/2008/07/09/213808.html
Lotus Domino单点登录方案
http://www.automatedlogic.com/domblog.nsf/dx/DominoTomcatSSOIntegration
Session机制
http://www.cnblogs.com/siye1982/archive/2008/01/24/1051048.html
CAS Domino Authentication
http://tp.its.yale.edu/pipermail/cas/2008-January/007188.html
Domino CAS单点登录方案
http://www-12.lotus.com/ldd/doc/tools/c/7.0/api70ug.nsf/85255d56004d2bfd85255b1800631684/ceda2cb8df47607f85256c3d005f816d - 转自http://blog.csdn.net/javachannel/archive/2006/05/24/752437.aspx
下面是登录模块DesktopSSOLoginModule的主体:
login()
方法。逻辑也是非常简单:先用
Cookie
来登陆,如果成功,则直接就进入系统,否则需要用户输入用户名和密码来登录系统。
public boolean login() throws LoginException{
try {
if (Cookielogin()) return true;
} catch (IOException ex) {
ex.printStackTrace();
}
if (passwordlogin()) return true;
throw new FailedLoginException();
}
|
下面是Cookielogin()
方法的实体,它的逻辑是:
先从
Cookie
文件中获得相应的
Cookie
值,通过身份效验服务效验
Cookie
的有效性。如果
cookie
有效
就算登录成功;如果不成功或
Cookie
不存在,用
cookie
登录就算失败。
public boolean Cookielogin() throws LoginException,IOException {
String cookieValue="";
int cookieIndex =foundCookie();
if (cookieIndex<0)
return false;
else
cookieValue = getCookieValue(cookieIndex);
username = cookieAuth(cookieValue);
if (! username.equals("failed")) {
loginSuccess = true;
return true;
}
return false;
}
|
用用户名和密码登录的方法要复杂一些,通过
Callback
的机制和屏幕输入输出进行信息交互,完成用户登录信息的获取;获取信息以后通过
userAuth
方法来调用远端
SSOAuth
的服务来判定当前登录的有效性。
public boolean passwordlogin() throws LoginException {
//
// Since we need input from a user, we need a callback handler
if (callbackHandler == null) {
throw new LoginException("No CallbackHandler defined");
}
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("Username");
callbacks[1] = new PasswordCallback("Password", false);
//
// Call the callback handler to get the username and password
try {
callbackHandler.handle(callbacks);
username = ((NameCallback)callbacks[0]).getName();
char[] temp = ((PasswordCallback)callbacks[1]).getPassword();
password = new char[temp.length];
System.arraycopy(temp, 0, password, 0, temp.length);
((PasswordCallback)callbacks[1]).clearPassword();
} catch (IOException ioe) {
throw new LoginException(ioe.toString());
} catch (UnsupportedCallbackException uce) {
throw new LoginException(uce.toString());
}
System.out.println();
String authresult ="";
try {
authresult = userAuth(username, password);
} catch (IOException ex) {
ex.printStackTrace();
}
if (! authresult.equals("failed")) {
loginSuccess= true;
clearPassword();
try {
updateCookie(authresult);
} catch (IOException ex) {
ex.printStackTrace();
}
return true;
}
loginSuccess = false;
username = null;
clearPassword();
System.out.println( "Login: PasswordLoginModule FAIL" );
throw new FailedLoginException();
}
|
CookieAuth
和
userAuth
方法都是利用
apahce
的
httpclient
工具包和远程的
SSOAuth
进行
http
连接,获取服务。
private String cookieAuth(String cookievalue) throws IOException{
String result = "failed";
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod(SSOServiceURL+Action1+cookievalue);
try {
httpclient.executeMethod(httpget);
result = httpget.getResponseBodyAsString();
} finally {
httpget.releaseConnection();
}
return result;
}
private String userAuth(String username, char[] password) throws IOException{
String result = "failed";
String passwd= new String(password);
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod(SSOServiceURL+Action2+username+"&password="+passwd);
passwd = null;
try {
httpclient.executeMethod(httpget);
result = httpget.getResponseBodyAsString();
} finally {
httpget.releaseConnection();
}
return result;
}
|
还有一个地方需要补充说明的是,在本样例中,用户名和密码的输入都会在屏幕上显示明文。如果希望用掩码形式来显示密码,以提高安全性,请参考:
http://java.sun.com/developer/technicalArticles/Security/pwordmask/
7
真正安全的全方位
SSO
解决方案:
Kerberos
我们的样例程序(桌面
SSO
和
WEB-SSO
)都有一个共性:要想将一个应用集成到我们的
SSO
解决方案中,或多或少的需要修改应用程序。
Web
应用需要配置一个我们预制的
filter
;桌面应用需要加上我们桌面
SSO
的
JAAS
模块(至少要修改
JAAS
的配置文件)。可是有很多程序是没有源代码和无法修改的,例如常用的远程通讯程序
telnet
和
ftp
等等一些操作系统自己带的常用的应用程序。这些程序是很难修改加入到我们的
SSO
的解决方案中。
事实上有一种全方位的
SSO
解决方案能够解决这些问题,这就是
Kerberos
协议(
RFC 1510
)。
Kerberos
是网络安全应用标准
(http://web.mit.edu/kerberos/)
,由
MIT
学校发明,被主流的操作系统所采用。在采用
kerberos
的平台中,登录和认证是由操作系统本身来维护,认证的凭证也由操作系统来保存,这样整个桌面都可以处于同一个
SSO
的系统保护中。操作系统中的各个应用(如
ftp,telnet
)只需要通过配置就能加入到
SSO
中。另外使用
Kerberos
最大的好处在于它的安全性。通过密钥算法的保证和密钥中心的建立,可以做到用户的密码根本不需要在网络中传输,而传输的信息也会十分的安全。
目前支持
Kerberos
的操作系统包括
Solaris, windows,Linux
等等主流的平台。只不过要搭建一个
Kerberos
的环境比较复杂,
KDC
(密钥分发中心)的建立也需要相当的步骤。
Kerberos
拥有非常成熟的
API
,包括
Java
的
API
。使用
Java Generic Security Services(GSS) API
并且使用
JAAS
中对
Kerberos
的支持(详细信息请参见
Sun
的
Java&Kerberos
教程
http://java.sun.com/ j2se/1.5.0/docs/guide/security/jgss/tutorials/index.html
),要将我们这个样例改造成对
Kerberos
的支持也是不难的。 值得一提的是在
JDK6.0
(
http://www.java.net/download/jdk6
)当中直接就包含了对
GSS
的支持,不需要单独下载
GSS
的包。
8
总结
本文的主要目的是阐述
SSO
的基本原理,并提供了一种实现的方式。通过对源代码的分析来掌握开发
SSO
服务的技术要点和充分理解
SSO
的应用范围。但是,本文仅仅说明了身份认证的服务,而另外一个和身份认证密不可分的服务
----
权限效验,却没有提到。要开发出真正的
SSO
的产品,在功能上、性能上和安全上都必须有更加完备的考虑。
资源链接