I need to secure my website using 2 layers. First is an LDAP check, next is a username/password entry. I have written both custom authentication filters for both checks.
If the LDAP filter fails the user should be redirected to an 'access denied' page, and if the username/password failed the user should be redirected back to the login page.
How can I set up these filters in my config.xml file? Here is what I have currently
<sec:http entry-point-ref="loginAuthenticationEntryPoint"
auto-config="false" use-expressions="true">
<sec:intercept-url pattern="/login.htm" access="isAnonymous()" />
<sec:intercept-url pattern="/*"
access="hasRole('ROLE_LDAP') and hasRole('ROLE_CRESTA')" />
<sec:custom-filter ref="ldapAuthenticationFilter"
before="FORM_LOGIN_FILTER" />
<sec:custom-filter ref="usernameAuthenticationFilter"
position="FORM_LOGIN_FILTER" />
</sec:http>
with
public class LdapAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter
and
public class CrestaUsernameAuthenticationFilter extends AbstractAuthenticationProcessingFilter
My current thinking is for each filter to add one of the required roles, but when the LDAP filter doesn't add both roles I am immediately denied access.
Much appreciated
I think that approach will not work because as soon as your LDAP filter returns successfully, Spring Security considers the user has been completely authenticated and skips the username/password filter.
In your situation I would use the standard form login security, customizing just my UserDetailsService so that instead of going just to Cresta to create the UserDetails instance, it would query your LDAP server too for user roles.
Related
I'm using Spring Security and I have a big problem.
After the user logs in and he closes the page, when he enters again in "mysite.com" he should be redirected to the "/dashboard" but instead he gets error 404, page not found.
The only way for him to log again is using either another browser or i rr the server.
What's wrong with my config?? It doesn't redirect to /dashboard if he is logged in already.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/settings", "/users", "/teams", "/docker-status", "/container-creation").hasAuthority("Administrator")
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/dashboard")
.failureUrl("/login?error")
.successHandler(authenticationSuccessHandler)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
}
Form and Basic Login Options
You might be wondering where the login form came from when you were prompted to log in, since we made no mention of any HTML files or JSPs. In fact, since we didn’t explicitly set a URL for the login page, Spring Security generates one automatically, based on the features that are enabled and using standard values for the URL which processes the submitted login, the default target URL the user will be sent to after logging in and so on. However, the namespace offers plenty of support to allow you to customize these options. For example, if you want to supply your own login page, you could use:
<http>
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page='/login.jsp'/>
</http>
Also note that we’ve added an extra intercept-url element to say that any requests for the login page should be available to anonymous users [3] and also the AuthenticatedVoter class for more details on how the value IS_AUTHENTICATED_ANONYMOUSLY is processed.]. Otherwise the request would be matched by the pattern /** and it wouldn’t be possible to access the login page itself! This is a common configuration error and will result in an infinite loop in the application. Spring Security will emit a warning in the log if your login page appears to be secured. It is also possible to have all requests matching a particular pattern bypass the security filter chain completely, by defining a separate http element for the pattern like this:
<http pattern="/css/**" security="none"/>
<http pattern="/login.jsp*" security="none"/>
<http use-expressions="false">
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page='/login.jsp'/>
</http>
From Spring Security 3.1 it is now possible to use multiple http elements to define separate security filter chain configurations for different request patterns. If the pattern attribute is omitted from an http element, it matches all requests. Creating an unsecured pattern is a simple example of this syntax, where the pattern is mapped to an empty filter chain [4]. We’ll look at this new syntax in more detail in the chapter on the Security Filter Chain.
It’s important to realise that these unsecured requests will be completely oblivious to any Spring Security web-related configuration or additional attributes such as requires-channel, so you will not be able to access information on the current user or call secured methods during the request. Use access='IS_AUTHENTICATED_ANONYMOUSLY' as an alternative if you still want the security filter chain to be applied.
If you want to use basic authentication instead of form login, then change the configuration to
<http use-expressions="false">
<intercept-url pattern="/**" access="ROLE_USER" />
<http-basic />
</http>
Basic authentication will then take precedence and will be used to prompt for a login when a user attempts to access a protected resource. Form login is still available in this configuration if you wish to use it, for example through a login form embedded in another web page.
Setting a Default Post-Login Destination
If a form login isn’t prompted by an attempt to access a protected resource, the default-target-url option comes into play. This is the URL the user will be taken to after successfully logging in, and defaults to "/". You can also configure things so that the user always ends up at this page (regardless of whether the login was "on-demand" or they explicitly chose to log in) by setting the always-use-default-target attribute to "true". This is useful if your application always requires that the user starts at a "home" page, for example:
<http pattern="/login.htm*" security="none"/>
<http use-expressions="false">
<intercept-url pattern='/**' access='ROLE_USER' />
<form-login login-page='/login.htm' default-target-url='/home.htm'
always-use-default-target='true' />
</http>
For even more control over the destination, you can use the authentication-success-handler-ref attribute as an alternative to default-target-url. The referenced bean should be an instance of AuthenticationSuccessHandler. You’ll find more on this in the Core Filters chapter and also in the namespace appendix, as well as information on how to customize the flow when authentication fails.
Spring Security Reference docs
I am developing a web application with Apache wicket(v 1.4) and spring(v 3.2) and i need to prevent users from logging in from two different
places at same time.
I tried to do it with spring security concurrency control,i added the following in my xml
<security:http create-session="never" auto-config="true">
<security:remember-me />
<security:intercept-url pattern="/**" />
<security:session-management>
<security:concurrency-control
max-sessions="1" error-if-maximum-exceeded="true"/>
</security:session-management>
</security:http>
but it doesn't seems to work.
Is there any wicket way to do it?Can anyone please help me?
You can track the sessions/users "manually".
For example: use a Set in YourApplication.java to keep the currently logged in users' names. In your signIn(String username, String password) method check whether this username is already in the set. Override Session#onInvalidate() to remove the username from the Set.
Since this Set is a global state the access to it should be synchronized.
While using spring security I am providing a particular page with ROLE_ANONYMOUS user.
<intercept-url pattern="/runApp*"
access="hasAnyRole('User', 'Admin','ROLE_ANONYMOUS')" />
There are many other intercept urls in the same http tag of spring security. This is my spring security code:
<http auto-config="true" use-expressions="true">
<intercept-url pattern='/welcome*' access="hasAnyRole('User', 'Admin')" />
<intercept-url pattern="/runApp*" access="hasAnyRole('User', 'Admin','ROLE_ANONYMOUS')" />
<form-login login-page="/login" authentication-failure-url="/login.jsp?login_error=true" default-target-url="/welcome" />
<logout logout-success-url="/login" invalidate-session="true" />
When user logins for the first time it redirects to welcome page. But when he wants to access runApp page he has to provide his credentials in the login page. But when he provides login credential it redirects to welcome page. Whereas I want it to redirect to particular runApp page.
Thanks.
There is another attribute in form-login element named always-use-default-target which defines redirect rule after login. If value of this attribute set to false, then user will be redirected to default-target-url only after requesting login page directly.
I came to a workaround. Not the best solution, but, if someone has something better to show, I'm all ears. When redirecting to login page for the credentials i am saving the data in the session. And when the registered user logins it goes to the controller where i get the data from the session and redirect it to the desired page.
Thanks for your support... :)
following is my security configs:
<security:http pattern="/login.*" security="none"/>
<security:http realm="myrealm">
<security:intercept-url pattern="/" access="ROLE_USER,ROLE_ADMIN,ROLE_GROUPADMIN,ROLE_GROUP,ROLE_LOCMGR"/>
<security:intercept-url pattern="/*jsp" access="ROLE_USER,ROLE_ADMIN,ROLE_GROUPADMIN,ROLE_GROUP,ROLE_LOCMGR"/>
<security:intercept-url pattern="/welcome.do" access="ROLE_ADMIN,ROLE_HD,ROLE_GROUPADMIN,ROLE_GROUP,ROLE_LOCMGR,ROLE_USER,ROLE_SCANNER"/>
<security:intercept-url pattern="/*do" access="ROLE_ADMIN,ROLE_GROUPADMIN,ROLE_GROUP,ROLE_LOCMGR,ROLE_USER"/>
<security:form-login login-page="/login.do"
default-target-url="/welcome.do"
always-use-default-target="true"
authentication-failure-url="/login.do?login_error=1"/>
<security:logout logout-success-url="/login.do" />
<security:http-basic/>
<security:anonymous />
</security:http>
<bean id="authProvider" class="AuthenticationProvider">
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="authProvider"/>
</security:authentication-manager>
I can see the login page, after entering credentials and submit, it is not redirecting and refreshes the same login page.
in DEBUG mode I can see: Authenticated SCOTT on local database
I get the error message on wrong login-password..and reset password or forgot password link also works and redirects. But, not welconme page
it's failing at this point, when I debug, principal has authorities as role_admin and password has the right value. but, newAuth has null values after this UsernamePasswordAuthenticationToken call!
Authentication newAuth = new UsernamePasswordAuthenticationToken(principal, password);
EDIT: It was trying to goe througth the Authentication Manager because in my config, I am using
authentication-manager and UsernamePasswordAuthenticationToken method is expecting 3 parameters.
UsernamePasswordAuthenticationToken(object principal, object credentials, collection authorities);
which will solve the issue!!
UsernamePasswordAuthenticationToken was trying to go througth the Authentication Manager because of the configs, UsernamePasswordAuthenticationToken method is expecting 3 parameters.
UsernamePasswordAuthenticationToken(object principal, object credentials, collection authorities);
by pasing the 3rd paramter authorities manager is satisfied :) and let the user to go through!!!
I guess what happens is that after the successfull login the browser actually gets redirected to /welcome.do, but the authenticated user is not authorized to see that page, so it gets sent back to the login page. Double-check (e.g. by enabling debug level logging) if the user really holds one of the authorities listed in:
<security:intercept-url pattern="/welcome.do" access="ROLE_ADMIN,ROLE_HD,ROLE_GROUPADMIN,ROLE_GROUP,ROLE_LOCMGR,ROLE_USER,ROLE_SCANNER"/>
I am sorry if the title is not clear enough. Here are the details.
Background
I am working on Spring based application that uses Spring 3.1.1 and Spring security 3.1.0. Here is the relevant fragment of our descriptor:
<security:http auto-config='true'>
<security:intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:form-login login-page='/login' authentication-failure-url="/login?authfailed=true"/>
</security:http>
The "sign-out" link on the web page refers to URL like ROOT-URL/j_spring_security_logout.
So, clicking on this URL brings us to login page (login.jsp) and can login again successfully.
Problem
If user logs-in into the application, waits until session is expired and then tries to sign-out he arrives to login page. This is fine. Then he types correct credentials and clicks login button. Now he is redirected to the same login page where username and password fields are empty instead of enter to the application. The second attempt to log-in succeeds.
Important: this happens only if the user was logged-in before, the session was expired and he tried to log-out. It does not happens for example if user clicks any other link after session expiration. In this case he is redirected to login page and can successfully login from the first attempt.
Analysis
My investigation showed the following.
We arrive to the login page twice due to HTTP redirect caused by SavedRequestAwareAuthenticationSuccessHandler.onAuthenticationSuccess() and happens because requestCache contains request to login page. requestCache is variable of type HttpSessionRequestCache that stores "cached" request in session attribute "SPRING_SECURITY_SAVED_REQUEST".
In normal situation this cache is used for redirecting to page requested by not-authenticated user after his authentication.
But here is what happens in our case.
The user logs-in. Then his session is expired. Then he clicks link to log-out. Since session is expired user is redirected to 'j_spring_security_logout' that redirects him to login page.
Somewhere on this way the login URL is cached as "requested", so when user logs in he is redirected to requested URL, i.e. to login page. When redirect happens the cached URL is removed, so infinite loop does not happen; second attempt to log-in succeeds.
Here are the relevant code reference:
ExceptionTranslationFilter.handleSpringSecurityException()
calls sendStartAuthentication() (line 168)
that does the following (lines 183-184):
SecurityContextHolder.getContext().setAuthentication(null);
requestCache.saveRequest(request, response);
But the requested URL at this point is login page. So, the login page is cached.
It looks like the saveRequest() just should not be called at this point, e.g. this smells as a bug in Spring framework...
I have solution to this problem and I will post it here. But my solution looks as a patch for me, so I hope somebody know the "right" solution.
Thanks in advance.
<intercept-url pattern="/login.jsp*" access="permitAll" />
<intercept-url pattern="/login*" access="permitAll" />
No reason to put any constraints on the login-page itself.
Try This, it works for me :
<security:form-login
login-page="/login.jsp"
default-target-url="/home.jsp"
always-use-default-target="true"
authentication-failure-url="/login?authfailed=true"/>
Replace:
.defaultSuccessUrl("/paginas/geral/index.jsf")
by:
.defaultSuccessUrl("/paginas/geral/index.jsf", true)
http.authorizeRequests() .anyRequest().authenticated()
.and() .formLogin()
.loginPage("/login.jsf")
.permitAll()
.usernameParameter("login")
.passwordParameter("senha")
.defaultSuccessUrl("/paginas/geral/index.jsf", true)
.failureUrl("/login.jsf?invalid=true");
it works for me. (spring-security-web: 4.1.3.RELEASE)