From ab11abedca88572cc27e4d40a710b7a7aed986ea Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Fri, 29 Apr 2016 17:50:48 +0200 Subject: [PATCH] SONAR-7482 Return identity providers info in system info --- .../platform/monitoring/SonarQubeMonitor.java | 90 ++++++++++++++++--- .../monitoring/SonarQubeMonitorTest.java | 83 ++++++++++++++--- 2 files changed, 152 insertions(+), 21 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SonarQubeMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SonarQubeMonitor.java index ab513629d81..4671717239b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SonarQubeMonitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SonarQubeMonitor.java @@ -19,30 +19,45 @@ */ package org.sonar.server.platform.monitoring; +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.base.Predicate; import java.io.File; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; import org.sonar.api.security.SecurityRealm; +import org.sonar.api.server.authentication.IdentityProvider; import org.sonar.process.ProcessProperties; +import org.sonar.server.authentication.IdentityProviderRepository; import org.sonar.server.platform.ServerLogging; import org.sonar.server.user.SecurityRealmFactory; +import static com.google.common.collect.FluentIterable.from; + public class SonarQubeMonitor extends BaseMonitorMBean implements SonarQubeMonitorMBean { + private static final Joiner COMMA_JOINER = Joiner.on(", "); + static final String BRANDING_FILE_PATH = "web/WEB-INF/classes/com/sonarsource/branding"; private final Settings settings; private final SecurityRealmFactory securityRealmFactory; + private final IdentityProviderRepository identityProviderRepository; private final Server server; private final ServerLogging serverLogging; public SonarQubeMonitor(Settings settings, SecurityRealmFactory securityRealmFactory, - Server server, ServerLogging serverLogging) { + IdentityProviderRepository identityProviderRepository, Server server, ServerLogging serverLogging) { this.settings = settings; this.securityRealmFactory = securityRealmFactory; + this.identityProviderRepository = identityProviderRepository; this.server = server; this.serverLogging = serverLogging; } @@ -62,27 +77,40 @@ public class SonarQubeMonitor extends BaseMonitorMBean implements SonarQubeMonit return serverLogging.getRootLoggerLevel().name(); } - public String getExternalUserAuthentication() { + @CheckForNull + private String getExternalUserAuthentication() { SecurityRealm realm = securityRealmFactory.getRealm(); - if (realm == null) { - return ""; - } - return realm.getName(); + return realm == null ? null : realm.getName(); + } + + private List getEnabledIdentityProviders() { + return from(identityProviderRepository.getAllEnabledAndSorted()) + .filter(MatchEnabled.INSTANCE) + .transform(IdentityProviderToName.INSTANCE) + .toList(); + } + + private List getAllowsToSignUpEnabledIdentityProviders() { + return from(identityProviderRepository.getAllEnabledAndSorted()) + .filter(MatchEnabled.INSTANCE) + .filter(MatchAllowsToSignUp.INSTANCE) + .transform(IdentityProviderToName.INSTANCE) + .toList(); } - public boolean getAutomaticUserCreation() { + private boolean getAutomaticUserCreation() { return settings.getBoolean(CoreProperties.CORE_AUTHENTICATOR_CREATE_USERS); } - public boolean getAllowUsersToSignUp() { + private boolean getAllowUsersToSignUp() { return settings.getBoolean(CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_PROPERTY); } - public boolean getForceAuthentication() { + private boolean getForceAuthentication() { return settings.getBoolean(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY); } - public boolean isOfficialDistribution() { + private boolean isOfficialDistribution() { // the dependency com.sonarsource:sonarsource-branding is shaded to webapp // during release (see sonar-web pom) File brandingFile = new File(server.getRootDir(), BRANDING_FILE_PATH); @@ -100,7 +128,9 @@ public class SonarQubeMonitor extends BaseMonitorMBean implements SonarQubeMonit Map attributes = new LinkedHashMap<>(); attributes.put("Server ID", getServerId()); attributes.put("Version", getVersion()); - attributes.put("External User Authentication", getExternalUserAuthentication()); + addIfNotNull("External User Authentication", getExternalUserAuthentication(), attributes); + addIfNotEmpty("Accepted external identity providers", getEnabledIdentityProviders(), attributes); + addIfNotEmpty("External identity providers whose users are allowed to sign themselves up", getAllowsToSignUpEnabledIdentityProviders(), attributes); attributes.put("Automatic User Creation", getAutomaticUserCreation()); attributes.put("Allow Users to Sign Up", getAllowUsersToSignUp()); attributes.put("Force authentication", getForceAuthentication()); @@ -111,6 +141,44 @@ public class SonarQubeMonitor extends BaseMonitorMBean implements SonarQubeMonit attributes.put("Logs Dir", settings.getString(ProcessProperties.PATH_LOGS)); attributes.put("Logs Level", getLogLevel()); return attributes; + } + + private static void addIfNotNull(String key, @Nullable String value, Map attributes) { + if (value != null) { + attributes.put(key, value); + } + } + + private static void addIfNotEmpty(String key, List values, Map attributes) { + if (!values.isEmpty()) { + attributes.put(key, COMMA_JOINER.join(values)); + } + } + + private enum IdentityProviderToName implements Function { + INSTANCE; + + @Override + public String apply(@Nonnull IdentityProvider input) { + return input.getName(); + } + } + private enum MatchEnabled implements Predicate { + INSTANCE; + + @Override + public boolean apply(@Nonnull IdentityProvider input) { + return input.isEnabled(); + } + } + + private enum MatchAllowsToSignUp implements Predicate { + INSTANCE; + + @Override + public boolean apply(@Nonnull IdentityProvider input) { + return input.allowsUsersToSignUp(); + } } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SonarQubeMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SonarQubeMonitorTest.java index a522c1df767..2de59d3a6c9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SonarQubeMonitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SonarQubeMonitorTest.java @@ -28,8 +28,11 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; +import org.sonar.api.security.SecurityRealm; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.log.LoggerLevel; +import org.sonar.server.authentication.IdentityProviderRepositoryRule; +import org.sonar.server.authentication.TestIdentityProvider; import org.sonar.server.platform.ServerLogging; import org.sonar.server.user.SecurityRealmFactory; @@ -42,9 +45,15 @@ public class SonarQubeMonitorTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); + @Rule + public IdentityProviderRepositoryRule identityProviderRepository = new IdentityProviderRepositoryRule(); + Settings settings = new Settings(); Server server = mock(Server.class); ServerLogging serverLogging = mock(ServerLogging.class); + SecurityRealmFactory securityRealmFactory = mock(SecurityRealmFactory.class); + + SonarQubeMonitor underTest = new SonarQubeMonitor(settings, securityRealmFactory, identityProviderRepository, server, serverLogging); @Before public void setUp() throws Exception { @@ -53,15 +62,14 @@ public class SonarQubeMonitorTest { @Test public void name_is_not_empty() { - assertThat(new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging).name()).isNotEmpty(); + assertThat(underTest.name()).isNotEmpty(); } @Test public void getServerId() { when(server.getStartedAt()).thenReturn(DateUtils.parseDate("2015-01-01")); - SonarQubeMonitor monitor = new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging); - Map attributes = monitor.attributes(); + Map attributes = underTest.attributes(); assertThat(attributes).containsKeys("Server ID", "Version"); } @@ -71,9 +79,8 @@ public class SonarQubeMonitorTest { FileUtils.write(new File(rootDir, SonarQubeMonitor.BRANDING_FILE_PATH), "1.2"); when(server.getRootDir()).thenReturn(rootDir); - SonarQubeMonitor monitor = new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging); - Map attributes = monitor.attributes(); + Map attributes = underTest.attributes(); assertThat(attributes).containsEntry("Official Distribution", Boolean.TRUE); } @@ -82,17 +89,73 @@ public class SonarQubeMonitorTest { File rootDir = temp.newFolder(); // branding file is missing when(server.getRootDir()).thenReturn(rootDir); - SonarQubeMonitor monitor = new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging); - Map attributes = monitor.attributes(); + Map attributes = underTest.attributes(); assertThat(attributes).containsEntry("Official Distribution", Boolean.FALSE); } @Test public void get_log_level() throws Exception { - SonarQubeMonitor monitor = new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging); - - Map attributes = monitor.attributes(); + Map attributes = underTest.attributes(); assertThat(attributes).containsEntry("Logs Level", "DEBUG"); } + + @Test + public void get_realm() throws Exception { + SecurityRealm realm = mock(SecurityRealm.class); + when(realm.getName()).thenReturn("LDAP"); + when(securityRealmFactory.getRealm()).thenReturn(realm); + + Map attributes = underTest.attributes(); + assertThat(attributes).containsEntry("External User Authentication", "LDAP"); + } + + @Test + public void no_realm() throws Exception { + when(securityRealmFactory.getRealm()).thenReturn(null); + + Map attributes = underTest.attributes(); + assertThat(attributes).doesNotContainKey("External User Authentication"); + } + + @Test + public void get_enabled_identity_providers() throws Exception { + identityProviderRepository.addIdentityProvider(new TestIdentityProvider() + .setKey("github") + .setName("GitHub") + .setEnabled(true)); + identityProviderRepository.addIdentityProvider(new TestIdentityProvider() + .setKey("bitbucket") + .setName("Bitbucket") + .setEnabled(true)); + identityProviderRepository.addIdentityProvider(new TestIdentityProvider() + .setKey("disabled") + .setName("Disabled") + .setEnabled(false)); + + Map attributes = underTest.attributes(); + assertThat(attributes).containsEntry("Accepted external identity providers", "Bitbucket, GitHub"); + } + + @Test + public void get_enabled_identity_providers_allowing_users_to_signup() throws Exception { + identityProviderRepository.addIdentityProvider(new TestIdentityProvider() + .setKey("github") + .setName("GitHub") + .setEnabled(true) + .setAllowsUsersToSignUp(true)); + identityProviderRepository.addIdentityProvider(new TestIdentityProvider() + .setKey("bitbucket") + .setName("Bitbucket") + .setEnabled(true) + .setAllowsUsersToSignUp(false)); + identityProviderRepository.addIdentityProvider(new TestIdentityProvider() + .setKey("disabled") + .setName("Disabled") + .setEnabled(false) + .setAllowsUsersToSignUp(true)); + + Map attributes = underTest.attributes(); + assertThat(attributes).containsEntry("External identity providers whose users are allowed to sign themselves up", "GitHub"); + } } -- 2.39.5