CAS + Spring Security Detect localhost - java

I am trying to implement an application with Spring security and CAS, it works fine on localhost but when I try to access it from an outside machine it and the application needs authentication it redirect to localhost too.
meaning
I access the application using https://172.16.1.50:8443/isxannouncements/
and when it needs authentication it should go to https://172.16.1.50:8443/cas/login/
but instead it goes to https://localhost:8443/isxannouncements/
which ofcourse breaks the application flow.
my config is
security-cas.xml
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://localhost:8443/isxannouncements/login"/>
</bean>
<!--
Allows changing where the CAS Server and CAS Service are easily
by specifying System Arguments or replacing the values only in one place.
Could also use external properties file -->
<context:property-placeholder
system-properties-mode="OVERRIDE" properties-ref="environment"/>
<util:properties id="environment">
<prop key="cas.service.host">localhost:8443</prop>
<prop key="cas.server.host">localhost:8443</prop>
</util:properties>
<!-- sends to the CAS Server, must be in entry-point-ref of security.xml -->
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="serviceProperties" ref="serviceProperties"/>
<property name="loginUrl" value="https://localhost:8443/cas/login" />
</bean>
<!-- authenticates CAS tickets, must be in custom-filter of security.xml -->
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/login"/>
</bean>
<bean id="casAuthProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="ticketValidator" ref="ticketValidator"/>
<property name="serviceProperties" ref="serviceProperties"/>
<property name="key" value="isxannouncements"/>
<property name="authenticationUserDetailsService" ref="DBUserServiceDetails"/>
<property name="statelessTicketCache" ref="statelessTicketCache"/>
</bean>
<bean id="statelessTicketCache" class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
<property name="cache">
<bean class="net.sf.ehcache.Cache"
init-method="initialise" destroy-method="dispose">
<constructor-arg value="casTickets"/>
<constructor-arg value="50"/>
<constructor-arg value="true"/>
<constructor-arg value="false"/>
<constructor-arg value="3600"/>
<constructor-arg value="900"/>
</bean>
</property>
</bean>
<bean id="ticketValidator" class="org.jasig.cas.client.validation.Saml11TicketValidator">
<constructor-arg value="https://localhost:8443/cas" />
<property name="encoding" value="utf8" />
</bean>
<!-- Handles a Single Logout Request from the CAS Server must be in custom-filter of security.xml -->
<bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
and my security.xml
<security:http pattern="/resources/images" security="none"/>
<security:http use-expressions="true" entry-point-ref="casEntryPoint">
<security:intercept-url pattern="/login/*"
access="permitAll"/>
<security:intercept-url pattern="/resources/**"
access="permitAll"/>
<security:intercept-url pattern="/logout"
access="permitAll"/>
<security:intercept-url pattern="/errors/**"
access="permitAll"/>
<security:intercept-url pattern="/approve-announcement**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/delete-announcement**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/edit-announcement**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/admin/**"
access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/META-INF"
access="hasRole('ROLE_USER')"/>
<security:access-denied-handler error-page="/errors/403"/>
<security:custom-filter ref="singleLogoutFilter" before="LOGOUT_FILTER"/>
<security:custom-filter ref="casFilter" position="CAS_FILTER"/>
<security:port-mappings>
<security:port-mapping http="8080" https="8443"/>
</security:port-mappings>
<security:logout logout-url="/logout"
logout-success-url="https://localhost:8443/cas/logout"/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthProvider" />
</security:authentication-manager>
how to fix this ??

Ok I found a workaround but I did not test it properly,
Inspired by this answer I did the following
since I have two domains that the user might use to access my application, the only way to get the domain the user used was to get from the request and then return it to the security provider.
I created a bean named serviceProperties and used it instead of the serviceproperties of spring, and I overrided the method of getService to return the service based on the domain name that the user to access the application.
Then I made this bean available at Web Application Context, and I passed in the session, I had already extracted the domain from the Request and put it in the Session.
So when the CasAuthenticationEntryPoint tries to get the service, I pass the service URL that I created from the session appended to it is the service name.

We handle this with property files. Anything that is specific to a certain environment (i.e. your local machine versus your test server) should be in a property file.
For example, create properties files for each environment with something like this:
localhost.properties:
cas.service.url=http://localhost/login
test.properties:
cas.service.url=http://mytestserver/login
And then configure spring security with the value from the properties file instead of directly as you have it above:
Your build process would then have a target for each environment to shuffle the appropriate files into place in the final artifact.

CAS works under domain. so you should use cas.example.com and define it in the cas.properties

Related

Authentication Failed: The user's credentials have expired. CAS v4.2

I have a problem that I do not know how to solve.
I have the CAS v4.2 configured on a tomcat 8 port 8443.
The spring-security configuration that I have, it does the redirection to the cas correctly, when I authenticate in the cas, in the logs it is clear that the authentication and the ticket generation have been correct.
I have configured so that the ticket has a duration of 2 weeks as indicated in the documentation. I have increased the cas session from 5 to 15 in the web.xml as they indicate in the possible errors that is pressed, but all this has resulted in the same.
After authenticating myself, I did not redirect myself to the home of the client application but it displays a message "Authentication Failed: The user's credentials have expired"
I do not know what I may be doing wrong or what may be missing by configuring in cas.properties properties according to version 4.2.
I would be grateful if you could tell me what this problem could be in order to continue.
Thanks in advance.
JDK8.
Spring 4.2.6.
CAS v4.2.
Tomcat8.
Spring-security.xml
<security:http entry-point-ref="casEntryPoint" auto-config="true" use-expressions="true">
<security:csrf disabled="false"/>
<security:custom-filter position="FIRST" ref="ajaxSessionFilter"/>
<!-- ACCESO SIN RESTRICCIONES -->
<security:intercept-url pattern="/static/**" access="permitAll"/>
<security:intercept-url pattern="/WEB-INF/views/**" access="permitAll"/>
<security:custom-filter ref="casAuthenticationFilter" after="CAS_FILTER"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
<bean id="casServiceProperties" class="org.springframework.security.cas.ServiceProperties"
p:service="http://localhost:8080/aap/j_spring_cas_security_check"
p:sendRenew="false" p:authenticateAllArtifacts="true" />
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"
p:serviceProperties-ref="casServiceProperties" p:loginUrl="https://cas:8443/cas/login" />
<bean id="ajaxSessionFilter" class="com.xxxx.auth.web.filters.ajax.SessionFilter">
<property name="homePage" value="https://cas:8443/cas/login"/>
</bean>
<bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="serviceProperties" ref="casServiceProperties"/>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/casfailed"/>
</bean>
</property>
<!-- -->
<property name="authenticationSuccessHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/"/>
</bean>
</property>
<property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
</bean>
<bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>
<!-- This filter redirects to the CAS Server to signal Single Logout should be performed -->
<bean id="requestSingleLogoutFilter"
class="org.springframework.security.web.authentication.logout.LogoutFilter"
p:filterProcessesUrl="/j_spring_cas_security_logout">
<constructor-arg value="https://cas:8443/cas/logout" />
<constructor-arg >
<bean
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
</constructor-arg>
</bean>
<!-- This filter handles a Single Logout Request from the CAS Server -->
<bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider"/>
</security:authentication-manager>
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="authenticationUserDetailsService">
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<constructor-arg ref="userDetailService" />
</bean>
</property>
<property name="serviceProperties" ref="casServiceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://cas:8443/cas" />
<property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
</bean>
</property>
<property name="key" value="CAS"/>
</bean>
<bean id="userDetailService" class="com.xxx.services.security.userdetails.PSOUserDetailsService"/>
cas.properties
# Decides whether SSO cookie should be created only under secure connections.
tgc.secure=true
# The expiration value of the SSO cookie
tgc.maxAge=1209600
# The name of the SSO cookie
tgc.name=TGC
# The path to which the SSO cookie will be scoped
tgc.path=/cas
# The expiration value of the SSO cookie for long-term authentications
tgc.remember.me.maxAge=1209600
# Decides whether SSO Warning cookie should be created only under secure connections.
warn.cookie.secure=true
# The expiration value of the SSO Warning cookie
warn.cookie.maxAge=1209600
# The name of the SSO Warning cookie
warn.cookie.name=CASPRIVACY
# The path to which the SSO Warning cookie will be scoped
warn.cookie.path=/cas
##
# Single Sign-On Session TGT Timeouts
#
# Inactivity Timeout Policy
tgt.timeout.maxTimeToLiveInSeconds=1209600
# Default Expiration Policy
tgt.maxTimeToLiveInSeconds=28800
tgt.timeToKillInSeconds=7200
##
# Service Ticket Timeout
#
st.timeToKillInSeconds=28800
st.numberOfUses=1
tgc.remember.me.maxAge=1209600
Cookie
"CASPRIVACY="";
Expires=Thu, 01-Jan-1970 00:00:10 GMT;
Path=/cas;
SecureTGC=eyJhbGciOiJIUzUxMiJ9.WlhsS2FHSkhZMmxQYVVwcllWaEphVXhEU214aWJVMXBUMmxLUWsxVVNUUlJNRXBFVEZWb1ZFMXFWVEpKYmpBdUxqRnNSVEl5T1U5SFdsQTRVWFpUTFc5VWIzRmpNRUV1T0Vac2J6QnRaMjl5ZVRWRk9XRnFNR3AwVFZKcFNIQklTVGt5YjJGelNWZE9XR0pEU2swM2VrMUJRekJYVUVjd1UwSnRaRGRaTTFwVlJHNVROekpNTjA5aWNsZGtjMEo2TkVGVVZYQkJWMGxPVEhKQkxWSmxVWEozZUdWRlpFaGxOV2xEYkhZdFgxUnRWbXBYY0hJeFZEWlpXQzFRVG1kcFdtNUJRa2RuTW5CdlRHOUxaRzB3VFMxQk56ZFNWelZ4YVdORVQxQXRVekEzTVVVNGNFSmxWVFJ2UkZwZmVFTTNWRzVFVlRWRmMyeFJRVXR3Y2tOMFlXMVhTVVJGT0ZoQ00xQlNaV0pMVTJGcVJrMVdPV1ZEVmxkU1ozaEtkeTVQYTJwSFEzTmhWRmxRVkdwSE0xZG5UVnBVZUVKQg.H2P1nCulIj3BtS-wOJr3PtOVGi1hT6y0PDP0MVSQerwv3khVB-lFQe2BdKNElUYzJhURtW-zwyZK3PuBh6p_eQ;
Expires=Wed, 18-Jan-2017 15:00:18 GMT;
Path=/cas;
Secure"
I respond to myself, and in case someone happens to be the same.
The problem lies in the PSOUserDetails, which had not overwritten the method for either the credentials did not expire.
Thanks

HTTP Basic with Spring Security XML configuration doesn't use HttpBasicConfigurer

It seems that XML configuration and Java are not performing the same tasks in Spring Security, regarding the HTTP Basic configuration.
When using the following Java configuration:
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
A HttpBasicConfigurer is used in order to use a different EntryPoint, when the request HTTP header X-Requested-With is XMLHttpRequest.
When using the configuration
<s:http use-expressions="true" create-session="ifRequired">
<s:intercept-url pattern='/**' access='isAuthenticated()' />
<s:http-basic />
<s:http />
The HTTPBassicConfigurer is not used.
Anybody knows how to add it using the XML configuration ?
The final solution based on the remarks provided by the people in this post, is that it is not possible to use HTTPBasicConfigurer with XML configuration. But there are other ways to perform almost the same thing that is implemented now in HTTPBasicConfigurer. My final solution used is mainly based on the remarks provided by Lea:
<s:http use-expressions="true" create-session="ifRequired" >
<s:intercept-url pattern='/**' access='isAuthenticated()' />
<s:http-basic entry-point-ref="entryPoint" />
</s:http>
<bean id="entryPoint"
class="org.springframework.security.web.authentication
.DelegatingAuthenticationEntryPoint">
<constructor-arg>
<map>
<entry key="hasHeader('X-Requested-With','XMLHttpRequest')"
value-ref="ajaxEntyPoint" />
</map>
</constructor-arg>
<property name="defaultEntryPoint" ref="defaultEntryPoint"/>
</bean>
<bean id="ajaxEntyPoint"
class="org.springframework.security.web.authentication.HttpStatusEntryPoint">
<constructor-arg name="httpStatus"
value="#{T(org.springframework.http.HttpStatus).UNAUTHORIZED}"/>
</bean>
<bean id="defaultEntryPoint"
class="org.springframework.security.web.authentication.www
.BasicAuthenticationEntryPoint">
<property name="realmName" value="My webservices"/>
</bean>
Basic authentication parameters can be declared explicitly with basic authentication filter:
<security:http use-expressions="true" entry-point-ref="entryPoint" authentication-manager-ref="authManager">
<security:custom-filter ref="advancedBasicFilter" position="BASIC_AUTH_FILTER"/>
<security:intercept-url pattern="/info/**" access="permitAll" />
<security:intercept-url pattern="/**" access="isAuthenticated()"/>
</security:http>
<bean id="advancedBasicFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<constructor-arg name="authenticationEntryPoint" ref="entryPoint"/>
<constructor-arg name="authenticationManager" ref="authManager"/>
</bean>
<bean id="entryPoint" class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<property name="realmName" value="My Realm"/>
</bean>
<security:authentication-manager id="authManager">
<security:authentication-provider user-service-ref="myOwnUserService" />
</security:authentication-manager>
If you are using xml config with the namespace, you do not use a HTTPBasicConfigurer, but attributes of the <http-basic> tag.
Extract from Spring Security Reference Manual Appendix The security namespace about <http-basic> tag :
Attributes
authentication-details-source-ref : Reference to an AuthenticationDetailsSource which will be used by the authentication filter
entry-point-ref Sets the AuthenticationEntryPoint which is used by the BasicAuthenticationFilter

How to redirect to a login-entry-point in a different EAR

In one of my deployed EARs I have a security context like so:
<security:http auto-config="false" use-expressions="true" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:intercept-url pattern="/login" filters="none" />
<security:intercept-url pattern="/**" access="isAuthenticated() and permitAll" />
<security:custom-filter position="FORM_LOGIN_FILTER" ref="ssoFilter" />
</security:http>
<bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login"/>
</bean>
Now in a second EAR I want to redirect to the login page of the first one. Can this be done somehow without extending the LoginUrlAuthenticationEntryPoint ?
Because currently if I try an absolute URL in the second EAR security context:
<property name="loginFormUrl" value="http://host/ear1ContextPath/login"/>
I get redirected to: http://host/ear2contextPath/login.
Which is incorrect.
Thanks
I managed to do this by implementing my own UrlAuthenticationFaliureHandler and handling the absolute URLs programatically (just do a servlet redirect and then break the filter chain).
Then I could inject the new FailureHandler in my custom filter like this:
<bean id="absoluteUrlLoginFailureHandler" class="tld.company.AbsoluteUrlAuthenticationFaliureHandler">
<property name="defaultFailureUrl" value="http://company.domain.tld/Login.html"/>
</bean>
<bean id="absoluteUrlFilter" class="tld.company.MyUserPassFilter">
<property name="authenticationFailureHandler" ref="absoluteUrlLoginFailureHandler"/>
</bean>
And then I set that filter in the namespace configuration:
<http auto-config="false" use-expressions="true" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:intercept-url pattern="/**" access="isAuthenticated() and permitAll" />
<custom-filter position="FORM_LOGIN_FILTER" ref="absoluteUrlFilter" />
</http>
The <entry-point-ref> element seems to handle absolute URLs by default.

how to create spring cas login link

I have Spring Security 3.0.3 with CAS. Some of my conf follows:
<security:http entry-point-ref="casAuthenticationEntryPoint" auto-config="true" >
<security:intercept-url pattern="/*/secure/**" access="ROLE_USER" />
<security:custom-filter position="CAS_FILTER" ref="casAuthenticationFilter" />
<security:anonymous enabled="false"/>
<security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/web/auth?logout" />
</security:http>
<bean id="casAuthenticationEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="${cas.app.url}/login"></property>
<property name="serviceProperties" ref="serviceProperties"></property>
</bean>
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service" value="${application.stack.hostname}/ctx/j_spring_cas_security_check" />
<property name="sendRenew" value="false" />
</bean>
If I access some of the secured content I get redirected to CAS login. After authentication I'm redirected back to the secure url I tried to access.
On every page I need to add "Log in" link that does the same thing. Where should this link point to? I tried ${cas.app.url}/login?service=${application.stack.hostname}/ctx/j_spring_cas_security_check but that does not seem to work.
Of course all the properties are replaced with appropriate full hostnames :)
It can point to any URL matching the pattern <security:intercept-url pattern="/*/secure/**" access="ROLE_USER" />
If I understand what you are looking for you should just be able to point them to ${cas.app.url}/login. Leave out the service parameter. This will take them to the login page of your cas server which will authenticate them to all of your secure services.

Implement SSO using CAS + Spring Security

I'm trying to implement SSO across several web applications using CAS and Spring Security. Expected case:
CAS - http:// localhost:8080/cas/
App A protected content - http: //localhost:8081/cas-client1/secure/index.html
App B protected content - http: //localhost:8081/cas-client2/secure/index.html
1) When user access cas-client1, CAS login form will be prompted and trigger authentication.
2) The same user access cas-client2, previous login should be recognized and no login form will be prompted
However, I am failed to implement step 2. CAS login form still prompted to user and therefore requires double login. Is there any wrong setting in my Spring Security configuration:
<security:http entry-point-ref="casAuthenticationEntryPoint" auto-config="true">
<security:intercept-url pattern="/secure/**" access="ROLE_USER" />
<security:custom-filter position="CAS_FILTER" ref="casAuthenticationFilter" />
</security:http>
<bean id="casAuthenticationEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="http://localhost:8080/cas/login" />
<property name="serviceProperties" ref="serviceProperties" />
</bean>
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<!-- http://localhost:8081/cas-client2 for app 2-->
<property name="service" value="http://localhost:8081/cas-client1/j_spring_cas_security_check" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider" />
</security:authentication-manager>
<bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/casfailed.jsp" />
</bean>
</property>
</bean>
<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="userDetailsService" ref="userService" />
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="http://localhost:8080/cas" />
</bean>
</property>
<property name="key" value="an_id_for_this_auth_provider_only" />
</bean>
<security:user-service id="userService">
<security:user name="wilson" password="wilson" authorities="ROLE_USER" />
</security:user-service>
The problem is finally solved. My CAS is using HTTP and therefore need to set secure cookies to false.
Modify ticketGrantingTicketCookieGenerator.xml
p:cookieSecure="false"

Categories

Resources