Is there a way to disable the redirect for Spring Security and the login page. My requirements specify the login should be part of the navigation menu.
Example:
You need to disable redirection in a couple of different places. Here's a sample based on https://github.com/Apress/beg-spring-boot-2/blob/master/chapter-13/springboot-rest-api-security-demo/src/main/java/com/apress/demo/config/WebSecurityConfig.java
In my case, I don't return json body but only HTTP status to indicate success/failure. But you can further customize the handlers to build the body. I also kept CSRF protection on.
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
public void initialize(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
// here you can customize queries when you already have credentials stored somewhere
var usersQuery = "select username, password, 'true' from users where username = ?";
var rolesQuery = "select username, role from users where username = ?";
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(usersQuery)
.authoritiesByUsernameQuery(rolesQuery)
;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// all URLs are protected, except 'POST /login' so anonymous user can authenticate
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.anyRequest().authenticated()
// 401-UNAUTHORIZED when anonymous user tries to access protected URLs
.and()
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
// standard login form that sends 204-NO_CONTENT when login is OK and 401-UNAUTHORIZED when login fails
.and()
.formLogin()
.successHandler((req, res, auth) -> res.setStatus(HttpStatus.NO_CONTENT.value()))
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
// standard logout that sends 204-NO_CONTENT when logout is OK
.and()
.logout()
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.NO_CONTENT))
// add CSRF protection to all URLs
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
;
}
}
Here's a deep explanation of the whole process, including CSRF and why you need a session: https://spring.io/guides/tutorials/spring-security-and-angular-js/
Scenarios that I tested:
happy path
GET /users/current (or any of your protected URLs)
request --> no cookie
<- response 401 + cookie XSRF-TOKEN
POST /login
-> header X-XSRF-TOKEN + cookie XSRF-TOKEN + body form with valid username/password
<- 204 + cookie JSESSIONID
GET /users/current
-> cookie JSESSIONID
<- 200 + body with user details
POST /logout
-> header X-XSRF-TOKEN + cookie XSRF-TOKEN + cookie JSESSIONID
<- 204
=== exceptional #1: bad credentials
POST /login
-> header X-XSRF-TOKEN + cookie XSRF-TOKEN + body form with bad username/password
<- 401
=== exceptional #2: no CSRF at /login (like a malicious request)
POST /login
-> cookie XSRF-TOKEN + body form with valid username/password
<- 401 (I would expect 403, but this should be fine)
=== exceptional #3: no CSRF at /logout (like a malicious request)
(user is authenticated)
POST /logout
-> cookie XSRF-TOKEN + cookie JSESSIONID + empty body
<- 403
(user is still authenticated)