From 0e07da9884292f090695c37faeb205a24c0b5ce9 Mon Sep 17 00:00:00 2001 From: Paul Marechal Date: Sat, 25 Nov 2023 03:07:57 -0500 Subject: [PATCH] refactor: introduce `AuthUser` interface Replace the references to `OAuth2User` by `AuthUser`. This allows downstream extenders to more easily contribute alternative OAuth2 providers: If the expected data is stored in different attributes it will be possible to bridge it by implementing the proper `AuthUser`. --- .../java/org/eclipse/openvsx/UserService.java | 63 +++++++------ .../eclipse/openvsx/security/AuthUser.java | 48 ++++++++++ .../openvsx/security/AuthUserFactory.java | 20 +++++ .../openvsx/security/DefaultAuthUser.java | 74 +++++++++++++++ .../openvsx/security/OAuth2UserServices.java | 89 ++++++++----------- .../org/eclipse/openvsx/RegistryAPITest.java | 13 ++- .../java/org/eclipse/openvsx/UserAPITest.java | 12 ++- .../openvsx/adapter/VSCodeAPITest.java | 12 ++- .../eclipse/openvsx/admin/AdminAPITest.java | 76 +++++++++++----- .../openvsx/cache/CacheServiceTest.java | 45 ++++++---- .../openvsx/web/SitemapControllerTest.java | 11 ++- 11 files changed, 334 insertions(+), 129 deletions(-) create mode 100644 server/src/main/java/org/eclipse/openvsx/security/AuthUser.java create mode 100644 server/src/main/java/org/eclipse/openvsx/security/AuthUserFactory.java create mode 100644 server/src/main/java/org/eclipse/openvsx/security/DefaultAuthUser.java diff --git a/server/src/main/java/org/eclipse/openvsx/UserService.java b/server/src/main/java/org/eclipse/openvsx/UserService.java index fd733701c..7a2b5a67b 100644 --- a/server/src/main/java/org/eclipse/openvsx/UserService.java +++ b/server/src/main/java/org/eclipse/openvsx/UserService.java @@ -9,9 +9,15 @@ ********************************************************************************/ package org.eclipse.openvsx; -import com.google.common.base.Joiner; -import jakarta.persistence.EntityManager; -import jakarta.transaction.Transactional; +import static org.eclipse.openvsx.cache.CacheService.CACHE_NAMESPACE_DETAILS_JSON; +import static org.eclipse.openvsx.util.UrlUtil.createApiUrl; + +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.StringUtils; import org.apache.tika.Tika; @@ -27,23 +33,24 @@ import org.eclipse.openvsx.json.NamespaceDetailsJson; import org.eclipse.openvsx.json.ResultJson; import org.eclipse.openvsx.repositories.RepositoryService; +import org.eclipse.openvsx.security.AuthUser; import org.eclipse.openvsx.security.IdPrincipal; import org.eclipse.openvsx.storage.StorageUtilService; -import org.eclipse.openvsx.util.*; +import org.eclipse.openvsx.util.ErrorResultException; +import org.eclipse.openvsx.util.NamingUtil; +import org.eclipse.openvsx.util.NotFoundException; +import org.eclipse.openvsx.util.TempFile; +import org.eclipse.openvsx.util.TimeUtil; +import org.eclipse.openvsx.util.UrlUtil; import org.springframework.cache.annotation.CacheEvict; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; -import java.io.IOException; -import java.nio.file.Files; -import java.util.List; -import java.util.Objects; -import java.util.UUID; +import com.google.common.base.Joiner; -import static org.eclipse.openvsx.cache.CacheService.CACHE_NAMESPACE_DETAILS_JSON; -import static org.eclipse.openvsx.util.UrlUtil.createApiUrl; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; @Component public class UserService { @@ -80,44 +87,44 @@ public UserData findLoggedInUser() { } @Transactional - public UserData registerNewUser(OAuth2User oauth2User) { + public UserData registerNewUser(AuthUser authUser) { var user = new UserData(); - user.setProvider("github"); - user.setAuthId(oauth2User.getName()); - user.setLoginName(oauth2User.getAttribute("login")); - user.setFullName(oauth2User.getAttribute("name")); - user.setEmail(oauth2User.getAttribute("email")); - user.setProviderUrl(oauth2User.getAttribute("html_url")); - user.setAvatarUrl(oauth2User.getAttribute("avatar_url")); + user.setProvider(authUser.getProviderId()); + user.setAuthId(authUser.getAuthId()); + user.setLoginName(authUser.getLoginName()); + user.setFullName(authUser.getFullName()); + user.setEmail(authUser.getEmail()); + user.setProviderUrl(authUser.getProviderUrl()); + user.setAvatarUrl(authUser.getAvatarUrl()); entityManager.persist(user); return user; } @Transactional - public UserData updateExistingUser(UserData user, OAuth2User oauth2User) { - if ("github".equals(user.getProvider())) { + public UserData updateExistingUser(UserData user, AuthUser authUser) { + if (authUser.getProviderId().equals(user.getProvider())) { var updated = false; - String loginName = oauth2User.getAttribute("login"); + String loginName = authUser.getLoginName(); if (loginName != null && !loginName.equals(user.getLoginName())) { user.setLoginName(loginName); updated = true; } - String fullName = oauth2User.getAttribute("name"); + String fullName = authUser.getFullName(); if (fullName != null && !fullName.equals(user.getFullName())) { user.setFullName(fullName); updated = true; } - String email = oauth2User.getAttribute("email"); + String email = authUser.getEmail(); if (email != null && !email.equals(user.getEmail())) { user.setEmail(email); updated = true; } - String providerUrl = oauth2User.getAttribute("html_url"); + String providerUrl = authUser.getProviderUrl(); if (providerUrl != null && !providerUrl.equals(user.getProviderUrl())) { user.setProviderUrl(providerUrl); updated = true; } - String avatarUrl = oauth2User.getAttribute("avatar_url"); + String avatarUrl = authUser.getAvatarUrl(); if (avatarUrl != null && !avatarUrl.equals(user.getAvatarUrl())) { user.setAvatarUrl(avatarUrl); updated = true; @@ -315,4 +322,4 @@ public ResultJson deleteAccessToken(UserData user, long id) { token.setActive(false); return ResultJson.success("Deleted access token for user " + user.getLoginName() + "."); } -} \ No newline at end of file +} diff --git a/server/src/main/java/org/eclipse/openvsx/security/AuthUser.java b/server/src/main/java/org/eclipse/openvsx/security/AuthUser.java new file mode 100644 index 000000000..5a1026434 --- /dev/null +++ b/server/src/main/java/org/eclipse/openvsx/security/AuthUser.java @@ -0,0 +1,48 @@ +/******************************************************************************** + * Copyright (c) 2023 Ericsson and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.openvsx.security; + +/** + * Encapsulate information about freshly authenticated users. + * + * Different OAuth2 providers may return the same information with different + * attribute keys. This interface allows bridging arbitrary providers. + */ +public interface AuthUser { + /** + * @return Non-human readable unique identifier. + */ + String getAuthId(); + /** + * @return The user's avatar URL. Some services require post-processing to get the actual value for it + * (the value returned is a template and you need to remplace variables). + */ + String getAvatarUrl(); + /** + * @return The user's email. + */ + String getEmail(); + /** + * @return The user's full name (first and last names). + */ + String getFullName(); + /** + * @return The login name for the user. Human-readable unique name. AKA username. + */ + String getLoginName(); + /** + * @return The authentication provider unique name, e.g. `github`, `eclipse`, etc. + */ + String getProviderId(); + /** + * @return The authentication provider URL. + */ + String getProviderUrl(); +} diff --git a/server/src/main/java/org/eclipse/openvsx/security/AuthUserFactory.java b/server/src/main/java/org/eclipse/openvsx/security/AuthUserFactory.java new file mode 100644 index 000000000..2ea73db53 --- /dev/null +++ b/server/src/main/java/org/eclipse/openvsx/security/AuthUserFactory.java @@ -0,0 +1,20 @@ +package org.eclipse.openvsx.security; + +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.stereotype.Service; + +@Service +public class AuthUserFactory { + + public AuthUser createAuthUser(String providerId, OAuth2User oauth2User) { + return new DefaultAuthUser( + oauth2User.getName(), + oauth2User.getAttribute("avatar_url"), + oauth2User.getAttribute("email"), + oauth2User.getAttribute("name"), + oauth2User.getAttribute("login"), + providerId, + oauth2User.getAttribute("html_url") + ); + } +} diff --git a/server/src/main/java/org/eclipse/openvsx/security/DefaultAuthUser.java b/server/src/main/java/org/eclipse/openvsx/security/DefaultAuthUser.java new file mode 100644 index 000000000..27d85d2cd --- /dev/null +++ b/server/src/main/java/org/eclipse/openvsx/security/DefaultAuthUser.java @@ -0,0 +1,74 @@ +/******************************************************************************** + * Copyright (c) 2023 Ericsson and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ +package org.eclipse.openvsx.security; + +public class DefaultAuthUser implements AuthUser { + + final String authId; + final String avatarUrl; + final String email; + final String fullName; + final String loginName; + final String providerId; + final String providerUrl; + + public DefaultAuthUser( + final String authId, + final String avatarUrl, + final String email, + final String fullName, + final String loginName, + final String providerId, + final String providerUrl + ) { + this.authId = authId; + this.avatarUrl = avatarUrl; + this.email = email; + this.fullName = fullName; + this.loginName = loginName; + this.providerId = providerId; + this.providerUrl = providerUrl; + } + + @Override + public String getAuthId() { + return authId; + } + + @Override + public String getAvatarUrl() { + return avatarUrl; + } + + @Override + public String getEmail() { + return email; + } + + @Override + public String getFullName() { + return fullName; + } + + @Override + public String getLoginName() { + return loginName; + } + + @Override + public String getProviderId() { + return providerId; + } + + @Override + public String getProviderUrl() { + return providerUrl; + } +} diff --git a/server/src/main/java/org/eclipse/openvsx/security/OAuth2UserServices.java b/server/src/main/java/org/eclipse/openvsx/security/OAuth2UserServices.java index f749e381f..137525166 100644 --- a/server/src/main/java/org/eclipse/openvsx/security/OAuth2UserServices.java +++ b/server/src/main/java/org/eclipse/openvsx/security/OAuth2UserServices.java @@ -9,7 +9,16 @@ ********************************************************************************/ package org.eclipse.openvsx.security; -import jakarta.persistence.EntityManager; +import static java.util.Collections.emptyList; +import static org.eclipse.openvsx.security.CodedAuthException.ECLIPSE_MISMATCH_GITHUB_ID; +import static org.eclipse.openvsx.security.CodedAuthException.ECLIPSE_MISSING_GITHUB_ID; +import static org.eclipse.openvsx.security.CodedAuthException.INVALID_GITHUB_USER; +import static org.eclipse.openvsx.security.CodedAuthException.NEED_MAIN_LOGIN; +import static org.eclipse.openvsx.security.CodedAuthException.UNSUPPORTED_REGISTRATION; +import static org.springframework.security.core.authority.AuthorityUtils.createAuthorityList; + +import java.util.Collection; + import org.apache.commons.lang3.StringUtils; import org.eclipse.openvsx.UserService; import org.eclipse.openvsx.eclipse.EclipseService; @@ -20,22 +29,17 @@ import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; -import java.util.Collection; -import java.util.Collections; - -import static org.eclipse.openvsx.security.CodedAuthException.*; +import jakarta.persistence.EntityManager; @Service public class OAuth2UserServices { @@ -45,43 +49,27 @@ public class OAuth2UserServices { private final RepositoryService repositories; private final EntityManager entityManager; private final EclipseService eclipse; + private final AuthUserFactory authUserFactory; private final DefaultOAuth2UserService delegate = new DefaultOAuth2UserService(); - private final OAuth2UserService oauth2; - private final OAuth2UserService oidc; public OAuth2UserServices( UserService users, TokenService tokens, RepositoryService repositories, EntityManager entityManager, - EclipseService eclipse + EclipseService eclipse, + AuthUserFactory authUserFactory ) { this.users = users; this.tokens = tokens; this.repositories = repositories; this.entityManager = entityManager; this.eclipse = eclipse; - this.oauth2 = new OAuth2UserService() { - @Override - public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { - return OAuth2UserServices.this.loadUser(userRequest); - } - }; - this.oidc = new OAuth2UserService() { - @Override - public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException { - return OAuth2UserServices.this.loadUser(userRequest); - } - }; + this.authUserFactory = authUserFactory; } - public OAuth2UserService getOauth2() { - return oauth2; - } - - public OAuth2UserService getOidc() { - return oidc; - } + public OAuth2UserService getOauth2() { return this::loadUser; } + public OAuth2UserService getOidc() { return this::loadUser; } @EventListener public void authenticationSucceeded(AuthenticationSuccessEvent event) { @@ -100,27 +88,25 @@ public void authenticationSucceeded(AuthenticationSuccessEvent event) { public IdPrincipal loadUser(OAuth2UserRequest userRequest) { var registrationId = userRequest.getClientRegistration().getRegistrationId(); - switch (registrationId) { - case "github": - return loadGitHubUser(userRequest); - case "eclipse": - return loadEclipseUser(userRequest); - default: - throw new CodedAuthException("Unsupported registration: " + registrationId, UNSUPPORTED_REGISTRATION); - } + return switch (registrationId) { + case "github" -> loadGitHubUser(userRequest); + case "eclipse" -> loadEclipseUser(userRequest); + default -> throw new CodedAuthException("Unsupported registration: " + registrationId, UNSUPPORTED_REGISTRATION); + }; } private IdPrincipal loadGitHubUser(OAuth2UserRequest userRequest) { - var authUser = delegate.loadUser(userRequest); - String loginName = authUser.getAttribute("login"); + var authUser = authUserFactory.createAuthUser("github", delegate.loadUser(userRequest)); + String loginName = authUser.getLoginName(); if (StringUtils.isEmpty(loginName)) throw new CodedAuthException("Invalid login: missing 'login' field.", INVALID_GITHUB_USER); - var userData = repositories.findUserByLoginName("github", loginName); - if (userData == null) + var userData = repositories.findUserByLoginName(authUser.getProviderId(), loginName); + if (userData == null) { userData = users.registerNewUser(authUser); - else + } else { users.updateExistingUser(userData, authUser); - return new IdPrincipal(userData.getId(), authUser.getName(), getAuthorities(userData)); + } + return new IdPrincipal(userData.getId(), authUser.getAuthId(), getAuthorities(userData)); } private IdPrincipal loadEclipseUser(OAuth2UserRequest userRequest) { @@ -155,15 +141,10 @@ private IdPrincipal loadEclipseUser(OAuth2UserRequest userRequest) { } private Collection getAuthorities(UserData userData) { - var role = userData.getRole(); - switch (role != null ? role : "") { - case UserData.ROLE_ADMIN: - return AuthorityUtils.createAuthorityList("ROLE_ADMIN"); - case UserData.ROLE_PRIVILEGED: - return AuthorityUtils.createAuthorityList("ROLE_PRIVILEGED"); - default: - return Collections.emptyList(); - } + return switch (userData.getRole()) { + case UserData.ROLE_ADMIN -> createAuthorityList("ROLE_ADMIN"); + case UserData.ROLE_PRIVILEGED -> createAuthorityList("ROLE_PRIVILEGED"); + default -> emptyList(); + }; } - -} \ No newline at end of file +} diff --git a/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java b/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java index d39abcdbd..f6f04c806 100644 --- a/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java @@ -29,6 +29,7 @@ import org.eclipse.openvsx.search.ExtensionSearch; import org.eclipse.openvsx.search.ISearchService; import org.eclipse.openvsx.search.SearchUtilService; +import org.eclipse.openvsx.security.AuthUserFactory; import org.eclipse.openvsx.security.OAuth2UserServices; import org.eclipse.openvsx.security.SecurityConfig; import org.eclipse.openvsx.security.TokenService; @@ -2399,9 +2400,10 @@ OAuth2UserServices oauth2UserServices( TokenService tokens, RepositoryService repositories, EntityManager entityManager, - EclipseService eclipse + EclipseService eclipse, + AuthUserFactory authUserFactory ) { - return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse); + return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse, authUserFactory); } @Bean @@ -2525,5 +2527,10 @@ PublishExtensionVersionHandler publishExtensionVersionHandler( extensionControl ); } + + @Bean + AuthUserFactory authUserFactory() { + return new AuthUserFactory(); + } } -} \ No newline at end of file +} diff --git a/server/src/test/java/org/eclipse/openvsx/UserAPITest.java b/server/src/test/java/org/eclipse/openvsx/UserAPITest.java index 2d96665fc..c6590ee48 100644 --- a/server/src/test/java/org/eclipse/openvsx/UserAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/UserAPITest.java @@ -38,6 +38,7 @@ import org.eclipse.openvsx.json.ResultJson; import org.eclipse.openvsx.json.UserJson; import org.eclipse.openvsx.repositories.RepositoryService; +import org.eclipse.openvsx.security.AuthUserFactory; import org.eclipse.openvsx.security.OAuth2UserServices; import org.eclipse.openvsx.security.SecurityConfig; import org.eclipse.openvsx.security.TokenService; @@ -563,9 +564,10 @@ OAuth2UserServices oauth2UserServices( TokenService tokens, RepositoryService repositories, EntityManager entityManager, - EclipseService eclipse + EclipseService eclipse, + AuthUserFactory authUserFactory ) { - return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse); + return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse, authUserFactory); } @Bean @@ -581,6 +583,10 @@ TokenService tokenService( LatestExtensionVersionCacheKeyGenerator latestExtensionVersionCacheKeyGenerator() { return new LatestExtensionVersionCacheKeyGenerator(); } + + @Bean + AuthUserFactory authUserFactory() { + return new AuthUserFactory(); + } } - } \ No newline at end of file diff --git a/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java b/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java index 24172cee1..e8e32c813 100644 --- a/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java @@ -27,6 +27,7 @@ import org.eclipse.openvsx.search.ExtensionSearch; import org.eclipse.openvsx.search.ISearchService; import org.eclipse.openvsx.search.SearchUtilService; +import org.eclipse.openvsx.security.AuthUserFactory; import org.eclipse.openvsx.security.OAuth2UserServices; import org.eclipse.openvsx.security.SecurityConfig; import org.eclipse.openvsx.security.TokenService; @@ -877,9 +878,10 @@ OAuth2UserServices oauth2UserServices( TokenService tokens, RepositoryService repositories, EntityManager entityManager, - EclipseService eclipse + EclipseService eclipse, + AuthUserFactory authUserFactory ) { - return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse); + return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse, authUserFactory); } @Bean @@ -966,6 +968,10 @@ LatestExtensionVersionCacheKeyGenerator latestExtensionVersionCacheKeyGenerator( FilesCacheKeyGenerator filesCacheKeyGenerator() { return new FilesCacheKeyGenerator(); } - } + @Bean + AuthUserFactory authUserFactory() { + return new AuthUserFactory(); + } + } } diff --git a/server/src/test/java/org/eclipse/openvsx/admin/AdminAPITest.java b/server/src/test/java/org/eclipse/openvsx/admin/AdminAPITest.java index b9a65926c..3a3da1f39 100644 --- a/server/src/test/java/org/eclipse/openvsx/admin/AdminAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/admin/AdminAPITest.java @@ -9,20 +9,57 @@ ********************************************************************************/ package org.eclipse.openvsx.admin; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import org.eclipse.openvsx.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.eclipse.openvsx.ExtensionService; +import org.eclipse.openvsx.ExtensionValidator; +import org.eclipse.openvsx.LocalRegistryService; +import org.eclipse.openvsx.MockTransactionTemplate; +import org.eclipse.openvsx.UpstreamRegistryService; +import org.eclipse.openvsx.UserService; import org.eclipse.openvsx.adapter.VSCodeIdService; import org.eclipse.openvsx.cache.CacheService; import org.eclipse.openvsx.cache.LatestExtensionVersionCacheKeyGenerator; import org.eclipse.openvsx.eclipse.EclipseService; -import org.eclipse.openvsx.entities.*; -import org.eclipse.openvsx.json.*; +import org.eclipse.openvsx.entities.AdminStatistics; +import org.eclipse.openvsx.entities.Extension; +import org.eclipse.openvsx.entities.ExtensionVersion; +import org.eclipse.openvsx.entities.Namespace; +import org.eclipse.openvsx.entities.NamespaceMembership; +import org.eclipse.openvsx.entities.PersonalAccessToken; +import org.eclipse.openvsx.entities.UserData; +import org.eclipse.openvsx.json.AdminStatisticsJson; +import org.eclipse.openvsx.json.ChangeNamespaceJson; +import org.eclipse.openvsx.json.ExtensionJson; +import org.eclipse.openvsx.json.NamespaceJson; +import org.eclipse.openvsx.json.NamespaceMembershipJson; +import org.eclipse.openvsx.json.NamespaceMembershipListJson; +import org.eclipse.openvsx.json.ResultJson; +import org.eclipse.openvsx.json.UserJson; +import org.eclipse.openvsx.json.UserPublishInfoJson; import org.eclipse.openvsx.publish.ExtensionVersionIntegrityService; import org.eclipse.openvsx.publish.PublishExtensionVersionHandler; import org.eclipse.openvsx.repositories.RepositoryService; import org.eclipse.openvsx.search.SearchUtilService; +import org.eclipse.openvsx.security.AuthUserFactory; import org.eclipse.openvsx.security.OAuth2UserServices; import org.eclipse.openvsx.security.SecurityConfig; import org.eclipse.openvsx.security.TokenService; @@ -48,20 +85,11 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.transaction.support.TransactionTemplate; -import jakarta.persistence.EntityManager; -import java.time.LocalDateTime; -import java.util.*; -import java.util.function.Consumer; -import java.util.stream.Collectors; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyCollection; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import jakarta.persistence.EntityManager; @WebMvcTest(AdminAPI.class) @AutoConfigureWebClient @@ -1197,9 +1225,10 @@ OAuth2UserServices oauth2UserServices( TokenService tokens, RepositoryService repositories, EntityManager entityManager, - EclipseService eclipse + EclipseService eclipse, + AuthUserFactory authUserFactory ) { - return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse); + return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse, authUserFactory); } @Bean @@ -1324,5 +1353,10 @@ VersionService versionService() { LatestExtensionVersionCacheKeyGenerator latestExtensionVersionCacheKeyGenerator() { return new LatestExtensionVersionCacheKeyGenerator(); } + + @Bean + AuthUserFactory authUserFactory() { + return new AuthUserFactory(); + } } } \ No newline at end of file diff --git a/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java b/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java index 9beb6ad4e..3e787e14c 100644 --- a/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java +++ b/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java @@ -9,16 +9,36 @@ * ****************************************************************************** */ package org.eclipse.openvsx.cache; -import jakarta.persistence.EntityManager; -import jakarta.transaction.Transactional; +import static org.eclipse.openvsx.cache.CacheService.CACHE_EXTENSION_JSON; +import static org.eclipse.openvsx.entities.FileResource.DOWNLOAD; +import static org.eclipse.openvsx.entities.FileResource.STORAGE_LOCAL; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + import org.eclipse.openvsx.ExtensionService; import org.eclipse.openvsx.LocalRegistryService; import org.eclipse.openvsx.UserService; import org.eclipse.openvsx.admin.AdminService; -import org.eclipse.openvsx.entities.*; +import org.eclipse.openvsx.entities.Extension; +import org.eclipse.openvsx.entities.ExtensionReview; +import org.eclipse.openvsx.entities.ExtensionVersion; +import org.eclipse.openvsx.entities.FileResource; +import org.eclipse.openvsx.entities.Namespace; +import org.eclipse.openvsx.entities.PersonalAccessToken; +import org.eclipse.openvsx.entities.UserData; import org.eclipse.openvsx.json.ExtensionJson; import org.eclipse.openvsx.json.ReviewJson; import org.eclipse.openvsx.repositories.RepositoryService; +import org.eclipse.openvsx.security.AuthUserFactory; import org.eclipse.openvsx.security.IdPrincipal; import org.eclipse.openvsx.util.TempFile; import org.eclipse.openvsx.util.TimeUtil; @@ -35,17 +55,8 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import java.io.IOException; -import java.nio.file.Files; -import java.time.LocalDateTime; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; - -import static org.eclipse.openvsx.cache.CacheService.CACHE_EXTENSION_JSON; -import static org.eclipse.openvsx.entities.FileResource.DOWNLOAD; -import static org.eclipse.openvsx.entities.FileResource.STORAGE_LOCAL; -import static org.junit.jupiter.api.Assertions.*; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles("test") @@ -72,6 +83,9 @@ class CacheServiceTest { @Autowired RepositoryService repositories; + @Autowired + AuthUserFactory authUserFactory; + @Test @Transactional void testGetExtension() throws IOException { @@ -118,7 +132,8 @@ void testUpdateExistingUser() throws IOException { var user = extVersion.getPublishedWith().getUser(); var oauthUser = new DefaultOAuth2User(authorities, attributes, "name"); - users.updateExistingUser(user, oauthUser); + var authUser = authUserFactory.createAuthUser(authority, oauthUser); + users.updateExistingUser(user, authUser); assertNull(cache.getCache(CACHE_EXTENSION_JSON).get(cacheKey, ExtensionJson.class)); var json = registry.getExtension(namespace.getName(), extension.getName(), extVersion.getTargetPlatform(), extVersion.getVersion()); diff --git a/server/src/test/java/org/eclipse/openvsx/web/SitemapControllerTest.java b/server/src/test/java/org/eclipse/openvsx/web/SitemapControllerTest.java index 9c1a107dd..e250fccad 100644 --- a/server/src/test/java/org/eclipse/openvsx/web/SitemapControllerTest.java +++ b/server/src/test/java/org/eclipse/openvsx/web/SitemapControllerTest.java @@ -14,6 +14,7 @@ import org.eclipse.openvsx.UserService; import org.eclipse.openvsx.eclipse.EclipseService; import org.eclipse.openvsx.repositories.RepositoryService; +import org.eclipse.openvsx.security.AuthUserFactory; import org.eclipse.openvsx.security.OAuth2UserServices; import org.eclipse.openvsx.security.SecurityConfig; import org.eclipse.openvsx.security.TokenService; @@ -75,14 +76,20 @@ OAuth2UserServices oauth2UserServices( TokenService tokens, RepositoryService repositories, EntityManager entityManager, - EclipseService eclipse + EclipseService eclipse, + AuthUserFactory authUserFactory ) { - return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse); + return new OAuth2UserServices(users, tokens, repositories, entityManager, eclipse, authUserFactory); } @Bean SitemapService sitemapService(RepositoryService repositories) { return new SitemapService(repositories); } + + @Bean + AuthUserFactory authUserFactory() { + return new AuthUserFactory(); + } } }