diff --git a/docs/modules/ROOT/pages/reactive/test/web/oauth2.adoc b/docs/modules/ROOT/pages/reactive/test/web/oauth2.adoc index 2548d96cf50..0f20a955cdc 100644 --- a/docs/modules/ROOT/pages/reactive/test/web/oauth2.adoc +++ b/docs/modules/ROOT/pages/reactive/test/web/oauth2.adoc @@ -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)) diff --git a/docs/modules/ROOT/pages/servlet/test/mockmvc/oauth2.adoc b/docs/modules/ROOT/pages/servlet/test/mockmvc/oauth2.adoc index 581f49adefa..696fac7688c 100644 --- a/docs/modules/ROOT/pages/servlet/test/mockmvc/oauth2.adoc +++ b/docs/modules/ROOT/pages/servlet/test/mockmvc/oauth2.adoc @@ -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") diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/DefaultOAuth2UserMixin.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/DefaultOAuth2UserMixin.java index 917062c905c..c5133e541fe 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/DefaultOAuth2UserMixin.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/DefaultOAuth2UserMixin.java @@ -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. @@ -42,10 +42,16 @@ @JsonIgnoreProperties(ignoreUnknown = true) abstract class DefaultOAuth2UserMixin { + @Deprecated @JsonCreator DefaultOAuth2UserMixin(@JsonProperty("authorities") Collection authorities, @JsonProperty("attributes") Map attributes, @JsonProperty("nameAttributeKey") String nameAttributeKey) { } + @JsonCreator + DefaultOAuth2UserMixin(@JsonProperty("name") String name, + @JsonProperty("attributes") Map attributes, + @JsonProperty("authorities") Collection authorities) { + } } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultOAuth2UserService.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultOAuth2UserService.java index 02930047b16..5bc9595d8fd 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultOAuth2UserService.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultOAuth2UserService.java @@ -96,7 +96,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic OAuth2AccessToken token = userRequest.getAccessToken(); Map attributes = this.attributesConverter.convert(userRequest).convert(response.getBody()); Collection authorities = getAuthorities(token, attributes, userNameAttributeName); - return new DefaultOAuth2User(authorities, attributes, userNameAttributeName); + return new DefaultOAuth2User(attributes.get(userNameAttributeName).toString(), attributes, authorities); } /** diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultReactiveOAuth2UserService.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultReactiveOAuth2UserService.java index ae3a65b52c0..e934b34ecab 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultReactiveOAuth2UserService.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/userinfo/DefaultReactiveOAuth2UserService.java @@ -138,7 +138,7 @@ public Mono 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) -> { diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/user/DefaultOAuth2User.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/user/DefaultOAuth2User.java index 6c80d7b64a2..ace741fd8e3 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/user/DefaultOAuth2User.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/user/DefaultOAuth2User.java @@ -36,11 +36,9 @@ * The default implementation of an {@link OAuth2User}. * *

- * User attribute names are not standardized between providers and therefore it is - * required to supply the key for the user's "name" attribute to one of - * the constructors. The key will be used for accessing the "name" of the - * {@code Principal} (user) via {@link #getAttributes()} and returning it from - * {@link #getName()}. + * User attribute names are not standardized between providers, and therefore it is + * required to supply the user's "name" or "name" attribute to one of + * the constructors. * * @author Joe Grandja * @author EddĂș MelĂ©ndez @@ -56,7 +54,7 @@ public class DefaultOAuth2User implements OAuth2User, Serializable { private final Map attributes; - private final String nameAttributeKey; + private final String name; /** * Constructs a {@code DefaultOAuth2User} using the provided parameters. @@ -65,23 +63,32 @@ public class DefaultOAuth2User implements OAuth2User, Serializable { * @param nameAttributeKey the key used to access the user's "name" from * {@link #getAttributes()} */ + @Deprecated public DefaultOAuth2User(Collection authorities, Map 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 attributes, + Collection 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 @@ -140,4 +147,11 @@ public String toString() { return sb.toString(); } + private static String getNameFromAttributes(Map 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(); + } + } diff --git a/test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java b/test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java index 360b7a22982..0cce15b39d1 100644 --- a/test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java +++ b/test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java @@ -848,7 +848,8 @@ private Map 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()); } } diff --git a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java index 8d0aac3e696..2bba7a50f97 100644 --- a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java +++ b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java @@ -1390,7 +1390,8 @@ private Map 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()); } }