Skip to content

Commit f0ef540

Browse files
MarcusKainthjzheaux
authored andcommitted
Add ability to set principalClaimName in ReactiveJwtAuthenticationConverter
Closes #12907
1 parent 46a40e7 commit f0ef540

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

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

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,26 +23,33 @@
2323
import org.springframework.security.authentication.AbstractAuthenticationToken;
2424
import org.springframework.security.core.GrantedAuthority;
2525
import org.springframework.security.oauth2.jwt.Jwt;
26+
import org.springframework.security.oauth2.jwt.JwtClaimNames;
2627
import org.springframework.util.Assert;
2728

2829
/**
2930
* Reactive version of {@link JwtAuthenticationConverter} for converting a {@link Jwt} to
3031
* a {@link AbstractAuthenticationToken Mono<AbstractAuthenticationToken>}.
3132
*
3233
* @author Eric Deandrea
34+
* @author Marcus Kainth
3335
* @since 5.2
3436
*/
3537
public final class ReactiveJwtAuthenticationConverter implements Converter<Jwt, Mono<AbstractAuthenticationToken>> {
3638

3739
private Converter<Jwt, Flux<GrantedAuthority>> jwtGrantedAuthoritiesConverter = new ReactiveJwtGrantedAuthoritiesConverterAdapter(
3840
new JwtGrantedAuthoritiesConverter());
3941

42+
private String principalClaimName = JwtClaimNames.SUB;
43+
4044
@Override
4145
public Mono<AbstractAuthenticationToken> convert(Jwt jwt) {
4246
// @formatter:off
4347
return this.jwtGrantedAuthoritiesConverter.convert(jwt)
4448
.collectList()
45-
.map((authorities) -> new JwtAuthenticationToken(jwt, authorities));
49+
.map((authorities) -> {
50+
String principalName = jwt.getClaimAsString(this.principalClaimName);
51+
return new JwtAuthenticationToken(jwt, authorities, principalName);
52+
});
4653
// @formatter:on
4754
}
4855

@@ -58,4 +65,14 @@ public void setJwtGrantedAuthoritiesConverter(
5865
this.jwtGrantedAuthoritiesConverter = jwtGrantedAuthoritiesConverter;
5966
}
6067

68+
/**
69+
* Sets the principal claim name. Defaults to {@link JwtClaimNames#SUB}.
70+
* @param principalClaimName The principal claim name
71+
* @since 6.1
72+
*/
73+
public void setPrincipalClaimName(String principalClaimName) {
74+
Assert.hasText(principalClaimName, "principalClaimName cannot be empty");
75+
this.principalClaimName = principalClaimName;
76+
}
77+
6178
}

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

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
3535
* Tests for {@link ReactiveJwtAuthenticationConverter}
3636
*
3737
* @author Eric Deandrea
38+
* @author Marcus Kainth
3839
* @since 5.2
3940
*/
4041
public class ReactiveJwtAuthenticationConverterTests {
@@ -68,4 +69,47 @@ public void convertWithOverriddenGrantedAuthoritiesConverter() {
6869
assertThat(authorities).containsExactly(new SimpleGrantedAuthority("blah"));
6970
}
7071

72+
@Test
73+
public void whenSettingNullPrincipalClaimName() {
74+
// @formatter:off
75+
assertThatIllegalArgumentException()
76+
.isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(null))
77+
.withMessage("principalClaimName cannot be empty");
78+
// @formatter:on
79+
}
80+
81+
@Test
82+
public void whenSettingEmptyPrincipalClaimName() {
83+
// @formatter:off
84+
assertThatIllegalArgumentException()
85+
.isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(""))
86+
.withMessage("principalClaimName cannot be empty");
87+
// @formatter:on
88+
}
89+
90+
@Test
91+
public void whenSettingBlankPrincipalClaimName() {
92+
// @formatter:off
93+
assertThatIllegalArgumentException()
94+
.isThrownBy(() -> this.jwtAuthenticationConverter.setPrincipalClaimName(" "))
95+
.withMessage("principalClaimName cannot be empty");
96+
// @formatter:on
97+
}
98+
99+
@Test
100+
public void convertWhenPrincipalClaimNameSet() {
101+
this.jwtAuthenticationConverter.setPrincipalClaimName("user_id");
102+
Jwt jwt = TestJwts.jwt().claim("user_id", "100").build();
103+
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
104+
assertThat(authentication.getName()).isEqualTo("100");
105+
}
106+
107+
@Test
108+
public void convertWhenPrincipalClaimNameSetAndClaimValueIsNotString() {
109+
this.jwtAuthenticationConverter.setPrincipalClaimName("user_id");
110+
Jwt jwt = TestJwts.jwt().claim("user_id", 100).build();
111+
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
112+
assertThat(authentication.getName()).isEqualTo("100");
113+
}
114+
71115
}

0 commit comments

Comments
 (0)