CAS + SSLHandshakeException + ValidatorException + PKIX path building failed + unable to find valid certification path to requested target

Sandy picture Sandy · Oct 29, 2012 · Viewed 11.4k times · Source

I am working on Central Authentication System (jasig.org) to implementing Single Sign On featute for my intranet web application. I have two tomcat instance running in my same machine(windows). Both tomcat instance have been configured to use SSL and have used self-signed sertificate (created using java keytool).

Tomcat1

Cas Server.

server.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" />

Tomcat2

myWebApp(using spring security)

server.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" />

below is the applicationContext-security.xml file of the myWebApp

<?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>

The issue I am facing is the below exception:

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)

Steps to replicate the above exception: 1) I tried accessing myWebApp using https://obll1973.abc.com:8663/myWebApp/protected/ 2) It is getting redirected to cas server i.e. https://obll1973.abc.com:8443/cas/login and after providing username/password Here the exception caught once myWebApp again send the request to cas server to validate the generated Token.

Any suggestion/help would be highly appriciated.

Answer

Imdad Areeph picture Imdad Areeph · Feb 12, 2013

Your Spring-CAS configuration looks fine.

The one and only reason SSLHandshakeException appears is due to the improper import of the SSL key into the created keystore or the JVM keystore.

During key creation have you followed the following

Note : the alias name that is the CN (here it is cas) should be same name as the machine's hostname.

to find the machine's host name, in console or command promt just type "hostname" without quotes.

Create a directory under root named app

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

What is your first and last name? [Unknown]: cas What is the name of your organizational unit? [Unknown]: MYCOMPANY What is the name of your organization? [Unknown]: MYCOMPANY What is the name of your City or Locality? [Unknown]: Bangalore What is the name of your State or Province? [Unknown]: Karnataka What is the two-letter country code for this unit? [Unknown]: IN Is CN=cas, OU=MYCOMPANY, O=MYCOMPANY, L=Bangalore, ST=Karnataka, C=IN correct? [no]: yes

Enter key password for (give the password mentioned above -- i.e caspasswd in this case) (RETURN if same as keystore password): Re-enter new password:

[root@localhost app]# keytool -exportcert -alias cas -file cas.crt -keystore .cas Enter keystore password: Certificate stored in file

[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 Enter keystore password: Owner: CN=cas, OU=MYCOMPANY, O=MYCOMPANY, L=Bangalore, ST=Karnataka, C=IN Issuer: CN=cas, OU=MYCOMPANY, O=MYCOMPANY, L=Bangalore, ST=Karnataka, C=IN Serial number: 510a6a63 Valid from: Thu Jan 31 18:28:11 IST 2013 until: Wed May 01 18:28:11 IST 2013 Certificate fingerprints: 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 Signature algorithm name: SHA1withRSA Version: 3 Trust this certificate? [no]: yes Certificate was added to keystore

[root@localhost app]# keytool -list -keystore /app/softwares/jdk1.6.0_27/jre/lib/security/cacerts -alias cas Enter keystore password: cas, Jan 31, 2013, trustedCertEntry, Certificate fingerprint (MD5): 52:8E:2E:74:C6:57:CD:B3:B0:B6:6C:17:D9:0D:77:F3

[root@localhost app]#

And Inside your tomcat server.xml you also use the https connector as following

<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" />

The above key was for CAS Server. You can create your own seperate key for the application.

But both key should be imported to the JVM cacerts keystore (How to : is mentioned below)

Now the most important part : suppose your CAS Server alias name is cas

and your application Server alias name is myapp

keep both the keys cas.crt and myapp.crt in both servers to import into JVM

Do the following in both server :

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

To verify use the following commands --

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

Be sure about the Java--JRE--LIB--SECURITY--CACERTS file if using mutiple versions of java

This will remove your error.

Note :

If after giving proper user credential browser is showing blank white page, modify the system's host file (/etc/hosts in linux and c:\windows\system32\driver\etc\hosts in windows)

add the cas server ip there

eg.

162.25.250.60 myapp 162.25.250.81 cas

Any doubt can be clarified.

You can refer the following :

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