*/
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;
}
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<String> getEnabledIdentityProviders() {
+ return from(identityProviderRepository.getAllEnabledAndSorted())
+ .filter(MatchEnabled.INSTANCE)
+ .transform(IdentityProviderToName.INSTANCE)
+ .toList();
+ }
+
+ private List<String> 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);
Map<String, Object> 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());
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<String, Object> attributes) {
+ if (value != null) {
+ attributes.put(key, value);
+ }
+ }
+
+ private static void addIfNotEmpty(String key, List<String> values, Map<String, Object> attributes) {
+ if (!values.isEmpty()) {
+ attributes.put(key, COMMA_JOINER.join(values));
+ }
+ }
+
+ private enum IdentityProviderToName implements Function<IdentityProvider, String> {
+ INSTANCE;
+
+ @Override
+ public String apply(@Nonnull IdentityProvider input) {
+ return input.getName();
+ }
+ }
+ private enum MatchEnabled implements Predicate<IdentityProvider> {
+ INSTANCE;
+
+ @Override
+ public boolean apply(@Nonnull IdentityProvider input) {
+ return input.isEnabled();
+ }
+ }
+
+ private enum MatchAllowsToSignUp implements Predicate<IdentityProvider> {
+ INSTANCE;
+
+ @Override
+ public boolean apply(@Nonnull IdentityProvider input) {
+ return input.allowsUsersToSignUp();
+ }
}
}
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;
@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 {
@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<String, Object> attributes = monitor.attributes();
+ Map<String, Object> attributes = underTest.attributes();
assertThat(attributes).containsKeys("Server ID", "Version");
}
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<String, Object> attributes = monitor.attributes();
+ Map<String, Object> attributes = underTest.attributes();
assertThat(attributes).containsEntry("Official Distribution", Boolean.TRUE);
}
File rootDir = temp.newFolder();
// branding file is missing
when(server.getRootDir()).thenReturn(rootDir);
- SonarQubeMonitor monitor = new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging);
- Map<String, Object> attributes = monitor.attributes();
+ Map<String, Object> 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<String, Object> attributes = monitor.attributes();
+ Map<String, Object> 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<String, Object> attributes = underTest.attributes();
+ assertThat(attributes).containsEntry("External User Authentication", "LDAP");
+ }
+
+ @Test
+ public void no_realm() throws Exception {
+ when(securityRealmFactory.getRealm()).thenReturn(null);
+
+ Map<String, Object> 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<String, Object> 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<String, Object> attributes = underTest.attributes();
+ assertThat(attributes).containsEntry("External identity providers whose users are allowed to sign themselves up", "GitHub");
+ }
}