$CIRRUS_BRANCH == $BRANCH_NIGHTLY ||
changesInclude('server/sonar-auth-saml/src/main/java/**/*.java', 'server/sonar-auth-saml/src/main/resources/**/*', 'server/sonar-db-dao/src/main/**/SAML*.java', 'private/it-core/src/test/java/org/sonarqube/tests/saml/*.java', 'server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/**/*.java')
+ldap_nightly_task_template: &LDAP_NIGHTLY_TASK_TEMPLATE
+ only_if: >-
+ $CIRRUS_BRANCH == $BRANCH_NIGHTLY ||
+ changesInclude('server/sonar-auth-ldap/src/main/java/**/*.java', 'server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/LdapCredentialsAuthentication.java', 'private/it-core/src/test/java/org/sonarqube/tests/ldap/*.java')
+
docker_build_container_template: &GKE_CONTAINER_TEMPLATE
dockerfile: private/docker/Dockerfile-build
builder_image_project: sonarqube-team
qa_ldap_task:
<<: *DEFAULT_TEMPLATE
<<: *BUILD_DEPENDANT_TASK_TEMPLATE
- <<: *NIGHTLY_TASK_TEMPLATE
+ <<: *LDAP_NIGHTLY_TASK_TEMPLATE
<<: *JAR_CACHE_TEMPLATE
<<: *GRADLE_CACHE_TEMPLATE
gke_container:
compileOnlyApi 'com.google.code.findbugs:jsr305'
compileOnlyApi 'javax.servlet:javax.servlet-api'
+ compileOnlyApi project(':server:sonar-process')
compileOnlyApi project(':sonar-core')
testImplementation 'com.tngtech.java:junit-dataprovider'
package org.sonar.auth.ldap;
import java.util.Map;
+import javax.annotation.CheckForNull;
+import org.sonar.api.config.Configuration;
import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
import static org.sonar.auth.ldap.LdapSettingsManager.DEFAULT_LDAP_SERVER_KEY;
+import static org.sonar.process.ProcessProperties.Property.SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE;
+import static org.sonar.process.ProcessProperties.Property.SONAR_SECURITY_REALM;
/**
* @author Evgeny Mandrikov
public static final String LDAP_SECURITY_REALM = "LDAP";
public static final String DEFAULT_LDAP_IDENTITY_PROVIDER_ID = LDAP_SECURITY_REALM + "_" + DEFAULT_LDAP_SERVER_KEY;
- private LdapUsersProvider usersProvider;
- private LdapGroupsProvider groupsProvider;
- private LdapAuthenticator authenticator;
- private final LdapSettingsManager settingsManager;
+ private static final Logger LOG = Loggers.get(LdapRealm.class);
- public LdapRealm(LdapSettingsManager settingsManager) {
- this.settingsManager = settingsManager;
+ private final boolean isLdapAuthActivated;
+ private final LdapUsersProvider usersProvider;
+ private final LdapGroupsProvider groupsProvider;
+ private final LdapAuthenticator authenticator;
+
+ public LdapRealm(LdapSettingsManager settingsManager, Configuration configuration) {
+ String realmName = configuration.get(SONAR_SECURITY_REALM.getKey()).orElse(null);
+ this.isLdapAuthActivated = LDAP_SECURITY_REALM.equals(realmName);
+ boolean ignoreStartupFailure = configuration.getBoolean(SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE.getKey()).orElse(false);
+ if (!isLdapAuthActivated) {
+ this.usersProvider = null;
+ this.groupsProvider = null;
+ this.authenticator = null;
+ } else {
+ Map<String, LdapContextFactory> contextFactories = settingsManager.getContextFactories();
+ Map<String, LdapUserMapping> userMappings = settingsManager.getUserMappings();
+ this.usersProvider = new DefaultLdapUsersProvider(contextFactories, userMappings);
+ this.authenticator = new DefaultLdapAuthenticator(contextFactories, userMappings);
+ this.groupsProvider = createGroupsProvider(contextFactories, userMappings, settingsManager);
+ testConnections(contextFactories, ignoreStartupFailure);
+ }
}
- /**
- * Initializes LDAP realm and tests connection.
- *
- * @throws LdapException if a NamingException was thrown during test
- */
- public void init() {
- Map<String, LdapContextFactory> contextFactories = settingsManager.getContextFactories();
- Map<String, LdapUserMapping> userMappings = settingsManager.getUserMappings();
- usersProvider = new DefaultLdapUsersProvider(contextFactories, userMappings);
- authenticator = new DefaultLdapAuthenticator(contextFactories, userMappings);
+ private static LdapGroupsProvider createGroupsProvider(Map<String, LdapContextFactory> contextFactories, Map<String, LdapUserMapping> userMappings,
+ LdapSettingsManager settingsManager) {
Map<String, LdapGroupMapping> groupMappings = settingsManager.getGroupMappings();
if (!groupMappings.isEmpty()) {
- groupsProvider = new DefaultLdapGroupsProvider(contextFactories, userMappings, groupMappings);
+ return new DefaultLdapGroupsProvider(contextFactories, userMappings, groupMappings);
+ } else {
+ return null;
}
- for (LdapContextFactory contextFactory : contextFactories.values()) {
- contextFactory.testConnection();
+ }
+
+ private static void testConnections(Map<String, LdapContextFactory> contextFactories, boolean ignoreStartupFailure) {
+ try {
+ for (LdapContextFactory contextFactory : contextFactories.values()) {
+ contextFactory.testConnection();
+ }
+ } catch (RuntimeException e) {
+ if (ignoreStartupFailure) {
+ LOG.error("IGNORED - LDAP realm failed to start: " + e.getMessage());
+ } else {
+ throw new LdapException("LDAP realm failed to start: " + e.getMessage(), e);
+ }
}
}
- public LdapAuthenticator doGetAuthenticator() {
+ @CheckForNull
+ public LdapAuthenticator getAuthenticator() {
return authenticator;
}
+ @CheckForNull
public LdapUsersProvider getUsersProvider() {
return usersProvider;
}
+ @CheckForNull
public LdapGroupsProvider getGroupsProvider() {
return groupsProvider;
}
+ public boolean isLdapAuthActivated() {
+ return isLdapAuthActivated;
+ }
}
import org.junit.ClassRule;
import org.junit.Test;
import org.mockito.Mockito;
+import org.sonar.api.config.Configuration;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.auth.ldap.server.LdapServer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.sonar.process.ProcessProperties.Property.SONAR_SECURITY_REALM;
public class KerberosTest {
@Before
public void before() {
MapSettings settings = configure();
- ldapRealm = new LdapRealm(new LdapSettingsManager(settings.asConfig()));
- ldapRealm.init();
-
- authenticator = ldapRealm.doGetAuthenticator();
+ ldapRealm = new LdapRealm(new LdapSettingsManager(settings.asConfig()), settings.asConfig());
+ authenticator = ldapRealm.getAuthenticator();
}
@Test
public void wrong_bind_password() {
MapSettings settings = configure()
.setProperty("ldap.bindPassword", "wrong_bind_password");
- LdapRealm wrongPasswordRealm = new LdapRealm(new LdapSettingsManager(settings.asConfig()));
- assertThatThrownBy(wrongPasswordRealm::init)
+ Configuration config = settings.asConfig();
+ LdapSettingsManager settingsManager = new LdapSettingsManager(config);
+ assertThatThrownBy(() -> new LdapRealm(settingsManager, config))
.isInstanceOf(LdapException.class)
- .hasMessage("Unable to open LDAP connection");
+ .hasMessage("LDAP realm failed to start: Unable to open LDAP connection");
}
.setProperty("ldap.bindPassword", "bind_password")
.setProperty("ldap.user.baseDn", "ou=users,dc=example,dc=org")
.setProperty("ldap.group.baseDn", "ou=groups,dc=example,dc=org")
- .setProperty("ldap.group.request", "(&(objectClass=groupOfUniqueNames)(uniqueMember={dn}))");
+ .setProperty("ldap.group.request", "(&(objectClass=groupOfUniqueNames)(uniqueMember={dn}))")
+ .setProperty(SONAR_SECURITY_REALM.getKey(), LdapRealm.LDAP_SECURITY_REALM);
}
}
import org.junit.ClassRule;
import org.junit.Test;
import org.mockito.Mockito;
+import org.sonar.api.config.Configuration;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.auth.ldap.server.LdapServer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.sonar.process.ProcessProperties.Property.SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE;
+import static org.sonar.process.ProcessProperties.Property.SONAR_SECURITY_REALM;
public class LdapRealmTest {
public void normal() {
MapSettings settings = new MapSettings()
.setProperty("ldap.url", server.getUrl())
- .setProperty("ldap.user.baseDn", "cn=users");
- LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings.asConfig()));
- realm.init();
- assertThat(realm.doGetAuthenticator()).isInstanceOf(DefaultLdapAuthenticator.class);
+ .setProperty("ldap.user.baseDn", "cn=users")
+ .setProperty(SONAR_SECURITY_REALM.getKey(), LdapRealm.LDAP_SECURITY_REALM);
+
+ LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings.asConfig()), settings.asConfig());
+ assertThat(realm.getAuthenticator()).isInstanceOf(DefaultLdapAuthenticator.class);
assertThat(realm.getUsersProvider()).isInstanceOf(LdapUsersProvider.class).isInstanceOf(DefaultLdapUsersProvider.class);
assertThat(realm.getGroupsProvider()).isNull();
}
MapSettings settings = new MapSettings()
.setProperty("ldap.url", "ldap://no-such-host")
.setProperty("ldap.group.baseDn", "cn=groups,dc=example,dc=org")
- .setProperty("ldap.user.baseDn", "cn=users,dc=example,dc=org");
- LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings.asConfig()));
- assertThatThrownBy(realm::init).isInstanceOf(LdapException.class).hasMessage("Unable to open LDAP connection");
+ .setProperty("ldap.user.baseDn", "cn=users,dc=example,dc=org")
+ .setProperty(SONAR_SECURITY_REALM.getKey(), LdapRealm.LDAP_SECURITY_REALM);
+ Configuration config = settings.asConfig();
+ LdapSettingsManager settingsManager = new LdapSettingsManager(config);
+ assertThatThrownBy(() -> new LdapRealm(settingsManager, config)).isInstanceOf(LdapException.class)
+ .hasMessage("LDAP realm failed to start: Unable to open LDAP connection");
+ }
+
+ @Test
+ public void noConnection_ignore_ignoreStartupFailure_is_false() {
+ MapSettings settings = new MapSettings()
+ .setProperty("ldap.url", "ldap://no-such-host")
+ .setProperty("ldap.group.baseDn", "cn=groups,dc=example,dc=org")
+ .setProperty("ldap.user.baseDn", "cn=users,dc=example,dc=org")
+ .setProperty(SONAR_SECURITY_REALM.getKey(), LdapRealm.LDAP_SECURITY_REALM)
+ .setProperty(SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE.getKey(), false);
+ ;
+ Configuration config = settings.asConfig();
+ LdapSettingsManager settingsManager = new LdapSettingsManager(config);
+ assertThatThrownBy(() -> new LdapRealm(settingsManager, config)).isInstanceOf(LdapException.class)
+ .hasMessage("LDAP realm failed to start: Unable to open LDAP connection");
+ }
+
+ @Test
+ public void noConnection_ignore_ignoreStartupFailure_is_true() {
+ MapSettings settings = new MapSettings()
+ .setProperty("ldap.url", "ldap://no-such-host")
+ .setProperty("ldap.group.baseDn", "cn=groups,dc=example,dc=org")
+ .setProperty("ldap.user.baseDn", "cn=users,dc=example,dc=org")
+ .setProperty(SONAR_SECURITY_REALM.getKey(), LdapRealm.LDAP_SECURITY_REALM)
+ .setProperty(SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE.getKey(), true);
+
+ LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings.asConfig()), settings.asConfig());
+ verifyRealm(realm);
+ }
+
+ @Test
+ public void should_not_activate_ldap_if_realm_is_not_set() {
+ MapSettings settings = new MapSettings();
+
+ LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings.asConfig()), settings.asConfig());
+ verifyDeactivatedRealm(realm);
+ }
+
+ @Test
+ public void should_not_activate_ldap_if_realm_is_not_ldap() {
+ MapSettings settings = new MapSettings()
+ .setProperty(SONAR_SECURITY_REALM.getKey(), "not_ldap");
+
+ LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings.asConfig()), settings.asConfig());
+ verifyDeactivatedRealm(realm);
+ }
- assertThat(realm.doGetAuthenticator()).isInstanceOf(DefaultLdapAuthenticator.class);
+ private static void verifyRealm(LdapRealm realm) {
+ assertThat(realm.getAuthenticator()).isInstanceOf(DefaultLdapAuthenticator.class);
LdapUsersProvider usersProvider = realm.getUsersProvider();
assertThat(usersProvider).isInstanceOf(LdapUsersProvider.class).isInstanceOf(DefaultLdapUsersProvider.class);
.isInstanceOf(LdapException.class)
.hasMessage("Unable to retrieve groups for user tester in server with key <default>");
+ assertThat(realm.isLdapAuthActivated()).isTrue();
+ }
+
+ private static void verifyDeactivatedRealm(LdapRealm realm) {
+ assertThat(realm.getAuthenticator()).isNull();
+ assertThat(realm.getUsersProvider()).isNull();
+ assertThat(realm.getGroupsProvider()).isNull();
+ assertThat(realm.isLdapAuthActivated()).isFalse();
+
}
}
import org.sonar.auth.ldap.LdapUserDetails;
import org.sonar.auth.ldap.LdapUsersProvider;
import org.sonar.db.user.UserDto;
-import org.sonar.process.ProcessProperties;
import org.sonar.server.authentication.event.AuthenticationEvent;
import org.sonar.server.authentication.event.AuthenticationEvent.Source;
import org.sonar.server.authentication.event.AuthenticationException;
public class LdapCredentialsAuthentication {
- private static final String LDAP_SECURITY_REALM = "LDAP";
-
private static final Logger LOG = Loggers.get(LdapCredentialsAuthentication.class);
private final Configuration configuration;
this.userRegistrar = userRegistrar;
this.authenticationEvent = authenticationEvent;
- String realmName = configuration.get(ProcessProperties.Property.SONAR_SECURITY_REALM.getKey()).orElse(null);
- this.isLdapAuthActivated = LDAP_SECURITY_REALM.equals(realmName);
-
- if (isLdapAuthActivated) {
- ldapRealm.init();
- this.ldapAuthenticator = ldapRealm.doGetAuthenticator();
- this.ldapUsersProvider = ldapRealm.getUsersProvider();
- this.ldapGroupsProvider = ldapRealm.getGroupsProvider();
- } else {
- this.ldapAuthenticator = null;
- this.ldapUsersProvider = null;
- this.ldapGroupsProvider = null;
- }
+ this.isLdapAuthActivated = ldapRealm.isLdapAuthActivated();
+ this.ldapAuthenticator = ldapRealm.getAuthenticator();
+ this.ldapUsersProvider = ldapRealm.getUsersProvider();
+ this.ldapGroupsProvider = ldapRealm.getGroupsProvider();
}
public Optional<UserDto> authenticate(Credentials credentials, HttpServletRequest request, AuthenticationEvent.Method method) {
private final String key;
private LdapIdentityProvider(String ldapServerKey) {
- this.key = LDAP_SECURITY_REALM + "_" + ldapServerKey;
+ this.key = LdapRealm.LDAP_SECURITY_REALM + "_" + ldapServerKey;
}
@Override
@Before
public void setUp() throws Exception {
settings.setProperty(ProcessProperties.Property.SONAR_SECURITY_REALM.getKey(), "LDAP");
- when(ldapRealm.doGetAuthenticator()).thenReturn(ldapAuthenticator);
+ settings.setProperty(ProcessProperties.Property.SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE.getKey(), "true");
+ when(ldapRealm.getAuthenticator()).thenReturn(ldapAuthenticator);
when(ldapRealm.getUsersProvider()).thenReturn(ldapUsersProvider);
when(ldapRealm.getGroupsProvider()).thenReturn(ldapGroupsProvider);
+ when(ldapRealm.isLdapAuthActivated()).thenReturn(true);
underTest = new LdapCredentialsAuthentication(settings.asConfig(), userRegistrar, authenticationEvent, ldapRealm);
}
@Test
public void authenticate_with_null_group_provider() {
reset(ldapRealm);
- when(ldapRealm.doGetAuthenticator()).thenReturn(ldapAuthenticator);
+ when(ldapRealm.getAuthenticator()).thenReturn(ldapAuthenticator);
when(ldapRealm.getUsersProvider()).thenReturn(ldapUsersProvider);
when(ldapRealm.getGroupsProvider()).thenReturn(null);
+ when(ldapRealm.isLdapAuthActivated()).thenReturn(true);
underTest = new LdapCredentialsAuthentication(settings.asConfig(), userRegistrar, authenticationEvent, ldapRealm);
LdapAuthenticator.Context authenticationContext = new LdapAuthenticator.Context(LOGIN, PASSWORD, request);
assertThat(identity.shouldSyncGroups()).isFalse();
verify(authenticationEvent).loginSuccess(request, LOGIN, Source.realm(BASIC, LDAP_SECURITY_REALM_NAME));
- verify(ldapRealm).init();
}
@Test
assertThat(provider.getDisplay()).isNull();
assertThat(provider.isEnabled()).isTrue();
verify(authenticationEvent).loginSuccess(request, LOGIN, Source.realm(BASIC, LDAP_SECURITY_REALM_NAME));
- verify(ldapRealm).init();
}
@Test
@Test
public void return_empty_user_when_ldap_not_activated() {
reset(ldapRealm);
- settings.clear();
+ when(ldapRealm.isLdapAuthActivated()).thenReturn(false);
underTest = new LdapCredentialsAuthentication(settings.asConfig(), userRegistrar, authenticationEvent, ldapRealm);
assertThat(underTest.authenticate(new Credentials(LOGIN, PASSWORD), request, BASIC)).isEmpty();
verifyNoInteractions(authenticationEvent);
- verifyNoInteractions(ldapRealm);
}
private void executeAuthenticate(@Nullable LdapUserDetails userDetails) {