JAVA-12754: Moved 2 articles to new module spring-security-web-login-2

This commit is contained in:
sampadawagde 2022-07-18 20:25:11 +05:30
parent b7033fadfd
commit 0db8c73f75
11 changed files with 375 additions and 0 deletions

View File

@ -0,0 +1,9 @@
## Spring Security Login - 2
This module contains articles about login/logout mechanisms with Spring Security.
## Relevant articles:
- [Manual Logout With Spring Security](https://www.baeldung.com/spring-security-manual-logout)
- [How to Disable Spring Security Logout Redirects](https://www.baeldung.com/spring-security-disable-logout-redirects)
- More articles: [[<-- prev]](/spring-security-modules/spring-security-web-login)

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-security-web-login-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-web-login-2</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,13 @@
package com.baeldung.logoutredirects;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LogoutApplication {
public static void main(String[] args) {
SpringApplication.run(LogoutApplication.class, args);
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.logoutredirects.securityconfig;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;
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;
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests(authz -> authz.mvcMatchers("/login")
.permitAll()
.anyRequest()
.authenticated())
.logout(logout -> logout.permitAll()
.logoutSuccessHandler((request, response, authentication) -> {
response.setStatus(HttpServletResponse.SC_OK);
}));
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.manuallogout;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ManualLogoutApplication {
public static void main(String[] args) {
SpringApplication.run(ManualLogoutApplication.class, args);
}
}

View File

@ -0,0 +1,95 @@
package com.baeldung.manuallogout;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.CACHE;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.COOKIES;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.EXECUTION_CONTEXTS;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.STORAGE;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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;
import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
@Configuration
@EnableWebSecurity
public class SimpleSecurityConfiguration {
private static Logger logger = LoggerFactory.getLogger(SimpleSecurityConfiguration.class);
@Order(4)
@Configuration
public static class LogoutOnRequestConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/request/**")
.authorizeRequests(authz -> authz.anyRequest()
.permitAll())
.logout(logout -> logout.logoutUrl("/request/logout")
.addLogoutHandler((request, response, auth) -> {
try {
request.logout();
} catch (ServletException e) {
logger.error(e.getMessage());
}
}));
}
}
@Order(3)
@Configuration
public static class DefaultLogoutConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/basic/**")
.authorizeRequests(authz -> authz.anyRequest()
.permitAll())
.logout(logout -> logout.logoutUrl("/basic/basiclogout"));
}
}
@Order(2)
@Configuration
public static class AllCookieClearingLogoutConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/cookies/**")
.authorizeRequests(authz -> authz.anyRequest()
.permitAll())
.logout(logout -> logout.logoutUrl("/cookies/cookielogout")
.addLogoutHandler(new SecurityContextLogoutHandler())
.addLogoutHandler((request, response, auth) -> {
for (Cookie cookie : request.getCookies()) {
String cookieName = cookie.getName();
Cookie cookieToDelete = new Cookie(cookieName, null);
cookieToDelete.setMaxAge(0);
response.addCookie(cookieToDelete);
}
}));
}
}
@Order(1)
@Configuration
public static class ClearSiteDataHeaderLogoutConfiguration extends WebSecurityConfigurerAdapter {
private static final ClearSiteDataHeaderWriter.Directive[] SOURCE = { CACHE, COOKIES, STORAGE, EXECUTION_CONTEXTS };
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/csd/**")
.authorizeRequests(authz -> authz.anyRequest()
.permitAll())
.logout(logout -> logout.logoutUrl("/csd/csdlogout")
.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(SOURCE))));
}
}
}

View File

@ -0,0 +1,5 @@
server.port=8081
logging.level.root=INFO
logging.level.org.springframework.security=DEBUG

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,34 @@
package com.baeldung.logoutredirects;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class)
@WebMvcTest()
public class LogoutApplicationUnitTest {
@Autowired
private MockMvc mockMvc;
@WithMockUser(value = "spring")
@Test
public void whenLogout_thenDisableRedirect() throws Exception {
this.mockMvc.perform(post("/logout").with(csrf()))
.andExpect(status().isOk())
.andExpect(jsonPath("$").doesNotExist())
.andExpect(unauthenticated())
.andReturn();
}
}

View File

@ -0,0 +1,96 @@
package com.baeldung.manuallogout;
import static org.junit.Assert.assertNull;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
@RunWith(SpringRunner.class)
@WebMvcTest()
public class ManualLogoutIntegrationTest {
private static final String CLEAR_SITE_DATA_HEADER = "Clear-Site-Data";
public static final int EXPIRY = 60 * 10;
public static final String COOKIE_NAME = "customerName";
public static final String COOKIE_VALUE = "myName";
public static final String ATTRIBUTE_NAME = "att";
public static final String ATTRIBUTE_VALUE = "attvalue";
@Autowired
private MockMvc mockMvc;
@WithMockUser(value = "spring")
@Test
public void givenLoggedUserWhenUserLogoutThenSessionClearedAndNecessaryCookieCleared() throws Exception {
this.mockMvc.perform(post("/basic/basiclogout").secure(true)
.with(csrf()))
.andExpect(status().is3xxRedirection())
.andExpect(unauthenticated())
.andReturn();
}
@WithMockUser(value = "spring")
@Test
public void givenLoggedUserWhenUserLogoutThenSessionClearedAndAllCookiesCleared() throws Exception {
MockHttpSession session = new MockHttpSession();
session.setAttribute(ATTRIBUTE_NAME, ATTRIBUTE_VALUE);
Cookie randomCookie = new Cookie(COOKIE_NAME, COOKIE_VALUE);
randomCookie.setMaxAge(EXPIRY); // 10 minutes
MockHttpServletRequest requestStateAfterLogout = this.mockMvc.perform(post("/cookies/cookielogout").secure(true)
.with(csrf())
.session(session)
.cookie(randomCookie))
.andExpect(status().is3xxRedirection())
.andExpect(unauthenticated())
.andExpect(cookie().maxAge(COOKIE_NAME, 0))
.andReturn()
.getRequest();
HttpSession sessionStateAfterLogout = requestStateAfterLogout.getSession();
assertNull(sessionStateAfterLogout.getAttribute(ATTRIBUTE_NAME));
}
@WithMockUser(value = "spring")
@Test
public void givenLoggedUserWhenUserLogoutThenClearDataSiteHeaderPresent() throws Exception {
this.mockMvc.perform(post("/csd/csdlogout").secure(true)
.with(csrf()))
.andDo(print())
.andExpect(status().is3xxRedirection())
.andExpect(header().exists(CLEAR_SITE_DATA_HEADER))
.andReturn();
}
@WithMockUser(value = "spring")
@Test
public void givenLoggedUserWhenUserLogoutOnRequestThenSessionCleared() throws Exception {
this.mockMvc.perform(post("/request/logout").secure(true)
.with(csrf()))
.andExpect(status().is3xxRedirection())
.andExpect(unauthenticated())
.andReturn();
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="15 seconds" debug="false">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%d{ISO8601}]-[%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>