EOS与开源单点登录产品cas集成指南

日期: 2008-10-09 作者:majs 来源:TechTarget中国 英文

  介绍cas sso产品的原理、安装、调试和与EOS应用的集成

  1 总体解决方案

  1.1 单点登录概述

  单点登录的英文名称为Single Sign-On,简写为SSO,它是一个用户认证的过程,允许用户一次性进行认证之后,就访问系统中不同的应用;而不需要访问每个应用时,都重新输入密码。IBM对SSO有一个形象的解释“单点登录、全网漫游”。
 
  SSO将一个企业内部所有域中的用户登录和用户帐号管理集中到一起,SSO的好处显而易见:
 
  1. 减少用户在不同系统中登录耗费的时间,减少用户登录出错的可能性
  2. 实现安全的同时避免了处理和保存多套系统用户的认证信息
  3. 减少了系统管理员增加、删除用户和修改用户权限的时间
  4. 增加了安全性:系统管理员有了更好的方法管理用户,包括可以通过直接禁止和删除用户来取消该用户对所有系统资源的访问权限
 
  对于内部有多种应用系统的企业来说,单点登录的效果是十分明显的。很多国际上的企业已经将单点登录作为系统设计的基本功能之一

  1.2 单点登录产品

  商业sso软件

  专门的SSO商业软件

  主要有:Netgrity的Siteminder,已经被CA收购。Novell 公司的iChain。RSA公司的ClearTrust等。

  门户产品供应商自己的SSO产品,如:BEA的WLES,IBM 的Tivoli Access Manager,Sun 公司的identity Server,Oracle公司的OID等。
 
  上述商业软件一般适用于客户对SSO的需求很高,并且企业内部采用Domino、SAP、Sieble等系统比较多的情况下。单点登录产品通常需要在应用软件中增加代理模块,而商业SSO产品主要针对大型软件制作了代码模块。

  因此,商业SSO软件除了价格问题外,另一个重要问题就是对客户自己的应用系统支持未必十分完善。

  开源sso软件

  l  Opensso

  n  https://opensso.dev.java.net/

  n  OpenSSO基于Sun Java System Access Manager,是Sun公司支持的一个开源的SSO项目。

  n  OpenSSO体系结构设计合理,功能比较强大。然而缺点是客户端支持不够广泛,似乎只是对基于J2EE的应用支持的比较好。

  l  josso

  n  http://www.josso.org/

  n  这是另一个Java写的单点登录产品,通常认为比OpenSSO更成熟一些。

  n  JOSSO支持的客户端包括Java,PHP和ASP。

  l  CAS

  n  http://www.ja-sig.org/products/cas/

  n  这是耶鲁大学开发的单点登录产品,也是我们最后选定的单点登录产品。

  n  CAS的优点很多,例如设计理念先进、体系结构合理、配置简单、客户端支持广泛、技术成熟等等。以后我们还要仔细介绍。

  经过广泛分析和比较,最后我们选定CAS作为我们的单点登录产品。我们确信这是目前能够找到的最好的开源单点登录产品

  1.3  单点登录实现机制

  SSO的实现机制不尽相同,大体分为Cookie机制和Session机制两大类。

  WebLogic通过Session共享认证信息。Session是一种服务器端机制,当客户端访问服务器时,服务器为客户端创建一个惟一的SessionID,以使在整个交互过程中始终保持状态,而交互的信息则可由应用自行指定,因此用Session方式实现SSO,不能在多个浏览器之间实现单点登录,但却可以跨域。

  WebSphere通过Cookie记录认证信息。Cookie是一种客户端机制,它存储的内容主要包括: 名字、值、过期时间、路径和域,路径与域合在一起就构成了Cookie的作用范围,因此用Cookie方式可实现SSO,但域名必须相同。

  目前大部分SSO产品采用的是Cookie机制,CAS也是如此。
 
  注意,这种机制要求实现单点登录的应用,其域名必须是相同的。例如:a.chinacreator.com,b.chinacreator.com就可以经过配置后实现SSO。
 
  以CAS为例,使用Cookie实现单点登录的原理图如图1所示。
 
  l  首先,单点登录分为“服务端”和“客户端”。服务端就是单点登录服务器,而客户端通常是“函数库”或者“插件”。需要使用单点登录的应用程序,需要把客户端插件安装到自己的系统中,或者将客户端函数库包括在代码中。单点登录的客户端通常替换了原来应用程序的认证部分的代码。

  l  某个应用程序首先要发起第1次认证。大部分情况下,应用程序中嵌入的客户端会把应用程序原来的登录画面屏蔽掉,而直接转到单点登录服务器的登录页面。

  CAS 基础模式

  上图是一个最基础的 CAS 协议, CAS Client 以 Filter 方式保护 Web 应用的受保护资源,过滤从客户端过来的每一个 Web 请求,同时, CAS Client 会分析 HTTP 请求中是否包请求 Service Ticket( 上图中的 Ticket) ,如果没有,则说明该用户是没有经过认证的,于是, CAS Client 会重定向用户请求到 CAS Server ( Step 2 )。 Step 3 是用户认证过程,如果用户提供了正确的 Credentials , CAS Server 会产生一个随机的 Service Ticket ,然后,缓存该 Ticket ,并且重定向用户到 CAS Client (附带刚才产生的 Service Ticket ), Service Ticket 是不可以伪造的,最后, Step 5 和 Step6 是 CAS Client 和 CAS Server 之间完成了一个对用户的身份核实,用 Ticket 查到 Username ,因为 Ticket 是 CAS Server 产生的,因此,所以 CAS Server 的判断是毋庸置疑的。

  该协议完成了一个很简单的任务,就是 User(david.turing) 打开 IE ,直接访问 helloservice 应用,它被立即重定向到 CAS Server 进行认证, User 可能感觉到浏览器在 helloservcie 和 casserver 之间重定向,但 User 是看不到, CAS Client 和 CAS Server 相互间的 Service Ticket 核实 (Validation) 过程。当 CAS Server 告知 CAS Client 用户 Service Ticket 对应确凿身份, CAS Client 才会对当前 Request 的用户进行服务。

  CAS 如何实现 SSO

  当我们的 Web 时代还处于初级阶段的时候, SSO 是通过共享 cookies 来实现,比如,下面三个域名要做 SSO :

  http://www.blogjava.net
  http://www.matrix.org.cn
  http://www.csdn.net

  如果通过 CAS 来集成这三个应用,那么,这三个域名都要做一些域名映射,
  http://blogjava.cas.org
  http://matrix.cas.org
  http://csdn.cas.org

  因为是同一个域,所以每个站点都能够共享基于 cas.org 的 cookies 。这种方法原始,不灵活而且有不少安全隐患,已经被抛弃了。

  CAS 可以很简单的实现跨域的 SSO ,因为,单点被控制在 CAS Server ,用户最有价值的 TGC-Cookie 只是跟 CAS Server 相关, CAS Server 就只有一个,因此,解决了 cookies 不能跨域的问题。

  回到 CAS 的基础协议图,当 Step3 完成之后, CAS Server 会向 User 发送一个 Ticket granting cookie (TGC) 给 User 的浏览器,这个 Cookie 就类似 Kerberos 的 TGT ,下次当用户被 Helloservice2 重定向到 CAS Server 的时候, CAS Server 会主动 Get 到这个 TGC cookie ,然后做下面的事情:

  1, 如果 User 的持有 TGC 且其还没失效,那么就走基础协议图的 Step4 ,达到了 SSO 的效果。

  2, 如果 TGC 失效,那么用户还是要重新认证 ( 走基础协议图的 Step3) 。

  1.5.3   CAS 的代理模式

  模式 1 已经能够满足大部分简单的 SSO 应用,现在,我们探讨一种更复杂的情况,即用户访问 helloservice , helloservice 又依赖于 helloservice2 来获取一些信息,如同:

  User à helloservice à helloservice2

  这种情况下,假设 helloservice2 也是需要对 User 进行身份验证才能访问,那么,为了不影响用户体验(过多的重定向导致 User 的 IE 窗口不停地 闪动 ) , CAS 引入了一种 Proxy 认证机制,即 CAS Client 可以代理用户去访问其它 Web 应用。

  代理的前提是需要 CAS Client 拥有用户的身份信息 ( 类似凭据 ) 。 与其说之前我们提到的 TGC 是用户持有对自己身份信息的一种凭据,则这里的 PGT 就是 CAS Client 端持有的对用户身份信息的一种凭据。凭借 TGC , User 可以免去输入密码以获取访问其它服务的 Service Ticket ,所以,这里,凭借 PGT , Web 应用可以代理用户去实现后端的认证,而无需前端用户的参与。

  如下面的 CAS Proxy 图所示, CAS Client 在基础协议之上,提供了一个额外的 PGT URL 给 CAS Server, 于是, CAS Server 可以通过 PGT URL 提供一个 PGT 给 CAS Client 。
      
  初学者可能会对上图的 PGT URL 感到迷惑,或者会问,为什么要这么麻烦,要通过一个额外的 URL( 而且是 SSL 的入口 ) 去传递 PGT ?如果直接在 Step 6 返回,则连用来做对应关系的 PGTIOU 都可以省掉。 PGTIOU 设计是从安全性考虑的,非常必要, CAS 协议安全性问题我会在后面一节介绍。

  于是, CAS Client 拿到了 PGT( PGTIOU-85…..ti2td ) ,这个 PGT 跟 TGC 同样地关键, CAS Client 可以通过 PGT 向后端 Web 应用进行认证。如下图所示, Proxy 认证与普通的认证其实差别不大, Step1, 2 与基础模式的 Step 1,2 几乎一样,唯一不同的是, Proxy 模式用的是 PGT 而不是 TGC ,是 Proxy Ticket ( PT )而不是 Service Ticket 。

  最终的结果是, helloservice2 明白 helloservice 所代理的客户是 David. Turing 同学,同时,根据本地策略, helloservice2 有义务为 PGTURL=http://helloservice/proxy 服务 (PGTURL 用于表示一个 Proxy 服务 ) ,于是它传递数据给 helloservice 。这样, helloservice 便完成一个代理者的角色,协助 User 返回他想要的数据。

  代理认证模式非常有用,它也是 CAS 协议 v2 的一个最大的变化,这种模式非常适合在复杂的业务领域中应用 SSO 。因为,以前我们实施 SSO 的时候,都是假定以 IE User 为 SSO 的访问者,忽视了业务系统作为 SSO 的访问者角色

  1.6    CAS安全性

  CAS 的安全性是一个非常重要的 Topic 。 CAS 从 v1 到 v3 ,都很依赖于 SSL ,它假定了这样一个事实,用户在一个非常不安全的网络环境中使用 SSO , Hacker 的 Sniffer 会很容易抓住所有的 Http Traffic ,包括通过 Http 传送的密码甚至 Ticket 票据

  1.7    CAS环境的搭建

  访问http://www.ja-sig.org/products/cas/downloads/index.html下载CAS的最新版本

  目前的版本是CAS Server 3.0.7 Final (stable),解压下载的zip文件。查看文件cas-server-3.0.7/webapp/WEB-INF文件夹,编辑deployerConfigContext.xml文件。这个文件是用来配置CAS的认证方式的,默认的方式是CAS自己写的演示代码,查看最后一行配置:

  <bean
         class=”org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler” />
 
  这个默认的认证类描述了,只要在认证界面输入的用户名和密码一致就算通过了验证。对这个类可以进行客户化或替换。比如CAS提供了进行LDAP(org.jasig.cas.adaptors.ldap. BindLdapAuthenticationHandler)或基于数据库验证(org.jasig.cas.adaptors.jdbc. QueryDatabaseAuthenticationHandler)等 具体参见cas-server-3.0.7/adaptors

  Tomcat5 和SSL的安装

  下载tomcat5并进行安装,安装后修改%CATALINA_HOME%/conf/server.xml文件内容:

  将

  <Connector port=”8443″
               maxThreads=”150″ minSpareThreads=”25″ maxSpareThreads=”75″

               enableLookups=”false” disableUploadTimeout=”true”

               acceptCount=”100″ debug=”0″ scheme=”https” secure=”true”

               clientAuth=”false” sslProtocol=”TLS” />

  这个语句前后的注释去掉,这样就设置了tomcat支持SSL连接
 
  证书的制作
  执行如下命令:
  %JAVA_HOME%/bin/keytool -genkey -alias tomcat -keyalg RSA -validity 365

  第1步操作用于删除原来的SSL文件(如果有的话)。第2步操作用于生成一个新的证书,最后的365代表证书有效的时间。

  输入第2步的指令后,会提示很多问题:

  首先要求输入密码,目前密码是changeit,这是SSL证书默认的密码。

  随后要求输入“公用名”。注意这个参数是很重要的,公用名应该和您的服务器网站的名称一致。对于内部网络,可以使用IP地址。例如我们就使用localhost。

  随后要求输入证书的“组织单位”和“组织”,这个输入您的公司名称或者其他什么的,都可以。

  随后输入“城市”、“省”、“国家”。国家输入的是代码,中国是cn。

  最后列出您输入的信息,并要求确认。输入“y”。

  例如我们输入的信息是:CN=192.168.1.6, OU=newchoice, O=newchoice, L=Beijing, ST=Beijing, C=cn correct?

  最后输入回车,确认密码。

  这样就创建了一个证书。此时,在Documents and SettingsAdministrator下面,生成一个.keystore文件,这个文件就是证书文件。

  %JAVA_HOME%/bin/keytool -export -alias tomcat -keypass changeit -file server.crt

  最后一个参数是文件名

  JVM证书的导入

  执行如下命令进行JVM证书导入:

  keytool –import –keystore $JAVA_HOMEjrelibsecuritycacerts
–file server.crt –alias tomcat
 
  如果报错信息是已经存在tomcat证书,就执行:

  keytool –delete –keystore $JAVA_HOMEjrelibsecuritycacerts
–file server.crt –alias tomcat

  然后再执行导入命令
 
  启动tomcat server,输入 https://localhost:8433后出现界面

  如果是IE的话,首先会弹出一个对话框,提示你证书不是由信任的机构颁发的。这个是很自然的,因为证书是自己生成的。

  单击“查看证书”,单击“安装证书”,在向导种选择“将所有的证书放在下面存储区”,然后单击“浏览”,选择“受信任的根证书颁发机构”。单击确定安装证书。这样IE以后就会认为证书是由受信任的机构颁发的。

  如果不想安装,也可以直接在对话框中单击“是”

  表示tomcat ssl 配置成功。
  部署CAS SERVER
  拷贝cas-server-3.0.7/ target/ cas.war到%CATALINA_HOME%/webapps下,然后启动tomcat

  在浏览器中,输入https://localhost:8443/cas/login,进入CAS的登录画面,如图所示。注意这个登录画面是重新定制过的,并不是原始的CAS登录画面。

  输入用户名和密码,例如user:123456。这里的用户名和密码,就是在3.2节LDAP中输入的用户名和密码。单击“登录”按钮,此时应该提示“登录成功”。这就表明CAS安装成功

  1.8    CAS client的使用

  访问http://www.ja-sig.org/products/cas/downloads/index.html 可以下载到yale java Client的2.1.1版本

  其实CAS client提供给了我们多种方式去实现SSO。这里我们用比较简单的方式去实现SSO。首先我们看CAS client的提供给我们使用的HTTP Filter:
<web-app>
 …
 <filter>
 <filter-name>CAS Filter</filter-name>
 <filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>
    <init-param>
       <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
       <param-value>https://secure.its.yale.edu/cas/login</param-value>
    </init-param>
    <init-param>
       <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
       <param-value>https://secure.its.yale.edu/cas/serviceValidate</param-value>
    </init-param>
    <init-param>
       <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>
       <param-value>your server name and port (e.g., www.yale.edu:8080)</param-value>
    </init-param>
 </filter>
 
 <filter-mapping>
    <filter-name>CAS Filter</filter-name>
    <url-pattern>/requires-cas-authetication/*</url-pattern>
 </filter-mapping>
 …
 </web-app>
 
  Eos应用的改造

  导入CAS client提供的casclient.jar

  导入CAS client提供的源码,将其拷贝到EOS工程的web模块/WEB-INFO/src下,进行编译

  编辑edu.yale.its.tp.cas.client.filter.CASFilter文件,拷贝以下代码到CASFilter文件的400行出,fc.doFilter(request, response); 之前
        // continue processing the request   

        session.removeAttribute(WebDriver.SESSION_CONTEXT);

        session.removeAttribute(“FILTER_EOS_USER_REGISTED”);
       
        //生成新的sessionContext
        SessionContext sessionContext = new SessionContext();
        sessionContext.setUserID(receipt.getUserName());

        sessionContext.setUserRemoteAddr(request.getRemoteAddr());

        sessionContext.setUploadRoot(WebDriverUpload.getUploadRoot());

        sessionContext.setHttpSessionId(session.getId());


        String xmlData = “<?xml version=”1.0″ encoding=”GB2312″ ?><root><data>”;

        xmlData += “<EOSOperator><userID>”+receipt.getUserName()+”</userID></EOSOperator>”;

        xmlData += “<SessionEntity><userID>”+receipt.getUserName()+”</userID><isCas>1</isCas><EOSOperator><userID>”+receipt.getUserName()+”</userID></EOSOperator></SessionEntity>”;

        xmlData += “</data></root>”;


        try{

            Document dom = XmlUtil.parseString(xmlData);
 
         //取得SessionEntity

         Node SessionEntity = XPathAPI.selectSingleNode(dom.getDocumentElement(),”/root/data/SessionEntity”);

         //将SessionEntity放到SessionContext中

         sessionContext.setEntity(SessionEntity);

            session.setAttribute(SessionContext.SESSION_SESSION_CONTEXT, sessionContext);

        }catch(Exception e){

        e.printStackTrace();

        }

  fc.doFilter(request, response);
 
  改造展现逻辑fbrole.proper.login,在调用业务逻辑前,添加一个数据设置构件

  修改业务逻辑fbrole.bizopr.login,如下

  修改web.xml配置,添加filter 如下:(放在fbframefilter配置之前)
<filter>
            <filter-name>CAS Filter</filter-name>

               <filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>
                  <init-param>
                          <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
                             <param-value>https://localhost:8443/cas/login</param-value>   
                      </init-param>   
                      <init-param>
                         <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
                             <param-value>https://localhost:8443/cas/serviceValidate</param-value>
                      </init-param>
                      <init-param>     
                          <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>

                          <param-value>localhost:8090</param-value>

                      </init-param>
       </filter>
      
      
        <filter-mapping>   
            <filter-name>CAS Filter</filter-name>   

            <url-pattern>/index.jsp</url-pattern>

        </filter-mapping>
        <filter-mapping>   
            <filter-name>CAS Filter</filter-name>   

            <url-pattern>/fbrole.proper.login.do</url-pattern>

        </filter-mapping>

  d
  进行测试

  启动三个app

  在app1上有个测试页面index.jsp,内容如下:
<%
       String context = request.getContextPath();

%>
<html>
<body>
  【<a href=”#” onclick=”entrysys(“<%=context%>/fbrole.proper.login.do”)”>进入系统1</a>】<br>

  【<a href=”#” onclick=”entrysys(“http://localhost:8090/fbrole.proper.login.do”)”>进入系统2</a>】<br>

</body>
</html>

  访问地址http://localhost:8090/index.jsp

  点击是,进入验证界面

  输入 sysadmin/sysadmin,进入app1

  点击【进入系统1】后,不需进行系统登录,而是直接进入系统首页

  同样,在点击【进入系统2】也是不需要系统登录,而是直接进入了app2的首页

  以上过程就实现了单点登录

  3、3

  注意事项

  如果在进行测试过程中出现类型以下异常:
  edu.yale.its.tp.cas.client.CASAuthenticationException: Unable to validate ProxyTicketValidator
  [[edu.yale.its.tp.cas.client.ProxyTicketValidator proxyList = [ null ]
  [edu.yale.its.tp.cas.client.ServiceTicketValidator casValidateUrl =
  [https: // sourcesite:8443/cas/proxyValidate] ticket=[ST-0-UMjsI0YOhF15RhutnkHW]
  service=[http%3A%2F%2Fdestsite%3A8080%2Fservlets-examples%2Fservlet%

  2FHelloWorldExample] renew=false]]]

  则说明,是证书出现了问题,按以下方面检查

  请确认证书是否用localhost来制作

  JVM证书是否做了导入

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

作者

majs
majs

相关推荐