From d5225abcafb18ff508a6e9cb912a788ac3f3aa34 Mon Sep 17 00:00:00 2001 From: Kieun Date: Tue, 3 Jan 2023 11:25:49 +0900 Subject: [PATCH] Fix extracting standard scope claim in OAuth2 JWT fixes ePages-de/restdocs-api-spec#217 This fixes does not break current implementation of treating scope claim as List --- .../restdocs/apispec/JwtSecurityHandler.kt | 4 ++++ .../apispec/JwtSecurityHandlerTest.kt | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/JwtSecurityHandler.kt b/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/JwtSecurityHandler.kt index 7363db1b..2e06b9bf 100644 --- a/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/JwtSecurityHandler.kt +++ b/restdocs-api-spec/src/main/kotlin/com/epages/restdocs/apispec/JwtSecurityHandler.kt @@ -62,9 +62,13 @@ internal class JwtSecurityHandler : SecurityRequirementsExtractor { try { val jwtMap = ObjectMapper().readValue>(decodedPayload) val scope = jwtMap["scope"] + // some of oauth2 authorization servers might return scope claims as a set of string if (scope is List<*>) { return scope as List } + if (scope is String) { // standard way of expressing scope claim + return scope.trim().split("\\s+".toRegex()) + } } catch (e: IOException) { // probably not JWT } diff --git a/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/JwtSecurityHandlerTest.kt b/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/JwtSecurityHandlerTest.kt index 08e5b114..43d3f060 100644 --- a/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/JwtSecurityHandlerTest.kt +++ b/restdocs-api-spec/src/test/kotlin/com/epages/restdocs/apispec/JwtSecurityHandlerTest.kt @@ -23,6 +23,16 @@ class JwtSecurityHandlerTest { then((securityRequirement as Oauth2).requiredScopes).containsExactly("scope1", "scope2") } + @Test + fun `should add scope list when standard oauth2 jwt is found in Authorization header`() { + givenRequestWithStandardOAuth2JwtInAuthorizationHeader() + + whenSecurityRequirementsExtracted(operation) + + then(securityRequirement).isNotNull + then((securityRequirement as Oauth2).requiredScopes).containsExactly("scope1", "scope2") + } + @Test fun `should return SecurityType of JWTBearer when non oauth2 jwt is found in Authorization header`() { givenRequestWithNonOAuth2JwtInAuthorizationHeader() @@ -72,6 +82,15 @@ class JwtSecurityHandlerTest { .build() } + private fun givenRequestWithStandardOAuth2JwtInAuthorizationHeader() { + operation = OperationBuilder().request("/some") + .header( + AUTHORIZATION, + "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6InNjb3BlMSBzY29wZTIiLCJleHAiOjE1MDc3NTg0OTgsImlhdCI6MTUwNzcxNTI5OCwianRpIjoiNDJhMGE5MWEtZDZlZC00MGNjLWIxMDYtZTkwY2RhZTQzZDZkIn0.yLPUhfQ5IIWaTwLO1qcGzAjXtqXnx-FRiF_yGQkiO2M" + ) + .build() + } + private fun givenRequestWithNonOAuth2JwtInAuthorizationHeader() { operation = OperationBuilder().request("/some") .header(