I wonder, is there any way to disable remember-me in Spring Security?
Scenario I want to implement is pretty common: after closing browser window I would like user's session to expire. Seems weird, but it doesn't work with Tomcat 7 & Spring Security 3.1.
We use auto-config in Spring Security configuration file, but there is no remember-me element.
What is the best solution to get it working? Thanks in advance!
Update Here is the usage scenario to clarify my problem:
User logs into restricted area, say, /secure.html
Then he closes the browser without logging out manually.
He opens the browser again and goes directly to /secure.html.
Current Spring's behaviour: page is displayed successfully. Expected behaviour: redirecting to login page.
New symptoms for differential diagnosis:
User is probable reathenticated because JSESSIONID in the same between browser close/open. How I could forse Tomcat or Spring to generate a new session for every browser session?
Update Fragment of Spring Security configuration:
<http auto-config="true">
<anonymous key="anonymous-security" />
<intercept-url pattern="/auth/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="ROLE_ADMIN" />
<form-login login-page="/auth/login.html"
default-target-url="/auth/default.html"
authentication-failure-url="/auth/failed.html" />
<logout logout-success-url="/auth/logout.html" delete-cookies="JSESSIONID" />
</http>
Update Documentation claims that there is no default remember-me configuration in auto-config="true" since 3.0 (we use 3.1):
In versions prior to 3.0, this list also included remember-me
functionality. This could cause some confusing errors with some
configurations and was removed in 3.0.
What's wrong with my web app?
Why don't you just logout the existing user by redirecting to: /j_spring_security_logout?
In my implementation with latest Spring security and Tomcat 6, I am using the following configuration: Is it similar to yours?
<http use-expressions="true" access-denied-page="/Error.xhtml">
<intercept-url access="isAuthenticated()" pattern="/secure.xhtml"/>
<form-login />
<logout invalidate-session="true" logout-success-url="/search.xhtml"/>
</http>
You can try adding a logouthandler to teminate the local session:
<!-- Logout handler terminating local session -->
<bean id="logoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
<property name="invalidateHttpSession" value="true" />
</bean>
In reality it defaults to true so you probably don't need the property to be set.
Problem clarification:
I ran into the same issue: my browser would remember my user.
Typically: after logging in to access a restricted area, closing the browser, then reopen it and enter the same restricted area it would let me access it when I expected to be prompted for credentials.
After playing around I noticed one important thing: this behavior is NOT consistent across browsers:
Eclipse's underlying browser does remember after closing
Chrome does remember after closing
IE (9) does NOT remember after closing
Firefox (16.0.1) does NOT remember after closing
Safari (5.1.7 for windows) does NOT remember after closing
More browser types & versions could be tested...
Solution:
A work around may be to try detect when a user is closing his browser, and trigger a log-out when this happens. Not too sure how doable that is though.
There might be a better solution, I'll update this answer if I find it.
Related
I'm trying to make a java web application truly stateless (although still using basic authentication) but since now a JSESSIONID cookie is always generated by our servlet container (Tomcat).
This my stack:
Java: 1.8
Spring: 4.1.6.RELEASE
Spring Security: 4.0.2.RELEASE
Tomcat: 7.0.93
We use XML configuration, so this is my security config file, where I used the STATELESS option for session creation:
<beans:bean id="requestCache" class="org.springframework.security.web.savedrequest.NullRequestCache" />
<http use-expressions="true" create-session="stateless" pattern="/api/**">
<request-cache ref="requestCache"/>
<csrf disabled="true"/>
<!-- REST ENDPOINTS PATH BASED -->
<intercept-url pattern="...."/>
<intercept-url pattern="...."/>
</http>
As documented in this response this should be enough to ensure that Spring Security won't create a session, but other parts of my application could still create one.
The question is: how do I track who's requesting the session creation?
Basically what I'm trying to do is adapt a backend used by a stateful java application, to be consumed in a stateless way by other client applications that will only make calls to a particular path (/api/**) as detailed in my security config file.
This stateful part uses some beans that are session-scoped; I need to use those same beans but in a request-scope way, thus my need to ensure that a JSESSIONID cookie is never created.
Trying for example to disable cookies altogheter in Tomcat (or in the browser) accomplishes this, so I'm trying a way to do it directly with Spring.
If you want to be sure sessions are not created, create a filter and wrapper the HttpServletRequest with a class the blocks/fails/ignores the getSession(...) calls.
I'm developing application using Spring MVC 4.X, using spring security 4.X for authentication/authorization and Thymeleaf 2.1.2 for view layer. I'm controlling access to controllers using #Secured annotion. Problem is, that Thymeleaf ignores these annotations when resolving sec:authorize-url attributes. Does anyone has working setup for this?
My security config looks like this:
<http use-expressions="true" entry-point-ref="authEntryPoint" security-context-repository-ref="sessionRepository">
<intercept-url pattern="/login/**" access="isAnonymous()"/>
<intercept-url pattern="/**" access="hasRole('USER')" />
<custom-filter position="FORM_LOGIN_FILTER" ref="usernamePasswordDomainAuthenticationFilter"/>
<logout logout-url="/logout"/>
</http>
and in servlet config, there is
<security:global-method-security secured-annotations="enabled" />
Controllers look like this:
#Secured("ROLE_EXAMPLE")
#Controller
#RequestMapping("/example")
public class ExampleController {
}
We use this Setup so security protects all controllers globally plus every controller (or controller's method if needed) can restrict access more if needed.
Everything works fine, secured controllers are not accessible for user without speciified role, thymeleaf-extras-springsecurity4 is obviously configured correctly, because sec-authorize="hasRole('EXAMPLE')" works as expected (and it takes #Secured into account).
But I feel it is prone to error to declare role both in controller and in the template, so I'd much rather use sec:authorize-url. By debugging, I found out, that it checks
if user hasRole('USER'), as declared in Security's xml config file, but it completely ignores #Secured annotations when using sec:authorize-url. In worst case, I could declare all the access in security's config file, but I like #Secured annotation much more.
Is it possible to make this setup work?
I need to use CORS with Spring Security. I've succeeded in getting login and basic security working, using a OncePerRequestFilter that is configured in app-beans.xml as follows:
<bean id="corsAwareAuthenticationFilter"class="org.broadinstitute.portal.servlet.CorsAwareAuthenticationFilter"/>
<security:http use-expressions="true">
<security:custom-filter ref="corsAwareAuthenticationFilter" after="PRE_AUTH_FILTER"/>
...
I basically followed the approach in this question: Cross-Origin Resource Sharing with Spring Security
My configuration for logout in app-beans.xml is simply:
<security:logout delete-cookies="JSESSIONID"/>
This works fine without CORS.
My problem is logging out. CORS is stopping access to j_spring_security_logout. Any idea why my OncePerRequestFilter is being called when logging in, but not when logging out?
Edited to add:
Thanks to alain.janinm, I solved the problem. I needed to set my filter to be called before the LOGOUT_FILTER. The following configuration addition solved the problem:
<security:custom-filter ref="corsAwareAuthenticationFilter" before="LOGOUT_FILTER"/>
Note, using position="LOGOUT_FILTER" didn't work, as that put my filter in the same position as the Spring LOGOUT_FILTER. My filter doesn't do the same thing as the LOGOUT_FILTER -- all mine does is to add the CORS headers. So I actually need the Spring LOGOUT_FILTER to still be called.
Thanks to alain.janinm, I solved the problem. I needed to set my filter to be called before the LOGOUT_FILTER. The following configuration addition solved the problem:
<security:custom-filter ref="corsAwareAuthenticationFilter" before="LOGOUT_FILTER"/>
Note, using position="LOGOUT_FILTER" didn't work, as that put my filter in the same position as the Spring LOGOUT_FILTER. My filter doesn't do the same thing as the LOGOUT_FILTER -- all mine does is to add the CORS headers. So I actually need the Spring LOGOUT_FILTER to still be called.
I'm trying to implement the Remember Me functionality that is part of Spring 3.1 to allow customers to automatically log in when they have previously selected that option in the login form. Here is my actual implementation:
In spring-security-config.xml:
<security:http auto-config="false" entry-point-ref="myEntryPoint" request-matcher="regex" disable-url-rewriting="true">
...
<security:remember-me key="mykey" authentication-success-handler-ref="rememberMeAuthenticationSuccessHandler"/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="acceleratorAuthenticationProvider" />
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
</security:authentication-manager>
<bean id="rememberMeAuthenticationSuccessHandler" class="uk.co.portaltech.qlaccelerator.storefront.security.RememberMeAuthenticationSuccessHandler" scope="tenant">
<property name="myCookieStrategy" ref="myCookieStrategy" />
<property name="customerFacade" ref="customerFacade" />
</bean>
<bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="myKey" />
</bean>
My login.jsp contains the spring rememeber me checkbox:
<form:checkbox id="_spring_security_remember_me" class="rememberMe" path="_spring_security_remember_me" />
When I access the site the first time (over HTTP session) it doesn't log me in automatically but as soon as I click on the login button (over HTTPS session) it automatically logs me in.
Is this the way it is supposed to work or am I missing something in the configuration to let Spring log me in when I access the site?
remember me lets the app remember the user across sessions. meaning, if the server bounces or if the user closed his browser and reopened it. in these cases, the user will not be asked again for his credentials.
in your case that you describe, the user (you) enter his credentials, and only then logs in? what is "automatically" means?
htlpful links:
remember me result is ignored by spring security, and i am still redirected to the login page
Configuring remember-me in spring security
Check if the remember-me cookie is flagged as "secure" (look in your browser's cookie list). If so, it won't be sent over HTTP connections, which would explain what you see.
The default is to create a secure cookie if the request is over HTTPS. You can change this using the useSecureCookie property of the RememberMeServices implementation you are using.
I'm using Spring 3.0.3 with Spring Security.
So, I have fairly lenient restrictions on an app I'm making. I only want to make sure that a person can log in and be authenticated in order to view the app. I don't want to grant roles to every potential user of this app (could be in the 10s of thousands).
So, it's been fine to use:
<security:intercept-url pattern="/**" access="isFullyAuthenticated()" requires-channel="https"/>
But now I want to be able to restrict people from using the app if I need to, so I created a role called ROLE_BANNED in the hopes that I could just assign roles to those people being problems.
So, now I'm trying this:
<security:intercept-url pattern="/**" access="isFullyAuthenticated() and not hasRole('ROLE_BANNED')" requires-channel="https"/>
This seemed to work at first, but it can't load my denied page. I believe that it is restricting access to the denied page. I can't load the denied page through the controller or as a jsp in WEB-INF.
Can someone show me how to allow authenticated users to access all of my app and send people with a specific role (ROLE_BANNED) to the denied page?
EDIT
Here is my whole security:http setup:
<security:http auto-config="true" access-denied-page="/denied" entry-point-ref="casAuthenticationEntryPoint" use-expressions="true">
<security:intercept-url pattern="/**" access="isFullyAuthenticated() and not hasRole('ROLE_BANNED')" requires-channel="https"/>
<security:intercept-url pattern="/denied" access="IS_AUTHENTICATED_FULLY" filters="none" />
<security:logout logout-url="/logout" logout-success-url="${cas.logoutUrl}" />
<security:session-management session-fixation-protection="none" />
<security:custom-filter after="CAS_FILTER" ref="casAuthenticationFilter"/>
<security:custom-filter before="CHANNEL_FILTER" ref="channelProcessingFilter" />
<security:port-mappings>
<security:port-mapping http="80" https="443" />
</security:port-mappings>
</security:http>
I have tried using a controller mapped denied page (/denied), a jsp page (/denied.jsp) and even a simple html page (/denied.html), but I get a 404 for every single one. I don't see anything in the log files when this occurs.
I ended up doing the following:
<security:intercept-url pattern="/**" access="isFullyAuthenticated()" requires-channel="https"/>
<security:intercept-url pattern="/banned" access="isFullyAuthenticated() and hasRole('ROLE_BANNED')" requires-channel="https"/>
Meaning that you have to be logged in for both cases, but you have to have the BANNED role to access the banned page.
I also added an aspect that runs before every controller method with RequestMethod.GET that checks to see if the user has the BANNED role and, if so, redirects them to /banned.
If anyone knows of a better way to do this, please add an answer.
As you said, I think you just need to make your "denied" page not require any security to access, so just add an intercept-url for that specific page...
This example is with Spring Security 2, but it should translate...
<intercept-url pattern="/denied.html" access="IS_AUTHENTICATED_ANONYMOUSLY" filters="none" />
Edit:
You'll probably also need to make your javascript, css, images, etc, also have a similar exemption from the security restrictions otherwise your page will not load up anything other than the plain text.