BAEL 3970 - Manual logout with Spring Security (#9075)
* Manual logout with Spring Security - Basic manual logout - logout with Clear Data Site Header * Add missing annotation for controller. Change mapping URL value. * Add intergration tests for manual logouts. * BAEL-3970 - Add asserts on test. Fix tests names. Remove unused imports.
This commit is contained in:
		
							parent
							
								
									f661797acb
								
							
						
					
					
						commit
						7fdcf68ccb
					
				| @ -0,0 +1,32 @@ | ||||
| package com.baeldung.manuallogout; | ||||
| 
 | ||||
| import org.springframework.security.core.context.SecurityContextHolder; | ||||
| import org.springframework.stereotype.Controller; | ||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||
| import org.springframework.web.bind.annotation.RequestMethod; | ||||
| 
 | ||||
| import javax.servlet.http.Cookie; | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import javax.servlet.http.HttpSession; | ||||
| 
 | ||||
| @Controller | ||||
| public class BasicAuthController { | ||||
| 
 | ||||
|     @RequestMapping(value = {"/basiclogout"}, method = RequestMethod.POST) | ||||
|     public String logout(HttpServletRequest request, HttpServletResponse response) { | ||||
|         HttpSession session; | ||||
|         SecurityContextHolder.clearContext(); | ||||
|         session = request.getSession(false); | ||||
|         if (session != null) { | ||||
|             session.invalidate(); | ||||
|         } | ||||
|         for (Cookie cookie : request.getCookies()) { | ||||
|             String cookieName = cookie.getName(); | ||||
|             Cookie cookieToDelete = new Cookie(cookieName, null); | ||||
|             cookieToDelete.setMaxAge(0); | ||||
|             response.addCookie(cookieToDelete); | ||||
|         } | ||||
|         return "redirect:/login?logout"; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,29 @@ | ||||
| package com.baeldung.manuallogout; | ||||
| 
 | ||||
| import org.springframework.security.core.Authentication; | ||||
| import org.springframework.security.core.context.SecurityContextHolder; | ||||
| import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler; | ||||
| import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter; | ||||
| import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive; | ||||
| import org.springframework.stereotype.Controller; | ||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||
| import org.springframework.web.bind.annotation.RequestMethod; | ||||
| 
 | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| 
 | ||||
| @Controller | ||||
| public class ClearSiteDataController { | ||||
| 
 | ||||
|     Directive[] SOURCE = {Directive.COOKIES, Directive.STORAGE, Directive.EXECUTION_CONTEXTS, Directive.CACHE}; | ||||
| 
 | ||||
|     @RequestMapping(value = {"/csdlogout"}, method = RequestMethod.POST) | ||||
|     public String logout(HttpServletRequest request, HttpServletResponse response) { | ||||
|         Authentication auth = SecurityContextHolder.getContext().getAuthentication(); | ||||
|         if (auth != null) { | ||||
|             ClearSiteDataHeaderWriter csdHeaderWriter = new ClearSiteDataHeaderWriter(SOURCE); | ||||
|             new HeaderWriterLogoutHandler(csdHeaderWriter).logout(request, response, auth); | ||||
|         } | ||||
|         return "redirect:/login?logout"; | ||||
|     } | ||||
| } | ||||
| @ -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); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,39 @@ | ||||
| package com.baeldung.manuallogout; | ||||
| 
 | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | ||||
| 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 SimpleSecurityConfiguration extends WebSecurityConfigurerAdapter { | ||||
| 
 | ||||
|     @Override | ||||
|     protected void configure(HttpSecurity http) throws Exception { | ||||
|         http.formLogin() | ||||
|                 .loginProcessingUrl("/login") | ||||
|                 .loginPage("/login") | ||||
|                 .usernameParameter("username") | ||||
|                 .passwordParameter("password") | ||||
|                 .defaultSuccessUrl("/") | ||||
|                 .failureUrl("/login?error"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void configure(AuthenticationManagerBuilder auth) throws Exception { | ||||
|         auth.inMemoryAuthentication() | ||||
|                 .withUser("user") | ||||
|                 .password("password") | ||||
|                 .roles("USER") | ||||
|                 .and() | ||||
|                 .withUser("manager") | ||||
|                 .password("password") | ||||
|                 .credentialsExpired(true) | ||||
|                 .accountExpired(true) | ||||
|                 .accountLocked(true) | ||||
|                 .authorities("WRITE_PRIVILEGES", "READ_PRIVILEGES") | ||||
|                 .roles("MANAGER"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,70 @@ | ||||
| package com.baeldung.manuallogout; | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| import javax.servlet.http.Cookie; | ||||
| import javax.servlet.http.HttpSession; | ||||
| 
 | ||||
| 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.*; | ||||
| 
 | ||||
| @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 givenLoggedUserWhenUserLogoutThenSessionCleared() 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("/basiclogout").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("/csdlogout").secure(true).with(csrf())) | ||||
|                 .andDo(print()) | ||||
|                 .andExpect(status().is3xxRedirection()) | ||||
|                 .andExpect(header().exists(CLEAR_SITE_DATA_HEADER)) | ||||
|                 .andReturn(); | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user