Bläddra i källkod

Add AuthenticationManager to Kotlin JwtDsl

Closes gh-10045
Eleftheria Stein 4 år sedan
förälder
incheckning
6a09ffe113

+ 8 - 1
config/src/main/kotlin/org/springframework/security/config/web/servlet/oauth2/resourceserver/JwtDsl.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -18,8 +18,10 @@ package org.springframework.security.config.web.servlet.oauth2.resourceserver
 
 import org.springframework.core.convert.converter.Converter
 import org.springframework.security.authentication.AbstractAuthenticationToken
+import org.springframework.security.authentication.AuthenticationManager
 import org.springframework.security.config.annotation.web.builders.HttpSecurity
 import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer
+import org.springframework.security.core.Authentication
 import org.springframework.security.oauth2.jwt.Jwt
 import org.springframework.security.oauth2.jwt.JwtDecoder
 
@@ -33,12 +35,16 @@ import org.springframework.security.oauth2.jwt.JwtDecoder
  * @property jwtDecoder the [JwtDecoder] to use.
  * @property jwkSetUri configures a [JwtDecoder] using a
  * <a target="_blank" href="https://tools.ietf.org/html/rfc7517">JSON Web Key (JWK)</a> URL
+ * @property authenticationManager the [AuthenticationManager] used to determine if the provided
+ * [Authentication] can be authenticated.
  */
 @OAuth2ResourceServerSecurityMarker
 class JwtDsl {
     private var _jwtDecoder: JwtDecoder? = null
     private var _jwkSetUri: String? = null
 
+    var authenticationManager: AuthenticationManager? = null
+
     var jwtAuthenticationConverter: Converter<Jwt, out AbstractAuthenticationToken>? = null
     var jwtDecoder: JwtDecoder?
         get() = _jwtDecoder
@@ -58,6 +64,7 @@ class JwtDsl {
             jwtAuthenticationConverter?.also { jwt.jwtAuthenticationConverter(jwtAuthenticationConverter) }
             jwtDecoder?.also { jwt.decoder(jwtDecoder) }
             jwkSetUri?.also { jwt.jwkSetUri(jwkSetUri) }
+            authenticationManager?.also { jwt.authenticationManager(authenticationManager) }
         }
     }
 }

+ 65 - 0
config/src/test/kotlin/org/springframework/security/config/web/servlet/oauth2/resourceserver/JwtDslTests.kt

@@ -26,17 +26,24 @@ 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.AuthenticationManager
+import org.springframework.security.authentication.ProviderManager
+import org.springframework.security.authentication.TestingAuthenticationProvider
 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.config.web.servlet.invoke
+import org.springframework.security.core.Authentication
 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.security.oauth2.server.resource.authentication.JwtAuthenticationToken
 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 [JwtDsl]
@@ -44,6 +51,16 @@ import org.springframework.test.web.servlet.get
  * @author Eleftheria Stein
  */
 class JwtDslTests {
+
+    private val jwtAuthenticationToken: Authentication = JwtAuthenticationToken(
+        Jwt.withTokenValue("token")
+            .header("alg", "none")
+            .claim(IdTokenClaimNames.SUB, "user")
+            .subject("mock-test-subject")
+            .build(),
+        emptyList()
+    )
+
     @Rule
     @JvmField
     val spring = SpringTestRule()
@@ -174,4 +191,52 @@ class JwtDslTests {
             }
         }
     }
+
+    @Test
+    fun `JWT when custom authentication manager configured then used`() {
+        this.spring.register(AuthenticationManagerConfig::class.java, AuthenticationController::class.java).autowire()
+        mockkObject(AuthenticationManagerConfig.AUTHENTICATION_MANAGER)
+        every {
+            AuthenticationManagerConfig.AUTHENTICATION_MANAGER.authenticate(any())
+        } returns this.jwtAuthenticationToken
+
+        this.mockMvc.get("/authenticated") {
+            header("Authorization", "Bearer token")
+        }.andExpect {
+            status { isOk() }
+            content { string("mock-test-subject") }
+        }
+
+        verify(exactly = 1) { AuthenticationManagerConfig.AUTHENTICATION_MANAGER.authenticate(any()) }
+    }
+
+    @EnableWebSecurity
+    open class AuthenticationManagerConfig : WebSecurityConfigurerAdapter() {
+
+        companion object {
+            val AUTHENTICATION_MANAGER: AuthenticationManager = ProviderManager(TestingAuthenticationProvider())
+        }
+
+        override fun configure(http: HttpSecurity) {
+            http {
+                authorizeRequests {
+                    authorize(anyRequest, authenticated)
+                }
+                oauth2ResourceServer {
+                    jwt {
+                        authenticationManager = AUTHENTICATION_MANAGER
+                    }
+                }
+            }
+        }
+    }
+
+    @RestController
+    class AuthenticationController {
+        @GetMapping("/authenticated")
+        fun authenticated(authentication: Authentication): String {
+            return authentication.name
+        }
+    }
+
 }