Spring Security Logout Back Button - spring-security

Does spring security have a way to prevent the last point below? I'm using 3.0.5
-user logs into my website
-user goes to any page in website and clicks log out
-log out link invalidates user session and sends them to the login page in my website
-in same browser, user navigates to new website (say cnn.com)
-user hits back button and they land at my login page
-user hits back button again and they end up at the page within the application that may have data that we dont want to be there. If they click any link on the page they immediately get sent to login page, but they can view the cached page from the browser cache...any way to not let them view this?
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
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-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="dc" />
<global-method-security />
<http access-denied-page="/auth/denied.html">
<intercept-url filters="none" pattern="/javax.faces.resource/**" />
<intercept-url filters="none" pattern="/services/rest-api/1.0/**" />
<intercept-url filters="none" pattern="/preregistered/*"/>
<intercept-url
pattern="/**/*.xhtml"
access="ROLE_NONE_GETS_ACCESS" />
<intercept-url
pattern="/auth/*"
access="ROLE_ANONYMOUS,ROLE_USER"/>
<intercept-url
pattern="/preregistered/*"
access="ROLE_ANONYMOUS,ROLE_USER"/>
<intercept-url
pattern="/registered/*"
access="ROLE_USER"
requires-channel="http"/>
<form-login
login-processing-url="/j_spring_security_check.html"
login-page="/auth/login.html"
default-target-url="/registered/home.html"
authentication-failure-url="/auth/login.html" />
<logout invalidate-session="true"
logout-url="/auth/logout.html"
success-handler-ref="DCLogoutSuccessHandler"/>
<anonymous username="guest" granted-authority="ROLE_ANONYMOUS"/>
<custom-filter after="FORM_LOGIN_FILTER" ref="xmlAuthenticationFilter" />
<session-management session-fixation-protection="none"/>
</http>
<!-- Configure the authentication provider -->
<authentication-manager alias="am">
<authentication-provider user-service-ref="userManager">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
<authentication-provider ref="xmlAuthenticationProvider" />
</authentication-manager>
</beans:beans>

the below filter took care of my situation:
package com.dc.api.service.impl;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
public class CacheControlFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse) response;
resp.setHeader("Expires", "Tue, 03 Jul 2001 06:00:00 GMT");
resp.setHeader("Last-Modified", new Date().toString());
resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
resp.setHeader("Pragma", "no-cache");
chain.doFilter(request, response);
}
#Override
public void destroy() {}
#Override
public void init(FilterConfig arg0) throws ServletException {}
}

to solve this problem you must add in your security xml config file :
<security:http auto-config="true" use-expressions="true">
<security:headers >
<security:cache-control />
<security:hsts/>
</security:headers>

In spring 3.0.x
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="cacheSeconds" value="0" />
</bean>
In spring 2.5.x
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="cacheSeconds" value="0" />
</bean>

Yes, I used spring-security 3.2.9.RELEASE and simply giving <security:headers /> in one the spring config file like applicationContext.xml file as in the above posts
<security:http
auto-config="true" use-expressions="true">
<security:headers />
</security:http>
so that user won't be able to go to visited other app pages
using browser back and forward buttons after logout.

If you, like me, didn't get it working after using c12's caching filter, and you are using <security:http auto-config="true"> make sure you don't need the auto-config="true" part anymore. It (looks like it) adds http basic authentication which does not handle logging out by protocol! This results in that you can GET your logout URL but hitting the back button will just bring you back since you're not really logged out.

Related

Spring Security UserDetailsService not called

I'm upgrading from Spring Security 3.2.5 to 4.0.4, working with the migration guide.
My UserDetailsService looks like this:
package com.me.security;
import org.springframework.security.core.userdetails.UserDetailsService;
public class Users implements UserDetailsService {
public Users() {
System.err.println("USERS CONSTRUCTOR");
}
#Override
public UserDetail loadUserByUsername(String name) {
System.err.println("LOAD BY USER NAME " + name);
throw new UsernameNotFoundException("User not found.");
}
}
My WEB-INF/applicationContext.xml has this:
<beans xmlns="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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<security:http disable-url-rewriting="true" use-expressions="false">
<security:intercept-url pattern="/auth/**" access="ROLE_ANONYMOUS"/>
<security:intercept-url pattern="/dashboard/**" access="ROLE_ADMIN,ROLE_USER"/>
<!-- ...more intercept-urls... -->
<security:access-denied-handler error-page="/pages/general/403.xhtml"/>
<security:form-login login-page="/auth/login.html"
username-parameter="j_username"
password-parameter="j_password"
login-processing-url="/j_spring_security_check"
default-target-url="/dashboard/"
authentication-failure-url="/auth/error.html"/>
<security:logout logout-success-url="/auth/login.html"
logout-url="/auth/login.html"
delete-cookies="JSESSIONID"
invalidate-session="true" />
<security:session-management invalid-session-url="/auth/login.html"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref='userDetailsService'/>
</security:authentication-manager>
<bean id="userDetailsService" class="com.me.security.Users"/>
</beans>
When I try to log in, my code does not get called. I do see the message from the Users constructor in the server logs, but not the one from its loadUserByUsername method.
Instead, no matter what I enter for user name and password, I get to my 403 error page.
(Maybe I've been looking at this for too long already...)
Why doesn't Spring call my UserDetailsService and what do I need to get it to work?
It sounds to be the csrf filter. In Spring Security 4.x it is activated by default: Migrating from Spring Security 3.x to 4.x. This may be problem if you are allways getting an HTTP 403.
Try disabling setting this inside the security:http element:
<csrf disabled="true"/>

Why is my custom authentication not working in Spring Security 3?

I'm having an issue with spring security 3 while trying to implement my own Customauthentication. Following this page steps I wrote this class:
public class CustomAuth implements AuthenticationManager {
#Override
public Authentication authenticate(Authentication auth)
throws AuthenticationException {
UserService service = new UserService();
User user = service.login((String) auth.getPrincipal(), new String(
DigestUtils.sha256((String) auth.getCredentials())));
LinkedList<GrantedAuthority> authorities = new LinkedList<>();
if (user != null) {
authorities.add(new SimpleGrantedAuthority(user.getRole()));
return new UsernamePasswordAuthenticationToken(user.getUsername(),
user.getPassword(), authorities);
}
return null;
}
}
And this is my spring-security.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http pattern="/resources/**" security="none" />
<security:http auto-config="true" >
<security:intercept-url pattern="/user/**"
access="ROLE_USER" />
<security:intercept-url pattern="/admin/**"
access="ROLE_ADMIN,ROLE_USER" />
<security:form-login login-page="/login"
authentication-failure-url="/login?error=true" />
<security:logout invalidate-session="true" />
<security:session-management>
<security:concurrency-control
max-sessions="1" />
</security:session-management>
</security:http>
<security:authentication-manager>
<security:authentication-provider ref="myAuthProvider" />
</security:authentication-manager>
<bean id="myAuthProvider" class="org.jhonnytunes.security.CustomAuth">
</bean>
</beans>
And tomcat7 is logging this while app not displaying at browser.
Im using:
Eclipse Kepler
Ubuntu 13.04
JDK 1.7
Tomcat7
Eclipse STS plugin
What can be this?
CustomAuth should implement AuthenticationProvider, not AuthenticationManager.
implements'AuthenticationProvider' instead of 'AuthenticationManager'
'throw new BadCredentialsException (String)' instead of 'return null'

Spring Security:redirection to a specific page based on roles in JSF

I work with JSF and Spring Security. I use a custom login page. I have two roles : Administrator and User.
My question is how to redirect to different pages for different roles. For example if the user is an administrator, he will be redirected to "dashboard_Admin.jsf" and if he is a simple user, he will be redirected to "dashboard_user.jsf".
This is my spring security file :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/pages/**"
access="hasRole('ROLE_ADMIN')" />
<security:form-login login-page="/login.jsf"
authentication-failure-url="/login.jsf?error=true"
default-target-url="/pages/admin/dashboard_Admin.jsf" />
<security:logout logout-success-url="/login.jsf"
delete-cookies="JSESSIONID" invalidate-session="true" />
<security:session-management
invalid-session-url="/login.jsf">
<security:concurrency-control
max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:user-service>
<security:user name="test" password="test"
authorities="ROLE_USER" />
<security:user name="sam" password="sam" authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
This is my doLogin method:
public String doLogin() throws ServletException, IOException {
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
.getRequestDispatcher("/j_spring_security_check?j_username=" + username
+ "&j_password=" + password);
dispatcher.forward((ServletRequest) context.getRequest(),
(ServletResponse) context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
return null;
}
I find a very easy solution without using Spring Security, and it works very good.
Thanks Ravi

Redirecting to specific page depending upon Authentication and Authorization

I am building an Application where I am authorizing the user based on his Role. Role is defined in Ldap. We have three roles finance, cloud and sales. Depending upon the role we want to redirect to the particular page on successful login. If login fails it should redirect to some error page.
I have written the following in spring-security.xml. I am not able to redirecting to different pages .
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
<http auto-config="true">
<intercept-url pattern="/finance*" access="ROLE_FINANCE" />
<logout logout-success-url="/logout" />
<intercept-url pattern="/cloud*" access="ROLE_CLOUD" />
<logout logout-success-url="/logout" />
<intercept-url pattern="/sales*" access="ROLE_SALES" />
<!-- <form-login login-page="/login1" default-target-url="/login1"
authentication-failure-url="/loginfailed" /> -->
<logout logout-success-url="/logout" />
<!-- <form-login login-page="/login.vtu" authentication-success-handler-ref="customHandler"
authentication-failure-url="/login.vtu?error=true" default-target-url="/login.vtu"
login-processing-url="/j_security_check" /> -->
</http>
<authentication-manager>
<ldap-authentication-provider
user-search-filter="(uid={0})"
user-search-base="cn=worldAdmin"
group-search-filter="(uniqueMember={0})"
group-search-base="cn=worldAdmin"
group-role-attribute="cn"
role-prefix="ROLE_">
</ldap-authentication-provider>
</authentication-manager>
<ldap-server url="ldap://localhost:12389/o=xyz" manager-dn="cn=xyzAdmin,cn=worldAdmin,o=xyz" manager-password="abc" />
</beans:beans>
Use authentication-success-handler-ref to redirect to the particular page based on User Role. (As per Spring Security, authentication-success-handler-ref Should not be used in combination with default-target-url (or always-use-default-target-url) as the
implementation should always deal with navigation to the subsequent destination)
Use authentication-failure-url to redirect when login fails:
<form-login login-page="/login.vtu" authentication-success-handler-ref="customHandler"
authentication-failure-url="/login.vtu?error=true" />
<bean id="customHandler" class="x.y.z.web.handler.CustomHandler " />
public class CustomHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
//authentication.getAuthorities() to check role
if(isFinancialRole){
response.sendRedirect(getFinancialRedirectUrl());
}
}
}
login.xhtml
<h:head >
<f:metadata>
<f:event type="preRenderView" listener="#{loginBean.onPageLoad}"/>
</f:metadata>
</h:head>
loginBean
public void onPageLoad(){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
try {
FacesContext.getCurrentInstance().getExternalContext().redirect(url);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Spring Security Config Error while server startup

If I keep remember-me element in security.xml file and startup a server then I got following error.
No UserDetailsService registered.......
If I remove this remember-me element then it works fine.
How to get rid of this error...
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<http auto-config="false" use-expressions="true"
access-denied-page="/login.jsp?error=true" entry-point-ref="authenticationEntryPoint">
<remember-me key="abcdefgh" />
<logout invalidate-session="true" />
<intercept-url pattern="/login.jsp" access="permitAll" />
<intercept-url pattern="/index.jsp" access="permitAll" />
<intercept-url pattern="/pub" access="isAuthenticated()" />
<intercept-url pattern="/*" access="permitAll" />
<custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
</http>
<beans:bean id="authenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"
p:authenticationManager-ref="customAuthenticationManager"
p:authenticationFailureHandler-ref="customAuthenticationFailureHandler"
p:authenticationSuccessHandler-ref="customAuthenticationSuccessHandler" />
<!-- Custom authentication manager. In order to authenticate, username and
password must not be the same -->
<beans:bean id="customAuthenticationManager" class="com.cv.pub.cmgt.framework.security.CustomAuthenticationManager" />
<!-- We just actually need to set the default failure url here -->
<beans:bean id="customAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
p:defaultFailureUrl="/login.jsp?error=true" />
<!-- We just actually need to set the default target url here -->
<beans:bean id="customAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler"
p:defaultTargetUrl="/pub" />
<!-- The AuthenticationEntryPoint is responsible for redirecting the user
to a particular page, like a login page, whenever the server sends back a
response requiring authentication -->
<!-- See Spring-Security Reference 5.4.1 for more info -->
<beans:bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
p:loginFormUrl="/login.jsp" />
<!-- The tag below has no use but Spring Security needs it to autowire the
parent property of org.springframework.security.authentication.ProviderManager.
Otherwise we get an error A probable bug. This is still under investigation -->
<authentication-manager />
</beans:beans>
Spring Security's provided RememberMeServices requires a UserDetailsService in order to work. This means you have two options:
1) If possible, I recommend this as your best option. Instead of writing a custom AuthenticationProvider, write a custom UserDetailsService. You can find an example UserDetailsService looking at InMemoryDaoImpl You can then wire it similar to the configuration below. Note you would remove your custom AuthenticationManager too.
<http ..>
...
<remember-me key="abcdefgh" />
</http>
<authentication-manager>
<authentication-provider user-service-ref="myUserService"/>
</authentication-manager>
<beans:bean id="myUserService" class="MyUserService"/>
2) Write your own RememberMeServices implementation that does not require a UserDetailsService. You can take a look at TokenBasedRememberMeServices for an example (but it requires UserDetailsService). If you want to use the namespace configuration your RememberMeServices implementation will need to implement LogoutHandler. You can then use the namespace to wire it.
<http ..>
...
<remember-me ref="myRememberMeServices"/>
</http>
<beans:bean id="myRememberMeServices" class="sample.MyRememberMeServices"/>

Resources