Problem Scenario
I\'m currently working on the login page of my application which is based on Spring boot and related Spring projects (like security
try to make login less restrictive . by adding the following to your security configuration:
http
.authorizeRequests()
.antMatchers("/login").permitAll()
...
Original thread
WARNING: Using a parameter to determine where you are redirecting to can open your application up to Open Redirect Vulnerabilities. Be very cautions when performing redirects based upon user input.
ContinueEntryPoint
Your first step is to create an AuthenticationEntryPoint
which is in charge of including a parameter with the URL to continue to in the URL when displaying the log in form. In this example, we will use the parameter name continue.
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.web.util.UriComponentsBuilder;
/**
* @author Rob Winch
*
*/
public class ContinueEntryPoint extends LoginUrlAuthenticationEntryPoint {
public ContinueEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
@Override
protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) {
String continueParamValue = UrlUtils.buildRequestUrl(request);
String redirect = super.determineUrlToUseForThisRequest(request, response, exception);
return UriComponentsBuilder.fromPath(redirect).queryParam("continue", continueParamValue).toUriString();
}
}
WebSecurityConfig
The next step is to include a Security configuration that uses the ContinueEntryPoint. For example:
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(new ContinueEntryPoint("/login"))
.and()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
LoginController
Finally, you should create a LoginController that redirects to the parameter if the user is already authenticated. For example:
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.NotBlank;
public class RedirectModel {
@Pattern(regexp="^/([^/].*)?$")
@NotBlank
private String continueUrl;
public void setContinue(String continueUrl) {
this.continueUrl = continueUrl;
}
public String getContinue() {
return continueUrl;
}
}
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(Principal principal, @Valid @ModelAttribute RedirectModel model, BindingResult result) {
if (!result.hasErrors() && principal != null) {
// do not redirect for absolute URLs (i.e. https://evil.com)
// do not redirect if we are not authenticated
return "redirect:" + model.getContinue();
}
return "login";
}
}
Complete Sample
You can find a complete sample in github at rwinch/spring-security-sample in the so-34087954-continue-on-login branch. You can easily download it if you prefer not to use git.