Spring 4 MVC + Security login page redisplayed - spring

I am implementing the security for my web application. The below are different event that takes place in authentication.
1) Successful login takes the users to the "dasboard" page.
2) Failure will take to the login page with the error.
3) The unauthenticated user access the secured page directly, redirected to the login, success takes to the dashboard, failure to the login with error.
4) The unauthenticated user access the secured page directly, redirected to the login, success takes to the dashboard, failure to the login with error.
The problem,
1) The user is successfully authenticated, views the dashboard page. Again he navigates directly to the login page, login is displayed. But, why should it? Should it not, by default, redirect to the dashboard? Should I need to check in my login controller if the user has already logged-in and redirect to dashboard or any configuration I am missing?
2) I have 3 role of users, super admin, admin and user. Can I redirect to different pages based on different role of users? If so how? If not how can this be implemented?
3) Based on the configuration I should be able to switch between LDAP auth or DB. If the app needs to be authenticated, in future, with ldap shall I inject the auth provider based on configuration? How do configure multiple authenticators?
Please share your wisdom/docs/links on "this is how it should be done" spring-security
My WebSecurityConfig.java
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().formLogin()
.loginPage("/login").loginProcessingUrl("/authenticate")
.defaultSuccessUrl("/dashboard").failureUrl("/login?error")
.usernameParameter("username").passwordParameter("password")
.permitAll().and().logout().logoutUrl("/logout").permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
AuthenticationProvider authenticationProvider = new CustomAuthenticationProvider();
auth.authenticationProvider(authenticationProvider);
}

1) As you said this can be easily done in your login controller. Just send a redirect instead of the login page if you know that the user is already logged in.
2) I think you mean the redirect after the user logged in, are you?
This can be achieved using a custom AuthenticationSuccessHandler. Maybe this question can give you more details.
3) You can configure multiple AuthenticationProviders (e.g. one for LDAP and one for DB) using an ProviderManager AuthenticationManager. An option would be to configure the AuthenticationProviders during startup in your java config based on the given environment or configuration values.

1) Create session when the user login.and always check that login session on you login page...if session is caught ,redirect to dashboard,....if session in null let it live on login page...
2) Create sessions according to the which user is login, for example if "super user" logins, create session of "superUser"....and vice-versa...
Now check that session,if session has value of superUser,redirect it to desired page for super user....and vice versa...
In both of these using session is good choice.

Related

Spring MVC based application is not landing to default success url while trying to access it using https url but working fine on http based url

While running the spring mvc based application on http, it is working fine but once the application is moved to https based configuration, we are not able to get successful landing url page. The url which are non authenticated is working fine but the authenticated urls are not reachable even after providing correct login credentials.
Please help me with the missing configurations/issues to resolve this problem.
The application is deployed over Jboss server.
Below are the configurations done as part of application.
protected void configure(HttpSecurity http) throws Exception {
System.out.println("I am configure");
http.csrf().disable();
// The pages does not require login
http.authorizeRequests().antMatchers("/login", "/logout", "/resetPassword", "/forgotPassword", "/change-password", "/confirm-account", "/registerPage", "/registerwithemail", "/resources/**", "/logoutSuccessful", "/login/**").permitAll();
http.authorizeRequests().antMatchers("/**").authenticated();
http.authorizeRequests().antMatchers("/home").authenticated();
http.authorizeRequests().antMatchers("/").authenticated();
// /userInfo page requires login as USER or ADMIN.
// If no login, it will redirect to /login page.
http.authorizeRequests().antMatchers("/userInfo").access("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')");
// For ADMIN only.
http.authorizeRequests().antMatchers("/admin").access("hasRole('ROLE_ADMIN')");
// When the user has logged in as XX.
// But access a page that requires role YY,
// AccessDeniedException will throw.
http.authorizeRequests().and().exceptionHandling().accessDeniedPage("/403");
http.headers().frameOptions().sameOrigin();
// Config for Login Form
http.authorizeRequests().and().formLogin()//
// Submit URL of login page.
.loginPage("/login")//
.loginProcessingUrl("/j_spring_security_check") // Submit URL
.defaultSuccessUrl("/home", true)// userInfo (Changed to) home
.failureUrl("/login?error=true")//
.usernameParameter("username")//
.passwordParameter("password")
// For Remember-me
.and().rememberMe().rememberMeParameter("remember-me").tokenRepository(persistentTokenRepository()).tokenValiditySeconds(86400)
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/logoutSuccessful").invalidateHttpSession(true).deleteCookies("JSESSIONID", "remember-me");
}
if there is any channel security for http/https is required, please let me know about the configurations as I'm also traversing internally to different module using ip and port based http url.

Spring Security loginPage Vs loginProcessingURL

what is the difference between loginPage vs loginProcessingURL.
.formLogin().loginPage("/login").usernameParameter("phone-number").passwordParameter("password")
Seems to be loginProcessingURL is like post method once user submits the data in the login page but when I remove also it is working fine. What is the significance of loginProcessingURL and how does it differ from loginPage?
The line loginPage("/login") instructs Spring Security
when authentication is required, redirect the browser to /login
we are in charge of rendering the login page when /login is requested
when authentication attempt fails, redirect the browser to
/login?error (since we have not specified otherwise)
we are in charge of rendering a failure page when /login?error is
requested
when we successfully logout, redirect the browser to /login?logout
(since we have not specified otherwise)
we are in charge of rendering a logout confirmation page when
/login?logout is requested
AND
.loginProcessingUrl("/login/process")
tells Spring Security to process the submitted credentials when sent the specified path and, by default, redirect user back to the page user came from. It will not pass the request to Spring MVC and your controller.
Refer documentation
Purpose of loginPage()
The loginPage() tells the framework where the user will be redirected when login is required. For example when you are not authorized to the page, you get redirected to this page. This page performs the login activity, for example when you implement a loginForm() or oauth2Login() like in my code using Google OAuth2,this page redirects to google login.
http.anonymous().and()
.authorizeRequests().antMatchers("/images**").permitAll().and()
.authorizeRequests().anyRequest().authenticated().and()
.oauth2Login()
.successHandler((request, response, authentication) -> {
request.authenticate(response);
})
.loginPage("/oauth2/authorization/google")
.loginProcessingUrl("/login")
Purpose of loginProcessingUrl()
The loginProcessingUrl() is the method that automatically set the rule antMatchers("/thisUrl").permitAll() to this URL so that when the response is returned (code, state, token, etc.) will be allowed to be GETed and this response is processed as you can see in the authenticate method of the request. Something more important is that this loginProcessingUrl() tells that the response should be processed to this URL. Without this the request.authenticate(response) will not be executed and authentication will not be returned or otherwise you implement another algorithm.
May the following code segment from spring security source code will help you:
loginPage the login page to redirect to if authentication is required
loginProcessingUrl the URL to validate username and password
DEFAULT_LOGIN_PAGE_URL = "/login"
/**
* Updates the default values for authentication.
*
* #throws Exception
*/
protected final void updateAuthenticationDefaults() {
if (loginProcessingUrl == null) {
loginProcessingUrl(loginPage);
}
//...
}

CSRF token expires during login

I'm working on Spring web application and I need to avoid problem with expire csrf token on login page, because if user is waiting too long and try to login only one way to resolve problem with csrf is to reload page and try to login again. But it's not user friendly and I want to avoid this situation.
First question: Is it possible in general(by spring security 3.2.4)? Without disable csrf.
I tried to use security="none" for login page and spring seciruty "login_check", but it's not working, i got infinity redirect or I got error that no mapping for url "myhost/login_check".
Second question: How can i do it?
Recommended solution
I would say that you should not disable csrf tokens on a production site. You may make session (and thus the csrf token) last longer (but it usually should not last longer than a day, especially for not-logged-in users as it is a DOS vector), but the real solution may be to automatically refresh the login page when the csrf token expires. You may use a
<META HTTP-EQUIV="REFRESH" CONTENT="csrf_timeout_in_seconds">
in your login page header. If the user lets the login page sit for hours, it should not bother him that the page got refreshed.
Second solution
A possible solution which does not require you to actually store sessions but allows for infinite timeout is that you can generate your csrf tokens with hashing from the session id and a server-side secret:
csrf = hash(sessionid+secret)
Note however that you need to really dig and override spring-security internal mechanisms, namely:
re-creating anonymous sessions on the fly if a request arrives and no such session exists
re-creating the csrf token on the fly from the session id
And choose a very secure hashing algorithm, preferably sha-512.
Third solution
You could have a small javascript that calls a no-op page on your server regularly (just before the session timeout), thus extending your session. This results in infinite session timeout only if the browser is on all the time, so the DOS aspect is mitigated.
Ok, one last solution
You can alter the CSRF token checking code, and disable it for the login page. This is actually synonymous with the second solution, but is specific for the login page, not generally for all anonymous sessions.
You can do this e.g. by setting a custom RequestMatcher in HttpSecurity:
http.csrf().requireCsrfProtectionMatcher(new MyCsrfRequestMatcher());
...
class MyCsrfRequestMatcher implements RequestMatcher {
#Override
public boolean matches(HttpServletRequest request) {
return !request.getServletPath().equals("/login");
}
}
Another option would be set no timeout for the session by default and then, when the user is authenticated, change the timeout to whatever you want. You can see an example of how to do this here.
In one of the projects I worked on, I implemented the following:
Implement an exception handler which handles CsrfException (or AccessDeniedException in general in my case). Forward the request to a controller method.
#ExceptionHandler(AccessDeniedException.class)
#ResponseStatus(value = HttpStatus.FORBIDDEN)
public void handleAccessDeniedException(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
request.setAttribute(WebAttributes.ACCESS_DENIED_403, accessDeniedException);
request.getRequestDispatcher("/Access_Denied").forward(request, response);
}
In the controller method, check whether the original request is for the login page. If so, show an appropriate message within the login page.
if ("/login".equals(request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH))) {
model.addAttribute("error", "An invalid security token has been detected. Please try again.");
return "login.jsp";
} else {
return "accessDenied.jsp";
}
With this approach, user will be able to retry the login without the need to refresh.
You can also make your CSRF protection rely on cookies and NOT server side session state. Spring Security has full support for this.
CookieCsrfTokenRepository
You will only receive a timeout if your cookie expires. This scales well since it's basically stateless (from the server's perspective).
#EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
Andrew

JSP/Tomcat secure login with sessionstorage

I have a system running on Tomcat, with HTML/JSP in front-end, and java/Spring/Struts in backend.
I made a login-feature where the user enters his username and password.
In backend, I validate the username and password to the stored user in DB.
If match, I store the username in HTTPsession:
session.setAttribute( "username", name );
Then, on every class-action in backend, I add the following code:
HttpSession session = request.getSession();
if(session.getAttribute("username") == null) {
return mapping.findForward("invalidUser");
}
the invalidUSer-mapping redirects the user back to the login-page.
How secure is this?
Is there a way to check the httpsession without adding my validation-code to every class?
Do you guys have tips (or examples/tutorials) on how to do this differently? The system is already created and in production, so I do not want to do too many architecural changes.
As you are already using Spring in your project, you may want to look into Spring Security to replace your bespoke security mechanisms. You can configure it to protect certain resources within your application, authenticate against bespoke database back-ends, LDAP directories, etc. This will allow you to remove all manual checking of the session to see if the user is authenticated, and will redirect anonymous users to the specified login page when they attempt to access protected resources.
Along with the spring security filter definition in web.xml, the configuration can be specified in a single spring-security.xml file (imported into your root app config) using the security:http namespace to define the login page, protected resources, logout page, security headers etc. You could use a org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl instance configured as a bean to define the user service which can be referenced by the authentication-provider - see the docs, its very flexible.
Hope that's useful.

Spring Security Recommended Design To Request User Login to Different User With Different Role

I have the following use case and need recommendations on the proper implementation. To be clear can this be done through configuration or do I need to implement new code?
Business Use Case
The business wants to allow a user to login via social media sites and access some of their pages. But in order to access pages that deal with $$ the user must login via the applications local account.
Technical Use Case
Allow users to login via Facebook or other provider and provide role USER_PARTIAL_RIGHTS
If user accesses a page with role USER_FULL_RIGHTS prompt the user to login to an account that is a local JDBC stored account.
This authentication must also ensure that the page is protected by USER_FULL_RIGHTS role and not other roles.
I am using grail spring security plugin, but I am expecting to have to customize the plugin.
So what are recommendations for doing this? A couple of ideas that I have are:
Technical Ideas
custom spring access denied handler
custom access denied controller instead of the stock jsp page
From what i understand from your question, here is my suggestion.
For login via Facebook use Spring Social. Here is the documentation. The implementations are straightforward. Write a custom signin method and set the authorities for partial rights, something like this:
public void signin(String userId) {
authorities = new ArrayList<GrantedAuthority>();
//set your partial rights authority
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userId, null, authorities));
}
And do a method level security implementation using the #secured annotation to access the page that needs full rights. Something like this
#Secured("USER_FULL_RIGHTS ")
yourMethod(){
//code
}
This would prompt for a login where can use authentication from applications local account.
What we ended up implementing is a controller that looks at the role and redirects the user to the correct landing page. Kinda messy, but it works.
Collection<GrantedAuthority> inferred = SpringSecurityUtils.findInferredAuthorities(SpringSecurityUtils.getPrincipalAuthorities());
if(ifAnyGranted('ROLE_FOO', inferred)) {
redirect(controller: 'foo',action: 'home')
return
}

Resources