From e7acd1219dfb7986262f84b3ea795308123ed1b2 Mon Sep 17 00:00:00 2001 From: Joe Grandja Date: Tue, 2 Feb 2021 04:35:39 -0500 Subject: [PATCH] Allow null or empty authorities for DefaultOAuth2User Make DefaultOAuth2User more inline with other part of spring-security. For example, - DefaultOAuth2AuthenticatedPrincipal - AbstractAuthenticationToken Closes gh-9366 --- .../oauth2/core/user/DefaultOAuth2User.java | 12 +++++--- .../core/oidc/user/DefaultOidcUserTests.java | 28 +++++++++++++++---- .../core/user/DefaultOAuth2UserTests.java | 28 +++++++++++-------- 3 files changed, 47 insertions(+), 21 deletions(-) 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 7657d6b1b7..b1231d2fa5 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 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. @@ -30,6 +30,8 @@ import java.util.SortedSet; import java.util.Comparator; import java.util.LinkedHashSet; +import org.springframework.security.core.authority.AuthorityUtils; + /** * The default implementation of an {@link OAuth2User}. * @@ -59,14 +61,16 @@ public class DefaultOAuth2User implements OAuth2User, Serializable { * @param attributes the attributes about the user * @param nameAttributeKey the key used to access the user's "name" from {@link #getAttributes()} */ - public DefaultOAuth2User(Collection authorities, Map attributes, String nameAttributeKey) { - Assert.notEmpty(authorities, "authorities cannot be empty"); + public DefaultOAuth2User(Collection authorities, Map attributes, + String nameAttributeKey) { Assert.notEmpty(attributes, "attributes cannot be empty"); Assert.hasText(nameAttributeKey, "nameAttributeKey cannot be empty"); if (!attributes.containsKey(nameAttributeKey)) { throw new IllegalArgumentException("Missing attribute '" + nameAttributeKey + "' in attributes"); } - this.authorities = Collections.unmodifiableSet(new LinkedHashSet<>(this.sortAuthorities(authorities))); + 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; } diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/oidc/user/DefaultOidcUserTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/oidc/user/DefaultOidcUserTests.java index 2fad69684f..25ced4f4cb 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/oidc/user/DefaultOidcUserTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/oidc/user/DefaultOidcUserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2021 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. @@ -18,6 +18,7 @@ package org.springframework.security.oauth2.core.oidc.user; import org.junit.Test; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; import org.springframework.security.oauth2.core.oidc.OidcIdToken; @@ -57,11 +58,6 @@ public class DefaultOidcUserTests { private static final OidcIdToken ID_TOKEN = new OidcIdToken("id-token-value", Instant.EPOCH, Instant.MAX, ID_TOKEN_CLAIMS); private static final OidcUserInfo USER_INFO = new OidcUserInfo(USER_INFO_CLAIMS); - @Test(expected = IllegalArgumentException.class) - public void constructorWhenAuthoritiesIsNullThenThrowIllegalArgumentException() { - new DefaultOidcUser(null, ID_TOKEN); - } - @Test(expected = IllegalArgumentException.class) public void constructorWhenIdTokenIsNullThenThrowIllegalArgumentException() { new DefaultOidcUser(AUTHORITIES, null); @@ -72,6 +68,26 @@ public class DefaultOidcUserTests { new DefaultOidcUser(AUTHORITIES, ID_TOKEN, "invalid"); } + @Test + public void constructorWhenAuthoritiesIsNullThenCreatedWithEmptyAuthorities() { + DefaultOidcUser user = new DefaultOidcUser(null, ID_TOKEN); + assertThat(user.getClaims()).containsOnlyKeys(IdTokenClaimNames.ISS, IdTokenClaimNames.SUB); + assertThat(user.getIdToken()).isEqualTo(ID_TOKEN); + assertThat(user.getName()).isEqualTo(SUBJECT); + assertThat(user.getAuthorities()).isEmpty(); + assertThat(user.getAttributes()).containsOnlyKeys(IdTokenClaimNames.ISS, IdTokenClaimNames.SUB); + } + + @Test + public void constructorWhenAuthoritiesIsEmptyThenCreated() { + DefaultOidcUser user = new DefaultOidcUser(AuthorityUtils.NO_AUTHORITIES, ID_TOKEN); + assertThat(user.getClaims()).containsOnlyKeys(IdTokenClaimNames.ISS, IdTokenClaimNames.SUB); + assertThat(user.getIdToken()).isEqualTo(ID_TOKEN); + assertThat(user.getName()).isEqualTo(SUBJECT); + assertThat(user.getAuthorities()).isEmpty(); + assertThat(user.getAttributes()).containsOnlyKeys(IdTokenClaimNames.ISS, IdTokenClaimNames.SUB); + } + @Test public void constructorWhenAuthoritiesIdTokenProvidedThenCreated() { DefaultOidcUser user = new DefaultOidcUser(AUTHORITIES, ID_TOKEN); diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/user/DefaultOAuth2UserTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/user/DefaultOAuth2UserTests.java index 3642b54abb..66c635f7c6 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/user/DefaultOAuth2UserTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/user/DefaultOAuth2UserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2021 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. @@ -41,16 +41,6 @@ public class DefaultOAuth2UserTests { private static final Map ATTRIBUTES = Collections.singletonMap( ATTRIBUTE_NAME_KEY, USERNAME); - @Test(expected = IllegalArgumentException.class) - public void constructorWhenAuthoritiesIsNullThenThrowIllegalArgumentException() { - new DefaultOAuth2User(null, ATTRIBUTES, ATTRIBUTE_NAME_KEY); - } - - @Test(expected = IllegalArgumentException.class) - public void constructorWhenAuthoritiesIsEmptyThenThrowIllegalArgumentException() { - new DefaultOAuth2User(Collections.emptySet(), ATTRIBUTES, ATTRIBUTE_NAME_KEY); - } - @Test(expected = IllegalArgumentException.class) public void constructorWhenAttributesIsNullThenThrowIllegalArgumentException() { new DefaultOAuth2User(AUTHORITIES, null, ATTRIBUTE_NAME_KEY); @@ -71,6 +61,22 @@ public class DefaultOAuth2UserTests { new DefaultOAuth2User(AUTHORITIES, ATTRIBUTES, "invalid"); } + @Test + public void constructorWhenAuthoritiesIsNullThenCreatedWithEmptyAuthorities() { + DefaultOAuth2User user = new DefaultOAuth2User(null, ATTRIBUTES, ATTRIBUTE_NAME_KEY); + assertThat(user.getName()).isEqualTo(USERNAME); + assertThat(user.getAuthorities()).isEmpty(); + assertThat(user.getAttributes()).containsOnlyKeys(ATTRIBUTE_NAME_KEY); + } + + @Test + public void constructorWhenAuthoritiesIsEmptyThenCreated() { + DefaultOAuth2User user = new DefaultOAuth2User(Collections.emptySet(), ATTRIBUTES, ATTRIBUTE_NAME_KEY); + assertThat(user.getName()).isEqualTo(USERNAME); + assertThat(user.getAuthorities()).isEmpty(); + assertThat(user.getAttributes()).containsOnlyKeys(ATTRIBUTE_NAME_KEY); + } + @Test public void constructorWhenAllParametersProvidedAndValidThenCreated() { DefaultOAuth2User user = new DefaultOAuth2User(AUTHORITIES, ATTRIBUTES, ATTRIBUTE_NAME_KEY);