I am trying to configure spring security 3 so that when a users is forced to login again (eg. when the session has timed out) the user will be taken back the the page they where on before the authorisation process began.
I am using a SavedRequestAwareAuthenticationSuccessHandler but the original request does not seem to be saved in the cache.
Below is my security configuration.
<security:http auto-config="false"
use-expressions="true"
access-denied-page="/views/auth/login?error=true"
entry-point-ref="authenticationEntryPoint" >
<security:intercept-url pattern="/*" access="hasRole('ROLE_USER')" />
<security:intercept-url pattern="/views/*" access="hasRole('ROLE_USER')" />
<security:intercept-url pattern="/data/*" access="hasRole('ROLE_USER')" />
<security:intercept-url pattern="/auth/*" access="permitAll" />
<security:logout invalidate-session="true" logout-success-url="/views/auth/login" logout-url="/views/auth/logout" />
<security:session-management invalid-session-url="/views/auth/login" >
<security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
<security:custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER"/>
</security:http>
<security:authentication-manager />
<bean id="authenticationFilter" class="com.security.web.filter.UsernamePasswordAuthenticationFilter">
<property name="allowSessionCreation" value="true" />
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler" ref="aAuthenticationFailureHandler" />
<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
</bean>
<bean id="authenticationManager" class="com.security.web.manager.AuthenticationManager" />
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint" >
<property name="loginFormUrl" value="/views/auth/login"/>
</bean>
<bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/views/auth/login?error=true"/>
</bean>
<bean id="authenticationSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/views"/>
</bean>
Any help would be appreciated.
I know this question is old, but I wanted to document what I found for others.
Short Answer
The problem is that if you use the invalid-session-url on the <session-management> tag, then the original request will not be saved in the cache.
Explanation
This is discussed at the spring source forum:
http://forum.springsource.org/showthread.php?89352-requestCache-null-when-using-session-management-gt-invalid-session-url
In the above forum, Luke Taylor, a senior member of the security team says:
The invalid-session-url implies that the previous session has expired and the user should start again. There's no connection with the RequestCache which is used for restoring a request after a user has logged in.
and
When a session expires you can't know that it is safe to continue with the requested URL as some required state may have been lost along with the session. It may be OK in your particular case, but it's not a safe assumption in general.
You may be missing this :
<bean id="requestCacheAwareFilter"
class="org.springframework.security.web.savedrequest.RequestCacheAwareFilter">
<constructor-arg ref="requestCache"/>
</bean>
<bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache"/>
also you need to add requestCache been to authenticationSuccessHandler
<property name="requestCache" ref="requestCache"/>
Related
I'm using spring authentication against ldap. If the provided user id and password exists in ldap, then I was able to get the user login. I would like to restrict this based on the user's memberOf attribute in the LDAP. If the user has memberOf attribute with a specific CN value (CN=adminaccess or CN=superadminaccess), then authentication/authorization should pass.Else authentication/authorization should fail.
<security:http auto-config="true" use-expressions="true" access-denied-page="/admin/auth/denied">
<security:intercept-url pattern="/admin/auth/login" access="permitAll" />
<security:intercept-url pattern="/admin/dashboard/*" access="hasAnyRole('ROLE_ADMINACCESS','ROLE_SUPERADMINACCESS')"/>
</security:http>
<security:authentication-manager>
<security:ldap-authentication-provider user-dn-pattern="CN={0},CN=Users" group-search-base="CN=adminaccess,CN=Users" />
</security:authentication-manager>
<bean id="ldapContext"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://xxx.ds.yyy.com:389/DC=xxx,DC=ds,DC=yyy,DC=com"/>
<property name="userDn" value="CN=aaa,CN=Users,DC=xxx,DC=ds,DC=yyy,DC=com"/>
<property name="password" value="thepassword"/>
</bean>
I always go to the Access Denied page with my above configuration. If I remove the access="hasAnyRole('ROLE_ADMINACCESS','ROLE_SUPERADMINACCESS')" from the security:intercept-url, I'm able to always access with valid user/password, even if the user is not part of adminaccess (which I was hoping would be restricted because my group -search-base had specified CN=adminaccess).
Wondering what the configuration should be:
To restrict access to just users who are memberOf CN=adminaccess and/or CN=superadminaccess
Specify correct group-search-base. If I specify only CN=Users, I'm getting a timeout as this is going against our corporate ldap. When I looked up users on LDAP browser, I couldnt find a "ou" that couldhelp. With my above configuration group-search-base="CN=adminaccess,CN=Users", I dont get a timeout, but I dont think it is correct either
Not sure if there is a better way, but I was able to successfully get this working using DefaultLdapAuthoritiesPopulator and updating to the below configuration:
<security:http auto-config="true" use-expressions="true" access-denied-page="/admin/auth/denied">
<security:intercept-url pattern="/admin/auth/login" access="permitAll" />
<security:intercept-url pattern="/admin/dashboard/*" access="hasAnyRole('ROLE_ADMINACCESS','ROLE_SUPERADMINACCESS')"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider
ref="ldapAuthProvider"></security:authentication-provider>
</security:authentication-manager>
<bean id="ldapContext"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://xxx.ds.yyy.com:389/DC=xxx,DC=ds,DC=yyy,DC=com"/>
<property name="userDn" value="CN=aaa,CN=Users,DC=xxx,DC=ds,DC=yyy,DC=com"/>
<property name="password" value="thepassword"/>
</bean>
<bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean
class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="ldapContext" />
<property name="userDnPatterns">
<list>
<value>CN={0},CN=Users</value>
</list>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="ldapContext" />
<constructor-arg value="CN=Users" />
<property name="groupRoleAttribute" value="CN" />
</bean>
</constructor-arg>
</bean>
With this configuration, if the login username/password provided is correct, all the groups that the user is "memberOf" (pattern CN=Users,DC=xxx,DC=ds,DC=yyy,DC=com), get loaded as his "roles" (prefixed with ROLE_) and I'm able to manage access to these roles using security:intercept-url
I try to implement my own example based on official tutorial Sparklr2/Tonr2. Everything looks good but when I remove from web.xml in my Tonr2 implementation, spring security filter I have exception:
No redirect URI has been established for the current request
I can't understand what URL should I use. Here is my code, for client implementation:
<!--apply the oauth client context -->
<oauth:client id="oauth2ClientFilter" />
<!--define an oauth 2 resource for sparklr -->
<oauth:resource id="provider" type="authorization_code" client-id="client" client-secret="secret"
access-token-uri="http://localhost:8080/provider/oauth/token" user-authorization-uri="http://localhost:8080/provider/oauth/authorize" scope="read,write" />
<beans:bean id="clientController" class="com.aouth.client.ClientController">
<beans:property name="trustedClientRestTemplate">
<oauth:rest-template resource="provider" />
</beans:property>
</beans:bean>
And for provider:
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic />
</http>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<!-- The OAuth2 protected resources are separated out into their own block so we can deal with authorization and error handling
separately. This isn't mandatory, but it makes it easier to control the behaviour. -->
<http pattern="/secured" create-session="never" access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/secured" access="ROLE_USER,SCOPE_READ" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<http-basic />
</http>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased" xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<oauth:resource-server id="resourceServerFilter" resource-id="resource" token-services-ref="tokenServices" />
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="clientDetailsService" ref="clientDetails"/>
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<http auto-config="true" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/test" access="ROLE_USER" />
<intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
</http>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service>
<user name="pr" password="pr" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices" >
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="client" resource-ids="resource" authorized-grant-types="authorization_code, implicit"
authorities="ROLE_CLIENT" scope="read,write" secret="secret" />
</oauth:client-details-service>
I just want my client to work without spring security. And when I need my protected resource I want to login only on provider side.
You 2nd XML that you pasted here is the spring's XML for the oauth-provider and the protected-resource, which in your case run in the same webapp. (you can separate them, of course, if you wish).
The client (the 1st pasted-XML) is a different story. If I understand you correctly, you want your client to run without Spring's help (to be a regular webapp, and not spring-security-oauth-client webapp).
You have to understand how oAuth works: the client tries to get to a protected resource; if it does not have the access-token, it is being redirected to the oAuth-provider (that shows the login page and supplies the token). By the standard, the request for the access-token MUST contain a "redirect-uri" param, so after a successful login, the oAuth-provider knows where to redirect the client to. The oAuth client does it for you, and if you delete the "oauth client" from your web.xml, you now have to implement this by yourself.
Thanks for your answer. But I still don't understand how spring
security influences my oAuth client. And can I use for client side
spring-oauth (spring-mvc) without spring-security?
When you write this line in your XML:
< oauth:client id="oauth2ClientFilter" />
it means that you use spring-security-oauth, which is a package dedicated for oauth, built on spring-security. If you dig in, it puts a special filter (OAuth2ClientContextFilter) in the chain that handles the oAuth stuff, that are relevant for the client. One of them is sending the request with all the params ("redirect-uri" is one of them).
If you decide NOT to use spring-security-oauth, well - you will have to implement this logic by yourself...
Hope that helps!
I am attempting to authenticate via X.509 smart card to my application. For the moment, my application doesn't have any users defined, so I'm trying to use anonymous authentication. I'll switch it to hasRole() once I create users.
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="myUserService" />
</security:authentication-manager>
<!-- TODO: Enable this once I am ready to start annotating the service interfaces -->
<security:global-method-security pre-post-annotations="enabled" />
<security:http use-expressions="true" authentication-manager-ref="authenticationManager" access-denied-page="/index2.xhtml" >
<security:anonymous enabled="true" />
<security:x509 subject-principal-regex="CN=(.*?)," user-service-ref="myUserService" />
<security:intercept-url pattern="/**" access="isAnonymous()" requires-channel="https" />
<!-- TODO: configure invalid-session-url, delete sessionid -->
<security:session-management>
<security:concurrency-control max-sessions="2" error-if-maximum-exceeded="true"/>
</security:session-management>
</security:http>
<bean id="roleVoter"
class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_USER > ROLE_AUTHENTICATED
ROLE_AUTHENTICATED > ROLE_UNAUTHENTICATED
ROLE_UNAUTHENTICATED > ROLE_ANONYMOUS
</value>
</property>
</bean>
It seems to be caught in the infinite loop issue, which I thought I was avoiding using isAnonymous().
I'm probably making a dumb error, so if someone can point out said stupidity, I'd be grateful.
The issue was a problem with configuring FacesServlet in web.xml. The FacesServlet was mapped to one path, which seemed to be incompatible with the intercept-url defined for Spring Security.
We've since jettisoned JSF (and good riddance).
In our app spring security uses ldap as a provider.
i am working on a change that will let you flip a flag in dev that will allow you to log in if your user/pass matches a value from database. the ldap server might be down and you can still log in.
What ive realized though is that some urls are secured with
#Secured( {"ROLE_USER","ROLE_MERCHANT"})
so i need to still have some dealings with spring security in order for my logins to work. How do i go about doing this?
You can configure 2 providers: one LDAP provider and another DAO provider.
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="yourLdapAuthenticationProvider" />
<sec:authentication-provider ref="yourDaoAuthenticationProvider" />
</sec:authentication-manager>
If the LDAP fails, it will fall back to DAO authentication provider.
You will need to configure your own authentication filter to inject that flag into yourDaoAuthenticationProvider so that when the authentication falls back to yourDaoAuthenticationProvider, it can check whether to proceed with further authentication (say, in development) or ignore it (say, in production). So, in your authenticationFilter, override setDetails() to store the flag:-
myAuthenticationFilter bean
#Override
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
YourObject yourObject = new YourObject(request.getParameter("devAuthAgainstDAO"));
authRequest.setDetails(yourObject);
}
With this, have your yourDaoAuthenticationProvider to check against this flag before proceeding with further authentication.
In the end, your configuration will look something like this:-
<sec:http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">
<sec:logout logout-success-url="/login.jsp"/>
<sec:intercept-url ... />
<sec:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthenticationFilter"/>
</sec:http>
<bean id="myAuthenticationFilter" class="[YOUR_CUSTOM_AUTHENTICATION_FILTER]">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler" ref="failureHandler"/>
<property name="authenticationSuccessHandler" ref="successHandler"/>
</bean>
<bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login.jsp"/>
</bean>
<bean id="successHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/welcome.jsp"/>
<property name="alwaysUseDefaultTargetUrl" value="true"/>
</bean>
<bean id="failureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login.jsp?login_error=1"/>
</bean>
<bean id="yourLdapAuthenticationProvider" ... />
<bean id="yourDaoAuthenticationProvider" ... />
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="yourLdapAuthenticationProvider"/>
<sec:authentication-provider ref="yourDaoAuthenticationProvider"/>
</sec:authentication-manager>
I am screwed with the spring security configuration issue
Here is my configuration
<security:global-method-security pre-post-annotations="enabled" />
<security:http auto-config="true">
<security:intercept-url pattern="/dologin" access="ROLE_USER,ROLE_ANONYMOUS" />
<security:form-login login-processing-url="/security_check" login-page="/onlogin" always-use-default-target="false" authentication-failure-url="/onlogin" default-target-url="/home" />
<security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/onlogout" />
<security:remember-me />
<security:http-basic/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="daoAuthenticationProvider"/>
</security:authentication-manager>
<bean id="anonymousAuthenticationProvider"
class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="badgerbadgerbadger" />
</bean>
<bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" />
</bean>
My problem is that when a request comes for authentication; I find there are only two providers registered.
org.springframework.security.authentication.AnonymousAuthenticationProvider#8fe4ad
org.springframework.security.authentication.RememberMeAuthenticationProvider#1db9cb9
What might me going wrong? Please describe?
I believe you need to identify your custom provider to spring security by using the security:custom-authentication-provider tag.
For example:
<bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<security:custom-authentication-provider />
<property name="userDetailsService" ref="userDetailsService" />
</bean>
You may need that on your anonymousAuthenticationProvider bean also.
Try the following:
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService"/>
</security:authentication-manager>
in your daoAuthenticationProvider you have a reference to userDetailsService, but I don't see such bean in your configuration.
check pervious error messages, I would expect to see a reference to missed bean there.
Use/define 'id' while defining security authentication manager.
For Example:
<security:authentication-manager id="authenticationManager" alias="authenticationManager">
<security:authentication-provider ref="daoAuthenticationProvider"/>
</security:authentication-manager>