Idiomatic Kotlin DSL for configuring HTTP security
Issue: gh-5558
This commit is contained in:
committed by
GitHub
parent
e306482a96
commit
2df1099da5
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Tests for [AnonymousDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class AnonymousDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `anonymous when custom principal then custom principal used`() {
|
||||
this.spring.register(PrincipalConfig::class.java, PrincipalController::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/principal")
|
||||
.andExpect {
|
||||
content { string("principal") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class PrincipalConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
anonymous {
|
||||
principal = "principal"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `anonymous when custom key then custom key used`() {
|
||||
this.spring.register(KeyConfig::class.java, PrincipalController::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/key")
|
||||
.andExpect {
|
||||
content { string("key".hashCode().toString()) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class KeyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
anonymous {
|
||||
key = "key"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `anonymous when disabled then responds with forbidden`() {
|
||||
this.spring.register(AnonymousDisabledConfig::class.java, PrincipalController::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/principal")
|
||||
.andExpect {
|
||||
content { string("") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AnonymousDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
anonymous {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `anonymous when custom authorities then authorities used`() {
|
||||
this.spring.register(AnonymousAuthoritiesConfig::class.java, PrincipalController::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/principal")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AnonymousAuthoritiesConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
anonymous {
|
||||
authorities = listOf(SimpleGrantedAuthority("TEST"))
|
||||
}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, hasAuthority("TEST"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PrincipalController {
|
||||
@GetMapping("/principal")
|
||||
fun principal(@AuthenticationPrincipal principal: String?): String? {
|
||||
return principal
|
||||
}
|
||||
|
||||
@GetMapping("/key")
|
||||
fun key(): String {
|
||||
return anonymousToken()
|
||||
.map { it.keyHash }
|
||||
.map { it.toString() }
|
||||
.orElse(null)
|
||||
}
|
||||
|
||||
private fun anonymousToken(): Optional<AnonymousAuthenticationToken> {
|
||||
return Optional.of(SecurityContextHolder.getContext())
|
||||
.map { it.authentication }
|
||||
.filter { it is AnonymousAuthenticationToken }
|
||||
.map { AnonymousAuthenticationToken::class.java.cast(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
* Tests for [AuthorizeRequestsDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class AuthorizeRequestsDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `request when secured by regex matcher then responds with forbidden`() {
|
||||
this.spring.register(AuthorizeRequestsByRegexConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/private")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when allowed by regex matcher then responds with ok`() {
|
||||
this.spring.register(AuthorizeRequestsByRegexConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/path")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AuthorizeRequestsByRegexConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(RegexRequestMatcher("/path", null), permitAll)
|
||||
authorize(RegexRequestMatcher(".*", null), authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/path")
|
||||
fun path() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secured by mvc then responds with forbidden`() {
|
||||
this.spring.register(AuthorizeRequestsByMvcConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/private")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when allowed by mvc then responds with OK`() {
|
||||
this.spring.register(AuthorizeRequestsByMvcConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/path")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/path.html")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/path/")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AuthorizeRequestsByMvcConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize("/path", permitAll)
|
||||
authorize("/**", authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/path")
|
||||
fun path() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secured by mvc path variables then responds based on path variable value`() {
|
||||
this.spring.register(MvcMatcherPathVariablesConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/user/user")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/user/deny")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class MvcMatcherPathVariablesConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize("/user/{userName}", "#userName == 'user'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/user/{user}")
|
||||
fun path(@PathVariable user: String) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secured by mvc with servlet path then responds based on servlet path`() {
|
||||
this.spring.register(MvcMatcherServletPathConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(MockMvcRequestBuilders.get("/spring/path")
|
||||
.with { request ->
|
||||
request.servletPath = "/spring"
|
||||
request
|
||||
})
|
||||
.andExpect(status().isForbidden)
|
||||
|
||||
this.mockMvc.perform(MockMvcRequestBuilders.get("/other/path")
|
||||
.with { request ->
|
||||
request.servletPath = "/other"
|
||||
request
|
||||
})
|
||||
.andExpect(status().isOk)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class MvcMatcherServletPathConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize("/path",
|
||||
"/spring",
|
||||
denyAll)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/path")
|
||||
fun path() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.BeanCreationException
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.http.HttpHeaders
|
||||
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.SpringTestRule
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.web.bind.annotation.RequestMethod
|
||||
import org.springframework.web.cors.CorsConfiguration
|
||||
import org.springframework.web.cors.CorsConfigurationSource
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
* Tests for [CorsDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class CorsDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `CORS when no MVC then exception`() {
|
||||
assertThatThrownBy { this.spring.register(DefaultCorsConfig::class.java).autowire() }
|
||||
.isInstanceOf(BeanCreationException::class.java)
|
||||
.hasMessageContaining("Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext")
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class DefaultCorsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
cors { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CORS when CORS configuration source bean then responds with CORS header`() {
|
||||
this.spring.register(CorsCrossOriginConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
{
|
||||
header(HttpHeaders.ORIGIN, "https://example.com")
|
||||
}.andExpect {
|
||||
header { exists("Access-Control-Allow-Origin") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
open class CorsCrossOriginConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
cors { }
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun corsConfigurationSource(): CorsConfigurationSource {
|
||||
val source = UrlBasedCorsConfigurationSource()
|
||||
val corsConfiguration = CorsConfiguration()
|
||||
corsConfiguration.allowedOrigins = listOf("*")
|
||||
corsConfiguration.allowedMethods = listOf(
|
||||
RequestMethod.GET.name,
|
||||
RequestMethod.POST.name)
|
||||
source.registerCorsConfiguration("/**", corsConfiguration)
|
||||
return source
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CORS when disabled then response does not include CORS header`() {
|
||||
this.spring.register(CorsDisabledConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
{
|
||||
header(HttpHeaders.ORIGIN, "https://example.com")
|
||||
}.andExpect {
|
||||
header { doesNotExist("Access-Control-Allow-Origin") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
open class CorsDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http.cors()
|
||||
http {
|
||||
cors {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun corsConfigurationSource(): CorsConfigurationSource {
|
||||
val source = UrlBasedCorsConfigurationSource()
|
||||
val corsConfiguration = CorsConfiguration()
|
||||
corsConfiguration.allowedOrigins = listOf("*")
|
||||
corsConfiguration.allowedMethods = listOf(
|
||||
RequestMethod.GET.name,
|
||||
RequestMethod.POST.name)
|
||||
source.registerCorsConfiguration("/**", corsConfiguration)
|
||||
return source
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy
|
||||
import org.springframework.security.web.csrf.CsrfTokenRepository
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.post
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
/**
|
||||
* Tests for [CsrfDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class CsrfDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `POST when CSRF enabled and no CSRF token then forbidden`() {
|
||||
this.spring.register(DefaultCsrfConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/test1")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `POST when CSRF enabled and CSRF token then status OK`() {
|
||||
this.spring.register(DefaultCsrfConfig::class.java, BasicController::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/test1") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class DefaultCsrfConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
csrf { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `POST when CSRF disabled and no CSRF token then status OK`() {
|
||||
this.spring.register(CsrfDisabledConfig::class.java, BasicController::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/test1")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CsrfDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
csrf {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CSRF when custom CSRF token repository then repo used`() {
|
||||
`when`(CustomRepositoryConfig.REPO.loadToken(any<HttpServletRequest>()))
|
||||
.thenReturn(DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token"))
|
||||
|
||||
this.spring.register(CustomRepositoryConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/test1")
|
||||
|
||||
verify(CustomRepositoryConfig.REPO).loadToken(any<HttpServletRequest>())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomRepositoryConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var REPO: CsrfTokenRepository = mock(CsrfTokenRepository::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
csrf {
|
||||
csrfTokenRepository = REPO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CSRF when require CSRF protection matcher then CSRF protection on matching requests`() {
|
||||
this.spring.register(RequireCsrfProtectionMatcherConfig::class.java, BasicController::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/test1")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
|
||||
this.mockMvc.post("/test2")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class RequireCsrfProtectionMatcherConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
csrf {
|
||||
requireCsrfProtectionMatcher = AntPathRequestMatcher("/test1")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CSRF when custom session authentication strategy then strategy used`() {
|
||||
this.spring.register(CustomStrategyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(formLogin())
|
||||
|
||||
verify(CustomStrategyConfig.STRATEGY, atLeastOnce())
|
||||
.onAuthentication(any(Authentication::class.java), any(HttpServletRequest::class.java), any(HttpServletResponse::class.java))
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomStrategyConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var STRATEGY: SessionAuthenticationStrategy = mock(SessionAuthenticationStrategy::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
formLogin { }
|
||||
csrf {
|
||||
sessionAuthenticationStrategy = STRATEGY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
override fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CSRF when ignoring request matchers then CSRF disabled on matching requests`() {
|
||||
this.spring.register(IgnoringRequestMatchersConfig::class.java, BasicController::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/test1")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
|
||||
this.mockMvc.post("/test2")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class IgnoringRequestMatchersConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
csrf {
|
||||
requireCsrfProtectionMatcher = AntPathRequestMatcher("/**")
|
||||
ignoringRequestMatchers(AntPathRequestMatcher("/test2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CSRF when ignoring ant matchers then CSRF disabled on matching requests`() {
|
||||
this.spring.register(IgnoringAntMatchersConfig::class.java, BasicController::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/test1")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
|
||||
this.mockMvc.post("/test2")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class IgnoringAntMatchersConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
csrf {
|
||||
requireCsrfProtectionMatcher = AntPathRequestMatcher("/**")
|
||||
ignoringAntMatchers("/test2")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class BasicController {
|
||||
@PostMapping("/test1")
|
||||
fun test1() {
|
||||
}
|
||||
|
||||
@PostMapping("/test2")
|
||||
fun test2() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.access.AccessDeniedException
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.core.userdetails.User.withUsername
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
* Tests for [ExceptionHandlingDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class ExceptionHandlingDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `request when exception handling enabled then returns forbidden`() {
|
||||
this.spring.register(ExceptionHandlingConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class ExceptionHandlingConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
exceptionHandling { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = AccessDeniedException::class)
|
||||
fun `request when exception handling disabled then throws exception`() {
|
||||
this.spring.register(ExceptionHandlingDisabledConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ExceptionHandlingDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
exceptionHandling {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `exception handling when custom access denied page then redirects to custom page`() {
|
||||
this.spring.register(AccessDeniedPageConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/admin") {
|
||||
with(user(withUsername("user").password("password").roles("USER").build()))
|
||||
}.andExpect {
|
||||
status { isForbidden }
|
||||
forwardedUrl("/access-denied")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AccessDeniedPageConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize("/admin", hasAuthority("ROLE_ADMIN"))
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
exceptionHandling {
|
||||
accessDeniedPage = "/access-denied"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `exception handling when custom access denied handler then handler used`() {
|
||||
this.spring.register(AccessDeniedHandlerConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/admin") {
|
||||
with(user(withUsername("user").password("password").roles("USER").build()))
|
||||
}.andExpect {
|
||||
status { isForbidden }
|
||||
forwardedUrl("/access-denied")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AccessDeniedHandlerConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
val customAccessDeniedHandler = AccessDeniedHandlerImpl()
|
||||
customAccessDeniedHandler.setErrorPage("/access-denied")
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize("/admin", hasAuthority("ROLE_ADMIN"))
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
exceptionHandling {
|
||||
accessDeniedHandler = customAccessDeniedHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `exception handling when default access denied handler for page then handlers used`() {
|
||||
this.spring.register(AccessDeniedHandlerForConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/admin1") {
|
||||
with(user(withUsername("user").password("password").roles("USER").build()))
|
||||
}.andExpect {
|
||||
status { isForbidden }
|
||||
forwardedUrl("/access-denied1")
|
||||
}
|
||||
|
||||
this.mockMvc.get("/admin2") {
|
||||
with(user(withUsername("user").password("password").roles("USER").build()))
|
||||
}.andExpect {
|
||||
status { isForbidden }
|
||||
forwardedUrl("/access-denied2")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AccessDeniedHandlerForConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
val customAccessDeniedHandler1 = AccessDeniedHandlerImpl()
|
||||
customAccessDeniedHandler1.setErrorPage("/access-denied1")
|
||||
val customAccessDeniedHandler2 = AccessDeniedHandlerImpl()
|
||||
customAccessDeniedHandler2.setErrorPage("/access-denied2")
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize("/admin1", hasAuthority("ROLE_ADMIN"))
|
||||
authorize("/admin2", hasAuthority("ROLE_ADMIN"))
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
exceptionHandling {
|
||||
defaultAccessDeniedHandlerFor(customAccessDeniedHandler1, AntPathRequestMatcher("/admin1"))
|
||||
defaultAccessDeniedHandlerFor(customAccessDeniedHandler2, AntPathRequestMatcher("/admin2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `exception handling when custom authentication entry point then entry point used`() {
|
||||
this.spring.register(AuthenticationEntryPointConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("http://localhost/custom-login")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AuthenticationEntryPointConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
exceptionHandling {
|
||||
authenticationEntryPoint = LoginUrlAuthenticationEntryPoint("/custom-login")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `exception handling when authentication entry point for page then entry points used`() {
|
||||
this.spring.register(AuthenticationEntryPointForConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/secured1")
|
||||
.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("http://localhost/custom-login1")
|
||||
}
|
||||
|
||||
this.mockMvc.get("/secured2")
|
||||
.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("http://localhost/custom-login2")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AuthenticationEntryPointForConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
val customAuthenticationEntryPoint1 = LoginUrlAuthenticationEntryPoint("/custom-login1")
|
||||
val customAuthenticationEntryPoint2 = LoginUrlAuthenticationEntryPoint("/custom-login2")
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
exceptionHandling {
|
||||
defaultAuthenticationEntryPointFor(customAuthenticationEntryPoint1, AntPathRequestMatcher("/secured1"))
|
||||
defaultAuthenticationEntryPointFor(customAuthenticationEntryPoint2, AntPathRequestMatcher("/secured2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
|
||||
import org.springframework.stereotype.Controller
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
|
||||
/**
|
||||
* Tests for [FormLoginDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class FormLoginDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `login page when form login configured then default login page created`() {
|
||||
this.spring.register(FormLoginConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/login")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when success then redirects to home`() {
|
||||
this.spring.register(FormLoginConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(formLogin())
|
||||
.andExpect {
|
||||
status().isFound
|
||||
redirectedUrl("/")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when failure then redirects to login page with error`() {
|
||||
this.spring.register(FormLoginConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(formLogin().password("invalid"))
|
||||
.andExpect {
|
||||
status().isFound
|
||||
redirectedUrl("/login?error")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class FormLoginConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
formLogin {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secure then redirects to default login page`() {
|
||||
this.spring.register(AllSecuredConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("http://localhost/login")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AllSecuredConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
formLogin {}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secure and custom login page then redirects to custom login page`() {
|
||||
this.spring.register(LoginPageConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("http://localhost/log-in")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class LoginPageConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
formLogin {
|
||||
loginPage = "/log-in"
|
||||
}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when custom success handler then used`() {
|
||||
this.spring.register(SuccessHandlerConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(formLogin())
|
||||
.andExpect {
|
||||
status().isFound
|
||||
redirectedUrl("/success")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class SuccessHandlerConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
formLogin {
|
||||
authenticationSuccessHandler = SimpleUrlAuthenticationSuccessHandler("/success")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when custom failure handler then used`() {
|
||||
this.spring.register(FailureHandlerConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(formLogin().password("invalid"))
|
||||
.andExpect {
|
||||
status().isFound
|
||||
redirectedUrl("/failure")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class FailureHandlerConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
formLogin {
|
||||
authenticationFailureHandler = SimpleUrlAuthenticationFailureHandler("/failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when custom failure url then used`() {
|
||||
this.spring.register(FailureHandlerConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(formLogin().password("invalid"))
|
||||
.andExpect {
|
||||
status().isFound
|
||||
redirectedUrl("/failure")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class FailureUrlConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
formLogin {
|
||||
failureUrl = "/failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when custom login processing url then used`() {
|
||||
this.spring.register(LoginProcessingUrlConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(formLogin("/custom"))
|
||||
.andExpect {
|
||||
status().isFound
|
||||
redirectedUrl("/")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class LoginProcessingUrlConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
formLogin {
|
||||
loginProcessingUrl = "/custom"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when default success url then redirected to url`() {
|
||||
this.spring.register(DefaultSuccessUrlConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(formLogin())
|
||||
.andExpect {
|
||||
status().isFound
|
||||
redirectedUrl("/custom")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class DefaultSuccessUrlConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
formLogin {
|
||||
defaultSuccessUrl("/custom", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when permit all then login page not protected`() {
|
||||
this.spring.register(PermitAllConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/custom/login")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class PermitAllConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
formLogin {
|
||||
loginPage = "/custom/login"
|
||||
permitAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
class LoginController {
|
||||
@GetMapping("/custom/login")
|
||||
fun loginPage() {}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class UserConfig {
|
||||
@Autowired
|
||||
fun configureGlobal(auth: AuthenticationManagerBuilder) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.http.HttpHeaders
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.XXssProtectionServerHttpHeadersWriter
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [HeadersDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class HeadersDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `headers when defaults enabled then default headers in response`() {
|
||||
this.spring.register(DefaultHeadersConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS, "nosniff") }
|
||||
header { string(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, XFrameOptionsHeaderWriter.XFrameOptionsMode.DENY.name) }
|
||||
header { string(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains") }
|
||||
header { string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate") }
|
||||
header { string(HttpHeaders.EXPIRES, "0") }
|
||||
header { string(HttpHeaders.PRAGMA, "no-cache") }
|
||||
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class DefaultHeadersConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when feature policy configured then header in response`() {
|
||||
this.spring.register(FeaturePolicyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { string("Feature-Policy", "geolocation 'self'") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class FeaturePolicyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
featurePolicy(policyDirectives = "geolocation 'self'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.core.AuthenticationException
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
/**
|
||||
* Tests for [HttpBasicDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class HttpBasicDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `http basic when configured then insecure request cannot access`() {
|
||||
this.spring.register(HttpBasicConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
status { isUnauthorized }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `http basic when configured then response includes basic challenge`() {
|
||||
this.spring.register(HttpBasicConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { string("WWW-Authenticate", "Basic realm=\"Realm\"") }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `http basic when valid user then permitted`() {
|
||||
this.spring.register(HttpBasicConfig::class.java, UserConfig::class.java, MainController::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("user", "password"))
|
||||
}.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HttpBasicConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
httpBasic {}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun httpBasicWhenCustomRealmThenUsed() {
|
||||
this.spring.register(CustomRealmConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { string("WWW-Authenticate", "Basic realm=\"Custom Realm\"") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomRealmConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
httpBasic {
|
||||
realmName = "Custom Realm"
|
||||
}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `http basic when custom authentication entry point then used`() {
|
||||
this.spring.register(CustomAuthenticationEntryPointConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
|
||||
verify<AuthenticationEntryPoint>(CustomAuthenticationEntryPointConfig.ENTRY_POINT)
|
||||
.commence(any(HttpServletRequest::class.java),
|
||||
any(HttpServletResponse::class.java),
|
||||
any(AuthenticationException::class.java))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomAuthenticationEntryPointConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var ENTRY_POINT: AuthenticationEntryPoint = mock(AuthenticationEntryPoint::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
httpBasic {
|
||||
authenticationEntryPoint = ENTRY_POINT
|
||||
}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `http basic when custom authentication details source then used`() {
|
||||
this.spring.register(CustomAuthenticationDetailsSourceConfig::class.java,
|
||||
UserConfig::class.java, MainController::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("username", "password"))
|
||||
}
|
||||
|
||||
verify(CustomAuthenticationDetailsSourceConfig.AUTHENTICATION_DETAILS_SOURCE)
|
||||
.buildDetails(any(HttpServletRequest::class.java))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomAuthenticationDetailsSourceConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var AUTHENTICATION_DETAILS_SOURCE = mock(AuthenticationDetailsSource::class.java) as AuthenticationDetailsSource<HttpServletRequest, *>
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
httpBasic {
|
||||
authenticationDetailsSource = AUTHENTICATION_DETAILS_SOURCE
|
||||
}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class UserConfig {
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails)
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
class MainController {
|
||||
@GetMapping("/")
|
||||
fun main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpHeaders
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.XXssProtectionServerHttpHeadersWriter
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.post
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
* Tests for [HttpSecurityDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class HttpSecurityDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `post when default security configured then CSRF prevents the request`() {
|
||||
this.spring.register(DefaultSecurityConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when default security configured then default headers are in the response`() {
|
||||
this.spring.register(DefaultSecurityConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header {
|
||||
string(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS, "nosniff")
|
||||
}
|
||||
header {
|
||||
string(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, XFrameOptionsHeaderWriter.XFrameOptionsMode.DENY.name)
|
||||
}
|
||||
header {
|
||||
string(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains")
|
||||
}
|
||||
header {
|
||||
string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")
|
||||
}
|
||||
header {
|
||||
string(HttpHeaders.EXPIRES, "0")
|
||||
}
|
||||
header {
|
||||
string(HttpHeaders.PRAGMA, "no-cache")
|
||||
}
|
||||
header {
|
||||
string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class DefaultSecurityConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class UserConfig {
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when it does not match the security request matcher then the security rules do not apply`() {
|
||||
this.spring.register(SecurityRequestMatcherConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
status { isNotFound }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when it matches the security request matcher then the security rules apply`() {
|
||||
this.spring.register(SecurityRequestMatcherConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/path")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class SecurityRequestMatcherConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
securityMatcher(RegexRequestMatcher("/path", null))
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when it does not match the security pattern matcher then the security rules do not apply`() {
|
||||
this.spring.register(SecurityPatternMatcherConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
status { isNotFound }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when it matches the security pattern matcher then the security rules apply`() {
|
||||
this.spring.register(SecurityPatternMatcherConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/path")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class SecurityPatternMatcherConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
securityMatcher("/path")
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `security pattern matcher when used with security request matcher then both apply`() {
|
||||
this.spring.register(MultiMatcherConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/path1")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/path2")
|
||||
.andExpect {
|
||||
status { isForbidden }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/path3")
|
||||
.andExpect {
|
||||
status { isNotFound }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class MultiMatcherConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
securityMatcher("/path1")
|
||||
securityMatcher(RegexRequestMatcher("/path2", null))
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.mock.web.MockHttpSession
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.post
|
||||
|
||||
/**
|
||||
* Tests for [LogoutDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class LogoutDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `logout when custom logout url then custom url used`() {
|
||||
this.spring.register(CustomLogoutUrlConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/custom/logout") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/login?logout")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomLogoutUrlConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
logout {
|
||||
logoutUrl = "/custom/logout"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logout when custom logout request matcher then custom request matcher used`() {
|
||||
this.spring.register(CustomLogoutRequestMatcherConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/custom/logout") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/login?logout")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomLogoutRequestMatcherConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
logout {
|
||||
logoutRequestMatcher = AntPathRequestMatcher("/custom/logout")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logout when custom success url then redirects to success url`() {
|
||||
this.spring.register(SuccessUrlConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/logout") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/login")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class SuccessUrlConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
logout {
|
||||
logoutSuccessUrl = "/login"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logout when custom success handler then redirects to success url`() {
|
||||
this.spring.register(SuccessHandlerConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/logout") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class SuccessHandlerConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
logout {
|
||||
logoutSuccessHandler = SimpleUrlLogoutSuccessHandler()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logout when permit all then logout allowed`() {
|
||||
this.spring.register(PermitAllConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/custom/logout") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/login?logout")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class PermitAllConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
logout {
|
||||
logoutUrl = "/custom/logout"
|
||||
permitAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logout when clear authentication false then authentication not cleared`() {
|
||||
this.spring.register(ClearAuthenticationFalseConfig::class.java).autowire()
|
||||
val currentContext = SecurityContextHolder.createEmptyContext()
|
||||
currentContext.authentication = TestingAuthenticationToken("user", "password", "ROLE_USER")
|
||||
val currentSession = MockHttpSession()
|
||||
currentSession.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, currentContext)
|
||||
|
||||
this.mockMvc.post("/logout") {
|
||||
with(csrf())
|
||||
session = currentSession
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/login?logout")
|
||||
}
|
||||
|
||||
assertThat(currentContext.authentication).isNotNull
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ClearAuthenticationFalseConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
logout {
|
||||
clearAuthentication = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logout when invalidate http session false then session not invalidated`() {
|
||||
this.spring.register(InvalidateHttpSessionFalseConfig::class.java).autowire()
|
||||
val currentSession = MockHttpSession()
|
||||
|
||||
this.mockMvc.post("/logout") {
|
||||
with(csrf())
|
||||
session = currentSession
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/login?logout")
|
||||
}
|
||||
|
||||
assertThat(currentSession.isInvalid).isFalse()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class InvalidateHttpSessionFalseConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
logout {
|
||||
invalidateHttpSession = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logout when delete cookies then cookies are cleared`() {
|
||||
this.spring.register(DeleteCookiesConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/logout") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/login?logout")
|
||||
cookie { maxAge("remove", 0) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class DeleteCookiesConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
logout {
|
||||
deleteCookies("remove")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logout when default logout success handler for request then custom handler used`() {
|
||||
this.spring.register(DefaultLogoutSuccessHandlerForConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/logout/default") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/login?logout")
|
||||
}
|
||||
|
||||
this.mockMvc.post("/logout/custom") {
|
||||
with(csrf())
|
||||
}.andExpect {
|
||||
status { isFound }
|
||||
redirectedUrl("/")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class DefaultLogoutSuccessHandlerForConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
logout {
|
||||
logoutRequestMatcher = AntPathRequestMatcher("/logout/**")
|
||||
defaultLogoutSuccessHandlerFor(SimpleUrlLogoutSuccessHandler(), AntPathRequestMatcher("/logout/custom"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `logout when custom logout handler then custom handler used`() {
|
||||
this.spring.register(CustomLogoutHandlerConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/logout") {
|
||||
with(csrf())
|
||||
}
|
||||
|
||||
verify(CustomLogoutHandlerConfig.HANDLER).logout(any(), any(), any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomLogoutHandlerConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var HANDLER: LogoutHandler = mock(LogoutHandler::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
logout {
|
||||
addLogoutHandler(HANDLER)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.Mockito.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
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
|
||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [OAuth2ClientDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class OAuth2ClientDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `oauth2Client when custom client registration repository then bean is not required`() {
|
||||
this.spring.register(ClientRepoConfig::class.java).autowire()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ClientRepoConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Client {
|
||||
clientRegistrationRepository = InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE
|
||||
.getBuilder("google").clientId("clientId").clientSecret("clientSecret")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `oauth2Client when custom authorized client repository then repository used`() {
|
||||
this.spring.register(ClientRepositoryConfig::class.java, ClientConfig::class.java).autowire()
|
||||
val authorizationRequest = OAuth2AuthorizationRequest
|
||||
.authorizationCode()
|
||||
.state("test")
|
||||
.clientId("clientId")
|
||||
.authorizationUri("https://test")
|
||||
.redirectUri("http://localhost/callback")
|
||||
.attributes(mapOf(Pair(OAuth2ParameterNames.REGISTRATION_ID, "registrationId")))
|
||||
.build()
|
||||
`when`(ClientRepositoryConfig.REQUEST_REPOSITORY.loadAuthorizationRequest(any()))
|
||||
.thenReturn(authorizationRequest)
|
||||
`when`(ClientRepositoryConfig.REQUEST_REPOSITORY.removeAuthorizationRequest(any(), any()))
|
||||
.thenReturn(authorizationRequest)
|
||||
`when`(ClientRepositoryConfig.CLIENT.getTokenResponse(any()))
|
||||
.thenReturn(OAuth2AccessTokenResponse
|
||||
.withToken("token")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.build())
|
||||
|
||||
this.mockMvc.get("/callback") {
|
||||
param("state", "test")
|
||||
param("code", "123")
|
||||
}
|
||||
|
||||
verify(ClientRepositoryConfig.CLIENT_REPOSITORY).saveAuthorizedClient(any(), any(), any(), any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ClientRepositoryConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var REQUEST_REPOSITORY: AuthorizationRequestRepository<OAuth2AuthorizationRequest> = mock(AuthorizationRequestRepository::class.java) as AuthorizationRequestRepository<OAuth2AuthorizationRequest>
|
||||
var CLIENT: OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> = mock(OAuth2AccessTokenResponseClient::class.java) as OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest>
|
||||
var CLIENT_REPOSITORY: OAuth2AuthorizedClientRepository = mock(OAuth2AuthorizedClientRepository::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Client {
|
||||
authorizedClientRepository = CLIENT_REPOSITORY
|
||||
authorizationCodeGrant {
|
||||
authorizationRequestRepository = REQUEST_REPOSITORY
|
||||
accessTokenResponseClient = CLIENT
|
||||
}
|
||||
}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class ClientConfig {
|
||||
@Bean
|
||||
open fun clientRegistrationRepository(): ClientRegistrationRepository {
|
||||
return InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE
|
||||
.getBuilder("google")
|
||||
.registrationId("registrationId")
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
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
|
||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
/**
|
||||
* Tests for [OAuth2LoginDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class OAuth2LoginDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `oauth2Login when custom client registration repository then bean is not required`() {
|
||||
this.spring.register(ClientRepoConfig::class.java).autowire()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ClientRepoConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Login {
|
||||
clientRegistrationRepository = InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE
|
||||
.getBuilder("google").clientId("clientId").clientSecret("clientSecret")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login page when oAuth2Login configured then default login page created`() {
|
||||
this.spring.register(OAuth2LoginConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/login")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class OAuth2LoginConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Login { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login page when custom login page then redirected to custom page`() {
|
||||
this.spring.register(LoginPageConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/custom-login")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class LoginPageConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Login {
|
||||
loginPage = "/custom-login"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
class LoginController {
|
||||
@GetMapping("/custom-login")
|
||||
fun loginPage() { }
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class ClientConfig {
|
||||
@Bean
|
||||
open fun clientRegistrationRepository(): ClientRegistrationRepository {
|
||||
return InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE
|
||||
.getBuilder("google").clientId("clientId").clientSecret("clientSecret")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames.SUB
|
||||
import org.springframework.security.oauth2.jwt.Jwt
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.access.AccessDeniedHandler
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [OAuth2ResourceServerDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class OAuth2ResourceServerDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `oauth2Resource server when custom entry point then entry point used`() {
|
||||
this.spring.register(EntryPointConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
|
||||
verify(EntryPointConfig.ENTRY_POINT).commence(any(), any(), any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class EntryPointConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var ENTRY_POINT: AuthenticationEntryPoint = mock(AuthenticationEntryPoint::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
oauth2ResourceServer {
|
||||
authenticationEntryPoint = ENTRY_POINT
|
||||
jwt { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun jwtDecoder(): JwtDecoder {
|
||||
return mock(JwtDecoder::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `oauth2Resource server when custom bearer token resolver then resolver used`() {
|
||||
this.spring.register(BearerTokenResolverConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
|
||||
verify(BearerTokenResolverConfig.RESOLVER).resolve(any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class BearerTokenResolverConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var RESOLVER: BearerTokenResolver = mock(BearerTokenResolver::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
oauth2ResourceServer {
|
||||
bearerTokenResolver = RESOLVER
|
||||
jwt { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun jwtDecoder(): JwtDecoder {
|
||||
return mock(JwtDecoder::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `oauth2Resource server when custom access denied handler then handler used`() {
|
||||
this.spring.register(AccessDeniedHandlerConfig::class.java).autowire()
|
||||
`when`(AccessDeniedHandlerConfig.DECODER.decode(anyString())).thenReturn(
|
||||
Jwt.withTokenValue("token")
|
||||
.header("alg", "none")
|
||||
.claim(SUB, "user")
|
||||
.build())
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
header("Authorization", "Bearer token")
|
||||
}
|
||||
|
||||
verify(AccessDeniedHandlerConfig.DENIED_HANDLER).handle(any(), any(), any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AccessDeniedHandlerConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var DENIED_HANDLER: AccessDeniedHandler = mock(AccessDeniedHandler::class.java)
|
||||
var DECODER: JwtDecoder = mock(JwtDecoder::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, denyAll)
|
||||
}
|
||||
oauth2ResourceServer {
|
||||
accessDeniedHandler = DENIED_HANDLER
|
||||
jwt { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun jwtDecoder(): JwtDecoder {
|
||||
return DECODER
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.web.PortMapperImpl
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Tests for [PortMapperDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class PortMapperDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `port mapper when specifying map then redirects to https port`() {
|
||||
this.spring.register(PortMapperMapConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("http://localhost:543")
|
||||
.andExpect {
|
||||
redirectedUrl("https://localhost:123")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class PortMapperMapConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
requiresChannel {
|
||||
secure(anyRequest, requiresSecure)
|
||||
}
|
||||
portMapper {
|
||||
map(543, 123)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `port mapper when specifying custom mapper then redirects to https port`() {
|
||||
this.spring.register(CustomPortMapperConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("http://localhost:543")
|
||||
.andExpect {
|
||||
redirectedUrl("https://localhost:123")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomPortMapperConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
val customPortMapper = PortMapperImpl()
|
||||
customPortMapper.setPortMappings(Collections.singletonMap("543", "123"))
|
||||
http {
|
||||
requiresChannel {
|
||||
secure(anyRequest, requiresSecure)
|
||||
}
|
||||
portMapper {
|
||||
portMapper = customPortMapper
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin
|
||||
import org.springframework.security.web.savedrequest.NullRequestCache
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl
|
||||
|
||||
/**
|
||||
* Tests for [RequestCacheDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class RequestCacheDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `GET when request cache enabled then redirected to cached page`() {
|
||||
this.spring.register(RequestCacheConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/test")
|
||||
|
||||
this.mockMvc.perform(formLogin())
|
||||
.andExpect {
|
||||
redirectedUrl("http://localhost/test")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class RequestCacheConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
requestCache { }
|
||||
formLogin { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GET when custom request cache then custom request cache used`() {
|
||||
this.spring.register(CustomRequestCacheConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/test")
|
||||
|
||||
this.mockMvc.perform(formLogin())
|
||||
.andExpect {
|
||||
redirectedUrl("/")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomRequestCacheConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
requestCache {
|
||||
requestCache = NullRequestCache()
|
||||
}
|
||||
formLogin { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.web.access.channel.ChannelProcessor
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
* Tests for [RequiresChannelDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class RequiresChannelDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `requires channel when requires secure then redirects to https`() {
|
||||
this.spring.register(RequiresSecureConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
redirectedUrl("https://localhost/")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class RequiresSecureConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
requiresChannel {
|
||||
secure(anyRequest, requiresSecure)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when channel matches mvc with servlet path then redirects based on servlet path`() {
|
||||
this.spring.register(MvcMatcherServletPathConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(MockMvcRequestBuilders.get("/spring/path")
|
||||
.with { request ->
|
||||
request.servletPath = "/spring"
|
||||
request
|
||||
})
|
||||
.andExpect(status().isFound)
|
||||
.andExpect(redirectedUrl("https://localhost/spring/path"))
|
||||
|
||||
this.mockMvc.perform(MockMvcRequestBuilders.get("/other/path")
|
||||
.with { request ->
|
||||
request.servletPath = "/other"
|
||||
request
|
||||
})
|
||||
.andExpect(MockMvcResultMatchers.status().isOk)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class MvcMatcherServletPathConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
requiresChannel {
|
||||
secure("/path",
|
||||
"/spring",
|
||||
requiresSecure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/path")
|
||||
fun path() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `requires channel when channel processors configured then channel processors used`() {
|
||||
`when`(ChannelProcessorsConfig.CHANNEL_PROCESSOR.supports(any())).thenReturn(true)
|
||||
this.spring.register(ChannelProcessorsConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
|
||||
verify(ChannelProcessorsConfig.CHANNEL_PROCESSOR).supports(any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ChannelProcessorsConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var CHANNEL_PROCESSOR: ChannelProcessor = mock(ChannelProcessor::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
requiresChannel {
|
||||
channelProcessors = listOf(CHANNEL_PROCESSOR)
|
||||
secure(anyRequest, requiresSecure)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.BeanCreationException
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION
|
||||
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration
|
||||
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import java.security.cert.Certificate
|
||||
import java.security.cert.CertificateFactory
|
||||
|
||||
/**
|
||||
* Tests for [Saml2Dsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class Saml2DslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `saml2Login when no relying party registration repository then exception`() {
|
||||
Assertions.assertThatThrownBy { this.spring.register(Saml2LoginNoRelyingPArtyRegistrationRepoConfig::class.java).autowire() }
|
||||
.isInstanceOf(BeanCreationException::class.java)
|
||||
.hasMessageContaining("relyingPartyRegistrationRepository cannot be null")
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class Saml2LoginNoRelyingPArtyRegistrationRepoConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
saml2Login { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login page when saml2Configured then default login page created`() {
|
||||
this.spring.register(Saml2LoginConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/login")
|
||||
.andExpect {
|
||||
status { isOk }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class Saml2LoginConfig : WebSecurityConfigurerAdapter() {
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
saml2Login {
|
||||
relyingPartyRegistrationRepository =
|
||||
InMemoryRelyingPartyRegistrationRepository(
|
||||
RelyingPartyRegistration.withRegistrationId("samlId")
|
||||
.remoteIdpEntityId("entityId")
|
||||
.assertionConsumerServiceUrlTemplate("{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI)
|
||||
.credentials { c -> c.add(Saml2X509Credential(loadCert("rod.cer"), VERIFICATION)) }
|
||||
.idpWebSsoUrl("ssoUrl")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : Certificate> loadCert(location: String): T {
|
||||
ClassPathResource(location).inputStream.use { inputStream ->
|
||||
val certFactory = CertificateFactory.getInstance("X.509")
|
||||
return certFactory.generateCertificate(inputStream) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.mock.web.MockHttpSession
|
||||
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.http.SessionCreationPolicy
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationException
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy
|
||||
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
/**
|
||||
* Tests for [SessionManagementDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class SessionManagementDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `session management when invalid session url then redirected to url`() {
|
||||
this.spring.register(InvalidSessionUrlConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with { request ->
|
||||
request.isRequestedSessionIdValid = false
|
||||
request.requestedSessionId = "id"
|
||||
request
|
||||
})
|
||||
.andExpect(status().isFound)
|
||||
.andExpect(redirectedUrl("/invalid"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class InvalidSessionUrlConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
sessionManagement {
|
||||
invalidSessionUrl = "/invalid"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session management when invalid session strategy then strategy used`() {
|
||||
this.spring.register(InvalidSessionStrategyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with { request ->
|
||||
request.isRequestedSessionIdValid = false
|
||||
request.requestedSessionId = "id"
|
||||
request
|
||||
})
|
||||
.andExpect(status().isFound)
|
||||
.andExpect(redirectedUrl("/invalid"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class InvalidSessionStrategyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
sessionManagement {
|
||||
invalidSessionStrategy = SimpleRedirectInvalidSessionStrategy("/invalid")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session management when session authentication error url then redirected to url`() {
|
||||
this.spring.register(SessionAuthenticationErrorUrlConfig::class.java).autowire()
|
||||
val session = mock(MockHttpSession::class.java)
|
||||
`when`(session.changeSessionId()).thenThrow(SessionAuthenticationException::class.java)
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with(authentication(mock(Authentication::class.java)))
|
||||
.session(session))
|
||||
.andExpect(status().isFound)
|
||||
.andExpect(redirectedUrl("/session-auth-error"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class SessionAuthenticationErrorUrlConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
sessionManagement {
|
||||
sessionAuthenticationErrorUrl = "/session-auth-error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session management when session authentication failure handler then handler used`() {
|
||||
this.spring.register(SessionAuthenticationFailureHandlerConfig::class.java).autowire()
|
||||
val session = mock(MockHttpSession::class.java)
|
||||
`when`(session.changeSessionId()).thenThrow(SessionAuthenticationException::class.java)
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with(authentication(mock(Authentication::class.java)))
|
||||
.session(session))
|
||||
.andExpect(status().isFound)
|
||||
.andExpect(redirectedUrl("/session-auth-error"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class SessionAuthenticationFailureHandlerConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
sessionManagement {
|
||||
sessionAuthenticationFailureHandler = SimpleUrlAuthenticationFailureHandler("/session-auth-error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session management when stateless policy then does not store session`() {
|
||||
this.spring.register(StatelessSessionManagementConfig::class.java).autowire()
|
||||
|
||||
val result = this.mockMvc.perform(get("/"))
|
||||
.andReturn()
|
||||
|
||||
assertThat(result.request.getSession(false)).isNull()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class StatelessSessionManagementConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
sessionManagement {
|
||||
sessionCreationPolicy = SessionCreationPolicy.STATELESS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session management when session authentication strategy then strategy used`() {
|
||||
this.spring.register(SessionAuthenticationStrategyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with(authentication(mock(Authentication::class.java)))
|
||||
.session(mock(MockHttpSession::class.java)))
|
||||
|
||||
verify(this.spring.getContext().getBean(SessionAuthenticationStrategy::class.java))
|
||||
.onAuthentication(any(Authentication::class.java),
|
||||
any(HttpServletRequest::class.java), any(HttpServletResponse::class.java))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class SessionAuthenticationStrategyConfig : WebSecurityConfigurerAdapter() {
|
||||
var mockSessionAuthenticationStrategy: SessionAuthenticationStrategy = mock(SessionAuthenticationStrategy::class.java)
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
sessionManagement {
|
||||
sessionAuthenticationStrategy = mockSessionAuthenticationStrategy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun sessionAuthenticationStrategy(): SessionAuthenticationStrategy {
|
||||
return this.mockSessionAuthenticationStrategy
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.mock
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509
|
||||
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
|
||||
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import java.security.cert.Certificate
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
|
||||
/**
|
||||
* Tests for [X509Dsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class X509DslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `x509 when configured with defaults then user authenticated`() {
|
||||
this.spring.register(X509Config::class.java).autowire()
|
||||
val certificate = loadCert<X509Certificate>("rod.cer")
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with(x509(certificate)))
|
||||
.andExpect(authenticated().withUsername("rod"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class X509Config : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
x509 { }
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
override fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("rod")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `x509 when configured with regex then user authenticated`() {
|
||||
this.spring.register(X509RegexConfig::class.java).autowire()
|
||||
val certificate = loadCert<X509Certificate>("rodatexampledotcom.cer")
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with(x509(certificate)))
|
||||
.andExpect(authenticated().withUsername("rod"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class X509RegexConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
x509 {
|
||||
subjectPrincipalRegex = "CN=(.*?)@example.com(?:,|$)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
override fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("rod")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `x509 when user details service configured then user details service used`() {
|
||||
this.spring.register(UserDetailsServiceConfig::class.java).autowire()
|
||||
val certificate = loadCert<X509Certificate>("rod.cer")
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with(x509(certificate)))
|
||||
.andExpect(authenticated().withUsername("rod"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class UserDetailsServiceConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("rod")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
val customUserDetailsService = InMemoryUserDetailsManager(userDetails)
|
||||
http {
|
||||
x509 {
|
||||
userDetailsService = customUserDetailsService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
override fun userDetailsService(): UserDetailsService {
|
||||
return mock(UserDetailsService::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `x509 when authentication user details service configured then custom user details service used`() {
|
||||
this.spring.register(AuthenticationUserDetailsServiceConfig::class.java).autowire()
|
||||
val certificate = loadCert<X509Certificate>("rod.cer")
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with(x509(certificate)))
|
||||
.andExpect(authenticated().withUsername("rod"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AuthenticationUserDetailsServiceConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("rod")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
val customUserDetailsService = InMemoryUserDetailsManager(userDetails)
|
||||
val customSource = UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>()
|
||||
customSource.setUserDetailsService(customUserDetailsService)
|
||||
http {
|
||||
x509 {
|
||||
authenticationUserDetailsService = customSource
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
override fun userDetailsService(): UserDetailsService {
|
||||
return mock(UserDetailsService::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `x509 when configured with principal extractor then principal extractor used`() {
|
||||
this.spring.register(X509PrincipalExtractorConfig::class.java).autowire()
|
||||
val certificate = loadCert<X509Certificate>("rodatexampledotcom.cer")
|
||||
|
||||
this.mockMvc.perform(get("/")
|
||||
.with(x509(certificate)))
|
||||
.andExpect(authenticated().withUsername("rod"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class X509PrincipalExtractorConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
val principalExtractor = SubjectDnX509PrincipalExtractor()
|
||||
principalExtractor.setSubjectDnRegex("CN=(.*?)@example.com(?:,|$)")
|
||||
http {
|
||||
x509 {
|
||||
x509PrincipalExtractor = principalExtractor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
override fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("rod")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : Certificate> loadCert(location: String): T {
|
||||
ClassPathResource(location).inputStream.use { inputStream ->
|
||||
val certFactory = CertificateFactory.getInstance("X.509")
|
||||
return certFactory.generateCertificate(inputStream) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.headers
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.http.HttpHeaders
|
||||
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.web.servlet.invoke
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [CacheControlDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class CacheControlDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `headers when cache control configured then cache control headers in response`() {
|
||||
this.spring.register(CacheControlConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate") }
|
||||
header { string(HttpHeaders.EXPIRES, "0") }
|
||||
header { string(HttpHeaders.PRAGMA, "no-cache") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CacheControlConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
cacheControl { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when cache control disabled then no cache control headers in response`() {
|
||||
this.spring.register(CacheControlDisabledConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { doesNotExist(HttpHeaders.CACHE_CONTROL) }
|
||||
header { doesNotExist(HttpHeaders.EXPIRES) }
|
||||
header { doesNotExist(HttpHeaders.PRAGMA) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CacheControlDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
cacheControl {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.headers
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.web.servlet.invoke
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.web.server.header.ContentSecurityPolicyServerHttpHeadersWriter
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [ContentSecurityPolicyDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class ContentSecurityPolicyDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `headers when content security policy configured then header in response`() {
|
||||
this.spring.register(ContentSecurityPolicyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(ContentSecurityPolicyServerHttpHeadersWriter.CONTENT_SECURITY_POLICY, "default-src 'self'") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ContentSecurityPolicyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
contentSecurityPolicy { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when content security policy configured with custom policy directives then custom directives in header`() {
|
||||
this.spring.register(CustomPolicyDirectivesConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(ContentSecurityPolicyServerHttpHeadersWriter.CONTENT_SECURITY_POLICY, "default-src 'self'; script-src trustedscripts.example.com") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomPolicyDirectivesConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
contentSecurityPolicy {
|
||||
policyDirectives = "default-src 'self'; script-src trustedscripts.example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when report only content security policy report only header in response`() {
|
||||
this.spring.register(ReportOnlyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(ContentSecurityPolicyServerHttpHeadersWriter.CONTENT_SECURITY_POLICY_REPORT_ONLY, "default-src 'self'") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ReportOnlyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
contentSecurityPolicy {
|
||||
reportOnly = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.headers
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.web.servlet.invoke
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [ContentTypeOptionsDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class ContentTypeOptionsDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `headers when content type options configured then X-Content-Type-Options header in response`() {
|
||||
this.spring.register(ContentTypeOptionsConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { string(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS, "nosniff") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ContentTypeOptionsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
contentTypeOptions { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when content type options disabled then X-Content-Type-Options header not in response`() {
|
||||
this.spring.register(ContentTypeOptionsDisabledConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { doesNotExist(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ContentTypeOptionsDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
contentTypeOptions {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.headers
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.web.servlet.invoke
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter
|
||||
import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [FrameOptionsDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class FrameOptionsDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `headers when frame options configured then frame options deny header`() {
|
||||
this.spring.register(FrameOptionsConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, XFrameOptionsHeaderWriter.XFrameOptionsMode.DENY.name) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class FrameOptionsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
frameOptions { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when frame options deny configured then frame options deny header`() {
|
||||
this.spring.register(FrameOptionsDenyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, XFrameOptionsHeaderWriter.XFrameOptionsMode.DENY.name) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class FrameOptionsDenyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
frameOptions {
|
||||
deny = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when frame options same origin configured then frame options same origin header`() {
|
||||
this.spring.register(FrameOptionsSameOriginConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN.name) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class FrameOptionsSameOriginConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
frameOptions {
|
||||
sameOrigin = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when frame options same origin and deny configured then frame options deny header`() {
|
||||
this.spring.register(FrameOptionsSameOriginAndDenyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, XFrameOptionsHeaderWriter.XFrameOptionsMode.DENY.name) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class FrameOptionsSameOriginAndDenyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
frameOptions {
|
||||
sameOrigin = true
|
||||
deny = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when frame options disabled then no frame options header in response`() {
|
||||
this.spring.register(FrameOptionsDisabledConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { doesNotExist(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class FrameOptionsDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
frameOptions {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.headers
|
||||
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [HttpPublicKeyPinningDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class HttpPublicKeyPinningDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
private val HPKP_RO_HEADER_NAME = "Public-Key-Pins-Report-Only"
|
||||
private val HPKP_HEADER_NAME = "Public-Key-Pins"
|
||||
|
||||
@Test
|
||||
fun `headers when HPKP configured and no pin then no headers in response`() {
|
||||
this.spring.register(HpkpNoPinConfig::class.java).autowire()
|
||||
|
||||
val result = this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andReturn()
|
||||
|
||||
Assertions.assertThat(result.response.headerNames).isEmpty()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HpkpNoPinConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpPublicKeyPinning { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when HPKP configured with pin then header in response`() {
|
||||
this.spring.register(HpkpPinConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(HPKP_RO_HEADER_NAME, "max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HpkpPinConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpPublicKeyPinning {
|
||||
pins = mapOf(Pair("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "sha256"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when HPKP configured with maximum age then maximum age in header`() {
|
||||
this.spring.register(HpkpMaxAgeConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(HPKP_RO_HEADER_NAME, "max-age=604800 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HpkpMaxAgeConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpPublicKeyPinning {
|
||||
pins = mapOf(Pair("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "sha256"))
|
||||
maxAgeInSeconds = 604800
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when HPKP configured with report only false then public key pins header in response`() {
|
||||
this.spring.register(HpkpReportOnlyFalseConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(HPKP_HEADER_NAME, "max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HpkpReportOnlyFalseConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpPublicKeyPinning {
|
||||
pins = mapOf(Pair("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "sha256"))
|
||||
reportOnly = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when HPKP configured with include subdomains then include subdomains in header`() {
|
||||
this.spring.register(HpkpIncludeSubdomainsConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header {
|
||||
string(HPKP_RO_HEADER_NAME,
|
||||
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; includeSubDomains")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HpkpIncludeSubdomainsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpPublicKeyPinning {
|
||||
pins = mapOf(Pair("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "sha256"))
|
||||
includeSubDomains = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when HPKP configured with report uri then report uri in header`() {
|
||||
this.spring.register(HpkpReportUriConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header {
|
||||
string(HPKP_RO_HEADER_NAME,
|
||||
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.com\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HpkpReportUriConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpPublicKeyPinning {
|
||||
pins = mapOf(Pair("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "sha256"))
|
||||
reportUri = "https://example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when HPKP disabled then no HPKP header in response`() {
|
||||
this.spring.register(HpkpDisabledConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header {
|
||||
doesNotExist(HPKP_RO_HEADER_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HpkpDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
httpPublicKeyPinning {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.headers
|
||||
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.web.servlet.invoke
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [HttpStrictTransportSecurityDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class HttpStrictTransportSecurityDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `headers when hsts configured then headers in response`() {
|
||||
this.spring.register(HstsConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HstsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpStrictTransportSecurity { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when hsts configured with preload then preload in header`() {
|
||||
this.spring.register(HstsPreloadConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HstsPreloadConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpStrictTransportSecurity {
|
||||
preload = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when hsts configured with max age then max age in header`() {
|
||||
this.spring.register(HstsMaxAgeConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, "max-age=1 ; includeSubDomains") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HstsMaxAgeConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpStrictTransportSecurity {
|
||||
maxAgeInSeconds = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when hsts configured and does not match then hsts header not in response`() {
|
||||
this.spring.register(HstsCustomMatcherConfig::class.java).autowire()
|
||||
|
||||
val result = this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andReturn()
|
||||
|
||||
Assertions.assertThat(result.response.headerNames).isEmpty()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HstsCustomMatcherConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
httpStrictTransportSecurity {
|
||||
requestMatcher = AntPathRequestMatcher("/secure/**")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when hsts disabled then hsts header not in response`() {
|
||||
this.spring.register(HstsDisabledConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { doesNotExist(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class HstsDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
httpStrictTransportSecurity {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.headers
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.web.servlet.invoke
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [ReferrerPolicyDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class ReferrerPolicyDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `headers when referrer policy configured then header in response`() {
|
||||
this.spring.register(ReferrerPolicyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { string("Referrer-Policy", ReferrerPolicyHeaderWriter.ReferrerPolicy.NO_REFERRER.policy) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ReferrerPolicyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
referrerPolicy { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when referrer policy configured with custom policy then custom policy in header`() {
|
||||
this.spring.register(ReferrerPolicyCustomPolicyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { string("Referrer-Policy", ReferrerPolicyHeaderWriter.ReferrerPolicy.SAME_ORIGIN.policy) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ReferrerPolicyCustomPolicyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
referrerPolicy {
|
||||
policy = ReferrerPolicyHeaderWriter.ReferrerPolicy.SAME_ORIGIN
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.headers
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
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.web.servlet.invoke
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.web.server.header.XXssProtectionServerHttpHeadersWriter
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [XssProtectionConfigDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class XssProtectionConfigDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `headers when XSS protection configured then header in response`() {
|
||||
this.spring.register(XssProtectionConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class XssProtectionConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
xssProtection { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when XSS protection with block false then mode is not block in header`() {
|
||||
this.spring.register(XssProtectionBlockFalseConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class XssProtectionBlockFalseConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
xssProtection {
|
||||
block = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when XSS protection disabled then X-XSS-Protection header is 0`() {
|
||||
this.spring.register(XssProtectionDisabledConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class XssProtectionDisabledConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
defaultsDisabled = true
|
||||
xssProtection {
|
||||
xssProtectionEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when XSS protection disabled then X-XSS-Protection header not in response`() {
|
||||
this.spring.register(XssProtectionDisabledFunctionConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
secure = true
|
||||
}.andExpect {
|
||||
header { doesNotExist(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION) }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class XssProtectionDisabledFunctionConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
xssProtection {
|
||||
disable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.oauth2.client
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.verify
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
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
|
||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [AuthorizationCodeGrantDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class AuthorizationCodeGrantDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `oauth2Client when custom authorization request repository then repository used`() {
|
||||
this.spring.register(RequestRepositoryConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/callback") {
|
||||
param("state", "test")
|
||||
param("code", "123")
|
||||
}
|
||||
|
||||
verify(RequestRepositoryConfig.REQUEST_REPOSITORY).loadAuthorizationRequest(any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class RequestRepositoryConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var REQUEST_REPOSITORY: AuthorizationRequestRepository<OAuth2AuthorizationRequest> = Mockito.mock(AuthorizationRequestRepository::class.java) as AuthorizationRequestRepository<OAuth2AuthorizationRequest>
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Client {
|
||||
authorizationCodeGrant {
|
||||
authorizationRequestRepository = REQUEST_REPOSITORY
|
||||
}
|
||||
}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `oauth2Client when custom access token response client then client used`() {
|
||||
this.spring.register(AuthorizedClientConfig::class.java, ClientConfig::class.java).autowire()
|
||||
val authorizationRequest = getOAuth2AuthorizationRequest()
|
||||
Mockito.`when`(AuthorizedClientConfig.REQUEST_REPOSITORY.loadAuthorizationRequest(any()))
|
||||
.thenReturn(authorizationRequest)
|
||||
Mockito.`when`(AuthorizedClientConfig.REQUEST_REPOSITORY.removeAuthorizationRequest(any(), any()))
|
||||
.thenReturn(authorizationRequest)
|
||||
Mockito.`when`(AuthorizedClientConfig.CLIENT.getTokenResponse(any()))
|
||||
.thenReturn(OAuth2AccessTokenResponse
|
||||
.withToken("token")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.build())
|
||||
|
||||
this.mockMvc.get("/callback") {
|
||||
param("state", "test")
|
||||
param("code", "123")
|
||||
}
|
||||
|
||||
verify(AuthorizedClientConfig.CLIENT).getTokenResponse(any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AuthorizedClientConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var REQUEST_REPOSITORY: AuthorizationRequestRepository<OAuth2AuthorizationRequest> = Mockito.mock(AuthorizationRequestRepository::class.java) as AuthorizationRequestRepository<OAuth2AuthorizationRequest>
|
||||
var CLIENT: OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> = Mockito.mock(OAuth2AccessTokenResponseClient::class.java) as OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest>
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Client {
|
||||
authorizationCodeGrant {
|
||||
authorizationRequestRepository = REQUEST_REPOSITORY
|
||||
accessTokenResponseClient = CLIENT
|
||||
}
|
||||
}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `oauth2Client when custom authorization request resolver then request resolver used`() {
|
||||
this.spring.register(RequestResolverConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/callback") {
|
||||
param("state", "test")
|
||||
param("code", "123")
|
||||
}
|
||||
|
||||
verify(RequestResolverConfig.REQUEST_RESOLVER).resolve(any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class RequestResolverConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var REQUEST_RESOLVER: OAuth2AuthorizationRequestResolver = Mockito.mock(OAuth2AuthorizationRequestResolver::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Client {
|
||||
authorizationCodeGrant {
|
||||
authorizationRequestResolver = REQUEST_RESOLVER
|
||||
}
|
||||
}
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class ClientConfig {
|
||||
@Bean
|
||||
open fun clientRegistrationRepository(): ClientRegistrationRepository {
|
||||
return InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE
|
||||
.getBuilder("google")
|
||||
.registrationId("registrationId")
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOAuth2AuthorizationRequest(): OAuth2AuthorizationRequest? {
|
||||
return OAuth2AuthorizationRequest
|
||||
.authorizationCode()
|
||||
.state("test")
|
||||
.clientId("clientId")
|
||||
.authorizationUri("https://test")
|
||||
.redirectUri("http://localhost/callback")
|
||||
.attributes(mapOf(Pair(OAuth2ParameterNames.REGISTRATION_ID, "registrationId")))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.oauth2.login
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.verify
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [AuthorizationEndpointDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class AuthorizationEndpointDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `oauth2Login when custom client registration repository then repository used`() {
|
||||
this.spring.register(ResolverConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/oauth2/authorization/google")
|
||||
|
||||
verify(ResolverConfig.RESOLVER).resolve(any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ResolverConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var RESOLVER: OAuth2AuthorizationRequestResolver = Mockito.mock(OAuth2AuthorizationRequestResolver::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Login {
|
||||
authorizationEndpoint {
|
||||
authorizationRequestResolver = RESOLVER
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `oauth2Login when custom authorization request repository then repository used`() {
|
||||
this.spring.register(RequestRepoConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/oauth2/authorization/google")
|
||||
|
||||
verify(RequestRepoConfig.REPOSITORY).saveAuthorizationRequest(any(), any(), any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class RequestRepoConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var REPOSITORY: AuthorizationRequestRepository<OAuth2AuthorizationRequest> = Mockito.mock(AuthorizationRequestRepository::class.java) as AuthorizationRequestRepository<OAuth2AuthorizationRequest>
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Login {
|
||||
authorizationEndpoint {
|
||||
authorizationRequestRepository = REPOSITORY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `oauth2Login when custom authorization uri repository then uri used`() {
|
||||
this.spring.register(AuthorizationUriConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/connect/google")
|
||||
|
||||
verify(AuthorizationUriConfig.REPOSITORY).saveAuthorizationRequest(any(), any(), any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AuthorizationUriConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var REPOSITORY: AuthorizationRequestRepository<OAuth2AuthorizationRequest> = Mockito.mock(AuthorizationRequestRepository::class.java) as AuthorizationRequestRepository<OAuth2AuthorizationRequest>
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2Login {
|
||||
authorizationEndpoint {
|
||||
authorizationRequestRepository = REPOSITORY
|
||||
baseUri = "/connect"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class ClientConfig {
|
||||
@Bean
|
||||
open fun clientRegistrationRepository(): ClientRegistrationRepository {
|
||||
return InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE
|
||||
.getBuilder("google").clientId("clientId").clientSecret("clientSecret")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.oauth2.login
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.mock
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
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
|
||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
|
||||
import org.springframework.security.oauth2.core.user.DefaultOAuth2User
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Tests for [RedirectionEndpointDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class RedirectionEndpointDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `oauth2Login when redirection endpoint configured then custom redirection endpoing used`() {
|
||||
this.spring.register(UserServiceConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
val registrationId = "registrationId"
|
||||
val attributes = HashMap<String, Any>()
|
||||
attributes[OAuth2ParameterNames.REGISTRATION_ID] = registrationId
|
||||
val authorizationRequest = OAuth2AuthorizationRequest
|
||||
.authorizationCode()
|
||||
.state("test")
|
||||
.clientId("clientId")
|
||||
.authorizationUri("https://test")
|
||||
.redirectUri("http://localhost/callback")
|
||||
.attributes(attributes)
|
||||
.build()
|
||||
Mockito.`when`(UserServiceConfig.REPOSITORY.removeAuthorizationRequest(ArgumentMatchers.any(), ArgumentMatchers.any()))
|
||||
.thenReturn(authorizationRequest)
|
||||
Mockito.`when`(UserServiceConfig.CLIENT.getTokenResponse(ArgumentMatchers.any()))
|
||||
.thenReturn(OAuth2AccessTokenResponse
|
||||
.withToken("token")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.build())
|
||||
Mockito.`when`(UserServiceConfig.USER_SERVICE.loadUser(ArgumentMatchers.any()))
|
||||
.thenReturn(DefaultOAuth2User(listOf(SimpleGrantedAuthority("ROLE_USER")), mapOf(Pair("user", "user")), "user"))
|
||||
|
||||
this.mockMvc.get("/callback") {
|
||||
param("code", "auth-code")
|
||||
param("state", "test")
|
||||
}.andExpect {
|
||||
redirectedUrl("/")
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class UserServiceConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var USER_SERVICE: OAuth2UserService<OAuth2UserRequest, OAuth2User> = mock(OAuth2UserService::class.java) as OAuth2UserService<OAuth2UserRequest, OAuth2User>
|
||||
var CLIENT: OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> = mock(OAuth2AccessTokenResponseClient::class.java) as OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest>
|
||||
var REPOSITORY: AuthorizationRequestRepository<OAuth2AuthorizationRequest> = mock(AuthorizationRequestRepository::class.java) as AuthorizationRequestRepository<OAuth2AuthorizationRequest>
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
oauth2Login {
|
||||
userInfoEndpoint {
|
||||
userService = USER_SERVICE
|
||||
}
|
||||
tokenEndpoint {
|
||||
accessTokenResponseClient = CLIENT
|
||||
}
|
||||
authorizationEndpoint {
|
||||
authorizationRequestRepository = REPOSITORY
|
||||
}
|
||||
redirectionEndpoint {
|
||||
baseUri = "/callback"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class ClientConfig {
|
||||
@Bean
|
||||
open fun clientRegistrationRepository(): ClientRegistrationRepository {
|
||||
return InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE
|
||||
.getBuilder("google")
|
||||
.registrationId("registrationId")
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.oauth2.login
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.mock
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
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
|
||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Tests for [TokenEndpointDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class TokenEndpointDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `oauth2Login when custom access token response client then client used`() {
|
||||
this.spring.register(TokenConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
val registrationId = "registrationId"
|
||||
val attributes = HashMap<String, Any>()
|
||||
attributes[OAuth2ParameterNames.REGISTRATION_ID] = registrationId
|
||||
val authorizationRequest = OAuth2AuthorizationRequest
|
||||
.authorizationCode()
|
||||
.state("test")
|
||||
.clientId("clientId")
|
||||
.authorizationUri("https://test")
|
||||
.redirectUri("http://localhost/login/oauth2/code/google")
|
||||
.attributes(attributes)
|
||||
.build()
|
||||
`when`(TokenConfig.REPOSITORY.removeAuthorizationRequest(any(), any()))
|
||||
.thenReturn(authorizationRequest)
|
||||
`when`(TokenConfig.CLIENT.getTokenResponse(any())).thenReturn(OAuth2AccessTokenResponse
|
||||
.withToken("token")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.build())
|
||||
|
||||
this.mockMvc.get("/login/oauth2/code/google") {
|
||||
param("code", "auth-code")
|
||||
param("state", "test")
|
||||
}
|
||||
|
||||
Mockito.verify(TokenConfig.CLIENT).getTokenResponse(any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class TokenConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var CLIENT: OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> = mock(OAuth2AccessTokenResponseClient::class.java) as OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest>
|
||||
var REPOSITORY: AuthorizationRequestRepository<OAuth2AuthorizationRequest> = mock(AuthorizationRequestRepository::class.java) as AuthorizationRequestRepository<OAuth2AuthorizationRequest>
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
oauth2Login {
|
||||
tokenEndpoint {
|
||||
accessTokenResponseClient = CLIENT
|
||||
}
|
||||
authorizationEndpoint {
|
||||
authorizationRequestRepository = REPOSITORY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class ClientConfig {
|
||||
@Bean
|
||||
open fun clientRegistrationRepository(): ClientRegistrationRepository {
|
||||
return InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE
|
||||
.getBuilder("google")
|
||||
.registrationId("registrationId")
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.oauth2.login
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
|
||||
import org.springframework.security.oauth2.core.user.DefaultOAuth2User
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Tests for [UserInfoEndpointDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class UserInfoEndpointDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `oauth2Login when custom user service then user service used`() {
|
||||
this.spring.register(UserServiceConfig::class.java, ClientConfig::class.java).autowire()
|
||||
|
||||
val registrationId = "registrationId"
|
||||
val attributes = HashMap<String, Any>()
|
||||
attributes[OAuth2ParameterNames.REGISTRATION_ID] = registrationId
|
||||
val authorizationRequest = OAuth2AuthorizationRequest
|
||||
.authorizationCode()
|
||||
.state("test")
|
||||
.clientId("clientId")
|
||||
.authorizationUri("https://test")
|
||||
.redirectUri("http://localhost/login/oauth2/code/google")
|
||||
.attributes(attributes)
|
||||
.build()
|
||||
`when`(UserServiceConfig.REPOSITORY.removeAuthorizationRequest(any(), any()))
|
||||
.thenReturn(authorizationRequest)
|
||||
`when`(UserServiceConfig.CLIENT.getTokenResponse(any()))
|
||||
.thenReturn(OAuth2AccessTokenResponse
|
||||
.withToken("token")
|
||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||
.build())
|
||||
`when`(UserServiceConfig.USER_SERVICE.loadUser(any()))
|
||||
.thenReturn(DefaultOAuth2User(listOf(SimpleGrantedAuthority("ROLE_USER")), mapOf(Pair("user", "user")), "user"))
|
||||
|
||||
this.mockMvc.get("/login/oauth2/code/google") {
|
||||
param("code", "auth-code")
|
||||
param("state", "test")
|
||||
}
|
||||
|
||||
Mockito.verify(UserServiceConfig.USER_SERVICE).loadUser(any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class UserServiceConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var USER_SERVICE: OAuth2UserService<OAuth2UserRequest, OAuth2User> = Mockito.mock(OAuth2UserService::class.java) as OAuth2UserService<OAuth2UserRequest, OAuth2User>
|
||||
var CLIENT: OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> = Mockito.mock(OAuth2AccessTokenResponseClient::class.java) as OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest>
|
||||
var REPOSITORY: AuthorizationRequestRepository<OAuth2AuthorizationRequest> = Mockito.mock(AuthorizationRequestRepository::class.java) as AuthorizationRequestRepository<OAuth2AuthorizationRequest>
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
oauth2Login {
|
||||
userInfoEndpoint {
|
||||
userService = USER_SERVICE
|
||||
}
|
||||
tokenEndpoint {
|
||||
accessTokenResponseClient = CLIENT
|
||||
}
|
||||
authorizationEndpoint {
|
||||
authorizationRequestRepository = REPOSITORY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class ClientConfig {
|
||||
@Bean
|
||||
open fun clientRegistrationRepository(): ClientRegistrationRepository {
|
||||
return InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE
|
||||
.getBuilder("google")
|
||||
.registrationId("registrationId")
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.oauth2.resourceserver
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.core.convert.converter.Converter
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames
|
||||
import org.springframework.security.oauth2.jwt.Jwt
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
* Tests for [JwtDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class JwtDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `JWT when custom JWT decoder then bean not required`() {
|
||||
this.spring.register(CustomJwtDecoderConfig::class.java).autowire()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomJwtDecoderConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2ResourceServer {
|
||||
jwt {
|
||||
jwtDecoder = mock(JwtDecoder::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `JWT when custom jwkSetUri then bean not required`() {
|
||||
this.spring.register(CustomJwkSetUriConfig::class.java).autowire()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomJwkSetUriConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
oauth2ResourceServer {
|
||||
jwt {
|
||||
jwkSetUri = "https://jwk-uri"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `opaque token when custom JWT authentication converter then converter used`() {
|
||||
this.spring.register(CustomJwtAuthenticationConverterConfig::class.java).autowire()
|
||||
`when`(CustomJwtAuthenticationConverterConfig.DECODER.decode(anyString())).thenReturn(
|
||||
Jwt.withTokenValue("token")
|
||||
.header("alg", "none")
|
||||
.claim(IdTokenClaimNames.SUB, "user")
|
||||
.build())
|
||||
`when`(CustomJwtAuthenticationConverterConfig.CONVERTER.convert(any()))
|
||||
.thenReturn(TestingAuthenticationToken("test", "this", "ROLE"))
|
||||
this.mockMvc.get("/") {
|
||||
header("Authorization", "Bearer token")
|
||||
}
|
||||
|
||||
verify(CustomJwtAuthenticationConverterConfig.CONVERTER).convert(any())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomJwtAuthenticationConverterConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var CONVERTER: Converter<Jwt, out AbstractAuthenticationToken> = mock(Converter::class.java) as Converter<Jwt, out AbstractAuthenticationToken>
|
||||
var DECODER: JwtDecoder = mock(JwtDecoder::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
oauth2ResourceServer {
|
||||
jwt {
|
||||
jwtAuthenticationConverter = CONVERTER
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun jwtDecoder(): JwtDecoder {
|
||||
return DECODER
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.oauth2.resourceserver
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.eq
|
||||
import org.mockito.Mockito.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.http.*
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal
|
||||
import org.springframework.security.oauth2.jwt.JwtClaimNames
|
||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.client.RestOperations
|
||||
|
||||
/**
|
||||
* Tests for [OpaqueTokenDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class OpaqueTokenDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `opaque token when defaults then uses introspection`() {
|
||||
this.spring.register(DefaultOpaqueConfig::class.java, AuthenticationController::class.java).autowire()
|
||||
val headers = HttpHeaders()
|
||||
headers.contentType = MediaType.APPLICATION_JSON
|
||||
val entity = ResponseEntity("{\n" +
|
||||
" \"active\" : true,\n" +
|
||||
" \"sub\": \"test-subject\",\n" +
|
||||
" \"scope\": \"message:read\",\n" +
|
||||
" \"exp\": 4683883211\n" +
|
||||
"}", headers, HttpStatus.OK)
|
||||
`when`(DefaultOpaqueConfig.REST.exchange(any(RequestEntity::class.java), eq(String::class.java)))
|
||||
.thenReturn(entity)
|
||||
|
||||
this.mockMvc.get("/authenticated") {
|
||||
header("Authorization", "Bearer token")
|
||||
}.andExpect {
|
||||
status { isOk }
|
||||
content { string("test-subject") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class DefaultOpaqueConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var REST: RestOperations = mock(RestOperations::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
oauth2ResourceServer {
|
||||
opaqueToken { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun rest(): RestOperations {
|
||||
return REST
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun tokenIntrospectionClient(): NimbusOpaqueTokenIntrospector {
|
||||
return NimbusOpaqueTokenIntrospector("https://example.org/introspect", REST)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `opaque token when custom introspector set then introspector used`() {
|
||||
this.spring.register(CustomIntrospectorConfig::class.java, AuthenticationController::class.java).autowire()
|
||||
`when`(CustomIntrospectorConfig.INTROSPECTOR.introspect(ArgumentMatchers.anyString()))
|
||||
.thenReturn(DefaultOAuth2AuthenticatedPrincipal(mapOf(Pair(JwtClaimNames.SUB, "mock-subject")), emptyList()))
|
||||
|
||||
this.mockMvc.get("/authenticated") {
|
||||
header("Authorization", "Bearer token")
|
||||
}
|
||||
|
||||
verify(CustomIntrospectorConfig.INTROSPECTOR).introspect("token")
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class CustomIntrospectorConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
var INTROSPECTOR: OpaqueTokenIntrospector = mock(OpaqueTokenIntrospector::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
oauth2ResourceServer {
|
||||
opaqueToken {
|
||||
introspector = INTROSPECTOR
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
class AuthenticationController {
|
||||
@GetMapping("/authenticated")
|
||||
fun authenticated(@AuthenticationPrincipal authentication: Authentication): String {
|
||||
return authentication.name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.session
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.web.MockHttpSession
|
||||
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.SpringTestRule
|
||||
import org.springframework.security.core.session.SessionInformation
|
||||
import org.springframework.security.core.session.SessionRegistry
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
|
||||
import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Tests for [SessionConcurrencyDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class SessionConcurrencyDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `session concurrency when maximum sessions then no more sessions allowed`() {
|
||||
this.spring.register(MaximumSessionsConfig::class.java, UserDetailsConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(post("/login")
|
||||
.with(csrf())
|
||||
.param("username", "user")
|
||||
.param("password", "password"))
|
||||
|
||||
this.mockMvc.perform(post("/login")
|
||||
.with(csrf())
|
||||
.param("username", "user")
|
||||
.param("password", "password"))
|
||||
.andExpect(status().isFound)
|
||||
.andExpect(redirectedUrl("/login?error"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class MaximumSessionsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
sessionManagement {
|
||||
sessionConcurrency {
|
||||
maximumSessions = 1
|
||||
maxSessionsPreventsLogin = true
|
||||
}
|
||||
}
|
||||
formLogin { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session concurrency when expired url then redirects to url`() {
|
||||
this.spring.register(ExpiredUrlConfig::class.java).autowire()
|
||||
|
||||
val session = MockHttpSession()
|
||||
val sessionInformation = SessionInformation("", session.id, Date(0))
|
||||
sessionInformation.expireNow()
|
||||
`when`(ExpiredUrlConfig.sessionRegistry.getSessionInformation(any())).thenReturn(sessionInformation)
|
||||
|
||||
this.mockMvc.perform(get("/").session(session))
|
||||
.andExpect(redirectedUrl("/expired-session"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ExpiredUrlConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
val sessionRegistry: SessionRegistry = mock(SessionRegistry::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
sessionManagement {
|
||||
sessionConcurrency {
|
||||
maximumSessions = 1
|
||||
expiredUrl = "/expired-session"
|
||||
sessionRegistry = sessionRegistry()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun sessionRegistry(): SessionRegistry {
|
||||
return sessionRegistry
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session concurrency when expired session strategy then strategy used`() {
|
||||
this.spring.register(ExpiredSessionStrategyConfig::class.java).autowire()
|
||||
|
||||
val session = MockHttpSession()
|
||||
val sessionInformation = SessionInformation("", session.id, Date(0))
|
||||
sessionInformation.expireNow()
|
||||
`when`(ExpiredSessionStrategyConfig.sessionRegistry.getSessionInformation(any())).thenReturn(sessionInformation)
|
||||
|
||||
this.mockMvc.perform(get("/").session(session))
|
||||
.andExpect(redirectedUrl("/expired-session"))
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ExpiredSessionStrategyConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
val sessionRegistry: SessionRegistry = mock(SessionRegistry::class.java)
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
sessionManagement {
|
||||
sessionConcurrency {
|
||||
maximumSessions = 1
|
||||
expiredSessionStrategy = SimpleRedirectSessionInformationExpiredStrategy("/expired-session")
|
||||
sessionRegistry = sessionRegistry()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun sessionRegistry(): SessionRegistry {
|
||||
return sessionRegistry
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class UserDetailsConfig {
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.session
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.web.MockHttpSession
|
||||
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.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.config.web.servlet.invoke
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
|
||||
/**
|
||||
* Tests for [SessionFixationDsl]
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
class SessionFixationDslTest {
|
||||
@Rule
|
||||
@JvmField
|
||||
var spring = SpringTestRule()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `session fixation when strategy is new session then new session created and attributes are not preserved`() {
|
||||
this.spring.register(NewSessionConfig::class.java, UserDetailsConfig::class.java).autowire()
|
||||
val givenSession = MockHttpSession()
|
||||
val givenSessionId = givenSession.id
|
||||
givenSession.clearAttributes()
|
||||
givenSession.setAttribute("name", "value")
|
||||
|
||||
val result = this.mockMvc.perform(MockMvcRequestBuilders.get("/")
|
||||
.with(httpBasic("user", "password"))
|
||||
.session(givenSession))
|
||||
.andReturn()
|
||||
|
||||
val resultingSession = result.request.getSession(false)
|
||||
assertThat(resultingSession).isNotEqualTo(givenSession)
|
||||
assertThat(resultingSession!!.id).isNotEqualTo(givenSessionId)
|
||||
assertThat(resultingSession.getAttribute("name")).isNull()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class NewSessionConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
sessionManagement {
|
||||
sessionFixation {
|
||||
newSession()
|
||||
}
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session fixation when strategy is migrate session then new session created and attributes are preserved`() {
|
||||
this.spring.register(MigrateSessionConfig::class.java, UserDetailsConfig::class.java).autowire()
|
||||
val givenSession = MockHttpSession()
|
||||
val givenSessionId = givenSession.id
|
||||
givenSession.clearAttributes()
|
||||
givenSession.setAttribute("name", "value")
|
||||
|
||||
val result = this.mockMvc.perform(MockMvcRequestBuilders.get("/")
|
||||
.with(httpBasic("user", "password"))
|
||||
.session(givenSession))
|
||||
.andReturn()
|
||||
|
||||
val resultingSession = result.request.getSession(false)
|
||||
assertThat(resultingSession).isNotEqualTo(givenSession)
|
||||
assertThat(resultingSession!!.id).isNotEqualTo(givenSessionId)
|
||||
assertThat(resultingSession.getAttribute("name")).isEqualTo("value")
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class MigrateSessionConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
sessionManagement {
|
||||
sessionFixation {
|
||||
migrateSession()
|
||||
}
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session fixation when strategy is change session id then session id changes and attributes preserved`() {
|
||||
this.spring.register(ChangeSessionIdConfig::class.java, UserDetailsConfig::class.java).autowire()
|
||||
val givenSession = MockHttpSession()
|
||||
val givenSessionId = givenSession.id
|
||||
givenSession.clearAttributes()
|
||||
givenSession.setAttribute("name", "value")
|
||||
|
||||
val result = this.mockMvc.perform(MockMvcRequestBuilders.get("/")
|
||||
.with(httpBasic("user", "password"))
|
||||
.session(givenSession))
|
||||
.andReturn()
|
||||
|
||||
val resultingSession = result.request.getSession(false)
|
||||
assertThat(resultingSession).isEqualTo(givenSession)
|
||||
assertThat(resultingSession!!.id).isNotEqualTo(givenSessionId)
|
||||
assertThat(resultingSession.getAttribute("name")).isEqualTo("value")
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class ChangeSessionIdConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
sessionManagement {
|
||||
sessionFixation {
|
||||
changeSessionId()
|
||||
}
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `session fixation when strategy is none then session does not change`() {
|
||||
this.spring.register(NoneConfig::class.java, UserDetailsConfig::class.java).autowire()
|
||||
val givenSession = MockHttpSession()
|
||||
val givenSessionId = givenSession.id
|
||||
givenSession.clearAttributes()
|
||||
givenSession.setAttribute("name", "value")
|
||||
|
||||
val result = this.mockMvc.perform(MockMvcRequestBuilders.get("/")
|
||||
.with(httpBasic("user", "password"))
|
||||
.session(givenSession))
|
||||
.andReturn()
|
||||
|
||||
val resultingSession = result.request.getSession(false)
|
||||
assertThat(resultingSession).isEqualTo(givenSession)
|
||||
assertThat(resultingSession!!.id).isEqualTo(givenSessionId)
|
||||
assertThat(resultingSession.getAttribute("name")).isEqualTo("value")
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class NoneConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
sessionManagement {
|
||||
sessionFixation {
|
||||
none()
|
||||
}
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class UserDetailsConfig {
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user