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).
Cas Server.
<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" />
myWebApp(using spring security)
<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.
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.
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