非常多系统的数据是相互冗余和反复的。数据的不一致性会给管理工作带来非常大的压力。业务和业务之间的相关性也越来越大,比如公司的计费系统和財务系统,財务系统和人事系统之间都不可避免的有着密切的关系。
整合曾经。进入每一个系统都须要进行登录,这种局面不仅给管理上带来了非常大的困难。在安全方面也埋下了重大的隐患。以下是一些著名的调查公司显示的统计数据:
- 用户每天平均 16 分钟花在身份验证任务上 - 资料来源: IDS
- 频繁的 IT 用户平均有 21 个password - 资料来源: NTA Monitor Password Survey
- 49% 的人写下了其password,而 67% 的人非常少改变它们
- 每 79 秒出现一起身份被窃事件 - 资料来源:National Small Business Travel Assoc
- 全球欺骗损失每年约 12B - 资料来源:Comm Fraud Control Assoc
- 到 2007 年,身份管理市场将成倍增长至 $4.5B - 资料来源:IDS
- 提高 IT 效率:对于每 1000 个受管用户,每用户可节省$70K
- 帮助台呼叫降低至少1/3,对于 10K 员工的公司,每年能够节省每用户 $75。或者合计 $648K
- 生产力提高:每一个新员工可节省 $1K。每一个老员工可节省 $350 �资料来源:Giga
- ROI 回报:7.5 到 13 个月 �资料来源:Gartner
全部著名的软件厂商都提供了对应的解决方式。在这里我并不想介绍自己公司(
Sun Microsystems)的产品,而是对SSO技术本身进行解析,而且提供自己开发这一类产品的方法和简单演示。有关我写这篇文章的目的。请參考我的博客(http://yuwang881.blog.sohu.com/3184816.html)。在颐和园内部有很多独立的景点。比如“苏州街”、“佛香阁”和“德和园”,都能够在各个景点门口单独买票。
非常多游客须要游玩全部德景点。这样的买票方式非常不方便,须要在每一个景点门口排队买票。钱包拿进拿出的。easy丢失,非常不安全。
于是绝大多数游客选择在大门口买一张通票(也叫套票),就能够玩遍全部的景点而不须要又一次再买票。
他们仅仅须要在每一个景点门口出示一下刚才买的套票就能够被同意进入每一个独立的景点。
- 全部应用系统共享一个身份认证系统。
统一的认证系统是SSO的前提之中的一个。认证系统的主要功能是将用户的登录信息和用户信息库相比較。对用户进行登录认证;认证成功后,认证系统应该生成统一的认证标志(ticket)。返还给用户。另外,认证系统还应该对ticket进行效验。推断其有效性。 - 全部应用系统可以识别和提取ticket信息
要实现SSO的功能,让用户仅仅登录一次,就必须让应用系统可以识别已经登录过的用户。应用系统应该能对ticket进行识别和提取。通过与认证系统的通讯。能自己主动推断当前用户是否登录过,从而完毕单点登录的功能。
有两点须要指出的是:
- 单一的用户信息数据库并非必须的,有很多系统不能将全部的用户信息都集中存储。应该同意用户信息放置在不同的存储中。例如以下图所看到的。其实。仅仅要统一认证系统。统一ticket的产生和效验,不管用户信息存储在什么地方,都能实现单点登录。
- 统一的认证系统并非说仅仅有单个的认证server,例如以下图所看到的,整个系统可以存在两个以上的认证server。这些server甚至可以是不同的产品。认证server之间要通过标准的通讯协议。互相交换认证信息。就能完毕更高级别的单点登录。
例如以下图,当用户在訪问应用系统
1时,由第一个认证server进行认证后,得到由此server产生的ticket。当他訪问应用系统4的时候,认证server2可以识别此ticket是由第一个server产生的。通过认证server之间标准的通讯协议(比如SAML)来交换认证信息,仍然可以完毕SSO的功能。
一个
Web应用由非常多个Web页面组成,每一个页面都有唯一的URL来定义。用户在浏览器的地址栏输入页面的URL。浏览器就会向Web Server去发送请求。例如以下图,浏览器向
Webserver发送了两个请求,申请了两个页面。这两个页面的请求是分别使用了两个单独的HTTP连接。所谓无状态的协议也就是表如今这里,浏览器和Webserver会在第一个请求完毕以后关闭连接通道。在第二个请求的时候又一次建立连接。Webserver并不区分哪个请求来自哪个client。对全部的请求都一视同仁。都是单独的连接。这种方式大大差别于传统的(Client/Server)C/S结构,在那样的应用中,client和server端会建立一个长时间的专用的连接通道。正是由于有了无状态的特性,每一个连接资源可以非常快被其它client所重用。一台Webserver才可以同一时候服务于成千上万的client。例如以下图所看到的,当浏览器訪问了页面
1时。webserver设置了一个cookie,并将这个cookie和页面1一起返回给浏览器。浏览器接到cookie之后,就会保存起来。在它訪问页面2的时候会把这个cookie也带上,Webserver接到请求时也能读出cookie的值。依据cookie值的内容就能够推断和恢复一些用户的信息状态。- 统一的身份认证服务。
- 改动Web应用,使得每一个应用都通过这个统一的认证服务来进行身份效验。
- Web-SSO的例子是由三个标准Web应用组成,压缩成三个zip文件,从http://gceclub.sun.com.cn/wangyu/web-sso/中下载。当中SSOAuth(http://gceclub.sun.com.cn/wangyu/web-sso/SSOAuth.zip)是身份认证服务;SSOWebDemo1(http://gceclub.sun.com.cn/wangyu/web-sso/SSOWebDemo1.zip)和SSOWebDemo2(http://gceclub.sun.com.cn/wangyu/web-sso/SSOWebDemo2.zip)是两个用来演示单点登录的Web应用。
这三个
Web应用之所以没有打成war包,是由于它们不能直接部署,依据读者的部署环境须要作出小小的改动。例子部署和执行的环境有一定的要求,须要符合Servlet2.3以上标准的J2EE容器才干执行(比如Tomcat5,Sun Application Server 8, Jboss 4等)。另外,身份认证服务须要JDK1.5的执行环境。之所以要用JDK1.5是由于笔者使用了一个线程安全的高性能的Java集合类“ConcurrentMap”。仅仅有在JDK1.5中才有。 - 这三个Web应用全然能够单独部署,它们能够分别部署在不同的机器,不同的操作系统和不同的J2EE的产品上。它们全然是标准的和平台无关的应用。可是有一个限制。那两台部署应用(demo1、demo2)的机器的域名须要同样,这在后面的章节中会解释到cookie和domain的关系以及怎样制作跨域的WEB-SSO
- 解压缩SSOAuth.zip文件,在/WEB-INF/下的web.xml中请改动“domainname”的属性以反映实际的应用部署情况。domainname须要设置为两个单点登录的应用(demo1和demo2)所属的域名。这个domainname和当前SSOAuth服务部署的机器的域名没有关系。
我缺省设置的是“
.sun.com”。假设你部署demo1和demo2的机器没有域名,请输入IP地址或主机名(如localhost),可是假设使用IP地址或主机名也就意味着demo1和demo2须要部署到一台机器上了。设置完后,依据你所选择的
J2EE容器,可能须要将SSOAuth这个文件夹压缩打包成war文件。用“jar -cvf SSOAuth.war SSOAuth/”就能够完毕这个功能。 - 解压缩SSOWebDemo1和SSOWebDemo2文件。分别在它们/WEB-INF/下找到web.xml文件。请改动当中的几个初始化參数
<init-param>
<param-name>SSOServiceURL</param-name>
<param-value>http://wangyu.prc.sun.com:8080/SSOAuth/SSOAuth</param-value>
</init-param>
<init-param>
<param-name>SSOLoginPage</param-name>
<param-value>http://wangyu.prc.sun.com:8080/SSOAuth/login.jsp</param-value>
</init-param>
将当中的SSOServiceURL和SSOLoginPage改动成部署SSOAuth应用的机器名、port号以及根路径(缺省是SSOAuth)以反映实际的部署情况。设置完后。依据你所选择的
J2EE容器。可能须要将SSOWebDemo1和SSOWebDemo2这两个文件夹压缩打包成两个war文件。用“jar -cvf SSOWebDemo1.war SSOWebDemo1/”就能够完毕这个功能。 - 请输入第一个web应用的測试URL(test.jsp),比如http://wangyu.prc.sun.com:8080/ SSOWebDemo1/test.jsp。假设是第一次訪问,便会自己主动跳转到登录界面。例如以下图
- 使用系统自带的三个帐号之中的一个登录(比如,username:wangyu,password:wangyu),便能成功的看到test.jsp的内容:显示当前username和欢迎信息。
- 请接着在同一个浏览器中输入第二个web应用的測试URL(test.jsp),比如http://wangyu.prc.sun.com:8080/ SSOWebDemo2/test.jsp。你会发现,不须要再次登录就能看到test.jsp的内容,相同是显示当前username和欢迎信息。并且欢迎信息中明白的显示当前的应用名称(demo2)。
package DesktopSSO;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SSOAuth extends HttpServlet {
static private ConcurrentMap accounts;
static private ConcurrentMap SSOIDs;
String cookiename="WangYuDesktopSSOID";
String domainname;
public void init(ServletConfig config) throws ServletException {
super.init(config);
domainname= config.getInitParameter("domainname");
cookiename = config.getInitParameter("cookiename");
SSOIDs = new ConcurrentHashMap();
accounts=new ConcurrentHashMap();
accounts.put("wangyu", "wangyu");
accounts.put("paul", "paul");
accounts.put("carol", "carol");
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
String action = request.getParameter("action");
String result="failed";
if (action==null) {
handlerFromLogin(request,response);
} else if (action.equals("authcookie")){
String myCookie = request.getParameter("cookiename");
if (myCookie != null) result = authCookie(myCookie);
out.print(result);
out.close();
} else if (action.equals("authuser")) {
result=authNameAndPasswd(request,response);
out.print(result);
out.close();
} else if (action.equals("logout")) {
String myCookie = request.getParameter("cookiename");
logout(myCookie);
out.close();
}
}
.....
}
|
- 假设用户还没有登录过,是第一次登录本系统,会被跳转到login.jsp页面(在后面会解释怎样跳转)。用户在提供了username和password以后,就会用handlerFromLogin()这种方法来验证。
- 假设用户已经登录过本系统,再訪问别的应用的时候,是不须要再次登录的。
由于浏览器会将第一次登录时产生的
cookie和请求一起发送。效验
cookie的有效性是SSOAuth的主要功能之中的一个。 - SSOAuth还能直接效验非login.jsp页面过来的username和password的效验请求。这个功能是用于非web应用的SSO,这在后面的桌面SSO中会用到。
- SSOAuth还提供logout服务。
private void handlerFromLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
String pass = (String)accounts.get(username);
if ((pass==null)||(!pass.equals(password)))
getServletContext().getRequestDispatcher("/failed.html").forward(request, response);
else {
String gotoURL = request.getParameter("goto");
String newID = createUID();
SSOIDs.put(newID, username);
Cookie wangyu = new Cookie(cookiename, newID);
wangyu.setDomain(domainname);
wangyu.setMaxAge(60000);
wangyu.setValue(newID);
wangyu.setPath("/");
response.addCookie(wangyu);
System.out.println("login success, goto back url:" + gotoURL);
if (gotoURL != null) {
PrintWriter out = response.getWriter();
response.sendRedirect(gotoURL);
out.close();
}
}
}
|
假设登录成功后,应该自己主动的将用户的浏览器指向用户最初想訪问的那个
URL。在handlerFromLogin()这种方法中。我们通过接收“goto”这个參数来保存用户最初訪问的URL,成功后便又一次定向到这个页面中。在这里我给了非常大的值(
1000分钟),导致的行为是:当你关闭浏览器(或者关机)。下次再打开浏览器訪问刚才的应用,仅仅要在1000分钟之内,就不须要再登录了。我这样做是以下要介绍的桌面SSO中所须要的功能。- Web应用中每个须要安全保护的URL在訪问曾经,都须要进行安全检查,假设发现没有登录(没有发现认证之后所带的cookie),就又一次定向到SSOAuth中的login.jsp进行登录。
- 登录成功后,系统会自己主动给你的浏览器设置cookie。证明你已经登录过了。
- 当你再訪问这个应用的须要保护的URL的时候。系统还是要进行安全检查的,可是这次系统可以发现对应的cookie。
- 有了这个cookie,还不能证明你就一定有权限訪问。由于有可能你已经logout,或者cookie已经过期了,或者身份认证服务重起过,这些情况下,你的cookie都可能无效。应用系统拿到这个cookie。还须要调用身份认证的服务,来推断cookie时候真的有效,以及当前的cookie相应的用户是谁。
- 假设cookie效验成功。就同意用户訪问当前请求的资源。
- 在每一个被訪问的资源中(JSP或Servlet)中都增加身份认证的服务。来获得cookie。而且推断当前用户是否登录过。只是这个笨方法没有人会用:-)。
- 能够通过一个controller,将全部的功能都写到一个servlet中。然后在URL映射的时候,映射到全部须要保护的URL集合中(比如*.jsp。/security/*等)。这种方法能够使用,只是,它的缺点是不能重用。
在每一个应用中都要部署一个同样的
servlet。 - Filter是比較好的方法。符合Servlet2.3以上的J2EE容器就具有部署filter的功能。(Filter的使用能够參考JavaWolrd的文章http://www.javaworld.com/javaworld/jw-06-2001/jw-0622-filters.html)Filter是一个具有非常好的模块化,可重用的编程API,用在SSO正合适只是。本例子就是使用一个filter来完毕以上的功能。
package SSO;
import java.io.*;
import java.net.*;
import java.util.*;
import java.text.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.*;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.GetMethod;
public class SSOFilter implements Filter {
private FilterConfig filterConfig = null;
private String cookieName="WangYuDesktopSSOID";
private String SSOServiceURL= "http://wangyu.prc.sun.com:8080/SSOAuth/SSOAuth";
private String SSOLoginPage= "http://wangyu.prc.sun.com:8080/SSOAuth/login.jsp";
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
if (filterConfig != null) {
if (debug) {
log("SSOFilter:Initializing filter");
}
}
cookieName = filterConfig.getInitParameter("cookieName");
SSOServiceURL = filterConfig.getInitParameter("SSOServiceURL");
SSOLoginPage = filterConfig.getInitParameter("SSOLoginPage");
}
.....
.....
}
|
由于当前的
Web应用非常可能和身份认证服务(SSOAuth)不在同一台机器上。所以须要让这个filter知道身份认证服务部署的URL。这样才干去调用它的服务。另外一点就是由于身份认证的服务调用是要通过http协议来调用的(在本例子中是这样设计的。读者全然能够设计自己的身份服务,使用别的调用协议,如RMI或SOAP等等),全部笔者引用了apache的commons工具包(具体信息情訪问apache 的站点http://jakarta.apache.org/commons/index.html),当中的“httpclient”能够大大简化http调用的编程。
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
if (debug) log("SSOFilter:doFilter()");
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String result="failed";
String url = request.getRequestURL().toString();
String qstring = request.getQueryString();
if (qstring == null) qstring ="";
//检查http请求的head是否有须要的cookie
String cookieValue ="";
javax.servlet.http.Cookie[] diskCookies = request.getCookies();
if (diskCookies != null) {
for (int i = 0; i < diskCookies.length; i++) {
if(diskCookies[i].getName().equals(cookieName)){
cookieValue = diskCookies[i].getValue();
//假设找到了对应的cookie则效验其有效性
result = SSOService(cookieValue);
if (debug) log("found cookies!");
}
}
}
if (result.equals("failed")) { //效验失败或没有找到cookie,则须要登录
response.sendRedirect(SSOLoginPage+"?goto="+url);
} else if (qstring.indexOf("logout") > 1) {//logout服务
if (debug) log("logout action!");
logoutService(cookieValue);
response.sendRedirect(SSOLoginPage+"?goto="+url);
} else {//效验成功
request.setAttribute("SSOUser",result);
Throwable problem = null;
try {
chain.doFilter(req, res);
} catch(Throwable t) {
problem = t;
t.printStackTrace();
}
if (problem != null) {
if (problem instanceof ServletException) throw (ServletException)problem;
if (problem instanceof IOException) throw (IOException)problem;
sendProcessingError(problem, res);
}
}
}
|
<filter-name>SSOFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
private String SSOService(String cookievalue) throws IOException {
String authAction = "?
action=authcookie&cookiename="; HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod(SSOServiceURL+authAction+cookievalue);
try {
httpclient.executeMethod(httpget);
String result = httpget.getResponseBodyAsString();
return result;
} finally {
httpget.releaseConnection();
}
}
private void logoutService(String cookievalue) throws IOException {
String authAction = "?action=logout&cookiename=";
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod(SSOServiceURL+authAction+cookievalue);
try {
httpclient.executeMethod(httpget);
httpget.getResponseBodyAsString();
} finally {
httpget.releaseConnection();
}
}
|
由于採用了
SSO,在网络上传递password的次数减少,风险减少是显然的,可是当前的方案却有其它的安全风险。由于cookie是一个用户登录的唯一凭据,对cookie的保护措施是系统安全的重要环节:- cookie的长度和复杂度
在本方案中,cookie是有一个固定的字符串(我的姓名)加上当前的时间戳。这种
cookie非常easy被伪造和推測。怀有恶意的用户假设推測到合法的
cookie就能够被当作已经登录的用户。随意訪问权限范围内的资源 - cookie的效验和保护
在本方案中,尽管password仅仅要传输一次就够了,可cookie在网络中是常常传来传去。一些网络探測工具(如
sniff, snoop,tcpdump等)能够非常easy捕获到cookie的数值。在本方案中,并没有考虑cookie在传输时候的保护。另外对cookie的效验也过于简单,并不去检查发送cookie的来源到底是不是cookie最初的拥有者,也就是说无法区分正常的用户和仿造cookie的用户。 - 当当中一个应用的安全性不好。其它全部的应用都会受到安全威胁
由于有SSO,所以当某个处于 SSO的应用被黒客攻破,那么非常easy攻破其它处于同一个SSO保护的应用。
- 当前所提供的登录认证模式仅仅有一种:username和password,并且为了简单,将username和password放在内存其中。
其实,用户身份信息的来源应该是多种多样的,能够是来自数据库中,
LDAP中,甚至于来自操作系统自身的用户列表。还有非常多其它的认证模式都是商务应用必不可少的,因此SSO的解决方式应该包含各种认证的模式,包含数字证书。Radius, SafeWord ,MemberShip,SecurID等多种方式。最为灵活的方式应该同意可插入的JAAS框架来扩展身份认证的接口 - 我们编写的Filter仅仅能用于J2EE的应用,而对于大量非Java的Web应用,却无法提供SSO服务。
- 在将Filter应用到Web应用的时候,须要对容器上的每个应用都要做对应的改动,又一次部署。而更加流行的做法是Agent机制:为每个应用server安装一个agent,就能够将SSO功能应用到这个应用server中的全部应用。
- 当前的方案不能支持分别位于不同domain的Web应用进行SSO。
这是由于浏览器在訪问
Webserver的时候,只会带上和当前webserver具有同样domain名称的那些cookie。要提供跨域的SSO的解决方式有非常多其它的方法,在这里就不多说了。Sun的Access Manager就具有跨域的SSO的功能。 - 另外,Filter的性能问题也是须要重视的方面。由于Filter会截获每个符合URL映射规则的请求,获得cookie。验证其有效性。这一系列任务是比較消耗资源的,特别是验证cookie有效性是一个远程的http的调用,来訪问SSOAuth的认证服务,有一定的延时。
因此在性能上须要做进一步的提高。比如在本例子中,假设将
URL映射从“.jsp”改成“/*”。也就是说filter对全部的请求都起作用。整个应用会变得非常慢。这是由于,页面其中包括了各种静态元素如
gif图片,css样式文件,和其它html静态页面,这些页面的訪问都要通过filter去验证。而其实,这些静态元素没有什么安全上的需求。应该在filter中进行推断,不去效验这些请求。性能会好非常多。另外,假设在
filter中加上一定的cache,而不须要每个cookie效验请求都去远端的身份认证服务中运行,性能也能大幅度提高。 - 另外系统还须要非常多其它的服务,如在内存中定时删除没用的cookie映射等等。都是一个严肃的解决方式须要考虑的问题。
在
WEB-SSO中。登录的凭据是靠浏览器的cookie机制来完毕的;在桌面应用中,能够将登录的凭证保存到不论什么地方,仅仅要全部SSO的桌面应用都共享这个凭证。- 执行此桌面SSO须要三个前提条件:
a) WEB-SSO的身份认证应用应该正在执行。由于我们在桌面SSO其中须要用到统一的认证服务
b) 当前桌面须要执行Mozilla或Netscape浏览器,由于我们将ticket保存到mozilla的cookie文件里
c) 必须在JDK1.4以上执行。(
WEB-SSO须要JDK1.5以上) - 解开desktopsso.zip文件,里面有两个文件夹bin和lib。
- bin文件夹下有一些脚本文件和配置文件,当中config.properties包括了三个须要配置的參数:
a) SSOServiceURL要指向WebSSO部署的身份认证的URL
b) SSOLoginPage要指向WebSSO部署的身份认证的登录页面URL
c) cookiefilepath要指向当前用户的mozilla所存放cookie的文件 - 在bin文件夹下另一个login.conf是用来配置JAAS登录模块,本例子提供了两个,读者能够随意选择当中一个(也能够都选),再又一次执行程序。查看登录认证的变化
- 在bin下的执行脚本可能须要作对应的改动
a) 假设是在unix下,各个jar文件须要用“:”来隔开,而不是“;”
b) java 执行程序须要放置在当前执行的路径下,否则须要加上java的路径全名。
这对一些行业有着不小的吸引力。
请看配置文件
login.conf
DesktopSSO {
desktopsso.share.PasswordLoginModule required;
desktopsso.share.DesktopSSOLoginModule required;
};
|
public class DesktopSSOLoginModule implements LoginModule {
..........
private String SSOServiceURL = "";
private String SSOLoginPage = "";
private static String cookiefilepath = "";
.........
|
SSOServiceURL=http://wangyu.prc.sun.com:8080/SSOAuth/SSOAuth
SSOLoginPage=http://wangyu.prc.sun.com:8080/SSOAuth/login.jsp
cookiefilepath=C://Documents and Settings//yw137672//Application Data//Mozilla//Profiles//default//hog6z1ji.slt//cookies.txt
|
(我试图解析
Internet Explorer的cookie文件但没有成功。)逻辑也是很easy:先用
Cookie来登陆,假设成功,则直接就进入系统。否则须要用户输入username和password来登录系统。
public boolean login() throws LoginException{
try {
if (Cookielogin()) return true;
} catch (IOException ex) {
ex.printStackTrace();
}
if (passwordlogin()) return true;
throw new FailedLoginException();
}
|
假设
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;
}
|
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();
}
|
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;
}
|
但是有非常多程序是没有源码和无法改动的,比如经常使用的远程通讯程序
telnet和ftp等等一些操作系统自己带的经常使用的应用程序。这些程序是非常难改动增加到我们的SSO的解决方式中。操作系统中的各个应用(如
ftp,telnet)仅仅须要通过配置就能增加到SSO中。另外使用Kerberos最大的优点在于它的安全性。通过密钥算法的保证和密钥中心的建立,能够做到用户的password根本不须要在网络中传输,而传输的信息也会十分的安全。要开发出真正的
SSO的产品,在功能上、性能上和安全上都必须有更加完备的考虑。- OpenSSO 的站点: https://opensso.dev.java.net
- 在java应用中使用掩码的password提示: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
- 我的博客http://yuwang881.blog.sohu.com/3184816.html