You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/04/11 07:18:21 UTC
[isis] branch master updated: ISIS-2606: adds avatarUrl and
realName to UserMemento
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push:
new ef6961a ISIS-2606: adds avatarUrl and realName to UserMemento
ef6961a is described below
commit ef6961a6779620333e5593047cfe159d9bcece64
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Apr 11 08:18:05 2021 +0100
ISIS-2606: adds avatarUrl and realName to UserMemento
---
api/applib/pom.xml | 14 +-
.../isis/applib/services/user/UserMemento.java | 64 +++++-
.../applib/services/user/UserMemento_Test.java | 217 ++++++++++++++++++++
core/internaltestsupport/pom.xml | 18 +-
security/spring/pom.xml | 7 +
...thenticationConverterOfOAuth2UserPrincipal.java | 43 +++-
...icationConverterOfOAuth2UserPrincipal_Test.java | 225 +++++++++++++++++++++
7 files changed, 556 insertions(+), 32 deletions(-)
diff --git a/api/applib/pom.xml b/api/applib/pom.xml
index ae98b79..c94f3dd 100644
--- a/api/applib/pom.xml
+++ b/api/applib/pom.xml
@@ -7,9 +7,9 @@
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -69,7 +69,7 @@
</build>
<dependencies>
-
+
<dependency>
<groupId>org.apache.isis.commons</groupId>
<artifactId>isis-commons</artifactId>
@@ -98,19 +98,13 @@
<artifactId>isis-core-internaltestsupport</artifactId>
<scope>test</scope>
</dependency>
-
+
<dependency>
<groupId>org.jmock</groupId>
<artifactId>jmock</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.assertj</groupId>
- <artifactId>assertj-core</artifactId>
- <scope>test</scope>
- </dependency>
-
</dependencies>
</project>
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
index 63f41b4..748da46 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/user/UserMemento.java
@@ -19,6 +19,7 @@
package org.apache.isis.applib.services.user;
import java.io.Serializable;
+import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -27,8 +28,12 @@ import java.util.stream.Stream;
import javax.annotation.Nullable;
+import org.apache.isis.applib.annotation.Collection;
import org.apache.isis.applib.annotation.CollectionLayout;
import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Optionality;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.Property;
import org.apache.isis.applib.annotation.PropertyLayout;
import org.apache.isis.commons.internal.base._Strings;
import org.apache.isis.commons.internal.collections._Lists;
@@ -106,12 +111,6 @@ public final class UserMemento implements Serializable {
this.roles = roles.collect(_Lists.toUnmodifiable());
}
- public UserMemento withRole(String role) {
- final List<RoleMemento> roles = new ArrayList<>(this.roles);
- roles.add(new RoleMemento(role));
- return new UserMemento(this.name, roles.stream());
- }
-
public String title() {
return name;
}
@@ -119,19 +118,68 @@ public final class UserMemento implements Serializable {
/**
* The user's login name.
*/
+ @Property
@PropertyLayout(sequence = "1.1")
@Getter
private final String name;
+ @Property(optionality = Optionality.OPTIONAL)
+ @PropertyLayout(sequence = "1.2")
+ @Getter
+ private String realName;
+
+ @Programmatic
+ public UserMemento withRealName(final String realName) {
+ val userMemento = copy();
+ userMemento.realName = realName;
+ return userMemento;
+ }
+
+ @Property(optionality = Optionality.OPTIONAL)
+ @PropertyLayout(sequence = "1.3")
+ @Getter
+ private URL avatarUrl;
+
+ @Programmatic
+ public UserMemento withAvatarUrl(final URL avatarUrl) {
+ val userMemento = copy();
+ userMemento.avatarUrl = avatarUrl;
+ return userMemento;
+ }
+
+ private UserMemento copy() {
+ return copy(this.roles);
+ }
+
+ private UserMemento copy(final List<RoleMemento> roles) {
+ val userMemento = new UserMemento(this.name, roles.stream());
+ userMemento.realName = this.realName;
+ userMemento.avatarUrl = this.avatarUrl;
+ return userMemento;
+ }
+
+
+
/**
* The roles associated with this user.
*/
- @CollectionLayout(sequence = "1.2")
+ @Collection
+ @CollectionLayout(sequence = "1.4")
private final List<RoleMemento> roles;
public List<RoleMemento> getRoles() {
return roles;
}
+ @Programmatic
+ public UserMemento withRole(String role) {
+ final List<RoleMemento> roles = new ArrayList<>(this.roles);
+ roles.add(new RoleMemento(role));
+ val userMemento = copy(roles);
+ return userMemento;
+ }
+
+
+
/**
* Determine if the specified name is this user.
*
@@ -143,11 +191,13 @@ public final class UserMemento implements Serializable {
return name.equals(userName);
}
+ @Programmatic
public Stream<String> streamRoleNames() {
return roles.stream()
.map(RoleMemento::getName);
}
+ @Programmatic
public boolean hasRoleName(final @Nullable String roleName) {
return streamRoleNames().anyMatch(myRoleName->myRoleName.equals(roleName));
}
diff --git a/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java b/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java
new file mode 100644
index 0000000..bd411d0
--- /dev/null
+++ b/api/applib/src/test/java/org/apache/isis/applib/services/user/UserMemento_Test.java
@@ -0,0 +1,217 @@
+package org.apache.isis.applib.services.user;
+
+import java.net.MalformedURLException;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import lombok.val;
+
+class UserMemento_Test {
+
+ @Nested
+ class constructor {
+
+ @Test
+ void name_only() {
+
+ // when
+ val userMemento = UserMemento.ofName("fredflintstone");
+
+ // then original unchanged
+ Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento.getRoles()).hasSize(0);
+ Assertions.assertThat(userMemento.getRealName()).isNull();
+ Assertions.assertThat(userMemento.getAvatarUrl()).isNull();
+ }
+
+ @Test
+ void name_and_roles() {
+
+ // when
+ val userMemento = UserMemento.ofNameAndRoleNames("fredflintstone", "CAVEMAN", "HUSBAND");
+
+ // then
+ Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento.getRealName()).isNull();
+ Assertions.assertThat(userMemento.getAvatarUrl()).isNull();
+ }
+ }
+
+ @Nested
+ class withRealName {
+
+ @Test
+ void user_and_roles_preserved_and_real_name_set() {
+ // copy
+ val userMemento = UserMemento.ofNameAndRoleNames("fredflintstone", "CAVEMAN", "HUSBAND");
+
+ // when
+ val userMemento2 = userMemento.withRealName("Fred Flintstone");
+
+ // then copy created
+ Assertions.assertThat(userMemento2).isNotSameAs(userMemento);
+
+ // then copy correct
+ Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento2.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento2.getRealName()).isEqualTo("Fred Flintstone");
+
+ // then original unchanged
+ Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento.getRealName()).isNull();
+ }
+
+ @Test
+ void user_and_roles_and_avatarUrl_preserved_and_real_name_set() throws MalformedURLException {
+ // copy
+ val userMemento = UserMemento.ofNameAndRoleNames("fredflintstone", "CAVEMAN", "HUSBAND")
+ .withAvatarUrl(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
+
+ // when
+ val userMemento2 = userMemento.withRealName("Fred Flintstone");
+
+ // then copy created
+ Assertions.assertThat(userMemento2).isNotSameAs(userMemento);
+
+ // then copy correct
+ Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento2.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento2.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
+ Assertions.assertThat(userMemento2.getRealName()).isEqualTo("Fred Flintstone");
+
+ // then original unchanged
+ Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
+ Assertions.assertThat(userMemento.getRealName()).isNull();
+ }
+ }
+
+ @Nested
+ class withAvatarUrl {
+
+ @Test
+ void user_and_roles_preserved_and_avatarUrl_set() throws MalformedURLException {
+
+ // copy
+ val userMemento = UserMemento.ofNameAndRoleNames("fredflintstone", "CAVEMAN", "HUSBAND");
+
+ // when
+ val userMemento2 = userMemento.withAvatarUrl(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
+
+ // then copy created
+ Assertions.assertThat(userMemento2).isNotSameAs(userMemento);
+
+ // then copy correct
+ Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento2.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento2.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
+
+ // then original unchanged
+ Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento.getAvatarUrl()).isNull();
+ }
+
+ @Test
+ void user_and_roles_and_real_name_preserved_and_avatarUrl_set() throws MalformedURLException {
+
+ // copy
+ val userMemento = UserMemento.ofNameAndRoleNames("fredflintstone", "CAVEMAN", "HUSBAND").withRealName("Fred Flintstone");
+
+ // when
+ val userMemento2 = userMemento.withAvatarUrl(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
+
+ // then copy created
+ Assertions.assertThat(userMemento2).isNotSameAs(userMemento);
+
+ // then copy correct
+ Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento2.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento2.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
+ Assertions.assertThat(userMemento2.getRealName()).isEqualTo("Fred Flintstone");
+
+ // then original unchanged
+ Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento.getRealName()).isEqualTo("Fred Flintstone");
+ Assertions.assertThat(userMemento.getAvatarUrl()).isNull();
+ }
+ }
+
+ @Nested
+ class withRole {
+
+ @Test
+ void user_and_roles_preserved_and_role_added() throws MalformedURLException {
+
+ // given
+ val userMemento = UserMemento.ofNameAndRoleNames("fredflintstone", "CAVEMAN", "HUSBAND");
+
+ // when
+ val userMemento2 = userMemento.withRole("WICKET_ROLE");
+
+ // then copy created
+ Assertions.assertThat(userMemento2).isNotSameAs(userMemento);
+
+ // then copy correct
+ Assertions.assertThat(userMemento2.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento2.getRoles()).hasSize(3);
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento2.streamRoleNames()).anyMatch(x -> x.equals("WICKET_ROLE"));
+
+ // then original unchanged
+ Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ }
+ }
+
+ @Nested
+ class all_the_withers {
+
+ @Test
+ void happy_case() throws MalformedURLException {
+
+ // when
+ val userMemento = UserMemento.ofName("fredflintstone")
+ .withRole("CAVEMAN")
+ .withRole("HUSBAND")
+ .withAvatarUrl(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"))
+ .withRealName("Fred Flintstone");
+
+ // then
+ Assertions.assertThat(userMemento.getName()).isEqualTo("fredflintstone");
+ Assertions.assertThat(userMemento.getRoles()).hasSize(2);
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("CAVEMAN"));
+ Assertions.assertThat(userMemento.streamRoleNames()).anyMatch(x -> x.equals("HUSBAND"));
+ Assertions.assertThat(userMemento.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
+ Assertions.assertThat(userMemento.getRealName()).isEqualTo("Fred Flintstone");
+ }
+ }
+
+}
diff --git a/core/internaltestsupport/pom.xml b/core/internaltestsupport/pom.xml
index d9e0184..855b216 100644
--- a/core/internaltestsupport/pom.xml
+++ b/core/internaltestsupport/pom.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
- license agreements. See the NOTICE file distributed with this work for additional
- information regarding copyright ownership. The ASF licenses this file to
- you under the Apache License, Version 2.0 (the "License"); you may not use
- this file except in compliance with the License. You may obtain a copy of
- the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
- by applicable law or agreed to in writing, software distributed under the
- License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
- OF ANY KIND, either express or implied. See the License for the specific
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
+ license agreements. See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership. The ASF licenses this file to
+ you under the Apache License, Version 2.0 (the "License"); you may not use
+ this file except in compliance with the License. You may obtain a copy of
+ the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
+ by applicable law or agreed to in writing, software distributed under the
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License. -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
diff --git a/security/spring/pom.xml b/security/spring/pom.xml
index d5d4867..9ee0d52 100644
--- a/security/spring/pom.xml
+++ b/security/spring/pom.xml
@@ -69,6 +69,13 @@
</exclusions>
</dependency>
+ <!-- test -->
+ <dependency>
+ <groupId>org.apache.isis.core</groupId>
+ <artifactId>isis-core-internaltestsupport</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
diff --git a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfOAuth2UserPrincipal.java b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfOAuth2UserPrincipal.java
index 783d47d..63de251 100644
--- a/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfOAuth2UserPrincipal.java
+++ b/security/spring/src/main/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfOAuth2UserPrincipal.java
@@ -1,5 +1,8 @@
package org.apache.isis.security.spring.authconverters;
+import java.net.MalformedURLException;
+import java.net.URL;
+
import org.springframework.core.annotation.Order;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.user.OAuth2User;
@@ -9,6 +12,7 @@ import org.apache.isis.applib.annotation.OrderPrecedence;
import org.apache.isis.applib.services.user.UserMemento;
import lombok.val;
+import lombok.var;
/**
* Interpret {@link Authentication} as containing an OAuth2 principal.
@@ -39,13 +43,40 @@ public class AuthenticationConverterOfOAuth2UserPrincipal implements Authenticat
val principal = authentication.getPrincipal();
if (principal instanceof OAuth2User) {
val oAuth2User = (OAuth2User) principal;
- final Object loginAttr = oAuth2User.getAttributes().get("login");
- val principalIdentity =
- loginAttr instanceof CharSequence
- ? ((CharSequence) loginAttr).toString()
- : oAuth2User.getName();
- return UserMemento.ofNameAndRoleNames(principalIdentity);
+ val username = usernameFrom(oAuth2User);
+ var userMemento = UserMemento.ofNameAndRoleNames(username);
+ userMemento = userMemento.withAvatarUrl(avatarUrlFrom(oAuth2User));
+ userMemento = userMemento.withRealName(realNameFrom(oAuth2User));
+ return userMemento;
+ }
+ return null;
+ }
+
+ protected static String usernameFrom(OAuth2User oAuth2User) {
+ val loginAttr = oAuth2User.getAttributes().get("login");
+ return loginAttr instanceof CharSequence
+ ? ((CharSequence) loginAttr).toString()
+ : oAuth2User.getName();
+ }
+
+ protected static URL avatarUrlFrom(OAuth2User oAuth2User) {
+ final Object avatarUrlObj = oAuth2User.getAttributes().get("avatar_url");
+ if(avatarUrlObj instanceof String) {
+ try {
+ return new URL((String)avatarUrlObj);
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ protected static String realNameFrom(OAuth2User oAuth2User) {
+ final Object nameAttr = oAuth2User.getAttributes().get("name");
+ if(nameAttr instanceof String) {
+ return (String)nameAttr;
}
return null;
}
+
}
diff --git a/security/spring/src/test/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfOAuth2UserPrincipal_Test.java b/security/spring/src/test/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfOAuth2UserPrincipal_Test.java
new file mode 100644
index 0000000..1ceab90
--- /dev/null
+++ b/security/spring/src/test/java/org/apache/isis/security/spring/authconverters/AuthenticationConverterOfOAuth2UserPrincipal_Test.java
@@ -0,0 +1,225 @@
+package org.apache.isis.security.spring.authconverters;
+
+import java.net.MalformedURLException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.oauth2.core.user.OAuth2User;
+
+import lombok.val;
+
+@ExtendWith(MockitoExtension.class)
+class AuthenticationConverterOfOAuth2UserPrincipal_Test {
+
+ @Mock Authentication mockAuthentication;
+
+ AuthenticationConverterOfOAuth2UserPrincipal converter;
+
+ @BeforeEach
+ void before() {
+ converter = new AuthenticationConverterOfOAuth2UserPrincipal();
+ }
+
+ @Nested
+ class userNameFrom {
+
+ @Test
+ void given_login_attr_exists_then_used() {
+
+ // given
+ final OAuth2User oAuth2User = new OAuth2User() {
+ @Override public String getName() { return "fred"; }
+ @Override public Map<String, Object> getAttributes() {
+ return Collections.singletonMap("login", "freddy");
+ }
+ @Override public Collection<? extends GrantedAuthority> getAuthorities() {
+ return Collections.emptyList();
+ }
+ };
+
+ // expect
+ Mockito.when(mockAuthentication.getPrincipal()).thenReturn(oAuth2User);
+
+ // when
+ val userMemento = converter.convert(mockAuthentication);
+
+ // then
+ Assertions.assertThat(userMemento).isNotNull();
+ Assertions.assertThat(userMemento.getName()).isEqualTo("freddy");
+
+ }
+
+ @Test
+ void given_no_login_attr_exists_then_name_instead_is_used() {
+
+ // given
+ final OAuth2User oAuth2User = new OAuth2User() {
+ @Override public String getName() { return "fred"; }
+ @Override public Map<String, Object> getAttributes() {
+ return Collections.emptyMap();
+ }
+ @Override public Collection<? extends GrantedAuthority> getAuthorities() {
+ return Collections.emptyList();
+ }
+ };
+
+ // expect
+ Mockito.when(mockAuthentication.getPrincipal()).thenReturn(oAuth2User);
+
+ // when
+ val userMemento = converter.convert(mockAuthentication);
+
+ // then
+ Assertions.assertThat(userMemento).isNotNull();
+ Assertions.assertThat(userMemento.getName()).isEqualTo("fred");
+
+ }
+ }
+
+ @Nested
+ class avatarUrl {
+
+ @Test
+ void given_avatarUrl_attr_exists_and_can_be_parsed_then_used() throws MalformedURLException {
+
+ // given
+ final OAuth2User oAuth2User = new OAuth2User() {
+ @Override public String getName() { return "fred"; }
+ @Override public Map<String, Object> getAttributes() {
+ return Collections.singletonMap("avatar_url", "https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png");
+ }
+ @Override public Collection<? extends GrantedAuthority> getAuthorities() {
+ return Collections.emptyList();
+ }
+ };
+
+ // expect
+ Mockito.when(mockAuthentication.getPrincipal()).thenReturn(oAuth2User);
+
+ // when
+ val userMemento = converter.convert(mockAuthentication);
+
+ // then
+ Assertions.assertThat(userMemento).isNotNull();
+ Assertions.assertThat(userMemento.getAvatarUrl()).isEqualTo(new java.net.URL("https://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png"));
+
+ }
+
+ @Test
+ void given_avatarUrl_attr_exists_but_cannot_be_parsed_then_not_used() throws MalformedURLException {
+
+ // given
+ final OAuth2User oAuth2User = new OAuth2User() {
+ @Override public String getName() { return "fred"; }
+ @Override public Map<String, Object> getAttributes() {
+ return Collections.singletonMap("avatar_url", "GARBAGE://upload.wikimedia.org/wikipedia/en/a/ad/Fred_Flintstone.png");
+ }
+ @Override public Collection<? extends GrantedAuthority> getAuthorities() {
+ return Collections.emptyList();
+ }
+ };
+
+ // expect
+ Mockito.when(mockAuthentication.getPrincipal()).thenReturn(oAuth2User);
+
+ // when
+ val userMemento = converter.convert(mockAuthentication);
+
+ // then
+ Assertions.assertThat(userMemento).isNotNull();
+ Assertions.assertThat(userMemento.getAvatarUrl()).isNull();
+ }
+
+ @Test
+ void given_avatarUrl_attr_does_not_exists_then_none() throws MalformedURLException {
+
+ // given
+ final OAuth2User oAuth2User = new OAuth2User() {
+ @Override public String getName() { return "fred"; }
+ @Override public Map<String, Object> getAttributes() {
+ return Collections.emptyMap();
+ }
+ @Override public Collection<? extends GrantedAuthority> getAuthorities() {
+ return Collections.emptyList();
+ }
+ };
+
+ // expect
+ Mockito.when(mockAuthentication.getPrincipal()).thenReturn(oAuth2User);
+
+ // when
+ val userMemento = converter.convert(mockAuthentication);
+
+ // then
+ Assertions.assertThat(userMemento).isNotNull();
+ Assertions.assertThat(userMemento.getAvatarUrl()).isNull();
+ }
+
+ }
+
+ @Nested
+ class realName {
+
+ @Test
+ void given_name_attr_exists_then_used() throws MalformedURLException {
+
+ // given
+ final OAuth2User oAuth2User = new OAuth2User() {
+ @Override public String getName() { return "fred"; }
+ @Override public Map<String, Object> getAttributes() {
+ return Collections.singletonMap("name", "Fred Flintstone");
+ }
+ @Override public Collection<? extends GrantedAuthority> getAuthorities() {
+ return Collections.emptyList();
+ }
+ };
+
+ // expect
+ Mockito.when(mockAuthentication.getPrincipal()).thenReturn(oAuth2User);
+
+ // when
+ val userMemento = converter.convert(mockAuthentication);
+
+ // then
+ Assertions.assertThat(userMemento).isNotNull();
+ Assertions.assertThat(userMemento.getRealName()).isEqualTo("Fred Flintstone");
+ }
+
+ @Test
+ void given_name_attr_does_not_exists_then_none() throws MalformedURLException {
+
+ // given
+ final OAuth2User oAuth2User = new OAuth2User() {
+ @Override public String getName() { return "fred"; }
+ @Override public Map<String, Object> getAttributes() {
+ return Collections.emptyMap();
+ }
+ @Override public Collection<? extends GrantedAuthority> getAuthorities() {
+ return Collections.emptyList();
+ }
+ };
+
+ // expect
+ Mockito.when(mockAuthentication.getPrincipal()).thenReturn(oAuth2User);
+
+ // when
+ val userMemento = converter.convert(mockAuthentication);
+
+ // then
+ Assertions.assertThat(userMemento).isNotNull();
+ Assertions.assertThat(userMemento.getRealName()).isNull();
+ }
+
+ }
+}