Skip to content

Commit

Permalink
Add copy constructor for DefaultOAuth2User
Browse files Browse the repository at this point in the history
Accepts null name for consistency with DefaultOAuth2AuthenticatedPrincipal.

The private static method DefaultOAuth2User.getNameFromAttributes was added in order to keep assertions about nameAttributeKey and the looked up name for the deprecated constructor.
  • Loading branch information
andreblanke committed Dec 8, 2024
1 parent 1cc7a73 commit 5b2212b
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 22 deletions.
4 changes: 2 additions & 2 deletions docs/modules/ROOT/pages/reactive/test/web/oauth2.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -509,9 +509,9 @@ Java::
[source,java,role="primary"]
----
OAuth2User oauth2User = new DefaultOAuth2User(
AuthorityUtils.createAuthorityList("SCOPE_message:read"),
"foo_user",
Collections.singletonMap("user_name", "foo_user"),
"user_name");
AuthorityUtils.createAuthorityList("SCOPE_message:read"));
client
.mutateWith(mockOAuth2Login().oauth2User(oauth2User))
Expand Down
4 changes: 2 additions & 2 deletions docs/modules/ROOT/pages/servlet/test/mockmvc/oauth2.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -514,9 +514,9 @@ Java::
[source,java,role="primary"]
----
OAuth2User oauth2User = new DefaultOAuth2User(
AuthorityUtils.createAuthorityList("SCOPE_message:read"),
"foo_user",
Collections.singletonMap("user_name", "foo_user"),
"user_name");
AuthorityUtils.createAuthorityList("SCOPE_message:read"));
mvc
.perform(get("/endpoint")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2024 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.
Expand Down Expand Up @@ -42,10 +42,16 @@
@JsonIgnoreProperties(ignoreUnknown = true)
abstract class DefaultOAuth2UserMixin {

@Deprecated
@JsonCreator
DefaultOAuth2UserMixin(@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities,
@JsonProperty("attributes") Map<String, Object> attributes,
@JsonProperty("nameAttributeKey") String nameAttributeKey) {
}

@JsonCreator
DefaultOAuth2UserMixin(@JsonProperty("name") String name,
@JsonProperty("attributes") Map<String, Object> attributes,
@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
OAuth2AccessToken token = userRequest.getAccessToken();
Map<String, Object> attributes = this.attributesConverter.convert(userRequest).convert(response.getBody());
Collection<GrantedAuthority> authorities = getAuthorities(token, attributes, userNameAttributeName);
return new DefaultOAuth2User(authorities, attributes, userNameAttributeName);
return new DefaultOAuth2User(attributes.get(userNameAttributeName).toString(), attributes, authorities);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public Mono<OAuth2User> loadUser(OAuth2UserRequest userRequest) throws OAuth2Aut
authorities.add(new SimpleGrantedAuthority("SCOPE_" + scope));
}

return new DefaultOAuth2User(authorities, attrs, userNameAttributeName);
return new DefaultOAuth2User(attrs.get(userNameAttributeName).toString(), attrs, authorities);
})
.onErrorMap((ex) -> (ex instanceof UnsupportedMediaTypeException ||
ex.getCause() instanceof UnsupportedMediaTypeException), (ex) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,9 @@
* The default implementation of an {@link OAuth2User}.
*
* <p>
* User attribute names are <b>not</b> standardized between providers and therefore it is
* required to supply the <i>key</i> for the user's &quot;name&quot; attribute to one of
* the constructors. The <i>key</i> will be used for accessing the &quot;name&quot; of the
* {@code Principal} (user) via {@link #getAttributes()} and returning it from
* {@link #getName()}.
* User attribute names are <b>not</b> standardized between providers, and therefore it is
* required to supply the user's &quot;name&quot; or &quot;name&quot; attribute to one of
* the constructors.
*
* @author Joe Grandja
* @author Eddú Meléndez
Expand All @@ -56,7 +54,7 @@ public class DefaultOAuth2User implements OAuth2User, Serializable {

private final Map<String, Object> attributes;

private final String nameAttributeKey;
private final String name;

/**
* Constructs a {@code DefaultOAuth2User} using the provided parameters.
Expand All @@ -65,23 +63,32 @@ public class DefaultOAuth2User implements OAuth2User, Serializable {
* @param nameAttributeKey the key used to access the user's &quot;name&quot; from
* {@link #getAttributes()}
*/
@Deprecated
public DefaultOAuth2User(Collection<? extends GrantedAuthority> authorities, Map<String, Object> attributes,
String nameAttributeKey) {
Assert.notEmpty(attributes, "attributes cannot be empty");
Assert.hasText(nameAttributeKey, "nameAttributeKey cannot be empty");
Assert.notNull(attributes.get(nameAttributeKey),
"Attribute value for '" + nameAttributeKey + "' cannot be null");
this(getNameFromAttributes(attributes, nameAttributeKey), attributes, authorities);
}

/**
* Constructs a {@code DefaultOAuth2User} using the provided parameters.
* @param name the name of the user
* @param authorities the authorities granted to the user
* @param attributes the attributes about the user
*/
public DefaultOAuth2User(String name, Map<String, Object> attributes,
Collection<? extends GrantedAuthority> authorities) {
Assert.notNull(name, "name cannot be null");
Assert.notEmpty(attributes, "attributes cannot be empty");
this.attributes = Collections.unmodifiableMap(new LinkedHashMap<>(attributes));
this.authorities = (authorities != null)
? Collections.unmodifiableSet(new LinkedHashSet<>(this.sortAuthorities(authorities)))
: Collections.unmodifiableSet(new LinkedHashSet<>(AuthorityUtils.NO_AUTHORITIES));
this.attributes = Collections.unmodifiableMap(new LinkedHashMap<>(attributes));
this.nameAttributeKey = nameAttributeKey;
this.name = (name != null) ? name : (String) this.attributes.get("sub");
}

@Override
public String getName() {
return this.getAttribute(this.nameAttributeKey).toString();
return this.name;
}

@Override
Expand Down Expand Up @@ -140,4 +147,11 @@ public String toString() {
return sb.toString();
}

private static String getNameFromAttributes(Map<String, Object> attributes, String nameAttributeKey) {
Assert.hasText(nameAttributeKey, "nameAttributeKey cannot be empty");
Assert.notNull(attributes.get(nameAttributeKey),
"Attribute value for '" + nameAttributeKey + "' cannot be null");
return attributes.get(nameAttributeKey).toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,8 @@ private Map<String, Object> defaultAttributes() {
}

private OAuth2User defaultPrincipal() {
return new DefaultOAuth2User(this.authorities.get(), this.attributes.get(), this.nameAttributeKey);
String name = this.attributes.get().get(this.nameAttributeKey).toString();
return new DefaultOAuth2User(name, this.attributes.get(), this.authorities.get());
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1390,7 +1390,8 @@ private Map<String, Object> defaultAttributes() {
}

private OAuth2User defaultPrincipal() {
return new DefaultOAuth2User(this.authorities.get(), this.attributes.get(), this.nameAttributeKey);
String name = this.attributes.get().get(this.nameAttributeKey).toString();
return new DefaultOAuth2User(name, this.attributes.get(), this.authorities.get());
}

}
Expand Down

0 comments on commit 5b2212b

Please sign in to comment.