单点登录(后文简称:sso)的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统(摘自百度百科)。整个流程中涉及到的角色有:
- 用户。
- 应用服务器,即业务系统。
- 单点登录服务器,所有业务系统登录的核心枢纽,后文简称用户中心。
关于token同步的思考
从其定义中不难发现,核心功能点:一处登录处处登录,注销亦然。那么如何实现一处登录处处登录,先抛开网上各种解决思路回到问题本身。用户中心登录成功后产生的token(或者说“票据”,后文统一称token)如果能够同步到各个业务系统,而各个业务系统能成功解析token后即可认为达到了一处登录处处登录。所以关键问题在于:
- 如何在用户中心登陆成功后将token同步到各个业务系统。
- 各业务系统如何能够成功解析token。
其中各业务系统解析token很好解决,和用户中心约定一套公用的加密/解密方式即可。那么问题一,由于token的存储一般在于浏览器,而从用户中心服务器发起请求到各个业务系统是在浏览器端写不了token的。那么换种思路,在登陆成功后从浏览器端向各个业务系统发起请求写入token。
关于登陆功能使用的思考
而由于用户中心被许多业务系统所使用,各系统所使用的开发语言未必能完全统一,于是有功能点二:登录服务的调用应该是易用且与平台语言无关的。这个问题可按两种不同的思路来解决:
- 业务系统没有登陆页面,直接跳转用户中心登陆并将token同步至所有业务系统。
- 业务系统有登陆页面,直接引用用户中心sso.js调用登陆并将token同步至所有业务系统。
关于登陆用户权限的思考
假定有业务系统A、B、C、D。用户1可登陆系统A、B,用户2可登陆系统B、C、D,于是有功能点三:用户中心应该可以控制用户所能登陆的业务系统。在登陆生成token时,加入能够登陆的业务系统信息,在登陆成功后,只向能够登陆的业务系统发起同步token的请求,并且各业务系统在token解析后需要验证token是否具有当前系统的登陆权限。
关于token刷新策略的思考
关于token的刷新策略,token应该什么时候刷新,在sso系统中,token刷新后又该如何通知到其他业务系统。第一个问题参考owin的cookie登陆,在请求中,判断token是否超过有效期的一半,超过则刷新。第二个问题就麻烦了,因为token的刷新是跟随正常请求的,我们就不能再使用像登陆那样依靠浏览器去通知所有业务系统了,关于这个问题,有三种解决思路:
- 各系统定时刷新token并通知各个业务系统。
- token只存于用户中心,向各个业务系统发放该token的key,各业务系统根据key向用户中心获取token并缓存,缓存的过期时间为是token下次应该刷新的时间。
- 共享一个分布式token存储系统,可使用redis,向各个业务系统发放token的key,需要刷新时直接使用key刷新redis中的token。
巴拉巴拉讲了一堆,也不知道大伙们能理解多少,权当记录我在开发过程中的一些思考吧,当然少不了大家喜闻乐见的GitHub地址:https://github.com/liuxx001/sso.git,下篇讲具体实现,最后先放个sso.js压压惊。
var sso = sso || {}; (function ($) { sso.host = "http://localhost:58806/"; sso.utils = { isEmpty: function(str) { if (typeof (str) === "undefined") return true; if (str.replace(/(^s*)|(s*$)/g, "").length === 0) return true; return false; } }; /** * 登陆 * @param {signInfo}登陆信息 * { userName:"", password:"", rememberMe:false, returnUrl:"" } */ sso.login = function(signInfo) { if (sso.utils.isEmpty(signInfo.userName)) { alert("用户名不能为空"); return; } if (sso.utils.isEmpty(signInfo.password)) { alert("登陆密码不能为空"); return; } $.ajax({ url: sso.host + "Account/SignIn", dataType: 'jsonp', type: 'GET', contentType: 'application/json', data: signInfo }); }; /** * 三方登陆 * @param {signInfo}登陆信息 * { loginProvider:"", providerKey:"", rememberMe:false, returnUrl:"" } */ sso.externalLogin = function(signInfo) { if (sso.utils.isEmpty(signInfo.loginProvider)) { alert("三方登陆来源不能为空"); return; } if (sso.utils.isEmpty(signInfo.providerKey)) { alert("三方登陆唯一Key不能为空"); return; } $.ajax({ url: sso.host + "Account/ExternalSignIn", dataType: 'jsonp', type: 'GET', contentType: 'application/json', data: signInfo }); }; /** * 注销 */ sso.logOut = function { $.ajax({ url: sso.host + "Account/SignOut", dataType: 'jsonp', type: 'GET', contentType: 'application/json', data: {} }); }; /** * sso服务器登陆成功后jsonp回调 * @param {string}需要通知的Url集合 */ sso.notify = function { var createScript = function (src) { $("<script><//script>").attr("src", src).appendTo("body"); }; var urlList = arguments; for (var i = 1; i < urlList.length; i++) { createScript(urlList[i]); } //延时执行,避免跳转时cookie还未写入成功 setTimeout(function { if (urlList[0] === "refresh") { window.location.reload; } else { window.location.href = urlList[0]; } }, 1000); }; /** * sso服务器登陆失败后jsonp回调 * @param {code}错误码 * @param {msg}错误消息 */ sso.error= function(code, msg) { alert(msg); } })(jQuery); //个人看的另外一篇文章http://www.blogjava.net/xcp/archive/2010/04/13/318125.html单点登录的机制其实是比较简单的,用一个现实中的例子做比较。颐和园是北京著名的旅游景点,也是我常去的地方。在颐和园内部有许多独立的景点,例如“苏州街”、“佛香阁”和“德和园”,都可以在各个景点门口单独买票。很多游客需要游玩所有德景点,这种买票方式很不方便,需要在每个景点门口排队买票,钱包拿进拿出的,容易丢失,很不安全。于是绝大多数游客选择在大门口买一张通票(也叫套票),就可以玩遍所有的景点而不需要重新再买票。他们只需要在每个景点门口出示一下刚才买的套票就能够被允许进入每个独立的景点。单点登录的机制也一样,如下图所示,当用户第一次访问应用系统 1 的时候,因为还没有登录,会被引导到认证系统中进行登录( 1 );根据用户提供的登录信息,认证系统进行身份效验,如果通过效验,应该返回给用户一个认证的凭据-- ticket ( 2 );用户再访问别的应用的时候( 3 , 5 )就会将这个 ticket 带上,作为自己认证的凭据,应用系统接受到请求之后会把 ticket 送到认证系统进行效验,检查 ticket 的合法性( 4 , 6 )。如果通过效验,用户就可以在不用再次登录的情况下访问应用系统 2 和应用系统 3 了。
从上面的视图可以看出,要实现 SSO ,需要以下主要的功能:
- 所有应用系统共享一个身份认证系统。 统一的认证系统是SSO的前提之一。认证系统的主要功能是将用户的登录信息和用户信息库相比较,对用户进行登录认证;认证成功后,认证系统应该生成统一的认证标志(ticket),返还给用户。另外,认证系统还应该对ticket进行效验,判断其有效性。
- 所有应用系统能够识别和提取ticket信息 要实现SSO的功能,让用户只登录一次,就必须让应用系统能够识别已经登录过的用户。应用系统应该能对ticket进行识别和提取,通过与认证系统的通讯,能自动判断当前用户是否登录过,从而完成单点登录的功能。
- 单一的用户信息数据库并不是必须的,有许多系统不能将所有的用户信息都集中存储,应该允许用户信息放置在不同的存储中,如下图所示。事实上,只要统一认证系统,统一ticket的产生和效验,无论用户信息存储在什么地方,都能实现单点登录。

- 统一的认证系统并不是说只有单个的认证服务器,如下图所示,整个系统可以存在两个以上的认证服务器,这些服务器甚至可以是不同的产品。认证服务器之间要通过标准的通讯协议,互相交换认证信息,就能完成更高级别的单点登录。如下图,当用户在访问应用系统1时,由第一个认证服务器进行认证后,得到由此服务器产生的ticket。当他访问应用系统4的时候,认证服务器2能够识别此ticket是由第一个服务器产生的,通过认证服务器之间标准的通讯协议(例如SAML)来交换认证信息,仍然能够完成SSO的功能。



- 统一的身份认证服务。
- 修改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应用的机器名、端口号以及根路径(缺省是SSOAuth)以反映实际的部署情况。设置完后,根据你所选择的J2EE容器,可能需要将SSOWebDemo1和SSOWebDemo2这两个目录压缩打包成两个war文件。用“jar -cvf SSOWebDemo1.war SSOWebDemo1/”就可以完成这个功能。
- 请输入第一个web应用的测试URL(test.jsp),例如http://wangyu.prc.sun.com:8080/ SSOWebDemo1/test.jsp,如果是第一次访问,便会自动跳转到登录界面,如下图
- 使用系统自带的三个帐号之一登录(例如,用户名:wangyu,密码:wangyu),便能成功的看到test.jsp的内容:显示当前用户名和欢迎信息。
- 请接着在同一个浏览器中输入第二个web应用的测试URL(test.jsp),例如http://wangyu.prc.sun.com:8080/ SSOWebDemo2/test.jsp。你会发现,不需要再次登录就能看到test.jsp的内容,同样是显示当前用户名和欢迎信息,而且欢迎信息中明确的显示当前的应用名称(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页面(在后面会解释如何跳转)。用户在提供了用户名和密码以后,就会用handlerFromLogin()这个方法来验证。
- 如果用户已经登录过本系统,再访问别的应用的时候,是不需要再次登录的。因为浏览器会将第一次登录时产生的cookie和请求一起发送。效验cookie的有效性是SSOAuth的主要功能之一。
- SSOAuth还能直接效验非login.jsp页面过来的用户名和密码的效验请求。这个功能是用于非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();
}
}
}
|
- 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");
}
.....
.....
}
|
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);
}
}
}
|
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();
}
}
|
- cookie的长度和复杂度 在本方案中,cookie是有一个固定的字符串(我的姓名)加上当前的时间戳。这样的cookie很容易被伪造和猜测。怀有恶意的用户如果猜测到合法的cookie就可以被当作已经登录的用户,任意访问权限范围内的资源
- cookie的效验和保护 在本方案中,虽然密码只要传输一次就够了,可cookie在网络中是经常传来传去。一些网络探测工具(如sniff, snoop,tcpdump等)可以很容易捕获到cookie的数值。在本方案中,并没有考虑cookie在传输时候的保护。另外对cookie的效验也过于简单,并不去检查发送cookie的来源究竟是不是cookie最初的拥有者,也就是说无法区分正常的用户和仿造cookie的用户。
- 当其中一个应用的安全性不好,其他所有的应用都会受到安全威胁 因为有SSO,所以当某个处于 SSO的应用被黒客攻破,那么很容易攻破其他处于同一个SSO保护的应用。
- 当前所提供的登录认证模式只有一种:用户名和密码,而且为了简单,将用户名和密码放在内存当中。事实上,用户身份信息的来源应该是多种多样的,可以是来自数据库中,LDAP中,甚至于来自操作系统自身的用户列表。还有很多其他的认证模式都是商务应用不可缺少的,因此SSO的解决方案应该包括各种认证的模式,包括数字证书,Radius, SafeWord ,MemberShip,SecurID等多种方式。最为灵活的方式应该允许可插入的JAAS框架来扩展身份认证的接口
- 我们编写的Filter只能用于J2EE的应用,而对于大量非Java的Web应用,却无法提供SSO服务。
- 在将Filter应用到Web应用的时候,需要对容器上的每一个应用都要做相应的修改,重新部署。而更加流行的做法是Agent机制:为每一个应用服务器安装一个agent,就可以将SSO功能应用到这个应用服务器中的所有应用。
- 当前的方案不能支持分别位于不同domain的Web应用进行SSO。这是因为浏览器在访问Web服务器的时候,仅仅会带上和当前web服务器具有相同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映射等等,都是一个严肃的解决方案需要考虑的问题。
- 运行此桌面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的路径全名。




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
|
public boolean login() throws LoginException{
try {
if (Cookielogin()) return true;
} catch (IOException ex) {
ex.printStackTrace();
}
if (passwordlogin()) return true;
throw new FailedLoginException();
}
|
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;
}
|