From 3a39b4fa08b15912c928af35fb7b77cd4b85ab64 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Mon, 23 Jul 2018 09:56:42 +0200 Subject: [PATCH] SONAR-11036 add WS api/alm_integration/list_repositories --- .../authentication/SafeModeUserSession.java | 10 +++ .../server/user/AbstractUserSession.java | 46 +++++++++++++ .../org/sonar/server/user/DoPrivileged.java | 10 +++ .../sonar/server/user/ServerUserSession.java | 16 ++++- .../server/user/ThreadLocalUserSession.java | 11 +++ .../org/sonar/server/user/UserSession.java | 67 +++++++++++++++++++ .../tester/AnonymousMockUserSession.java | 11 +++ .../sonar/server/tester/MockUserSession.java | 35 +++++++++- .../sonar/server/tester/UserSessionRule.java | 21 ++++++ .../server/user/TestUserSessionFactory.java | 10 +++ 10 files changed, 232 insertions(+), 5 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java index 3660f91d871..b4bc28aed76 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java @@ -81,6 +81,16 @@ public class SafeModeUserSession extends AbstractUserSession { return Collections.emptyList(); } + @Override + public Optional getIdentityProvider() { + return Optional.empty(); + } + + @Override + public Optional getExternalIdentity() { + return Optional.empty(); + } + @Override public boolean isLoggedIn() { return false; diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java index 1bc20879f51..2a92147ee59 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java @@ -23,11 +23,14 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Optional; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import org.sonar.core.permission.ProjectPermissions; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.permission.OrganizationPermission; +import org.sonar.db.user.UserDto; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; @@ -38,6 +41,49 @@ public abstract class AbstractUserSession implements UserSession { private static final String INSUFFICIENT_PRIVILEGES_MESSAGE = "Insufficient privileges"; private static final ForbiddenException INSUFFICIENT_PRIVILEGES_EXCEPTION = new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE); private static final String AUTHENTICATION_IS_REQUIRED_MESSAGE = "Authentication is required"; + + protected static Identity computeIdentity(UserDto userDto) { + switch (userDto.getExternalIdentityProvider()) { + case "github": + return new Identity(IdentityProvider.GITHUB, externalIdentityOf(userDto)); + case "bitbucket": + return new Identity(IdentityProvider.BITBUCKET, externalIdentityOf(userDto)); + case "sonarqube": + return new Identity(IdentityProvider.SONARQUBE, null); + default: + return new Identity(IdentityProvider.OTHER, externalIdentityOf(userDto)); + } + } + + @CheckForNull + private static ExternalIdentity externalIdentityOf(UserDto userDto) { + String externalId = userDto.getExternalId(); + String externalLogin = userDto.getExternalLogin(); + if (externalId == null && externalLogin == null) { + return null; + } + return new ExternalIdentity(externalId == null ? externalLogin : externalId, externalLogin); + } + + protected static final class Identity { + private final IdentityProvider identityProvider; + private final ExternalIdentity externalIdentity; + + private Identity(IdentityProvider identityProvider, @Nullable ExternalIdentity externalIdentity) { + this.identityProvider = identityProvider; + this.externalIdentity = externalIdentity; + } + + public IdentityProvider getIdentityProvider() { + return identityProvider; + } + + @CheckForNull + public ExternalIdentity getExternalIdentity() { + return externalIdentity; + } + } + @Override public final boolean hasPermission(OrganizationPermission permission, OrganizationDto organization) { return hasPermission(permission, organization.getUuid()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java b/server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java index 434d3731e85..e86febc71fb 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java @@ -102,6 +102,16 @@ public final class DoPrivileged { return true; } + @Override + public Optional getIdentityProvider() { + return Optional.empty(); + } + + @Override + public Optional getExternalIdentity() { + return Optional.empty(); + } + @Override protected boolean hasPermissionImpl(OrganizationPermission permission, String organizationUuid) { return true; diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java index e366d1713da..8bf2423859b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java @@ -46,6 +46,8 @@ import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.OrganizationFlags; import static java.util.Objects.requireNonNull; +import static java.util.Optional.of; +import static java.util.Optional.ofNullable; import static org.apache.commons.lang.StringUtils.defaultIfEmpty; /** @@ -120,6 +122,16 @@ public class ServerUserSession extends AbstractUserSession { return userDto != null && userDto.isRoot(); } + @Override + public Optional getIdentityProvider() { + return ofNullable(userDto).map(d -> computeIdentity(d).getIdentityProvider()); + } + + @Override + public Optional getExternalIdentity() { + return ofNullable(userDto).map(d -> computeIdentity(d).getExternalIdentity()); + } + @Override protected boolean hasPermissionImpl(OrganizationPermission permission, String organizationUuid) { if (permissionsByOrganizationUuid == null) { @@ -147,7 +159,7 @@ public class ServerUserSession extends AbstractUserSession { protected Optional componentUuidToProjectUuid(String componentUuid) { String projectUuid = projectUuidByComponentUuid.get(componentUuid); if (projectUuid != null) { - return Optional.of(projectUuid); + return of(projectUuid); } try (DbSession dbSession = dbClient.openSession(false)) { com.google.common.base.Optional component = dbClient.componentDao().selectByUuid(dbSession, componentUuid); @@ -158,7 +170,7 @@ public class ServerUserSession extends AbstractUserSession { // checked on the project (represented by its main branch) projectUuid = defaultIfEmpty(component.get().getMainBranchProjectUuid(), component.get().projectUuid()); projectUuidByComponentUuid.put(componentUuid, projectUuid); - return Optional.of(projectUuid); + return of(projectUuid); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java index 8b7fb1b6ee2..9b4e09ac4a2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java @@ -21,6 +21,7 @@ package org.sonar.server.user; import java.util.Collection; import java.util.List; +import java.util.Optional; import javax.annotation.CheckForNull; import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; @@ -84,6 +85,16 @@ public class ThreadLocalUserSession implements UserSession { return get().getGroups(); } + @Override + public Optional getIdentityProvider() { + return get().getIdentityProvider(); + } + + @Override + public Optional getExternalIdentity() { + return get().getExternalIdentity(); + } + @Override public boolean isLoggedIn() { return get().isLoggedIn(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java index 645254afcf3..56a41cc39cb 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java @@ -21,12 +21,17 @@ package org.sonar.server.user; import java.util.Collection; import java.util.List; +import java.util.Objects; +import java.util.Optional; import javax.annotation.CheckForNull; +import javax.annotation.concurrent.Immutable; import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.permission.OrganizationPermission; import org.sonar.db.user.GroupDto; +import static java.util.Objects.requireNonNull; + public interface UserSession { /** @@ -63,6 +68,68 @@ public interface UserSession { */ Collection getGroups(); + /** + * This enum supports by name only the few providers for which specific code exists. + */ + enum IdentityProvider { + SONARQUBE, GITHUB, BITBUCKET, OTHER + } + + /** + * @return empty if user is anonymous + */ + Optional getIdentityProvider(); + + @Immutable + final class ExternalIdentity { + private final String id; + private final String login; + + public ExternalIdentity(String id, String login) { + this.id = requireNonNull(id, "id can't be null"); + this.login = requireNonNull(login, "login can't be null"); + } + + public String getId() { + return id; + } + + public String getLogin() { + return login; + } + + @Override + public String toString() { + return "ExternalIdentity{" + + "id='" + id + '\'' + + ", login='" + login + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ExternalIdentity that = (ExternalIdentity) o; + return Objects.equals(id, that.id) && + Objects.equals(login, that.login); + } + + @Override + public int hashCode() { + return Objects.hash(id, login); + } + } + + /** + * @return empty if {@link #getIdentityProvider()} returns empty or {@link IdentityProvider#SONARQUBE} + */ + Optional getExternalIdentity(); + /** * Whether the user is logged-in or anonymous. */ diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/AnonymousMockUserSession.java b/server/sonar-server/src/test/java/org/sonar/server/tester/AnonymousMockUserSession.java index e080df152cc..c7ec3312f6f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/tester/AnonymousMockUserSession.java +++ b/server/sonar-server/src/test/java/org/sonar/server/tester/AnonymousMockUserSession.java @@ -21,6 +21,7 @@ package org.sonar.server.tester; import java.util.Collection; import java.util.Collections; +import java.util.Optional; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.user.GroupDto; @@ -64,6 +65,16 @@ public class AnonymousMockUserSession extends AbstractMockUserSession getIdentityProvider() { + return Optional.empty(); + } + + @Override + public Optional getExternalIdentity() { + return Optional.empty(); + } + @Override public boolean hasMembershipImpl(OrganizationDto organizationDto) { return false; diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/MockUserSession.java b/server/sonar-server/src/test/java/org/sonar/server/tester/MockUserSession.java index 91afb2ea4dd..851fdb97a32 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/tester/MockUserSession.java +++ b/server/sonar-server/src/test/java/org/sonar/server/tester/MockUserSession.java @@ -22,12 +22,15 @@ package org.sonar.server.tester; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Objects; +import java.util.Optional; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; +import org.sonar.server.user.AbstractUserSession; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Arrays.asList; +import static java.util.Objects.requireNonNull; +import static org.sonar.server.user.UserSession.IdentityProvider.SONARQUBE; public class MockUserSession extends AbstractMockUserSession { private final String login; @@ -36,6 +39,8 @@ public class MockUserSession extends AbstractMockUserSession { private Integer userId; private String name; private List groups = new ArrayList<>(); + private IdentityProvider identityProvider; + private ExternalIdentity externalIdentity; public MockUserSession(String login) { super(MockUserSession.class); @@ -44,6 +49,7 @@ public class MockUserSession extends AbstractMockUserSession { setUuid(login + "uuid"); setUserId(login.hashCode()); setName(login + " name"); + setInternalIdentity(); } public MockUserSession(UserDto userDto) { @@ -53,6 +59,9 @@ public class MockUserSession extends AbstractMockUserSession { setUuid(userDto.getUuid()); setUserId(userDto.getId()); setName(userDto.getName()); + AbstractUserSession.Identity identity = computeIdentity(userDto); + this.identityProvider = identity.getIdentityProvider(); + this.externalIdentity = identity.getExternalIdentity(); } @Override @@ -80,7 +89,7 @@ public class MockUserSession extends AbstractMockUserSession { } public MockUserSession setUuid(String uuid) { - this.uuid = Objects.requireNonNull(uuid); + this.uuid = requireNonNull(uuid); return this; } @@ -90,7 +99,7 @@ public class MockUserSession extends AbstractMockUserSession { } public MockUserSession setName(String s) { - this.name = Objects.requireNonNull(s); + this.name = requireNonNull(s); return this; } @@ -114,4 +123,24 @@ public class MockUserSession extends AbstractMockUserSession { return this; } + @Override + public Optional getIdentityProvider() { + return Optional.ofNullable(identityProvider); + } + + public void setExternalIdentity(IdentityProvider identityProvider, ExternalIdentity externalIdentity) { + checkArgument(identityProvider != SONARQUBE); + this.identityProvider = identityProvider; + this.externalIdentity = requireNonNull(externalIdentity); + } + + public void setInternalIdentity() { + this.identityProvider = SONARQUBE; + this.externalIdentity = null; + } + + @Override + public Optional getExternalIdentity() { + return Optional.ofNullable(externalIdentity); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java b/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java index a3df41abed9..8a54d0e919d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java @@ -22,6 +22,7 @@ package org.sonar.server.tester; import com.google.common.base.Preconditions; import java.util.Collection; import java.util.List; +import java.util.Optional; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.junit.rules.TestRule; @@ -138,6 +139,16 @@ public class UserSessionRule implements TestRule, UserSession { return this; } + public UserSessionRule setExternalIdentity(IdentityProvider identityProvider, ExternalIdentity externalIdentity) { + ensureMockUserSession().setExternalIdentity(identityProvider, externalIdentity); + return this; + } + + public UserSessionRule setInternalIdentity() { + ensureMockUserSession().setInternalIdentity(); + return this; + } + @Override public Statement apply(Statement statement, Description description) { return this.statement(statement); @@ -268,6 +279,16 @@ public class UserSessionRule implements TestRule, UserSession { return currentUserSession.getGroups(); } + @Override + public Optional getIdentityProvider() { + return currentUserSession.getIdentityProvider(); + } + + @Override + public Optional getExternalIdentity() { + return currentUserSession.getExternalIdentity(); + } + @Override public boolean isLoggedIn() { return currentUserSession.isLoggedIn(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/TestUserSessionFactory.java b/server/sonar-server/src/test/java/org/sonar/server/user/TestUserSessionFactory.java index 7b055ab52a2..dd1cb95c440 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/TestUserSessionFactory.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/TestUserSessionFactory.java @@ -87,6 +87,16 @@ public class TestUserSessionFactory implements UserSessionFactory { throw notImplemented(); } + @Override + public Optional getIdentityProvider() { + throw notImplemented(); + } + + @Override + public Optional getExternalIdentity() { + throw notImplemented(); + } + @Override public boolean isLoggedIn() { return user != null; -- 2.39.5