java实现简单的单点登录(4)

下面是登录模块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();
 }
 
  CookieAuthuserAuth方法都是利用apahcehttpclient工具包和远程的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/
 
当前方案的安全局限性
当前这个 WEB-SSO 的方案是一个比较简单的雏形,主要是用来演示 SSO 的概念和说明 SSO 技术的实现方式。有很多方面还需要完善,其中安全性是非常重要的一个方面。
我们说过,采用 SSO 技术的主要目的之一就是加强安全性,降低安全风险。因为采用了 SSO ,在网络上传递密码的次数减少,风险降低是显然的,但是当前的方案却有其他的安全风险。由于 cookie 是一个用户登录的唯一凭据,对 cookie 的保护措施是系统安全的重要环节:
  • cookie的长度和复杂度
    在本方案中,cookie是有一个固定的字符串(我的姓名)加上当前的时间戳。这样的cookie很容易被伪造和猜测。怀有恶意的用户如果猜测到合法的cookie就可以被当作已经登录的用户,任意访问权限范围内的资源
  • cookie的效验和保护
    在本方案中,虽然密码只要传输一次就够了,可cookie在网络中是经常传来传去。一些网络探测工具(如sniff, snoop,tcpdump等)可以很容易捕获到cookie的数值。在本方案中,并没有考虑cookie在传输时候的保护。另外对cookie的效验也过于简单,并不去检查发送cookie的来源究竟是不是cookie最初的拥有者,也就是说无法区分正常的用户和仿造cookie的用户。
  • 当其中一个应用的安全性不好,其他所有的应用都会受到安全威胁
    因为有SSO,所以当某个处于 SSO的应用被黒客攻破,那么很容易攻破其他处于同一个SSO保护的应用。
这些安全漏洞在商业的 SSO 解决方案中都会有所考虑,提供相关的安全措施和保护手段,例如 Sun 公司的 Access Manager cookie 的复杂读和对 cookie 的保护都做得非常好。另外在 OpneSSO  https://opensso.dev.java.net )的架构指南中也给出了部分安全措施的解决方案。
当前方案的功能和性能局限性
除了安全性,当前方案在功能和性能上都需要很多的改进:
  • 当前所提供的登录认证模式只有一种:用户名和密码,而且为了简单,将用户名和密码放在内存当中。事实上,用户身份信息的来源应该是多种多样的,可以是来自数据库中,LDAP中,甚至于来自操作系统自身的用户列表。还有很多其他的认证模式都是商务应用不可缺少的,因此SSO的解决方案应该包括各种认证的模式,包括数字证书,Radius, SafeWord MemberShipSecurID等多种方式。最为灵活的方式应该允许可插入的JAAS框架来扩展身份认证的接口
  • 我们编写的Filter只能用于J2EE的应用,而对于大量非JavaWeb应用,却无法提供SSO服务。
  • 在将Filter应用到Web应用的时候,需要对容器上的每一个应用都要做相应的修改,重新部署。而更加流行的做法是Agent机制:为每一个应用服务器安装一个agent,就可以将SSO功能应用到这个应用服务器中的所有应用。
  • 当前的方案不能支持分别位于不同domainWeb应用进行SSO。这是因为浏览器在访问Web服务器的时候,仅仅会带上和当前web服务器具有相同domain名称的那些cookie。要提供跨域的SSO的解决方案有很多其他的方法,在这里就不多说了。SunAccess Manager就具有跨域的SSO的功能。
  • 另外,Filter的性能问题也是需要重视的方面。因为Filter会截获每一个符合URL映射规则的请求,获得cookie,验证其有效性。这一系列任务是比较消耗资源的,特别是验证cookie有效性是一个远程的http的调用,来访问SSOAuth的认证服务,有一定的延时。因此在性能上需要做进一步的提高。例如在本样例中,如果将URL映射从“.jsp改成“/*,也就是说filter对所有的请求都起作用,整个应用会变得非常慢。这是因为,页面当中包含了各种静态元素如gif图片,css样式文件,和其他html静态页面,这些页面的访问都要通过filter去验证。而事实上,这些静态元素没有什么安全上的需求,应该在filter中进行判断,不去效验这些请求,性能会好很多。另外,如果在filter中加上一定的cache,而不需要每一个cookie效验请求都去远端的身份认证服务中执行,性能也能大幅度提高。
  • 另外系统还需要很多其他的服务,如在内存中定时删除无用的cookie映射等等,都是一个严肃的解决方案需要考虑的问题。
桌面 SSO 的实现
WEB-SSO 的概念延伸开,我们可以把 SSO 的技术拓展到整个桌面的应用,不仅仅局限在浏览器。 SSO 的概念和原则都没有改变,只需要再做一点点的工作,就可以完成桌面  SSO  的应用。
桌面 SSO WEB-SSO 一样,关键的技术也在于如何在用户登录过后保存登录的凭据。在 WEB-SSO 中,登录的凭据是靠浏览器的 cookie 机制来完成的;在桌面应用中,可以将登录的凭证保存到任何地方,只要所有 SSO 的桌面应用都共享这个凭证。
从网站可以下载一个简单的桌面 SSO 的样例 (http://gceclub.sun.com.cn/wangyu/desktop-sso/desktopsso.zip) 和全部源码( http://gceclub.sun.com.cn/wangyu/desktop-sso/desktopsso_src.zip ),虽然简单,但是它具有桌面 SSO 大多数的功能,稍微加以扩充就可以成为自己的解决方案。
 
6.1 桌面样例的部署
  1. 运行此桌面SSO需要三个前提条件:
    a) WEB-SSO
    的身份认证应用应该正在运行,因为我们在桌面SSO当中需要用到统一的认证服务
    b) 
    当前桌面需要运行MozillaNetscape浏览器,因为我们将ticket保存到mozillacookie文件中
    c) 
    必须在JDK1.4以上运行。(WEB-SSO需要JDK1.5以上)
  2. 解开desktopsso.zip文件,里面有两个目录binlib
  3. bin目录下有一些脚本文件和配置文件,其中config.properties包含了三个需要配置的参数:
    a) SSOServiceURL
    要指向WebSSO部署的身份认证的URL
    b) SSOLoginPage
    要指向WebSSO部署的身份认证的登录页面URL
    c) cookiefilepath
    要指向当前用户的mozilla所存放cookie的文件
  4. bin目录下还有一个login.conf是用来配置JAAS登录模块,本样例提供了两个,读者可以任意选择其中一个(也可以都选),再重新运行程序,查看登录认证的变化
  5. bin下的运行脚本可能需要作相应的修改
    a) 
    如果是在unix下,各个jar文件需要用“:来隔开,而不是“;
    b) java 
    运行程序需要放置在当前运行的路径下,否则需要加上java的路径全名。
 
6.2 桌面样例的运行
样例程序包含三个简单的 Java 控制台程序,这三个程序单独运行都需要登录。如果运行第一个命叫“ GameSystem 的程序,提示需要输入用户名和密码:
效验成功以后,便会显示当前登录的用户的基本信息等等。
  这时候再运行第二个桌面 Java 应用( mailSystem )的时候,就不需要再登录了,直接就显示出来刚才登录的用户。
第三个应用是 logout ,运行它之后,用户便退出系统。再访问的时候,又需要重新登录了。请读者再制裁执行完 logout 之后,重新验证一下前两个应用的 SSO :先运行第二个应用,再运行第一个,会看到相同的效果。
我们的样例并没有在这里停步,事实上,本样例不仅能够和在几个 Java 应用之间 SSO ,还能和浏览器进行 SSO ,也就是将浏览器也当成是桌面的一部分。这对一些行业有着不小的吸引力。
这时候再打开 Mozilla 浏览器,访问以前提到的那两个 WEB 应用,会发现只要桌面应用如果登录过, Web 应用就不用再登录了,而且能显示刚才登录的用户的信息。读者可以在几个桌面和 Web 应用之间进行登录和 logout 的试验,看看它们之间的 SSO
6.3 桌面样例的源码分析
桌面 SSO 的样例使用了 JAAS (要了解 JAAS 的详细的信息请参考 http://java.sun.com/products/jaas )。 JAAS 是对 PAM Pluggable Authentication Module )的 Java 实现,来完成  Java 应用可插拔的安全认证模块。使用 JAAS 作为 Java 应用的安全认证模块有很多好处,最主要的是不需要修改源代码就可以更换认证方式。例如原有的 Java 应用如果使用 JAAS 的认证,如果需要应用 SSO ,只需要修改 JAAS 的配置文件就行了。现在在流行的 J2EE 和其他  Java 的产品中,用户的身份认证都是通过 JAAS 来完成的。在样例中,我们就展示了这个功能。请看配置文件 login.conf

 

   DesktopSSO { 
   desktopsso.share.PasswordLoginModule required; 
   desktopsso.share.DesktopSSOLoginModule required; 
};
 

 

当我们注解掉第二个模块的时候,只有第一个模块起作用。在这个模块的作用下,只有 test 用户(密码是 12345 )才能登录。当我们注解掉第一个模块的时候,只有第二个模块起作用,桌面 SSO 才会起作用。  

 

所有的 Java 桌面样例程序都是标准 JAAS 应用,熟悉 JAAS 的程序员会很快了解。 JAAS 中主要的是登录模块( LoginModule )。下面是 SSO 登录模块的源码:
 public class DesktopSSOLoginModule implements LoginModule { 
   .......... 
   private String SSOServiceURL = ""; 
   private String SSOLoginPage = ""; 
   private static String cookiefilepath = "";   
   .........  
 
config.properties 的文件中,我们配置了它们的值:
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 
  SSOServiceURL SSOLoginPage 成员变量指向了在 Web-SSO 中用过的身份认证模块: SSOAuth ,这就说明在桌面系统中我们试图和 Web 应用共用一个认证服务。而 cookiefilepath 成员变量则泄露了一个“天机”:我们使用了 Mozilla 浏览器的 cookie 文件来保存登录的凭证。换句话说,和 Mozilla 共用了一个保存登录凭证的机制。之所以用 Mozilla 是应为它的 Cookie 文件格式简单,很容易编程访问和修改任意的 Cookie 值。(我试图解析 Internet Explorer cookie 文件但没有成功。)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值