cas server 实现LDAP、数据库认证

懵懂的女人 提交于 2020-04-07 08:55:45

cas server(4.2.7) + client相关的配置 

  1. 支持数据库验证用户
  2. 支持LDAP验证用户(LDAP相关安装请相见:https://blog.csdn.net/u011196623/article/details/82502570)

cas server 端 数据库验证

  • 支持数据库验证用户,在deployerConfigContext.xml中配置
<!--数据库认证 开始-->
    <alias name="personDirectoryPrincipalResolver" alias="primaryPrincipalResolver" />
      <bean id="myauthhandler" class="org.jasig.cas.jdbc.hander.JdbcUsernamePasswordAuthHandlerImpl">
               <property name="dataSource" ref="dataSource" /><!--指定数据源-->
               <!--设置加密方式,这里要看数据库中存储的密码的加密方式是什么,要配置相应的加密器-->
               <property ref="MyPasswordEncoder" name="passwordEncoder"></property>
               <!--<property name="maxFailureTimes" value="3" /> -->
               <!-- 这里对应JdbcUsernamePasswordAuthHandlerImpl类里的maxFailureTimes属性 -->
        </bean>
      <bean id="dataSource"  class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiName" value="java:/comp/env/DBSERVER" />
                   <property name="lookupOnStartup" value="true"/>
                   <property name="resourceRef" value="false" />
           </bean>
           <bean id="MyPasswordEncoder" class="org.jasig.cas.authentication.handler.MyPasswordEncoder"></bean>
    <!--数据库认证 结束->

    
     <util:map id="authenticationHandlersResolvers">
       <!-- proxyPrincipalResolver对应的类为BasicPrincipalResolver
       proxyAuthenticationHandler对应的类 HttpBasedServiceCredentialsAuthenticationHandler
       primaryPrincipalResolver对应的类为personDirectoryPrincipalResolver -->
        <entry key-ref="myauthhandler" value-ref="proxyPrincipalResolver" />
        <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
        <entry key-ref="ldapAuthHandler" value-ref="proxyPrincipalResolver" /> <!--新增ldap认证的入口 -->
        <!--primaryAuthenticationHandler为类QueryDatabaseAuthenticationHandler,primaryPrincipalResolver为类 PersonDirectoryPrincipalResolver  <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> -->
    </util:map>

  • 重写JdbcUsernamePasswordAuthHandlerImpl实现自定义的功能,例如账号密码错误多少次后账号封停等。
  • 生成证书 在 sso-cas-server-client\cas-server\webapps\cas\tools\gen-cer-store.sh下面由对应的示例
HOST_NAME=`hostname` // 需要与cas client中的cas.properties的casserver.hostname一直
SERVER_DN="CN=sso, OU=Linkage, O=Linkage, L=Nanjing, S=Jiangsu, C=CN"
KS_PASS="-storepass changeit"
KEYINFO="-keyalg RSA"
LIB_PATH="/home/soft/jdk/jre/lib/security/cacerts"

keytool -genkey -alias casserver -dname "$SERVER_DN" $KS_PASS -keystore server.keystore $KEYINFO -keypass changeit -validity 3600
keytool -export -trustcacerts -alias casserver -file server.cer $KS_PASS -keystore server.keystore
keytool -import -trustcacerts -alias casserver -file server.cer $KS_PASS -keystore  $LIB_PATH

此时会生成server.keystore和server.cer 2个证书,
server.keystore将文件复制到tomcat/conf下面,此证书放在服务端。
将server.cer文件复制到tomcat/bin下面,此证书放在客户端,然后在客户端的tomcat/bin下执行
$JAVA_HOME是jdk路径,防止意外先执行删除
keytool -delete -alias casserver -keystore "$JAVA_HOME/jre/lib/security/cacerts" -storepass changeit
在执行导入
keytool -import -alias casserver -file "server.cer" -keystore "$JAVA_HOME/jre/lib/security/cacerts" 

示例
 keytool -import -alias casserver -file "server.cer" -keystore "/home/soft/jdk/jre/lib/security/cacerts" 
  • 在服务端的tomcat的conf/server.xml 配置https,在<GlobalNamingResources>里面配置Resource ,注意此处的name ="DBSERVER" 应与deployerConfigContext.xml配置中的jndiName对应的value,java:/comp/env/DBSERVER 一致
 <Connector port="443" protocol="HTTP/1.1" SSLEnabled="true"   
        maxThreads="150" scheme="https" secure="true" 
        clientAuth="false" keystoreFile="./conf/server.keystore" keyAlias="casserver"  keystorePass="changeit"  sslProtocol="TLS" />


<Resource name="DBSERVER"                      
               type="javax.sql.DataSource"          
               driverClassName="com.mysql.jdbc.Driver"           
               url="jdbc:mysql://192.168.11.144:3306/demo?useSSL=true"                 
               username="xxx"                 
               password="xxx"              
               maxIdle="40"               
               maxWait="4000"                 
               maxActive="250"                         
               removeAbandoned="true" 
               removeAbandonedTimeout="180"
               logAbandoned="true"
               factory="org.apache.commons.dbcp.BasicDataSourceFactory" />
  • 由于生成证书是依赖与域名,gen-cer-store.sh 脚本中的 SERVER_DN="CN=sso ...", CN即是域名。那么此时需要在客户端的hosts文件中添加sso域名解析的IP
  • 在tomcat的conf/context.xml.里面添加

    <ResourceLink global=" DBSERVER " name=" DBSERVER" type="javax.sql.DataSource"/>

cas server 端 LDAP验证 

  •    在 deployerConfigContext.xml配置中 将数据库认证注释掉,然后再authenticationHandlersResolvers中配置
<util:map id="authenticationHandlersResolvers">
       <!-- proxyPrincipalResolver对应的类为BasicPrincipalResolver
       proxyAuthenticationHandler对应的类 HttpBasedServiceCredentialsAuthenticationHandler
       primaryPrincipalResolver对应的类为personDirectoryPrincipalResolver -->
       <!-- <entry key-ref="myauthhandler" value-ref="proxyPrincipalResolver" />--> <!--数据库认证-->
        <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
        <entry key-ref="ldapAuthHandler" value-ref="proxyPrincipalResolver" /> <!--新增ldap认证的入口 -->
        <!--primaryAuthenticationHandler为类QueryDatabaseAuthenticationHandler,primaryPrincipalResolver为类 PersonDirectoryPrincipalResolver  <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> -->
    </util:map>
    
    
    <!--LDAP begin-->
    <bean id="ldapAuthHandler" class="org.jasig.cas.authentication.handler.LdapAuthentication"
          p:principalIdAttribute="uid"
          c:authenticator-ref="authenticator">
        <property name="principalAttributeMap">
            <map>
                <!-- | This map provides a simple attribute resolution mechanism. | Keys
                    are LDAP attribute names, values are CAS attribute names. | Use this facility
                    instead of a PrincipalResolver if LDAP is | the only attribute source. -->
                <entry key="uid" value="username" />
                <entry key="cn" value="commonname" />
                <entry key="mail" value="mail" />
                <entry key="userPassword" value="password" />
                <!--
                <entry key="member" value="member" />
                <entry key="displayName" value="displayName" />
                  -->
            </map>
        </property>

    </bean>

    <bean id="authenticator" class="org.ldaptive.auth.Authenticator"
          c:resolver-ref="dnResolver" c:handler-ref="authHandler" />

    <bean id="dnResolver" class="org.ldaptive.auth.PooledSearchDnResolver"
          p:baseDn="${ldap.authn.baseDn}"
          p:subtreeSearch="true"
          p:allowMultipleDns="false"
          p:connectionFactory-ref="searchPooledLdapConnectionFactory"
          p:userFilter="${ldap.authn.searchFilter}" />

    <bean id="searchPooledLdapConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory"
          p:connectionPool-ref="searchConnectionPool" />

    <bean id="searchConnectionPool" parent="abstractConnectionPool"
          p:connectionFactory-ref="searchConnectionFactory" />

    <bean id="searchConnectionFactory" class="org.ldaptive.DefaultConnectionFactory"
          p:connectionConfig-ref="searchConnectionConfig" />

    <bean id="searchConnectionConfig" parent="abstractConnectionConfig"
          p:connectionInitializer-ref="bindConnectionInitializer" />

    <bean id="bindConnectionInitializer" class="org.ldaptive.BindConnectionInitializer"
          p:bindDn="${ldap.authn.managerDN}">
        <property name="bindCredential">
            <bean class="org.ldaptive.Credential" c:password="${ldap.authn.managerPassword}" />
        </property>
    </bean>

    <bean id="abstractConnectionPool"
          abstract="true"
          class="org.ldaptive.pool.BlockingConnectionPool"
          init-method="initialize"
          destroy-method="close"
          p:poolConfig-ref="ldapPoolConfig"
          p:validator-ref="searchValidator"
      />  <!--   p:pruneStrategy-ref="pruneStrategy" p:blockWaitTime="${ldap.pool.blockWaitTime}"-->

    <bean id="abstractConnectionConfig" abstract="true" class="org.ldaptive.ConnectionConfig"
          p:ldapUrl="${ldap.url}"
          p:useStartTLS="${ldap.useStartTLS}"/>
        <!--   p:connectTimeout="${ldap.connectTimeout}"
          p:sslConfig-ref="sslConfig" />-->

    <bean id="ldapPoolConfig" class="org.ldaptive.pool.PoolConfig"
          p:minPoolSize="${ldap.pool.minSize}" p:maxPoolSize="${ldap.pool.maxSize}"
          p:validateOnCheckOut="${ldap.pool.validateOnCheckout}"
          p:validatePeriodically="${ldap.pool.validatePeriodically}"
          />

    <!-- <bean id="sslConfig" class="org.ldaptive.ssl.SslConfig">
         <property name="credentialConfig">
             <bean class="org.ldaptive.ssl.X509CredentialConfig"
                   p:trustCertificates="${ldap.trustedCert}" />
         </property>
     </bean>-->

    <bean id="searchValidator" class="org.ldaptive.pool.SearchValidator" />

    <bean id="authHandler" class="org.ldaptive.auth.PooledBindAuthenticationHandler"
          p:connectionFactory-ref="bindPooledLdapConnectionFactory" />

    <bean id="bindPooledLdapConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory"
          p:connectionPool-ref="bindConnectionPool" />

    <bean id="bindConnectionPool" parent="abstractConnectionPool"
          p:connectionFactory-ref="bindConnectionFactory" />

    <bean id="bindConnectionFactory" class="org.ldaptive.DefaultConnectionFactory"
          p:connectionConfig-ref="bindConnectionConfig" />

    <bean id="bindConnectionConfig" parent="abstractConnectionConfig" />
  <!--LDAP end-->

 

  •    LdapAuthentication为自定义验证用户 extends LdapAuthenticationHandler,然后再此类中实现了账号密码错误3次,账号封停20分钟,如不需要自定义,则直接配置
    <bean id="ldapAuthHandler" class="org.jasig.cas.authentication.LdapAuthenticationHandler"  

cas client 端 集成 

 

  • 在pom文件中添加
      <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>4.2.5.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-cas</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-cas-client</artifactId>
            <version>3.0.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
  • 新增cas.properties 配置文件
casserver.ip=192.168.2.1 // sso server的ip
casserver.port=443       // sso server的端口号
casserver.hostname=hostname   // sso server的hostname,生成证书的时候用到
casclient.url=192.168.11.1/applicatioon
  • 新增 springsecurity.xml 文件内容如下
<?xml version="1.0" encoding="UTF-8"?>
   <beans:beans xmlns="http://www.springframework.org/schema/beans" xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    http://www.springframework.org/schema/security  http://www.springframework.org/schema/security/spring-security-4.2.xsd">
    <!--下面是不需要验证,不会通过cas server验证-->
    <security:http pattern="/css/**" security="none" />
    <security:http pattern="/js/**" security="none" />
    <security:http pattern="/images/**" security="none" />
    <security:http pattern="/bootstrap/**" security="none" />
    <security:http pattern="/fonts/**" security="none" />
    <security:http pattern="/jquery/**" security="none" />
    <security:http pattern="/ligerUI/**" security="none" />
    <security:http pattern="/sound/**" security="none" />
    <security:http pattern="/vender/**" security="none" /> 

   <security:http entry-point-ref="casProcessingFilterEntryPoint">
    <!--       <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> -->
           <security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
         <!--  <security:intercept-url pattern="/" access="permitAll" /> --> 
         <security:custom-filter ref="requestCasLogoutFilter" before="LOGOUT_FILTER" /> 
          <security:custom-filter ref="singleLogoutFilter" before="CAS_FILTER" />
          <security:custom-filter ref="casFilter" position="CAS_FILTER"/>
<!--           <security:logout invalidate-session="true" logout-success-url="https://${casserver.ip}:${casserver.port}/cas/logout?service=${casclient.url}"    logout-url="/j_spring_security_logout" /> -->
            <security:csrf disabled="true"/>  
          <!-- <security:logout  logout-success-url="https://${casserver.ip}:${casserver.port}/cas/logout?service=${casclient.url}" invalidate-session="true" /> -->
    </security:http>
    <beans:bean id="casProcessingFilterEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
        <beans:property name="loginUrl" value="https://${casserver.ip}:${casserver.port}/cas/login" />
        <beans:property name="serviceProperties" ref="serviceProperties" />
    </beans:bean>
    <beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
        <beans:property name="service" value="${casclient.url}/j_spring_cas_security_check" />
        <beans:property name="sendRenew" value="false" />
    </beans:bean>
    <beans:bean id="casFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
        <beans:property name="authenticationManager" ref="authenticationManager" />
            <beans:property name="authenticationFailureHandler">
            <beans:bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
                <beans:property name="defaultFailureUrl" value="/WEB-INF/view/caserror.jsp"/>
            </beans:bean>
        </beans:property>
        <beans:property name="filterProcessesUrl" value="/j_spring_cas_security_check"/>
    </beans:bean>
     <security:authentication-manager alias="authenticationManager">

      <security:authentication-provider ref="casAuthenticationProvider"/>

   </security:authentication-manager>

    <beans:bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
        <!-- <custom-authentication-provider /> -->
        <beans:property name="authenticationUserDetailsService">
        <beans:bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
            <beans:constructor-arg ref="userDetailsService" />
        </beans:bean>
        </beans:property>
        <beans:property name="serviceProperties" ref="serviceProperties" />
        <beans:property name="ticketValidator">
            <beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
                <!--  <beans:constructor-arg index="0" value="http://${casserver.hostname}:${casserver.port}/cas" />-->
                <beans:constructor-arg index="0" value="https://${casserver.hostname}:${casserver.port}/cas" />
            </beans:bean>
        </beans:property>
        <beans:property name="key" value="an_id_for_this_auth_provider_only" />
    </beans:bean>
    
    <beans:bean id="userDetailsService"
      class="com.ais.esns.service.SyUserDetailsService">
   </beans:bean>
    
    <beans:bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener" />
<!--  <bean id="casLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/> -->

    <!-- 认证提供者 -->
<beans:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter" /> 
   <beans:bean id="requestCasLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
      <!-- 指定登出成功后需要跳转的地址,这里指向Cas Server的登出URL,以实现单点登出 -->
      <beans:constructor-arg value="https://${casserver.ip}:${casserver.port}/cas/logout?service=${casclient.url}"/>
       <beans:constructor-arg>
         <beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
       </beans:constructor-arg>
       <!-- 该Filter需要处理的地址,默认是Spring Security的默认登出地址“/j_spring_security_logout”-->
       <beans:property name="filterProcessesUrl" value="/j_spring_security_logout"/>
   </beans:bean>
<!-- <beans:property name="casServerUrlPrefix" value="https://${casserver.ip}:${casserver.port}/cas"></beans:property> -->
<!-- </beans:bean> -->
</beans:beans>

  • 在客户端的web.xml中配置
<listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

     <filter>
         <filter-name>springSecurityFilterChain</filter-name>
         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
     </filter>
    <filter-mapping>
         <filter-name>springSecurityFilterChain</filter-name>
         <url-pattern>/*</url-pattern>
     </filter-mapping>
  • 客户端如何获取sso的登录名
   // request 是HttpServletRequest 
       Object securityContext= request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
        if(securityContext!=null&&securityContext instanceof SecurityContextImpl){
            SecurityContextImpl sContextImpl=(SecurityContextImpl)securityContext;
            userName=sContextImpl.getAuthentication().getName();
            }

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!