diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/addingcustomfilter/CustomFilterAfterTests.java b/docs/src/test/java/org/springframework/security/docs/servlet/addingcustomfilter/CustomFilterAfterTests.java new file mode 100644 index 0000000000..7653a7ce87 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/addingcustomfilter/CustomFilterAfterTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2004-present 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.docs.servlet.addingcustomfilter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + CustomFilterAfterTests.UserDetailsConfig.class, + CustomFilterAfterTests.ApiController.class, + SecurityConfigAfter.class }) +@WebAppConfiguration +public class CustomFilterAfterTests { + + @Autowired + private WebApplicationContext context; + + private MockMvc mvc; + + @BeforeEach + void setup() { + this.mvc = MockMvcBuilders.webAppContextSetup(this.context) + .defaultRequest(get("/api").with(user("user"))) + .apply(springSecurity()) + .build(); + } + + @Test + void tenantFilterWhenHeaderMissingThenAccessDenied() { + assertThatExceptionOfType(AccessDeniedException.class) + .isThrownBy(() -> this.mvc.perform(get("/api")).andReturn()); + } + + @Test + void tenantFilterWhenHeaderPresentThenContinuesFilterChain() throws Exception { + this.mvc.perform(get("/api").header("X-Tenant-Id", "some-tenant-id")) + .andExpect(status().isOk()) + .andExpect(authenticated().withUsername("user")); + } + + @Configuration + static class UserDetailsConfig { + @Bean + UserDetailsService userDetailsService() { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build(); + return new InMemoryUserDetailsManager(user); + } + } + + @RestController + static class ApiController { + + @GetMapping("/api") + String api() { + return "ok"; + } + + } +} diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/addingcustomfilter/CustomFilterTests.java b/docs/src/test/java/org/springframework/security/docs/servlet/addingcustomfilter/CustomFilterBeforeTests.java similarity index 96% rename from docs/src/test/java/org/springframework/security/docs/servlet/addingcustomfilter/CustomFilterTests.java rename to docs/src/test/java/org/springframework/security/docs/servlet/addingcustomfilter/CustomFilterBeforeTests.java index 5c6acbdb56..8c7ac75a29 100644 --- a/docs/src/test/java/org/springframework/security/docs/servlet/addingcustomfilter/CustomFilterTests.java +++ b/docs/src/test/java/org/springframework/security/docs/servlet/addingcustomfilter/CustomFilterBeforeTests.java @@ -45,11 +45,11 @@ import org.springframework.web.bind.annotation.RestController; @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { - CustomFilterTests.UserDetailsConfig.class, - CustomFilterTests.ApiController.class, + CustomFilterBeforeTests.UserDetailsConfig.class, + CustomFilterBeforeTests.ApiController.class, SecurityConfigBefore.class }) @WebAppConfiguration -public class CustomFilterTests { +public class CustomFilterBeforeTests { @Autowired private WebApplicationContext context; diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/addingcustomfilter/CustomFilterAfterTests.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/addingcustomfilter/CustomFilterAfterTests.kt new file mode 100644 index 0000000000..b5f6528054 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/addingcustomfilter/CustomFilterAfterTests.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2004-present 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.kt.docs.servlet.addingcustomfilter + +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.core.userdetails.User +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.provisioning.InMemoryUserDetailsManager +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.context.web.WebAppConfiguration +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.web.context.WebApplicationContext +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController + +@ExtendWith(SpringExtension::class) +@ContextConfiguration( + classes = [ + CustomFilterAfterTests.UserDetailsConfig::class, + CustomFilterAfterTests.ApiController::class, + SecurityConfigAfter::class + ] +) +@WebAppConfiguration +class CustomFilterAfterTests { + + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mvc: MockMvc + + @BeforeEach + fun setup() { + this.mvc = MockMvcBuilders.webAppContextSetup(this.context) + .apply(springSecurity()) + .build(); + } + + @Test + fun tenantFilterWhenHeaderMissingThenAccessDenied() { + assertThatExceptionOfType(Exception::class.java) + .isThrownBy { this.mvc.perform(get("/api").with(user("user"))).andReturn() } + } + + @Test + fun tenantFilterWhenHeaderPresentThenContinuesFilterChain() { + this.mvc.perform(get("/api") + .with(user("user")) + .header("X-Tenant-Id", "some-tenant-id")) + .andExpect(status().isOk) + .andExpect(authenticated().withUsername("user")) + } + + @Configuration + open class UserDetailsConfig { + @Bean + open fun userDetailsService(): UserDetailsService { + @Suppress("DEPRECATION") + val user: UserDetails = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build() + return InMemoryUserDetailsManager(user) + } + } + + @RestController + class ApiController { + + @GetMapping("/api") + fun api(): String { + return "ok" + } + + } +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/addingcustomfilter/CustomFilterTests.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/addingcustomfilter/CustomFilterBeforeTests.kt similarity index 96% rename from docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/addingcustomfilter/CustomFilterTests.kt rename to docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/addingcustomfilter/CustomFilterBeforeTests.kt index 0dbbbde2b4..cc296b67bc 100644 --- a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/addingcustomfilter/CustomFilterTests.kt +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/addingcustomfilter/CustomFilterBeforeTests.kt @@ -45,13 +45,13 @@ import org.springframework.web.bind.annotation.RestController @ExtendWith(SpringExtension::class) @ContextConfiguration( classes = [ - CustomFilterTests.UserDetailsConfig::class, - CustomFilterTests.ApiController::class, + CustomFilterBeforeTests.UserDetailsConfig::class, + CustomFilterBeforeTests.ApiController::class, SecurityConfigBefore::class ] ) @WebAppConfiguration -class CustomFilterTests { +class CustomFilterBeforeTests { @Autowired private lateinit var context: WebApplicationContext