Skip to content

Commit 3dfafbb

Browse files
authored
Merge pull request #1 from jzheaux/gh-14186
Polish Custom Username Location
2 parents 91e2203 + 00493dc commit 3dfafbb

File tree

11 files changed

+111
-235
lines changed

11 files changed

+111
-235
lines changed

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/DefaultOAuth2UserDeserializer.java

Lines changed: 0 additions & 60 deletions
This file was deleted.

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/DefaultOAuth2UserMixin.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -24,7 +24,6 @@
2424
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
2525
import com.fasterxml.jackson.annotation.JsonProperty;
2626
import com.fasterxml.jackson.annotation.JsonTypeInfo;
27-
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
2827

2928
import org.springframework.security.core.GrantedAuthority;
3029
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
@@ -38,7 +37,6 @@
3837
* @see OAuth2ClientJackson2Module
3938
*/
4039
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
41-
@JsonDeserialize(using = DefaultOAuth2UserDeserializer.class)
4240
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
4341
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
4442
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -50,10 +48,4 @@ abstract class DefaultOAuth2UserMixin {
5048
@JsonProperty("nameAttributeKey") String nameAttributeKey) {
5149
}
5250

53-
@JsonCreator
54-
DefaultOAuth2UserMixin(@JsonProperty("attributes") Map<String, Object> attributes,
55-
@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities,
56-
@JsonProperty("name") String name) {
57-
}
58-
5951
}

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/DefaultOidcUserDeserializer.java

Lines changed: 0 additions & 61 deletions
This file was deleted.

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/DefaultOidcUserMixin.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2020 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,7 +23,6 @@
2323
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
2424
import com.fasterxml.jackson.annotation.JsonProperty;
2525
import com.fasterxml.jackson.annotation.JsonTypeInfo;
26-
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
2726

2827
import org.springframework.security.core.GrantedAuthority;
2928
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
@@ -39,7 +38,6 @@
3938
* @see OAuth2ClientJackson2Module
4039
*/
4140
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
42-
@JsonDeserialize(using = DefaultOidcUserDeserializer.class)
4341
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
4442
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
4543
@JsonIgnoreProperties(value = { "attributes" }, ignoreUnknown = true)
@@ -51,10 +49,4 @@ abstract class DefaultOidcUserMixin {
5149
@JsonProperty("nameAttributeKey") String nameAttributeKey) {
5250
}
5351

54-
@JsonCreator
55-
DefaultOidcUserMixin(@JsonProperty("idToken") OidcIdToken idToken, @JsonProperty("userInfo") OidcUserInfo userInfo,
56-
@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities,
57-
@JsonProperty("name") String name) {
58-
}
59-
6052
}

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/JsonNodeUtils.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -16,16 +16,13 @@
1616

1717
package org.springframework.security.oauth2.client.jackson2;
1818

19-
import java.util.Collection;
2019
import java.util.Map;
2120
import java.util.Set;
2221

2322
import com.fasterxml.jackson.core.type.TypeReference;
2423
import com.fasterxml.jackson.databind.JsonNode;
2524
import com.fasterxml.jackson.databind.ObjectMapper;
2625

27-
import org.springframework.security.core.GrantedAuthority;
28-
2926
/**
3027
* Utility class for {@code JsonNode}.
3128
*
@@ -40,9 +37,6 @@ abstract class JsonNodeUtils {
4037
static final TypeReference<Map<String, Object>> STRING_OBJECT_MAP = new TypeReference<Map<String, Object>>() {
4138
};
4239

43-
static final TypeReference<Collection<? extends GrantedAuthority>> GRANTED_AUTHORITY_COLLECTION = new TypeReference<Collection<? extends GrantedAuthority>>() {
44-
};
45-
4640
static String findStringValue(JsonNode jsonNode, String fieldName) {
4741
if (jsonNode == null) {
4842
return null;
@@ -68,12 +62,4 @@ static JsonNode findObjectNode(JsonNode jsonNode, String fieldName) {
6862
return (value != null && value.isObject()) ? value : null;
6963
}
7064

71-
static <T> T findValueByPath(JsonNode jsonNode, String path, Class<T> type, ObjectMapper mapper) {
72-
if (jsonNode == null) {
73-
return null;
74-
}
75-
JsonNode value = jsonNode.path(path);
76-
return (value != null && !value.isMissingNode()) ? mapper.convertValue(value, type) : null;
77-
}
78-
7965
}

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultOAuth2UserService.java

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -20,12 +20,8 @@
2020
import java.util.LinkedHashSet;
2121
import java.util.Map;
2222

23-
import org.springframework.context.expression.MapAccessor;
2423
import org.springframework.core.ParameterizedTypeReference;
2524
import org.springframework.core.convert.converter.Converter;
26-
import org.springframework.expression.Expression;
27-
import org.springframework.expression.spel.standard.SpelExpressionParser;
28-
import org.springframework.expression.spel.support.SimpleEvaluationContext;
2925
import org.springframework.http.RequestEntity;
3026
import org.springframework.http.ResponseEntity;
3127
import org.springframework.security.core.GrantedAuthority;
@@ -80,7 +76,8 @@ public class DefaultOAuth2UserService implements OAuth2UserService<OAuth2UserReq
8076

8177
private Converter<OAuth2UserRequest, RequestEntity<?>> requestEntityConverter = new OAuth2UserRequestEntityConverter();
8278

83-
private final SpelExpressionParser parser = new SpelExpressionParser();
79+
private Converter<OAuth2UserRequest, Converter<Map<String, Object>, Map<String, Object>>> attributesConverter = (
80+
request) -> (attributes) -> attributes;
8481

8582
private RestOperations restOperations;
8683

@@ -97,10 +94,35 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
9794
RequestEntity<?> request = this.requestEntityConverter.convert(userRequest);
9895
ResponseEntity<Map<String, Object>> response = getResponse(userRequest, request);
9996
OAuth2AccessToken token = userRequest.getAccessToken();
100-
Map<String, Object> attributes = response.getBody();
97+
Map<String, Object> attributes = this.attributesConverter.convert(userRequest).convert(response.getBody());
10198
Collection<GrantedAuthority> authorities = getAuthorities(token, attributes);
102-
String name = getName(attributes, userNameAttributeName);
103-
return new DefaultOAuth2User(attributes, authorities, name);
99+
return new DefaultOAuth2User(authorities, attributes, userNameAttributeName);
100+
}
101+
102+
/**
103+
* Use this strategy to adapt user attributes into a format understood by Spring
104+
* Security; by default, the original attributes are preserved.
105+
*
106+
* <p>
107+
* This can be helpful, for example, if the user attribute is nested. Since Spring
108+
* Security needs the username attribute to be at the top level, you can use this
109+
* method to do:
110+
*
111+
* <pre>
112+
* DefaultOAuth2UserService userService = new DefaultOAuth2UserService();
113+
* userService.setAttributesConverter((userRequest) -> (attributes) ->
114+
* Map&lt;String, Object&gt; userObject = (Map&lt;String, Object&gt;) attributes.get("user");
115+
* attributes.put("user-name", userObject.get("user-name"));
116+
* return attributes;
117+
* });
118+
* </pre>
119+
* @param attributesConverter the attribute adaptation strategy to use
120+
* @since 6.3
121+
*/
122+
public void setAttributesConverter(
123+
Converter<OAuth2UserRequest, Converter<Map<String, Object>, Map<String, Object>>> attributesConverter) {
124+
Assert.notNull(attributesConverter, "attributesConverter cannot be null");
125+
this.attributesConverter = attributesConverter;
104126
}
105127

106128
private ResponseEntity<Map<String, Object>> getResponse(OAuth2UserRequest userRequest, RequestEntity<?> request) {
@@ -174,16 +196,6 @@ private Collection<GrantedAuthority> getAuthorities(OAuth2AccessToken token, Map
174196
return authorities;
175197
}
176198

177-
private String getName(Map<String, Object> attributes, String userNameAttributeName) {
178-
Assert.notEmpty(attributes, "attributes cannot be empty");
179-
Assert.hasText(userNameAttributeName, "userNameAttributeName cannot be empty");
180-
SimpleEvaluationContext context = SimpleEvaluationContext.forPropertyAccessors(new MapAccessor())
181-
.withRootObject(attributes)
182-
.build();
183-
Expression expression = this.parser.parseExpression(userNameAttributeName);
184-
return expression.getValue(context, String.class);
185-
}
186-
187199
/**
188200
* Sets the {@link Converter} used for converting the {@link OAuth2UserRequest} to a
189201
* {@link RequestEntity} representation of the UserInfo Request.

oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/OAuth2AuthenticationTokenMixinTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -36,6 +36,7 @@
3636
import org.springframework.security.jackson2.SecurityJackson2Modules;
3737
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
3838
import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens;
39+
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;
3940
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
4041
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
4142
import org.springframework.security.oauth2.core.oidc.StandardClaimNames;
@@ -193,7 +194,7 @@ private static String asJson(DefaultOAuth2User oauth2User) {
193194
" \"@class\": \"java.util.Collections$UnmodifiableMap\",\n" +
194195
" \"username\": \"user\"\n" +
195196
" },\n" +
196-
" \"name\": \"user\"\n" +
197+
" \"nameAttributeKey\": \"username\"\n" +
197198
" }";
198199
// @formatter:on
199200
}
@@ -205,7 +206,7 @@ private static String asJson(DefaultOidcUser oidcUser) {
205206
" \"authorities\": " + asJson(oidcUser.getAuthorities(), "java.util.Collections$UnmodifiableSet") + ",\n" +
206207
" \"idToken\": " + asJson(oidcUser.getIdToken()) + ",\n" +
207208
" \"userInfo\": " + asJson(oidcUser.getUserInfo()) + ",\n" +
208-
" \"name\": \"" + oidcUser.getName() + "\"\n" +
209+
" \"nameAttributeKey\": \"" + IdTokenClaimNames.SUB + "\"\n" +
209210
" }";
210211
// @formatter:on
211212
}

0 commit comments

Comments
 (0)