编写你自己的单点登录二(SSO)服务

6 桌面 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)
    当前桌面需要运行 Mozilla Netscape 浏览器,因为我们将 ticket 保存到 mozilla cookie 文件中
    c)
    必须在 JDK1.4 以上运行。( WEB-SSO 需要 JDK1.5 以上)
  2. 解开 desktopsso.zip 文件,里面有两个目录 bin lib
  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 的程序,提示需要输入用户名和密码:
编写你自己的单点登录二(SSO)服务
效验成功以后,便会显示当前登录的用户的基本信息等等。
编写你自己的单点登录二(SSO)服务
  这时候再运行第二个桌面 Java 应用( mailSystem )的时候,就不需要再登录了,直接就显示出来刚才登录的用户。
编写你自己的单点登录二(SSO)服务
第三个应用是 logout ,运行它之后,用户便退出系统。再访问的时候,又需要重新登录了。请读者再制裁执行完 logout 之后,重新验证一下前两个应用的 SSO :先运行第二个应用,再运行第一个,会看到相同的效果。
我们的样例并没有在这里停步,事实上,本样例不仅能够和在几个 Java 应用之间 SSO ,还能和浏览器进行 SSO ,也就是将浏览器也当成是桌面的一部分。这对一些行业有着不小的吸引力。
这时候再打开 Mozilla 浏览器,访问以前提到的那两个 WEB 应用,会发现只要桌面应用如果登录过, Web 应用就不用再登录了,而且能显示刚才登录的用户的信息。读者可以在几个桌面和 Web 应用之间进行登录和 logout 的试验,看看它们之间的 SSO
编写你自己的单点登录二(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 文件但没有成功。)
下面是登录模块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 的产品,在功能上、性能上和安全上都必须有更加完备的考虑。
作者简介
王昱是 Sun 中国工程研究院的 Java 工程师,现在的主要负责全球合作伙伴的技术支持。作为一名 Java 资深工程师和架构师,王昱在 Java 的很多领域都有多年的造诣,特别是在 Java 虚拟机、 J2EE 技术 ( 包括 EJB, JSP/Servlet, JMS Web services 等技术 ) 、集群技术和 Java 应用性能调优上有着较为丰富的经验。曾经多次在重要的 Java 会议发表演讲,并在国际著名的 Java 技术站 点发表文章。
 
资源链接

你可能感兴趣的:(应用服务器,Web,网络应用,SSO,sun)