I have configured custom session management like :
<sec:session-management session-fixation-protection="none">
<sec:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</sec:session-management>
And remember me like :
<sec:remember-me />
<sec:custom-filter ref="rememberMeFilter" after="REMEMBER_ME_FILTER"/>
<bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="springRocks"/>
</bean>
and when i log-in with remember me check and close the browser and open the new browser again and remember me is not working, instead of that i am getting session exceeded error. Because i have set the max-sessions=1.
Can any one help me out from this.
Thanks in advance.
I faced the same issue too, I wanted to use session concurrency control as well as remember-me. My config is slightly different, i dont throw an error to user if max-session is exceeded, instead i simply expire the old session so that the user can continue with the new session. With the spring provided beans it wont work as expected. As I login 2nd time, concurrency control kicks in and expires the old session, then the user continues with the newly created session. But when the user tries to access the system with the 1st session, ConcurrentSessionFilter detects that this session was expired and redirects to the configured expired-url, which is normal and expected.
But my requirement was different, if the user tries to use the 1st session, the 2nd session should be expired and the user should be re-authenticated and then a new session should be created for the user to continue. Basically, the user can switch between different browsers without actually entering username/password using the remember-me option checked-on, but there will be only one active session in the server. Session will be expired/created as and when user switches between different browsers.
I managed to achieve that by extending and customizing the spring beans. If your requirement is simmilar i could help u with my config.
Related
Could someone help me on this. appreciate your help.
I am using Spring security 3.1 with create-session="stateless" option.
Which throwing "InsufficientAuthenticationException" : "Full authentication is required to access this resource" exception of ExceptionTranslationFilter.
I am not able to understand what I am doing wrong and why I am getting this exception . As this exception stated that the credentials are not proper but I can see the credentials are going through request.Still I am getting 401 unauthorized
Fact is that the user is able to login properly & I get the message on console also. But again it is redirecting to login page due to access denied exception.
Here I am putting the code
Spring-Security.xml
<http entry-point-ref="negotiateSecurityFilterEntryPoint"
create-session="stateless" >
<intercept-url pattern="/user/loginuser" access="ROLE_ANONYMOUS"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
<custom-filter ref="securityContextPersistenceFilter" after="BASIC_AUTH_FILTER" />
<custom-filter ref="ldapAuthFilter" position="CAS_FILTER" />
<custom-filter ref="databaseAuthFilter" position="FORM_LOGIN_FILTER" />
</http>
<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name='securityContextRepository'>
<bean class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<property name='allowSessionCreation' value='false' />
</bean>
</property>
</bean>
As far as I know, that's exactly what stateless is meant to do.
Once you set create-session parameter as stateless, on every http call the SecurityContextPersistenceFilter won't be even called (by default) or, even if you force it to be called according to your configuration, it won't be any session level security information in the SecurityContextHolder.
This stateless pattern is intended to be used in a Rest style architecture, where authentication and authorization information is sent on every request. Better said, I don't think that stateless session creation pattern should be used unless you are developing a full stateless application
I found a good post about this, Spring Security Session Management, look carefully section 2. When Is The Session Created?
So stateless session creation strategy does not fit to a classic login form pattern.
In your scenario, I guesss that what is happening is that, once the login request is completed and the request is authenticathed, it is probably redirecting to a kind of welcome page using an HTTP 301 or 302 redirect, redirection which again is not carrying authentication info, so ends redirecting again to login page.
If you simply use "ifRequired" as session-creation, or as it is the default value, just don't set it, I bet your login would end successfully and redirect to wherever it should correctly without asking to log in again. And, if you do it like this, avoid setting the SecurityContextPersistenceFilter, it is configured automatically.
I've set up saml context within my app with initial key manager bean:
<!-- Central storage of cryptographic keys -->
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<constructor-arg value="classpath:security/samlKeystore.jks"/>
<constructor-arg type="java.lang.String" value="nalle123"/>
<constructor-arg>
<map>
<entry key="apollo" value="nalle123"/>
</map>
</constructor-arg>
<constructor-arg type="java.lang.String" value="apollo"/>
</bean>
And this config works fine for my IDP. Namely it successfully authenticates user after incoming SAML messages were verified.
Also, I've tried to simply replace this manager with EmptyKeyManager implementation, but error above appears.
There are few questions that would be good to know before these changes would be deployed to production :).
How does it work take into account that my IDP knows nothing about imported default public key from samlKeystore.jks?
How to correctly replace initial implementation of keyManager with EmptyKeyManager in case it is not required for my config?
As you can find in the manual (chapter 8.1), you can only use EmptyKeyManager in case your application doesn't need to create digital signatures. The error you mention suggests Spring SAML does need to create one in your usage pattern. Perhaps you are using HTTP-Artifact binding and require outgoing ArtifactRequest messages to be signed?
The manual also shows the exact line of configuration to replace your current keyManager with the EmptyKeyManager.
I'm using spring-security-kerberos to authenticate the remote users - this works well. The problem that I have is that sometimes users do not have the kerberos ticket in place and I need to use another form of authentication. I've wrote my own Authentication Provider (myCusomAuthenticationProvider) for this purpose. This custom provider should ask the user for BASIC authentication and uses several LDAP servers to authenticate the user based on username and password.
The problem that I see is that my custom authentication manager always gets KerberosServiceRequestToken as the authentication token and I don't manage to get UsernamePasswordAuthenticationToken. How can I make the server return both "Negotiate" and "Basic" methods to the browser and have my own provider handle the basic authentication?
I've found a way to do it with some tweaks to the spring-security-kerberos code but I'm trying to find a better way to do this.
web.xml: http://pastebin.com/embed.php?i=ZidnBMwZ
root-context-with-krb.xml: http://pastebin.com/c8vfUZfV
This answer will help you Optional kerberos authentication
And if you're need more custom, then extends KerberosAuthenticationProvider by your class MyCustomAuthenticationProvider and paste it to class attribute:
<bean id="kerberosAuthenticationProvider" class="com.test.MyCustomAuthenticationProvider">
<property name="kerberosClient">
<bean class="org.springframework.security.extensions.kerberos.SunJaasKerberosClient">
<property name="debug" value="${krb.debug}"/>
</bean>
</property>
<property name="userDetailsService" ref="dummyUserDetailsService"/>
</bean>
my application currently has one authentication defined for a specific URL, with a custom filter, where user is authenticated by extracting the user details from the URL (in the query string). This is working fine.
Now I want to add a new authentication using an identity certificate for a different URL pattern (the authentication is completely different from the first one, it has a differnt user details service etc). I saw there's already support for x509 cert authentication in spring security. I want to understand what is the best configuration I should do considering the following:
I want users access the different URL patterns to be authenticated by the relevant authentication, and not try first with one authentication and if that fails then try the other one. This is why I think I may need 2 different authentication managers?
My application must be in HTTPS for all URLs
I need to configure tomcat in a way where client authentication is required only for the specific URL pattern, not to all the application.
Here is what I have so far for the first authentication, any help would be appreciated:
security-applicationContext.xml:
<sec:http pattern="/urlAuth1" auto-config="false" entry-point-ref="url1EntryPoint">
<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" requires-channel="https" />
<sec:custom-filter position="PRE_AUTH_FILTER" ref="urlPreAuthFilter"/>
</sec:http>
<bean id="urlPreAuthFilter" class="com.myapp.security.UrlPreAuthenticatedFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="urlPreAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" ref="urlUserDetailsService" />
</bean>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="urlPreAuthProvider" />
</sec:authentication-manager>
Thanks!
EDIT - 30.01.13:
I added the following section to my security context.xml. When I debug my app when accessing both URLs patterns, I see that for first URL pattern (/urlAuth1) the getProviders() in the authenticationManager returns just one provider which is the urlPreAuthProvider, and for the second URL pattern (/certAuthTest) it returns two providers - the anonymous and preauthenticatedprovider which I guess are registered by default. For me this is OK since it means each pattern goes through the correct providers. I want to make sure I am not missing anything, does it seem right to you?
<sec:http pattern="/certAuthTest" auto-config="false">
<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" requires-channel="https" />
<sec:x509 subject-principal-regex="CN=(.*?)," user-service-ref="certUserDetailsService"/>
</sec:http>
regarding the web.xml configuration for clientAuth, I'll do some more reading and see if this works. Thanks!
You can declare separate authentication manager beans for each URL pattern you want and then assign them to the individual filter chains using the authentication-manager-ref attribute on the <http /> element.
<http pattern="/someapi/**" authentication-manager-ref="someapiAuthMgr">
...
</http>
You can use the standard ProviderManager bean for the individual authentication managers.
To enforce HTTPS for all requests, you can use standard web.xml settings.
Client certificate authentication takes place when the SSL connection is established. So you either have it or you don't. Investigate the clientAuth tomcat connector setting. You can set it to "want" to ask for a client certificate but not require one for the SSL connection to succeed.
My Spring Security XML is as following:
<http use-expressions="true">
<intercept-url pattern="/login" access="isAnonymous()" requires-channel="https"/>
<intercept-url pattern="/login/" access="isAnonymous()" requires-channel="https" />
<intercept-url pattern="/logout-success" access="isAnonymous()" />
<intercept-url pattern="/logout-success/" access="isAnonymous()" />
<intercept-url pattern="/logout" access="isAuthenticated()" />
<intercept-url pattern="/**" access="hasRole('ROLE_SUPER_ADMIN')" />
<form-login login-page="/login/" default-target-url="/example/Login_execute"/>
<logout logout-url="/logout" logout-success-url="/logout-success" />
<remember-me services-ref="rememberMeServices"/>
<port-mappings>
<port-mapping http="8080" https="8443"/>
</port-mappings>
</http>
...
<beans:bean id="userDetailsService" class="com.myownpackage.UserAccountServiceImpl"/>
<beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:property name="userDetailsService" ref="userDetailsService" />
<beans:property name="tokenRepository" ref="persistentTokenRepository" />
<beans:property name="key" value="myownkey" />
</beans:bean>
<beans:bean id="persistentTokenRepository" class="com.myownpackage.PersistentTokenRepositoryImpl" />
Whenever I login and I tick the remember me, my program will save something to remember me database table (that's correct).
If I close my browser, re-open the browser, and open a page which requires authentication, my program will execute processAutoLoginCookie at PersistentTokenBasedRememberMeServices and returning correct UserDetails (that's also correct)
BUT, even so, I am still redirected to the login page.
By the way, the login page is customized, and what I do is just displaying JSP file with a form for login.
Is there any step I missed when writing the spring security XML?
Spring Security's "Remember Me" uses a Cookie in the client side, which is your browser.
From Spring's DOCS:
Remember-me or persistent-login authentication refers to web sites
being able to remember the identity of a principal between sessions.
This is typically accomplished by sending a cookie to the browser,
with the cookie being detected during future sessions and causing
automated login to take place. Spring Security provides the necessary
hooks for these operations to take place, and has two concrete
remember-me implementations. One uses hashing to preserve the security
of cookie-based tokens and the other uses a database or other
persistent storage mechanism to store the generated tokens.
Spring's idea is that you will be able to login automatically between different Sessions:
Server's Sessions, meaning when the Server "bounces" (goes down and then up), are handled, for example, by Persistency.
Clients' Session are handled by the browser (Cookies). The browser uses a Cookie that Spring sends, the Server verifies this Cookie and lets the user login automatically , without the need to enter credentials again.
Check the Cookies within your browser.
HTH.
Ohad.