From 175155ba6a4059b6303a52eaa7268644f636da3c Mon Sep 17 00:00:00 2001
From: h_sharifi
Date: Wed, 3 Jan 2024 13:56:31 +0330
Subject: [PATCH 1/7] BAEL-7275: add controller for claims test
---
.../java/com/baeldung/web/ArticlesController.java | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/oauth-authorization-server/client-server/src/main/java/com/baeldung/web/ArticlesController.java b/oauth-authorization-server/client-server/src/main/java/com/baeldung/web/ArticlesController.java
index 269225189..70db60337 100644
--- a/oauth-authorization-server/client-server/src/main/java/com/baeldung/web/ArticlesController.java
+++ b/oauth-authorization-server/client-server/src/main/java/com/baeldung/web/ArticlesController.java
@@ -1,5 +1,7 @@
package com.baeldung.web;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
@@ -7,7 +9,8 @@
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
-import javax.servlet.http.HttpServletRequest;
+import java.text.ParseException;
+import java.util.Map;
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient;
@@ -29,4 +32,14 @@ public String[] getArticles(
.bodyToMono(String[].class)
.block();
}
+
+ @GetMapping(value = "/claims")
+ public String getClaims(
+ @RegisteredOAuth2AuthorizedClient("articles-client-authorization-code") OAuth2AuthorizedClient authorizedClient
+ ) throws ParseException {
+ SignedJWT signedJWT = SignedJWT.parse(authorizedClient.getAccessToken().getTokenValue());
+ JWTClaimsSet claimsSet = signedJWT.getJWTClaimsSet();
+ Map claims = claimsSet.getClaims();
+ return claims.get("authorities").toString();
+ }
}
\ No newline at end of file
From 6212a2d352b770b12f5f85c7915f25ceb85166a7 Mon Sep 17 00:00:00 2001
From: h_sharifi
Date: Wed, 3 Jan 2024 13:57:02 +0330
Subject: [PATCH 2/7] BAEL-7275: add CLIENT_CREDENTIALS grant type
---
.../main/java/com/baeldung/config/AuthorizationServerConfig.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/AuthorizationServerConfig.java b/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/AuthorizationServerConfig.java
index b27e589e1..234521a17 100644
--- a/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/AuthorizationServerConfig.java
+++ b/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/AuthorizationServerConfig.java
@@ -44,6 +44,7 @@ public RegisteredClientRepository registeredClientRepository() {
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
+ .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/articles-client-oidc")
.redirectUri("http://127.0.0.1:8080/authorized")
.scope(OidcScopes.OPENID)
From add9b82f73cf216183ce5a5ce88225dd446717cb Mon Sep 17 00:00:00 2001
From: h_sharifi
Date: Wed, 3 Jan 2024 13:57:45 +0330
Subject: [PATCH 3/7] BAEL-7275: add token customizer for adding claims
---
.../config/DefaultSecurityConfig.java | 33 +++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/DefaultSecurityConfig.java b/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/DefaultSecurityConfig.java
index 2ab6d4360..52a464520 100644
--- a/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/DefaultSecurityConfig.java
+++ b/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/DefaultSecurityConfig.java
@@ -1,14 +1,23 @@
package com.baeldung.config;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.oauth2.core.OAuth2TokenType;
+import org.springframework.security.oauth2.server.authorization.JwtEncodingContext;
+import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
import static org.springframework.security.config.Customizer.withDefaults;
@EnableWebSecurity
@@ -33,4 +42,28 @@ UserDetailsService users() {
return new InMemoryUserDetailsManager(user);
}
+ @Bean
+ @Profile("basic-claim")
+ public OAuth2TokenCustomizer jwtTokenCustomizer() {
+ return (context) -> {
+ if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
+ context.getClaims().claims((claims) -> {
+ claims.put("claim-1", "value-1");
+ claims.put("claim-2", "value-2");
+ });
+ }
+ };
+ }
+
+ @Bean
+ @Profile("authority-claim")
+ public OAuth2TokenCustomizer tokenCustomizer(@Qualifier("users") UserDetailsService userDetailsService) {
+ return (context) -> {
+ UserDetails userDetails = userDetailsService.loadUserByUsername(context.getPrincipal().getName());
+ Collection authorities = userDetails.getAuthorities();
+ context.getClaims().claims(claims ->
+ claims.put("authorities", authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())));
+ };
+ }
+
}
From c422e3275c33bbcf7de33b06b67c4b673e2f24c2 Mon Sep 17 00:00:00 2001
From: h_sharifi
Date: Wed, 3 Jan 2024 13:58:10 +0330
Subject: [PATCH 4/7] BAEL-7275: add spring-boot-starter-test dependency
---
.../spring-authorization-server/pom.xml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/oauth-authorization-server/spring-authorization-server/pom.xml b/oauth-authorization-server/spring-authorization-server/pom.xml
index 24cd20a28..5f22ca701 100644
--- a/oauth-authorization-server/spring-authorization-server/pom.xml
+++ b/oauth-authorization-server/spring-authorization-server/pom.xml
@@ -29,6 +29,10 @@
spring-security-oauth2-authorization-server
${spring-auth-server.version}
+
+ org.springframework.boot
+ spring-boot-starter-test
+
From 9d2453f7779e91c6e55fd0a13c5d9c977e8ce8d2 Mon Sep 17 00:00:00 2001
From: h_sharifi
Date: Wed, 3 Jan 2024 13:59:25 +0330
Subject: [PATCH 5/7] BAEL-7275: add test case for CLIENT_CREDENTIALS grant
type
---
.../java/CustomClaimsConfigurationTest.java | 72 +++++++++++++++++++
1 file changed, 72 insertions(+)
create mode 100644 oauth-authorization-server/spring-authorization-server/src/test/java/CustomClaimsConfigurationTest.java
diff --git a/oauth-authorization-server/spring-authorization-server/src/test/java/CustomClaimsConfigurationTest.java b/oauth-authorization-server/spring-authorization-server/src/test/java/CustomClaimsConfigurationTest.java
new file mode 100644
index 000000000..e7e0b389d
--- /dev/null
+++ b/oauth-authorization-server/spring-authorization-server/src/test/java/CustomClaimsConfigurationTest.java
@@ -0,0 +1,72 @@
+import com.baeldung.OAuth2AuthorizationServerApplication;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+
+import java.text.ParseException;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = OAuth2AuthorizationServerApplication.class)
+@ActiveProfiles(value = "basic-claim")
+public class CustomClaimsConfigurationTest {
+
+ private static final String ISSUER_URL = "http://localhost:";
+ private static final String USERNAME = "articles-client";
+ private static final String PASSWORD = "secret";
+ private static final String GRANT_TYPE = "client_credentials";
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @LocalServerPort
+ private int serverPort;
+
+ @Test
+ public void givenAccessToken_whenGetCustomClaim_thenSuccess() throws ParseException {
+ String url = ISSUER_URL + serverPort + "/oauth2/token";
+ HttpHeaders headers = new HttpHeaders();
+ headers.setBasicAuth(USERNAME, PASSWORD);
+ MultiValueMap params = new LinkedMultiValueMap<>();
+ params.add("grant_type", GRANT_TYPE);
+ HttpEntity> requestEntity = new HttpEntity<>(params, headers);
+ ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, TokenDTO.class);
+
+ SignedJWT signedJWT = SignedJWT.parse(response.getBody().getAccessToken());
+ JWTClaimsSet claimsSet = signedJWT.getJWTClaimsSet();
+ Map claims = claimsSet.getClaims();
+
+ assertEquals("value-1", claims.get("claim-1"));
+ assertEquals("value-2", claims.get("claim-2"));
+ }
+
+ static class TokenDTO {
+ @JsonProperty("access_token")
+ private String accessToken;
+ @JsonProperty("token_type")
+ private String tokenType;
+ @JsonProperty("expires_in")
+ private String expiresIn;
+ @JsonProperty("scope")
+ private String scope;
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+ }
+
+}
\ No newline at end of file
From ef8dc4974e6c5282d9acb2187ece56572ad9e6ba Mon Sep 17 00:00:00 2001
From: h_sharifi
Date: Sat, 6 Jan 2024 13:41:14 +0330
Subject: [PATCH 6/7] BAEL-7275: remove extra space
---
.../src/test/java/CustomClaimsConfigurationTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/oauth-authorization-server/spring-authorization-server/src/test/java/CustomClaimsConfigurationTest.java b/oauth-authorization-server/spring-authorization-server/src/test/java/CustomClaimsConfigurationTest.java
index e7e0b389d..b506d0cb5 100644
--- a/oauth-authorization-server/spring-authorization-server/src/test/java/CustomClaimsConfigurationTest.java
+++ b/oauth-authorization-server/spring-authorization-server/src/test/java/CustomClaimsConfigurationTest.java
@@ -38,7 +38,7 @@ public class CustomClaimsConfigurationTest {
@Test
public void givenAccessToken_whenGetCustomClaim_thenSuccess() throws ParseException {
- String url = ISSUER_URL + serverPort + "/oauth2/token";
+ String url = ISSUER_URL + serverPort + "/oauth2/token";
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(USERNAME, PASSWORD);
MultiValueMap params = new LinkedMultiValueMap<>();
From aa549080007bc1e110dfb224def9d29a5c7d25ab Mon Sep 17 00:00:00 2001
From: h_sharifi
Date: Sun, 7 Jan 2024 18:09:07 +0330
Subject: [PATCH 7/7] BAEL-7275: move client_credential in the first step
---
.../java/com/baeldung/config/AuthorizationServerConfig.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/AuthorizationServerConfig.java b/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/AuthorizationServerConfig.java
index 234521a17..0630afe86 100644
--- a/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/AuthorizationServerConfig.java
+++ b/oauth-authorization-server/spring-authorization-server/src/main/java/com/baeldung/config/AuthorizationServerConfig.java
@@ -42,9 +42,9 @@ public RegisteredClientRepository registeredClientRepository() {
.clientId("articles-client")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
+ .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
- .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/articles-client-oidc")
.redirectUri("http://127.0.0.1:8080/authorized")
.scope(OidcScopes.OPENID)