4

我正在开发中央身份验证系统 (jasig.org) 以为我的 Intranet Web 应用程序实施单点登录功能。我有两个 tomcat 实例在我的同一台机器(Windows)上运行。两个 tomcat 实例都已配置为使用 SSL 并使用自签名证书(使用 java keytool 创建)。

雄猫1

Cas 服务器。

服务器.xml

<Connector port="8443" maxHttpHeaderSize="8192" SSLEnabled="true"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" disableUploadTimeout="true"
               acceptCount="100" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" 
           keystoreFile="C:/Users/sandip.paul/.keystore"
           keystorePass="changeit"
           truststoreFile="C:/Program Files/Java/jdk1.6.0_20/jre/lib/security/cacerts" />

雄猫2

myWebApp(使用弹簧安全)

服务器.xml

<Connector port="8663" maxHttpHeaderSize="8192" SSLEnabled="true"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" disableUploadTimeout="true"
               acceptCount="100" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />

下面是 myWebApp 的 applicationContext-security.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:security="http://www.springframework.org/schema/security"
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                        http://www.springframework.org/schema/security
                        http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">

    <!--
        Enable security, let the casAuthenticationEntryPoint handle all intercepted urls.
        The CAS_FILTER needs to be in the right position within the filter chain.
    -->
    <security:http entry-point-ref="casProcessingFilterEntryPoint" auto-config="true">
        <security:intercept-url pattern="/protected/**" access="IS_AUTHENTICATED_FULLY" />
    </security:http>

    <!--
        Required for the casProcessingFilter, so define it explicitly set and
        specify an Id Even though the authenticationManager is created by
        default when namespace based config is used.
    -->
    <security:authentication-manager alias="authenticationManager" />

    <!--
        This section is used to configure CAS. The service is the
        actual redirect Client URL that will be triggered after the CAS login sequence.
    -->
    <bean id="serviceProperties" class="org.springframework.security.ui.cas.ServiceProperties">
        <property name="service" value="https://obll1973.abc.com:8663/myWebApp/j_spring_cas_security_check"/>
        <property name="sendRenew" value="false"/>
    </bean>

    <!-- 
        The customUserDetailsService provides ROLE & other Details and 
        create an object of UserDetail for this application.
    -->
    <bean id="customUserDetailsService"
        class="edu.sandip.cas.client.authentication.CustomUserDetailsService">
    </bean>

    <!-- 
        The CasProcessingFilter has very similar properties to the 
        AuthenticationProcessingFilter (used for form-based logins).

        The CAS Processing filter handles the redirect from the CAS server 
        and starts the ticket validation.
    -->
    <bean id="casProcessingFilter" class="org.springframework.security.ui.cas.CasProcessingFilter">
        <security:custom-filter after="CAS_PROCESSING_FILTER"/>
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="authenticationFailureUrl" value="/casfailed.jsp"/>
        <property name="defaultTargetUrl" value="/"/>
    </bean>

    <!--
        The entryPoint intercepts all the CAS authentication requests.
        It redirects to the CAS loginUrl for the CAS login page.
    -->
    <bean id="casProcessingFilterEntryPoint" 
        class="org.springframework.security.ui.cas.CasProcessingFilterEntryPoint">
        <property name="loginUrl" value="https://obll1973.abc.com:8443/cas/login"/>
        <property name="serviceProperties" ref="serviceProperties"/>
    </bean>

    <!-- 
        Handles the CAS ticket processing.
    -->
    <bean id="casAuthenticationProvider" 
        class="org.springframework.security.providers.cas.CasAuthenticationProvider">
        <security:custom-authentication-provider />
        <property name="userDetailsService" ref="customUserDetailsService" />
        <property name="serviceProperties" ref="serviceProperties" />
        <property name="ticketValidator">
            <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
                <constructor-arg index="0" value="https://obll1973.abc.com:8443/cas" />
            </bean>
        </property>
        <property name="key" value="an_id_for_this_auth_provider_only"/>    
    </bean>

    <!-- 
        To access request.getRemoteUser() from client application  
    -->
    <bean id="wrappingFilter" class="org.jasig.cas.client.util.HttpServletRequestWrapperFilter" />
</beans>

我面临的问题是以下异常:

java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:341)
    org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:305)
    org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:50)
    org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:207)
    org.springframework.security.providers.cas.CasAuthenticationProvider.authenticateNow(CasAuthenticationProvider.java:145)
    org.springframework.security.providers.cas.CasAuthenticationProvider.authenticate(CasAuthenticationProvider.java:131)
    org.springframework.security.providers.ProviderManager.doAuthentication(ProviderManager.java:188)
    org.springframework.security.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:46)
    org.springframework.security.ui.cas.CasProcessingFilter.attemptAuthentication(CasProcessingFilter.java:94)
    org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:258)
    org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)
    org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
    org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)

复制上述异常的步骤:1)我尝试使用https://obll1973.abc.com:8663/myWebApp/protected/访问 myWebApp 2)它被重定向到 cas 服务器,即https://obll1973.abc.com: 8443/cas/login并在提供用户名/密码后在这里捕获异常,一旦 myWebApp 再次向 cas 服务器发送请求以验证生成的令牌。

任何建议/帮助都会受到高度评价。

4

1 回答 1

8

您的 Spring-CAS 配置看起来不错。

出现SSLHandshakeException的唯一原因是 SSL 密钥不正确地导入到创建的密钥库或 JVM 密钥库中。

在创建密钥期间,您是否遵循以下

注意:CN 的别名(这里是 cas)应该与机器的主机名相同。

要查找机器的主机名,在控制台或命令提示符中只需键入不带引号的“主机名”。

在根目录下创建一个名为 app 的目录

[root@localhost app]# keytool -genkey -alias cas -keyalg RSA -keystore .cas -storepass caspasswd

你的名字和姓氏是什么?[未知]: cas 你的组织单位叫什么名字?[未知]:MYCOMPANY 贵组织的名称是什么?[未知]:MYCOMPANY 您所在城市或地区的名称是什么?[未知]:班加罗尔 您所在的州或省的名称是什么?[未知]:卡纳塔克邦这个单位的两个字母的国家代码是什么?[未知]:IN CN=cas、OU=MYCOMPANY、O=MYCOMPANY、L=Bangalore、ST=Karnataka、C=IN 是否正确?[否]:是的

Enter key password for (给出上面提到的密码——在这种情况下是 caspasswd) (如果与 keystore 密码相同则返回): 重新输入新密码:

[root@localhost app]# keytool -exportcert -alias cas -file cas.crt -keystore .cas 输入密钥库密码:证书存储在文件中

[root@localhost app]# ls cas.crt softwares test.class test.java tomcat7027CAS

[root@localhost app]# keytool -import -alias cas -file cas.crt -keystore /app/softwares/jdk1.6.0_27/jre/lib/security/cacerts 输入密钥库密码: Owner: CN=cas, OU=MYCOMPANY , O=MYCOMPANY, L=Bangalore, ST=Karnataka, C=IN 发行人:CN=cas, OU=MYCOMPANY, O=MYCOMPANY, L=Bangalore, ST=Karnataka, C=IN 序列号:510a6a63 有效期自:周四一月31 18:28:11 IST 2013 直到:Wed May 01 18:28:11 IST 2013 证书指纹:MD5: 52:8E:2E:74:C6:57:CD:B3:B0:B6:6C:17:D9 :0D:77:F3 SHA1: 1F:AA:4C:22:B9:16:DC:AA:D4:87:07:CF:DD:B2:11:A6:AE:36:9A:DB 签名算法名称: SHA1withRSA 版本: 3 信任这个证书吗?[否]:是 证书已添加到密钥库

[root@localhost app]# keytool -list -keystore /app/softwares/jdk1.6.0_27/jre/lib/security/cacerts -alias cas 输入密钥库密码:cas,2013 年 1 月 31 日,trustedCertEntry,证书指纹(MD5) : 52:8E:2E:74:C6:57:CD:B3:B0:B6:6C:17:D9:0D:77:F3

[root@localhost 应用程序]#

在您的 tomcat server.xml 中,您还可以使用 https 连接器,如下所示

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
               maxThreads="150" scheme="https" keystoreFile="/app/.cas" keystorePass="mykeypassword" 
    secure="true" connectionTimeout="240000" 
               clientAuth="false" sslProtocol="TLS" allowUnsafeLegacyRenegotiation="true" />
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8069" protocol="AJP/1.3" redirectPort="8443" />

上述密钥用于 CAS 服务器。您可以为应用程序创建自己的单独密钥。

但是这两个密钥都应该导入到 JVM cacerts 密钥库中(如何:在下面提到)

现在最重要的部分: 假设您的 CAS 服务器别名是 cas

并且您的应用程序服务器别名是 myapp

将密钥 cas.crt 和 myapp.crt 保留在两个服务器中以导入 JVM

在两个服务器中执行以下操作:

1) keytool -import -alias cas -file /app/cas.crt -keystore /usr/java/jdk1.5.0_22/jre/lib/security/cacerts

2) keytool -import -alias myapp -file /app/cas.crt -keystore /usr/java/jdk1.5.0_22/jre/lib/security/cacerts

要验证使用以下命令 -

1) keytool -list -v -keystore /usr/java/jdk1.5.0_22/jre/lib/security/cacerts -alias cas

2) keytool -list -v -keystore /usr/java/jdk1.5.0_22/jre/lib/security/cacerts -alias myapp

如果使用多个版本的 java,请确保 Java--JRE--LIB--SECURITY--CACERTS 文件

这将消除您的错误。

笔记 :

如果在提供正确的用户凭据后浏览器显示空白页面,请修改系统的主机文件(Linux 中的 /etc/hosts 和 Windows 中的 c:\windows\system32\driver\etc\hosts)

在那里添加 cas 服务器 ip

例如。

162.25.250.60 myapp 162.25.250.81 cas

任何疑问都可以澄清。

您可以参考以下内容:

https://wiki.jasig.org/display/CASUM/SSL+Troubleshooting+and+Reference+Guide

于 2013-02-12T09:19:31.553 回答