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

    下面是登录模块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/
    真正安全的全方位 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 的包。
     
    总结
    本文的主要目的是阐述 SSO 的基本原理,并提供了一种实现的方式。通过对源代码的分析来掌握开发 SSO 服务的技术要点和充分理解 SSO 的应用范围。但是,本文仅仅说明了身份认证的服务,而另外一个和身份认证密不可分的服务 ---- 权限效验,却没有提到。要开发出真正的 SSO 的产品,在功能上、性能上和安全上都必须有更加完备的考虑。
     
    资源链接


猜你喜欢

转载自cn-done.iteye.com/blog/1061283