| 
					
				 | 
			
			
				@@ -0,0 +1,180 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Copyright 2002-2022 the original author or authors. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Licensed under the Apache License, Version 2.0 (the "License"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * you may not use this file except in compliance with the License. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * You may obtain a copy of the License at 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *      https://www.apache.org/licenses/LICENSE-2.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Unless required by applicable law or agreed to in writing, software 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * distributed under the License is distributed on an "AS IS" BASIS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * See the License for the specific language governing permissions and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * limitations under the License. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+package org.springframework.security.config.annotation.web 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import io.mockk.every 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import io.mockk.mockk 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import io.mockk.spyk 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import io.mockk.verify 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.assertj.core.api.Assertions.assertThat 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.junit.jupiter.api.Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.junit.jupiter.api.assertDoesNotThrow 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.junit.jupiter.api.extension.ExtendWith 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.beans.factory.annotation.Autowired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.context.annotation.Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.config.annotation.ObjectPostProcessor 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.config.test.SpringTestContext 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.config.test.SpringTestContextExtension 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.core.context.SecurityContext 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.core.userdetails.PasswordEncodedUser 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.web.FilterChainProxy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.web.context.* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.test.web.servlet.MockMvc 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@ExtendWith(SpringTestContextExtension::class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class SecurityContextDslTests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @JvmField 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    val spring = SpringTestContext(this) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Autowired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lateinit var mvc: MockMvc 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fun `configure when registering object post processor then invoked on security context persistence filter`() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        spring.register(ObjectPostProcessorConfig::class.java).autowire() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        verify { ObjectPostProcessorConfig.objectPostProcessor.postProcess(any<SecurityContextPersistenceFilter>()) } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @EnableWebSecurity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    open class ObjectPostProcessorConfig : WebSecurityConfigurerAdapter() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        override fun configure(http: HttpSecurity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:off 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                securityContext { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        @Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        open fun objectPostProcessor(): ObjectPostProcessor<Any> = objectPostProcessor 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        companion object { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var objectPostProcessor: ObjectPostProcessor<Any> = spyk(ReflectingObjectPostProcessor()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            class ReflectingObjectPostProcessor : ObjectPostProcessor<Any> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                override fun <O> postProcess(`object`: O): O = `object` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fun `security context when invoked twice then uses original security context repository`() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        spring.register(DuplicateDoesNotOverrideConfig::class.java).autowire() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        every { DuplicateDoesNotOverrideConfig.SECURITY_CONTEXT_REPOSITORY.loadContext(any<HttpRequestResponseHolder>()) } returns mockk<SecurityContext>(relaxed = true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        mvc.perform(get("/")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        verify(exactly = 1) { DuplicateDoesNotOverrideConfig.SECURITY_CONTEXT_REPOSITORY.loadContext(any<HttpRequestResponseHolder>()) } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @EnableWebSecurity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    open class DuplicateDoesNotOverrideConfig : WebSecurityConfigurerAdapter() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        override fun configure(http: HttpSecurity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:off 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                securityContext { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    securityContextRepository = SECURITY_CONTEXT_REPOSITORY 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                securityContext { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        companion object { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var SECURITY_CONTEXT_REPOSITORY = mockk<SecurityContextRepository>(relaxed = true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fun `security context when security context repository not configured then does not throw exception`() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        spring.register(SecurityContextRepositoryDefaultsSecurityContextRepositoryConfig::class.java).autowire() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assertDoesNotThrow { mvc.perform(get("/")) } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @EnableWebSecurity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    open class SecurityContextRepositoryDefaultsSecurityContextRepositoryConfig : WebSecurityConfigurerAdapter(true) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        override fun configure(http: HttpSecurity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:off 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                addFilterAt<WebAsyncManagerIntegrationFilter>(WebAsyncManagerIntegrationFilter()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                anonymous { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                securityContext { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                authorizeRequests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    authorize(anyRequest, permitAll) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                httpBasic { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        override fun configure(auth: AuthenticationManagerBuilder) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:off 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            auth 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .inMemoryAuthentication() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .withUser("user").password("password").roles("USER") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fun `security context when require explicit save is true then configure SecurityContextHolderFilter`() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val repository = HttpSessionSecurityContextRepository() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val testContext = spring.register(RequireExplicitSaveConfig::class.java) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        testContext.autowire() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val filterChainProxy = testContext.context.getBean(FilterChainProxy::class.java) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // @formatter:off 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val filterTypes = filterChainProxy.getFilters("/").toList() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assertThat(filterTypes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .anyMatch { it is SecurityContextHolderFilter } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .noneMatch { it is SecurityContextPersistenceFilter } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // @formatter:on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val mvcResult = mvc.perform(SecurityMockMvcRequestBuilders.formLogin()).andReturn() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val securityContext = repository 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .loadContext(HttpRequestResponseHolder(mvcResult.request, mvcResult.response)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assertThat(securityContext.authentication).isNotNull 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @EnableWebSecurity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    open class RequireExplicitSaveConfig : WebSecurityConfigurerAdapter() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        override fun configure(http: HttpSecurity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:off 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                formLogin { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                securityContext { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    requireExplicitSave = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        override fun configure(auth: AuthenticationManagerBuilder) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:off 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            auth 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .inMemoryAuthentication() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .withUser(PasswordEncodedUser.user()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // @formatter:on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |