SSO单点登录之CAS-Server

Prerequisites


  • CAS Server 3.5.x.,下文以$CAS-SERVER表示。
  • CAS Client 3.3.x.,下文以$CAS-CLIENT表示。
  • Tomcat 7.x,下文以$CAS_TOMCAT_HOME表示。
  • GateIn-3.8.1.Final-tomcat-7,下文以$GATEIN_HOME表示。

最近公司需要对之前的多个Web应用系统进行整合,希望用户在登录某个应用系统时,能直接访问其他的Web应用系统,且不需要再次登录。既我们经常说的单点登录,最后,我选择了CAS,并将其整合进了GateIn portal。接下来,将整理一下原理和整合步骤。
所有项目代码示例可在github上下载。

CAS介绍


CAS(Central Authentication Service)是Yale大学发起的一个开源项目,旨在为Web应用系统提供一种可靠的单点登录。单点登录,既在多个应用系统中,用户只需登录一次就可以访问所有相互信任的应用系统。CAS Client支持非常多的客户端,包括JAVA、PHP、Ruby等。

接下来,接介绍一下CAS系统。

CAS 系统组成


CAS系统架构由两部分组成,CAS ServerCAS Clients,两者可以通过多种协议进行通信。

CAS Server


CAS Server是一个构建在Spring Framework上的Java servlet,通过分配和诊断tickets,负责认证用户以及授权。

CAS Clients


CAS Clients负责对用户的认证工作,CAS Clients负责处理对客户端受保护资源的访问请求,需要登录时,重定向到CAS Server

CAS Clients与受保护的客户端应用部署在一起,以Filter方式保护受保护的资源。

CAS协议流程


CAS协议流程如下图所示,展示了用户同时访问多个应用系统的流程。多个应用系统能实现单点登录的基本流程为,当用户首次访问需要登录才能访问的页面时,会自动重定向到CAS Server的登陆页面,成功认证完后,会在CAS Server的域中设置CASTGCCookie,最终登陆完成后,服务器会创建一个session会话,用于之后与应用系统的交互。当用户同时再登陆另外一个应用系统时,同样会跟之前一样,重定向到CAS Server的登陆页面,区别是此时已经有了CAS Server域中的CASTGC,重定向时会附带该CookieCAS Server验证之后返回一个ticket,之后浏览器重新请求原访问页面,并附带ticket参数,CAS Server诊断有效后,返回原应用系统的重定向,且设置该域的session Cookie,浏览器最后请求原页面,并附带session Cookei,应用系统诊断后返回请求内容。

需要注意的是,当成功登陆完某个系统后,如果继续再访问该系统的其他资源页面,是不需要再次与CAS Server进行交互的,应用系统将根据session直接进行诊断。

GateIn Portal集成CAS Server


部署CAS


  1. 打开$CAS_TOMCAT_HOME/webapps/$CAS-SERVER/WEB-INF/deployerConfigContext.xml,替换:
    1
    <bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
    为如下:
    1
    2
    3
    4
    5
    6
    7
    <bean class="org.gatein.sso.cas.plugin.AuthenticationPlugin">
    <property name="gateInProtocol"><value>http</value></property>
    <property name="gateInHost"><value>localhost</value></property>
    <property name="gateInPort"><value>8080</value></property>
    <property name="gateInContext"><value>portal</value></property>
    <property name="httpMethod"><value>POST</value></property>
    </bean>
    如上所示,用来配置GateIn Portal的服务地址。
  2. 下载GateIn SSO package下载地址,解压后,将其cas/plugin/WEB-INF/lib下的jar包拷贝到$CAS_TOMCAT_HOME/webapps/$CAS-SERVER/WEB-INF/lib目录。
  3. 默认,登出用户时CAS Server会展示一个CAS提供的登出页面,然后跳转回Portal页,如果想要保留原有Portal的登出,打开$CAS_TOMCAT_HOME/webapps/$CAS-SERVER/WEB-INF/cas-servlet.xml,添加followServiceRedirects="true"参数:
    1
    2
    3
    4
    5
    6
     <bean id="logoutController"  class="org.jasig.cas.web.LogoutController"
    p:centralAuthenticationService-ref="centralAuthenticationService"
    p:logoutView="casLogoutView"
    p:warnCookieGenerator-ref="warnCookieGenerator"
    p:ticketGrantingTicketCookieGenerator-ref="ticketGrantingTicketCookieGenerator"
    p:followServiceRedirects="true"/>

部署GateIn Portal


  1. 为了能让Portal使用CAS Server提供的单点登陆系统,首先配置PortalSSO参数,在$GATEIN_HOME/gatein/conf/configuration.properties文件中,修改和添加如下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    gatein.sso.enabled=true
    gatein.sso.callback.enabled=${gatein.sso.enabled}
    gatein.sso.login.module.enabled=${gatein.sso.enabled}
    gatein.sso.login.module.class=org.gatein.sso.agent.login.SSOLoginModule
    gatein.sso.server.url=http://localhost:8086/cas-server
    gatein.sso.portal.url=http://localhost:8080
    gatein.sso.filter.logout.class=org.gatein.sso.agent.filter.CASLogoutFilter
    gatein.sso.filter.logout.url=${gatein.sso.server.url}/logout
    gatein.sso.filter.login.sso.url=${gatein.sso.server.url}/login?service=${gatein.sso.portal.url}/@@portal.container.name@@/initiatessologin

    如上,为配置CAS Server的服务器信息等。

  2. 如果需要改变账户系统的存储方式, 比如改为MySQL数据库,还需要在$GATEIN_HOME/gatein/conf/configuration.properties文件中修改成如下所示,同时,下载mysql-connect-java.jar``jar包,放入$GATEIN_HOME/lib目录下。

    1
    2
    3
    4
    5
    gatein.idm.datasource.name=jdbcidm
    gatein.idm.datasource.driver=com.mysql.jdbc.Driver
    gatein.idm.datasource.url=jdbc:mysql://localhost:3306/jdbcidm_${name}
    gatein.idm.datasource.username=root
    gatein.idm.datasource.password=123

    $GATEIN_HOME/conf/server.xml<GlobalNamingResources></GlobalNamingResources>节点中声明绑定的数据源,添加如下,字段含义可参考该文,注意,数据库名必须为jdbcidm_portal,且需要提前手动创建,无法自动创建,但是GateIn Portal会自动创建用户相关表:

    1
    <Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" logAbandoned="true" maxActive="20" maxIdle="10" maxWait="10000" minEvictableIdleTimeMillis="60000" name="exo-idm_portal" password="123" removeAbandoned="true" removeAbandonedTimeout="10" type="javax.sql.DataSource" url="jdbc:mysql://localhost:3306/jdbcidm_portal" username="root"/>

    GateIn PortalCAS整合后,账户系统将由GateIn Portal接管,也就是说,如果GateIn Portal服务没有开启,则CAS Server将无法进行认证。

  3. $GATEIN_HOME/conf/server.xmlHost元素下添加ServletAccessValve,如:

    1
    2
    3
    4
    5
    6
    7
    <Host name="localhost" appBase="webapps"
    unpackWARs="true" autoDeploy="true">

    <Valve className="org.gatein.sso.agent.tomcat.ServletAccessValve" />

    <!-- SingleSignOn valve, share authentication between web applications
    ...

    其目的是开启SSO组件,将其加入Catalina容器的请求处理管道中,这样,SSO组件将有机会处理每一个Request请求。

修改portal项目根路径


GateIn portal项目的默认网址格式为:{ip}:{port}/portal/*,如果我们想把根路径的portal改成其他的,如ots-portal,并不能简单的像其他Tomcat``webapp一样,直接修改目录名即可,因为portal有多个应用依赖,且portal关键字还作为容器名等在整个生命周期中起作用,最终经过大量分析测试,实现了更名,接下来,将总结修改的配置文件:

  • $GATEIN_HOME/conf/jaas.conf
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
      gatein-domain {
    org.exoplatform.web.login.FilterDisabledLoginModule required
    portalContainerName=ots-portal
    realmName=gatein-domain;
    org.gatein.security.oauth.jaas.OAuthLoginModule required
    portalContainerName=ots-portal
    realmName=gatein-domain;
    org.gatein.sso.integration.SSODelegateLoginModule required
    enabled="#{gatein.sso.login.module.enabled}"
    delegateClassName="#{gatein.sso.login.module.class}"
    portalContainerName=ots-portal
    realmName=gatein-domain
    password-stacking=useFirstPass;
    org.exoplatform.services.security.j2ee.TomcatLoginModule required
    portalContainerName=ots-portal
    realmName=gatein-domain;
    };
  • $GATEIN_HOME/gatein/conf/configuration.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <object-param>
    <name>portal</name>
    <object type="org.exoplatform.container.definition.PortalContainerDefinition">
    <!-- The name of the portal container -->
    <field name="name">
    <string>ots-portal</string>
    </field>
    <!-- The name of the context name of the rest web application -->
    <field name="restContextName">
    <string>rest</string>
    </field>
    <!-- The name of the realm -->
    <field name="realmName">
    <string>gatein-domain</string>
    </field>
    </object>
    </object-param>
  • $GATEIN_HOME/webapps/ots-portal/WEB-INF/web.xml
    1
    2
    3
    4
    5
    <display-name>ots-portal</display-name>
    <context-param>
    <param-name>org.exoplatform.frameworks.jcr.command.web.fckeditor.digitalAssetsWorkspace</param-name>
    <param-value>ots-portal</param-value>
    </context-param>
  • $GATEIN_HOME/webapps/ROOT/index.jsp
    1
    2
    3
    4
    <%
    response.setStatus(response.SC_MOVED_TEMPORARILY);
    response.setHeader("Location", "/ots-portal");
    %>
  • 最后,当然同样需要将portal目录名改为ots-portal

如上修改之后,就可以通过网址{ip}:{port}/ots-portal/*来进行访问了。

注意点


更改根目录之后,其认证相关信息存储的库名将由jdbcidm_portal变为jdbcidm_ots-portal

参考