2
0
Эх сурвалжийг харах

Add ability to set principalClaimName in ReactiveJwtAuthenticationConverter

Closes #12907
Marcus Kainth 2 жил өмнө
parent
commit
f0ef54050e

+ 19 - 2
oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverter.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -23,6 +23,7 @@ import org.springframework.core.convert.converter.Converter;
 import org.springframework.security.authentication.AbstractAuthenticationToken;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.jwt.JwtClaimNames;
 import org.springframework.util.Assert;
 
 /**
@@ -30,6 +31,7 @@ import org.springframework.util.Assert;
  * a {@link AbstractAuthenticationToken Mono<AbstractAuthenticationToken>}.
  *
  * @author Eric Deandrea
+ * @author Marcus Kainth
  * @since 5.2
  */
 public final class ReactiveJwtAuthenticationConverter implements Converter<Jwt, Mono<AbstractAuthenticationToken>> {
@@ -37,12 +39,17 @@ public final class ReactiveJwtAuthenticationConverter implements Converter<Jwt,
 	private Converter<Jwt, Flux<GrantedAuthority>> jwtGrantedAuthoritiesConverter = new ReactiveJwtGrantedAuthoritiesConverterAdapter(
 			new JwtGrantedAuthoritiesConverter());
 
+	private String principalClaimName = JwtClaimNames.SUB;
+
 	@Override
 	public Mono<AbstractAuthenticationToken> convert(Jwt jwt) {
 		// @formatter:off
 		return this.jwtGrantedAuthoritiesConverter.convert(jwt)
 				.collectList()
-				.map((authorities) -> new JwtAuthenticationToken(jwt, authorities));
+				.map((authorities) -> {
+					String principalName = jwt.getClaimAsString(this.principalClaimName);
+					return new JwtAuthenticationToken(jwt, authorities, principalName);
+				});
 		// @formatter:on
 	}
 
@@ -58,4 +65,14 @@ public final class ReactiveJwtAuthenticationConverter implements Converter<Jwt,
 		this.jwtGrantedAuthoritiesConverter = jwtGrantedAuthoritiesConverter;
 	}
 
+	/**
+	 * Sets the principal claim name. Defaults to {@link JwtClaimNames#SUB}.
+	 * @param principalClaimName The principal claim name
+	 * @since 6.1
+	 */
+	public void setPrincipalClaimName(String principalClaimName) {
+		Assert.hasText(principalClaimName, "principalClaimName cannot be empty");
+		this.principalClaimName = principalClaimName;
+	}
+
 }

+ 45 - 1
oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/ReactiveJwtAuthenticationConverterTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
  * Tests for {@link ReactiveJwtAuthenticationConverter}
  *
  * @author Eric Deandrea
+ * @author Marcus Kainth
  * @since 5.2
  */
 public class ReactiveJwtAuthenticationConverterTests {
@@ -68,4 +69,47 @@ public class ReactiveJwtAuthenticationConverterTests {
 		assertThat(authorities).containsExactly(new SimpleGrantedAuthority("blah"));
 	}
 
+	@Test
+	public void whenSettingNullPrincipalClaimName() {
+		// @formatter:off
+		assertThatIllegalArgumentException()
+				.isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(null))
+				.withMessage("principalClaimName cannot be empty");
+		// @formatter:on
+	}
+
+	@Test
+	public void whenSettingEmptyPrincipalClaimName() {
+		// @formatter:off
+		assertThatIllegalArgumentException()
+				.isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(""))
+				.withMessage("principalClaimName cannot be empty");
+		// @formatter:on
+	}
+
+	@Test
+	public void whenSettingBlankPrincipalClaimName() {
+		// @formatter:off
+		assertThatIllegalArgumentException()
+				.isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(" "))
+				.withMessage("principalClaimName cannot be empty");
+		// @formatter:on
+	}
+
+	@Test
+	public void convertWhenPrincipalClaimNameSet() {
+		this.jwtAuthenticationConverter.setPrincipalClaimName("user_id");
+		Jwt jwt = TestJwts.jwt().claim("user_id", "100").build();
+		AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
+		assertThat(authentication.getName()).isEqualTo("100");
+	}
+
+	@Test
+	public void convertWhenPrincipalClaimNameSetAndClaimValueIsNotString() {
+		this.jwtAuthenticationConverter.setPrincipalClaimName("user_id");
+		Jwt jwt = TestJwts.jwt().claim("user_id", 100).build();
+		AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
+		assertThat(authentication.getName()).isEqualTo("100");
+	}
+
 }