diff --git a/server/src/main/java/org/eclipse/openvsx/OVSXConfig.java b/server/src/main/java/org/eclipse/openvsx/OVSXConfig.java index e3bb7eab..fc392739 100644 --- a/server/src/main/java/org/eclipse/openvsx/OVSXConfig.java +++ b/server/src/main/java/org/eclipse/openvsx/OVSXConfig.java @@ -58,8 +58,6 @@ public void setAttributeNames(Map attributeNames) { public static class AttributeNames { - public static final AttributeNames EMPTY = new AttributeNames(); - private String avatarUrl; private String email; private String fullName; diff --git a/server/src/main/java/org/eclipse/openvsx/security/AuthUserFactory.java b/server/src/main/java/org/eclipse/openvsx/security/AuthUserFactory.java index 061bfc67..ada4fb1e 100644 --- a/server/src/main/java/org/eclipse/openvsx/security/AuthUserFactory.java +++ b/server/src/main/java/org/eclipse/openvsx/security/AuthUserFactory.java @@ -1,58 +1,69 @@ package org.eclipse.openvsx.security; -import java.util.NoSuchElementException; +import java.util.HashMap; +import java.util.Map; import org.eclipse.openvsx.OVSXConfig; import org.eclipse.openvsx.OVSXConfig.AuthConfig.AttributeNames; import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; -@Service +@Component public class AuthUserFactory { - private static final AttributeNames GITHUB_ATTRIBUTES = new AttributeNames(); + protected static final Map DEFAULTS = new HashMap<>(); + + public static class MissingProvider extends Exception { + public MissingProvider(String provider) { super("Missing configuration: ovsx.auth.attribute-names." + provider); } + } static { - GITHUB_ATTRIBUTES.setAvatarUrl("avatar_url"); - GITHUB_ATTRIBUTES.setEmail("email"); - GITHUB_ATTRIBUTES.setFullName("name"); - GITHUB_ATTRIBUTES.setLoginName("login"); - GITHUB_ATTRIBUTES.setProviderUrl("html_url"); + var github = new AttributeNames(); + github.setAvatarUrl("avatar_url"); + github.setEmail("email"); + github.setFullName("name"); + github.setLoginName("login"); + github.setProviderUrl("html_url"); + DEFAULTS.put("github", github); } - private final OVSXConfig config; + protected final OVSXConfig config; - public AuthUserFactory( - OVSXConfig config - ) { + public AuthUserFactory(OVSXConfig config) { this.config = config; } - public AuthUser createAuthUser(String providerId, OAuth2User oauth2User) { - var attributeNames = getAttributeNames(providerId); + /** + * @param provider The configured OAuth2 provider from which the user object came from. + * @param user The OAuth2 user object to get attributes from. + * @return An {@link AuthUser} instance with attributes set according to the current configuration. + * @throws MissingProvider if an attribute name mapping is missing for the given provider. + */ + public AuthUser createAuthUser(String provider, OAuth2User user) throws MissingProvider { + var attr = getAttributeNames(provider); return new DefaultAuthUser( - oauth2User.getName(), - oauth2User.getAttribute(attributeNames.getAvatarUrl()), - oauth2User.getAttribute(attributeNames.getEmail()), - oauth2User.getAttribute(attributeNames.getFullName()), - oauth2User.getAttribute(attributeNames.getLoginName()), - providerId, - oauth2User.getAttribute(attributeNames.getProviderUrl()) + user.getName(), + getAttribute(user, attr.getAvatarUrl()), + getAttribute(user, attr.getEmail()), + getAttribute(user, attr.getFullName()), + getAttribute(user, attr.getLoginName()), + provider, + getAttribute(user, attr.getProviderUrl()) ); } + protected T getAttribute(OAuth2User oauth2User, String attribute) { + return attribute == null ? null : oauth2User.getAttribute(attribute); + } + /** * @param provider The provider to get the attribute mappings for. * @return The relevant attribute mappings. */ - private AttributeNames getAttributeNames(String provider) { + protected AttributeNames getAttributeNames(String provider) throws MissingProvider { var attributeNames = config.getAuth().getAttributeNames().get(provider); - if (attributeNames == null) { - return switch (provider) { - case "github" -> GITHUB_ATTRIBUTES; - default -> throw new NoSuchElementException("No attributes found for provider: " + provider); - }; - } + if (attributeNames == null) attributeNames = DEFAULTS.get(provider); + if (attributeNames == null) throw new MissingProvider(provider); return attributeNames; } } diff --git a/server/src/main/java/org/eclipse/openvsx/security/DefaultAuthUser.java b/server/src/main/java/org/eclipse/openvsx/security/DefaultAuthUser.java index 27d85d2c..6b6cc837 100644 --- a/server/src/main/java/org/eclipse/openvsx/security/DefaultAuthUser.java +++ b/server/src/main/java/org/eclipse/openvsx/security/DefaultAuthUser.java @@ -11,13 +11,13 @@ 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; + protected final String authId; + protected final String avatarUrl; + protected final String email; + protected final String fullName; + protected final String loginName; + protected final String providerId; + protected final String providerUrl; public DefaultAuthUser( final String authId, 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 28e7c05d..5222513a 100644 --- a/server/src/main/java/org/eclipse/openvsx/security/OAuth2UserServices.java +++ b/server/src/main/java/org/eclipse/openvsx/security/OAuth2UserServices.java @@ -21,13 +21,13 @@ import static org.springframework.security.core.authority.AuthorityUtils.createAuthorityList; import java.util.Collection; -import java.util.NoSuchElementException; import org.apache.commons.lang3.StringUtils; import org.eclipse.openvsx.UserService; import org.eclipse.openvsx.eclipse.EclipseService; import org.eclipse.openvsx.entities.UserData; import org.eclipse.openvsx.repositories.RepositoryService; +import org.eclipse.openvsx.security.AuthUserFactory.MissingProvider; import org.eclipse.openvsx.util.ErrorResultException; import org.springframework.context.event.EventListener; import org.springframework.security.authentication.AuthenticationServiceException; @@ -94,14 +94,10 @@ public void authenticationSucceeded(AuthenticationSuccessEvent event) { } public IdPrincipal loadUser(OAuth2UserRequest userRequest) { - var registrationId = userRequest.getClientRegistration().getRegistrationId(); - if (registrationId == "eclipse") { - return loadEclipseUser(userRequest); - } else try { - return loadGenericUser(userRequest); - } catch (NoSuchElementException e) { - throw new CodedAuthException("Unsupported registration: " + registrationId, UNSUPPORTED_REGISTRATION, e); - } + return switch (userRequest.getClientRegistration().getRegistrationId()) { + case "eclipse" -> loadEclipseUser(userRequest); + default -> loadGenericUser(userRequest); + }; } private OAuth2User springLoadUser(OAuth2UserRequest userRequest) { @@ -110,9 +106,16 @@ private OAuth2User springLoadUser(OAuth2UserRequest userRequest) { : springOAuth2UserService.loadUser(userRequest); } + private AuthUser loadAuthUser(OAuth2UserRequest userRequest) { + try { + return authUserFactory.createAuthUser(userRequest.getClientRegistration().getRegistrationId(), springLoadUser(userRequest)); + } catch (MissingProvider e) { + throw new CodedAuthException(e.getMessage(), UNSUPPORTED_REGISTRATION); + } + } + private IdPrincipal loadGenericUser(OAuth2UserRequest userRequest) { - var registrationId = userRequest.getClientRegistration().getRegistrationId(); - var authUser = authUserFactory.createAuthUser(registrationId, springLoadUser(userRequest)); + var authUser = loadAuthUser(userRequest); if (StringUtils.isEmpty(authUser.getLoginName())) { throw new CodedAuthException("Invalid login: missing 'login' field.", INVALID_USER); }