diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2019-09-27 16:25:53 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-10-07 20:21:06 +0200 |
commit | 274c9faaf56a985b6221b923ddf964b809b8aa9d (patch) | |
tree | 20c8e239c4f53e982520911db715c22738608ae4 /server/sonar-auth-ldap/src/test | |
parent | 69dd7210a6086f1e7687aee5ee2986a91cab0885 (diff) | |
download | sonarqube-274c9faaf56a985b6221b923ddf964b809b8aa9d.tar.gz sonarqube-274c9faaf56a985b6221b923ddf964b809b8aa9d.zip |
SONAR-12471 Embed LDAP authentication
Diffstat (limited to 'server/sonar-auth-ldap/src/test')
26 files changed, 2287 insertions, 0 deletions
diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/CallbackHandlerImplTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/CallbackHandlerImplTest.java new file mode 100644 index 00000000000..c0acc7801c0 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/CallbackHandlerImplTest.java @@ -0,0 +1,48 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class CallbackHandlerImplTest { + + @Test + public void test() throws Exception { + NameCallback nameCallback = new NameCallback("username"); + PasswordCallback passwordCallback = new PasswordCallback("password", false); + new CallbackHandlerImpl("tester", "secret").handle(new Callback[] {nameCallback, passwordCallback}); + + assertThat(nameCallback.getName()).isEqualTo("tester"); + assertThat(passwordCallback.getPassword()).isEqualTo("secret".toCharArray()); + } + + @Test(expected = UnsupportedCallbackException.class) + public void unsupportedCallback() throws Exception { + new CallbackHandlerImpl("tester", "secret").handle(new Callback[] {mock(Callback.class)}); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/ContextHelperTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/ContextHelperTest.java new file mode 100644 index 00000000000..73029df57cd --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/ContextHelperTest.java @@ -0,0 +1,53 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import javax.naming.Context; +import javax.naming.NamingException; +import org.junit.Test; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; + +public class ContextHelperTest { + + @Test + public void shouldSwallow() throws Exception { + Context context = mock(Context.class); + doThrow(new NamingException()).when(context).close(); + ContextHelper.close(context, true); + ContextHelper.closeQuietly(context); + } + + @Test(expected = NamingException.class) + public void shouldNotSwallow() throws Exception { + Context context = mock(Context.class); + doThrow(new NamingException()).when(context).close(); + ContextHelper.close(context, false); + } + + @Test + public void normal() throws NamingException { + ContextHelper.close(null, true); + ContextHelper.closeQuietly(null); + ContextHelper.close(mock(Context.class), true); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/KerberosTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/KerberosTest.java new file mode 100644 index 00000000000..c49205a83b5 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/KerberosTest.java @@ -0,0 +1,84 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import java.io.File; +import javax.servlet.http.HttpServletRequest; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.mockito.Mockito; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.security.Authenticator; +import org.sonar.api.security.ExternalGroupsProvider; +import org.sonar.auth.ldap.server.LdapServer; + +import static org.assertj.core.api.Assertions.assertThat; + +public class KerberosTest { + + static { + System.setProperty("java.security.krb5.conf", new File("target/krb5.conf").getAbsolutePath()); + } + + @ClassRule + public static LdapServer server = new LdapServer("/krb.ldif"); + + @Test + public void test() { + MapSettings settings = configure(); + LdapRealm ldapRealm = new LdapRealm(new LdapSettingsManager(settings, new LdapAutodiscovery())); + + ldapRealm.init(); + + assertThat(ldapRealm.doGetAuthenticator().doAuthenticate(new Authenticator.Context("Godin@EXAMPLE.ORG", "wrong_user_password", Mockito.mock(HttpServletRequest.class)))) + .isFalse(); + assertThat(ldapRealm.doGetAuthenticator().doAuthenticate(new Authenticator.Context("Godin@EXAMPLE.ORG", "user_password", Mockito.mock(HttpServletRequest.class)))).isTrue(); + // Using default realm from krb5.conf: + assertThat(ldapRealm.doGetAuthenticator().doAuthenticate(new Authenticator.Context("Godin", "user_password", Mockito.mock(HttpServletRequest.class)))).isTrue(); + + assertThat(ldapRealm.getGroupsProvider().doGetGroups(new ExternalGroupsProvider.Context("godin", Mockito.mock(HttpServletRequest.class)))).containsOnly("sonar-users"); + } + + @Test + public void wrong_bind_password() { + MapSettings settings = configure() + .setProperty("ldap.bindPassword", "wrong_bind_password"); + LdapRealm ldapRealm = new LdapRealm(new LdapSettingsManager(settings, new LdapAutodiscovery())); + try { + ldapRealm.init(); + Assert.fail(); + } catch (LdapException e) { + assertThat(e.getMessage()).isEqualTo("Unable to open LDAP connection"); + } + } + + private static MapSettings configure() { + return new MapSettings() + .setProperty("ldap.url", server.getUrl()) + .setProperty("ldap.authentication", LdapContextFactory.AUTH_METHOD_GSSAPI) + .setProperty("ldap.bindDn", "SonarQube@EXAMPLE.ORG") + .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}))"); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapAuthenticatorTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapAuthenticatorTest.java new file mode 100644 index 00000000000..da91691ee46 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapAuthenticatorTest.java @@ -0,0 +1,129 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.auth.ldap.server.LdapServer; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LdapAuthenticatorTest { + + /** + * A reference to the original ldif file + */ + public static final String USERS_EXAMPLE_ORG_LDIF = "/users.example.org.ldif"; + /** + * A reference to an aditional ldif file. + */ + public static final String USERS_INFOSUPPORT_COM_LDIF = "/users.infosupport.com.ldif"; + @ClassRule + public static LdapServer exampleServer = new LdapServer(USERS_EXAMPLE_ORG_LDIF); + @ClassRule + public static LdapServer infosupportServer = new LdapServer(USERS_INFOSUPPORT_COM_LDIF, "infosupport.com", "dc=infosupport,dc=com"); + + @Test + public void testNoConnection() { + exampleServer.disableAnonymousAccess(); + try { + LdapSettingsManager settingsManager = new LdapSettingsManager(LdapSettingsFactory.generateAuthenticationSettings(exampleServer, null, LdapContextFactory.AUTH_METHOD_SIMPLE), + new LdapAutodiscovery()); + LdapAuthenticator authenticator = new LdapAuthenticator(settingsManager.getContextFactories(), settingsManager.getUserMappings()); + authenticator.authenticate("godin", "secret1"); + } finally { + exampleServer.enableAnonymousAccess(); + } + } + + @Test + public void testSimple() { + LdapSettingsManager settingsManager = new LdapSettingsManager(LdapSettingsFactory.generateAuthenticationSettings(exampleServer, null, LdapContextFactory.AUTH_METHOD_SIMPLE), + new LdapAutodiscovery()); + LdapAuthenticator authenticator = new LdapAuthenticator(settingsManager.getContextFactories(), settingsManager.getUserMappings()); + + assertThat(authenticator.authenticate("godin", "secret1")).isTrue(); + assertThat(authenticator.authenticate("godin", "wrong")).isFalse(); + + assertThat(authenticator.authenticate("tester", "secret2")).isTrue(); + assertThat(authenticator.authenticate("tester", "wrong")).isFalse(); + + assertThat(authenticator.authenticate("notfound", "wrong")).isFalse(); + // SONARPLUGINS-2493 + assertThat(authenticator.authenticate("godin", "")).isFalse(); + assertThat(authenticator.authenticate("godin", null)).isFalse(); + } + + @Test + public void testSimpleMultiLdap() { + LdapSettingsManager settingsManager = new LdapSettingsManager( + LdapSettingsFactory.generateAuthenticationSettings(exampleServer, infosupportServer, LdapContextFactory.AUTH_METHOD_SIMPLE), new LdapAutodiscovery()); + LdapAuthenticator authenticator = new LdapAuthenticator(settingsManager.getContextFactories(), settingsManager.getUserMappings()); + + assertThat(authenticator.authenticate("godin", "secret1")).isTrue(); + assertThat(authenticator.authenticate("godin", "wrong")).isFalse(); + + assertThat(authenticator.authenticate("tester", "secret2")).isTrue(); + assertThat(authenticator.authenticate("tester", "wrong")).isFalse(); + + assertThat(authenticator.authenticate("notfound", "wrong")).isFalse(); + // SONARPLUGINS-2493 + assertThat(authenticator.authenticate("godin", "")).isFalse(); + assertThat(authenticator.authenticate("godin", null)).isFalse(); + + // SONARPLUGINS-2793 + assertThat(authenticator.authenticate("robby", "secret1")).isTrue(); + assertThat(authenticator.authenticate("robby", "wrong")).isFalse(); + } + + @Test + public void testSasl() { + LdapSettingsManager settingsManager = new LdapSettingsManager(LdapSettingsFactory.generateAuthenticationSettings(exampleServer, null, LdapContextFactory.AUTH_METHOD_CRAM_MD5), + new LdapAutodiscovery()); + LdapAuthenticator authenticator = new LdapAuthenticator(settingsManager.getContextFactories(), settingsManager.getUserMappings()); + + assertThat(authenticator.authenticate("godin", "secret1")).isTrue(); + assertThat(authenticator.authenticate("godin", "wrong")).isFalse(); + + assertThat(authenticator.authenticate("tester", "secret2")).isTrue(); + assertThat(authenticator.authenticate("tester", "wrong")).isFalse(); + + assertThat(authenticator.authenticate("notfound", "wrong")).isFalse(); + } + + @Test + public void testSaslMultipleLdap() { + LdapSettingsManager settingsManager = new LdapSettingsManager( + LdapSettingsFactory.generateAuthenticationSettings(exampleServer, infosupportServer, LdapContextFactory.AUTH_METHOD_CRAM_MD5), new LdapAutodiscovery()); + LdapAuthenticator authenticator = new LdapAuthenticator(settingsManager.getContextFactories(), settingsManager.getUserMappings()); + + assertThat(authenticator.authenticate("godin", "secret1")).isTrue(); + assertThat(authenticator.authenticate("godin", "wrong")).isFalse(); + + assertThat(authenticator.authenticate("tester", "secret2")).isTrue(); + assertThat(authenticator.authenticate("tester", "wrong")).isFalse(); + + assertThat(authenticator.authenticate("notfound", "wrong")).isFalse(); + + assertThat(authenticator.authenticate("robby", "secret1")).isTrue(); + assertThat(authenticator.authenticate("robby", "wrong")).isFalse(); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapAutoDiscoveryWarningLogTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapAutoDiscoveryWarningLogTest.java new file mode 100644 index 00000000000..d002577a44c --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapAutoDiscoveryWarningLogTest.java @@ -0,0 +1,100 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.utils.log.LogTester; +import org.sonar.api.utils.log.LoggerLevel; +import org.sonar.auth.ldap.server.ApacheDS; +import org.sonar.auth.ldap.server.LdapServer; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class LdapAutoDiscoveryWarningLogTest { + + @Rule + public LogTester logTester = new LogTester(); + + @ClassRule + public static LdapServer server = new LdapServer("/users.example.org.ldif"); + + @Test + public void does_not_display_log_when_not_using_auto_discovery() { + MapSettings settings = new MapSettings() + .setProperty("ldap.url", server.getUrl()); + LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings, new LdapAutodiscovery())); + assertThat(realm.getName()).isEqualTo("LDAP"); + + realm.init(); + + assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty(); + } + + @Test + public void display_warning_log_when_using_auto_discovery_to_detect_server_url() { + LdapAutodiscovery ldapAutodiscovery = mock(LdapAutodiscovery.class); + when(ldapAutodiscovery.getLdapServers("example.org")).thenReturn(singletonList(new LdapAutodiscovery.LdapSrvRecord(server.getUrl(), 1, 1))); + // ldap.url setting is not set + LdapRealm realm = new LdapRealm(new LdapSettingsManager(new MapSettings().setProperty("ldap.realm", "example.org"), + ldapAutodiscovery)); + + realm.init(); + + assertThat(logTester.logs(LoggerLevel.WARN)).contains("Auto-discovery feature is deprecated, please use 'ldap.url' to specify LDAP url"); + } + + @Test + public void display_warning_log_when_using_auto_discovery_to_detect_user_baseDn_on_single_server() { + // ldap.user.baseDn setting is not set + MapSettings settings = new MapSettings().setProperty("ldap.url", server.getUrl()).setProperty("ldap.realm", "example.org"); + LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings, new LdapAutodiscovery())); + + realm.init(); + + assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly("Auto-discovery feature is deprecated, please use 'ldap.user.baseDn' to specify user search dn"); + } + + @Test + public void display_warning_log_when_using_auto_discovery_to_detect_user_baseDn_on_multiple_servers() throws Exception { + ApacheDS server2 = ApacheDS.start("example.org", "dc=example,dc=org", "target/ldap-work2/"); + server2.importLdif(LdapAutoDiscoveryWarningLogTest.class.getResourceAsStream("/users.example.org.ldif")); + MapSettings settings = new MapSettings() + .setProperty("ldap.servers", "example,infosupport") + // ldap.XXX.user.baseDn settings are not set on both servers + .setProperty("ldap.example.url", server.getUrl()) + .setProperty("ldap.example.realm", "example.org") + .setProperty("ldap.infosupport.url", server2.getUrl()) + .setProperty("ldap.infosupport.realm", "infosupport.org"); + LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings, new LdapAutodiscovery())); + + realm.init(); + + assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly( + "Auto-discovery feature is deprecated, please use 'ldap.example.user.baseDn' to specify user search dn", + "Auto-discovery feature is deprecated, please use 'ldap.infosupport.user.baseDn' to specify user search dn"); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapAutodiscoveryTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapAutodiscoveryTest.java new file mode 100644 index 00000000000..989a3305fd7 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapAutodiscoveryTest.java @@ -0,0 +1,93 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import java.net.UnknownHostException; +import java.util.Arrays; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import org.junit.Test; +import org.mockito.Mockito; +import org.sonar.auth.ldap.LdapAutodiscovery.LdapSrvRecord; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class LdapAutodiscoveryTest { + + @Test + public void testGetDnsDomain() { + assertThat(LdapAutodiscovery.getDnsDomainName("localhost")).isNull(); + assertThat(LdapAutodiscovery.getDnsDomainName("godin.example.org")).isEqualTo("example.org"); + assertThat(LdapAutodiscovery.getDnsDomainName("godin.usr.example.org")).isEqualTo("usr.example.org"); + } + + @Test + public void testGetDnsDomainWithoutParameter() { + try { + LdapAutodiscovery.getDnsDomainName(); + } catch (UnknownHostException e) { + fail(e.getMessage()); + } + } + + @Test + public void testGetDnsDomainDn() { + assertThat(LdapAutodiscovery.getDnsDomainDn("example.org")).isEqualTo("dc=example,dc=org"); + } + + @Test + public void testEqualsAndHashCode() { + assertThat(new LdapSrvRecord("http://foo:389", 1, 1)).isEqualTo(new LdapSrvRecord("http://foo:389", 2, 0)); + assertThat(new LdapSrvRecord("http://foo:389", 1, 1)).isNotEqualTo(new LdapSrvRecord("http://foo:388", 1, 1)); + + assertThat(new LdapSrvRecord("http://foo:389", 1, 1).hashCode()).isEqualTo(new LdapSrvRecord("http://foo:389", 1, 1).hashCode()); + } + + @Test + public void testGetLdapServer() throws NamingException { + DirContext context = mock(DirContext.class); + Attributes attributes = mock(Attributes.class); + Attribute attribute = mock(Attribute.class); + NamingEnumeration namingEnumeration = mock(NamingEnumeration.class); + + when(context.getAttributes(Mockito.anyString(), Mockito.<String[]>anyObject())).thenReturn(attributes); + when(attributes.get(Mockito.eq("srv"))).thenReturn(attribute); + when(attribute.getAll()).thenReturn(namingEnumeration); + when(namingEnumeration.hasMore()).thenReturn(true, true, true, true, true, false); + when(namingEnumeration.next()) + .thenReturn("10 40 389 ldap5.example.org.") + .thenReturn("0 10 389 ldap3.example.org") + .thenReturn("0 60 389 ldap1.example.org") + .thenReturn("0 30 389 ldap2.example.org") + .thenReturn("10 60 389 ldap4.example.org"); + + assertThat(new LdapAutodiscovery().getLdapServers(context, "example.org.")).extracting("serverUrl") + .isEqualTo( + Arrays.asList("ldap://ldap1.example.org:389", "ldap://ldap2.example.org:389", "ldap://ldap3.example.org:389", "ldap://ldap4.example.org:389", + "ldap://ldap5.example.org:389")); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapGroupMappingTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapGroupMappingTest.java new file mode 100644 index 00000000000..5a9acab0469 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapGroupMappingTest.java @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import org.junit.Test; +import org.sonar.api.config.internal.MapSettings; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LdapGroupMappingTest { + + @Test + public void defaults() { + LdapGroupMapping groupMapping = new LdapGroupMapping(new MapSettings(), "ldap"); + + assertThat(groupMapping.getBaseDn()).isNull(); + assertThat(groupMapping.getIdAttribute()).isEqualTo("cn"); + assertThat(groupMapping.getRequest()).isEqualTo("(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))"); + assertThat(groupMapping.getRequiredUserAttributes()).isEqualTo(new String[] {"dn"}); + + assertThat(groupMapping.toString()).isEqualTo("LdapGroupMapping{" + + "baseDn=null," + + " idAttribute=cn," + + " requiredUserAttributes=[dn]," + + " request=(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))}"); + } + + @Test + public void backward_compatibility() { + MapSettings settings = new MapSettings() + .setProperty("ldap.group.objectClass", "group") + .setProperty("ldap.group.memberAttribute", "member"); + LdapGroupMapping groupMapping = new LdapGroupMapping(settings, "ldap"); + + assertThat(groupMapping.getRequest()).isEqualTo("(&(objectClass=group)(member={0}))"); + } + + @Test + public void custom_request() { + MapSettings settings = new MapSettings() + .setProperty("ldap.group.request", "(&(|(objectClass=posixGroup)(objectClass=groupOfUniqueNames))(|(memberUid={uid})(uniqueMember={dn})))"); + LdapGroupMapping groupMapping = new LdapGroupMapping(settings, "ldap"); + + assertThat(groupMapping.getRequest()).isEqualTo("(&(|(objectClass=posixGroup)(objectClass=groupOfUniqueNames))(|(memberUid={0})(uniqueMember={1})))"); + assertThat(groupMapping.getRequiredUserAttributes()).isEqualTo(new String[] {"uid", "dn"}); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapGroupsProviderTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapGroupsProviderTest.java new file mode 100644 index 00000000000..a2aab4bc3c0 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapGroupsProviderTest.java @@ -0,0 +1,149 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import java.util.Collection; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.auth.ldap.server.LdapServer; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LdapGroupsProviderTest { + + /** + * A reference to the original ldif file + */ + public static final String USERS_EXAMPLE_ORG_LDIF = "/users.example.org.ldif"; + /** + * A reference to an aditional ldif file. + */ + public static final String USERS_INFOSUPPORT_COM_LDIF = "/users.infosupport.com.ldif"; + + @ClassRule + public static LdapServer exampleServer = new LdapServer(USERS_EXAMPLE_ORG_LDIF); + @ClassRule + public static LdapServer infosupportServer = new LdapServer(USERS_INFOSUPPORT_COM_LDIF, "infosupport.com", "dc=infosupport,dc=com"); + + @Test + public void defaults() throws Exception { + MapSettings settings = LdapSettingsFactory.generateSimpleAnonymousAccessSettings(exampleServer, null); + + LdapSettingsManager settingsManager = new LdapSettingsManager(settings, new LdapAutodiscovery()); + LdapGroupsProvider groupsProvider = new LdapGroupsProvider(settingsManager.getContextFactories(), settingsManager.getUserMappings(), settingsManager.getGroupMappings()); + Collection<String> groups; + + groups = groupsProvider.getGroups("tester"); + assertThat(groups).containsOnly("sonar-users"); + + groups = groupsProvider.getGroups("godin"); + assertThat(groups).containsOnly("sonar-users", "sonar-developers"); + + groups = groupsProvider.getGroups("notfound"); + assertThat(groups).isEmpty(); + } + + @Test + public void defaultsMultipleLdap() { + MapSettings settings = LdapSettingsFactory.generateSimpleAnonymousAccessSettings(exampleServer, infosupportServer); + + LdapSettingsManager settingsManager = new LdapSettingsManager(settings, new LdapAutodiscovery()); + LdapGroupsProvider groupsProvider = new LdapGroupsProvider(settingsManager.getContextFactories(), settingsManager.getUserMappings(), settingsManager.getGroupMappings()); + + Collection<String> groups; + + groups = groupsProvider.getGroups("tester"); + assertThat(groups).containsOnly("sonar-users"); + + groups = groupsProvider.getGroups("godin"); + assertThat(groups).containsOnly("sonar-users", "sonar-developers"); + + groups = groupsProvider.getGroups("notfound"); + assertThat(groups).isEmpty(); + + groups = groupsProvider.getGroups("testerInfo"); + assertThat(groups).containsOnly("sonar-users"); + + groups = groupsProvider.getGroups("robby"); + assertThat(groups).containsOnly("sonar-users", "sonar-developers"); + } + + @Test + public void posix() { + MapSettings settings = LdapSettingsFactory.generateSimpleAnonymousAccessSettings(exampleServer, null); + settings.setProperty("ldap.group.request", "(&(objectClass=posixGroup)(memberUid={uid}))"); + LdapSettingsManager settingsManager = new LdapSettingsManager(settings, new LdapAutodiscovery()); + LdapGroupsProvider groupsProvider = new LdapGroupsProvider(settingsManager.getContextFactories(), settingsManager.getUserMappings(), settingsManager.getGroupMappings()); + + Collection<String> groups; + + groups = groupsProvider.getGroups("godin"); + assertThat(groups).containsOnly("linux-users"); + } + + @Test + public void posixMultipleLdap() { + MapSettings settings = LdapSettingsFactory.generateSimpleAnonymousAccessSettings(exampleServer, infosupportServer); + settings.setProperty("ldap.example.group.request", "(&(objectClass=posixGroup)(memberUid={uid}))"); + settings.setProperty("ldap.infosupport.group.request", "(&(objectClass=posixGroup)(memberUid={uid}))"); + LdapSettingsManager settingsManager = new LdapSettingsManager(settings, new LdapAutodiscovery()); + LdapGroupsProvider groupsProvider = new LdapGroupsProvider(settingsManager.getContextFactories(), settingsManager.getUserMappings(), settingsManager.getGroupMappings()); + + Collection<String> groups; + + groups = groupsProvider.getGroups("godin"); + assertThat(groups).containsOnly("linux-users"); + + groups = groupsProvider.getGroups("robby"); + assertThat(groups).containsOnly("linux-users"); + } + + @Test + public void mixed() { + MapSettings settings = LdapSettingsFactory.generateSimpleAnonymousAccessSettings(exampleServer, infosupportServer); + settings.setProperty("ldap.example.group.request", "(&(|(objectClass=groupOfUniqueNames)(objectClass=posixGroup))(|(uniqueMember={dn})(memberUid={uid})))"); + LdapSettingsManager settingsManager = new LdapSettingsManager(settings, new LdapAutodiscovery()); + LdapGroupsProvider groupsProvider = new LdapGroupsProvider(settingsManager.getContextFactories(), settingsManager.getUserMappings(), settingsManager.getGroupMappings()); + + Collection<String> groups; + + groups = groupsProvider.getGroups("godin"); + assertThat(groups).containsOnly("sonar-users", "sonar-developers", "linux-users"); + } + + @Test + public void mixedMultipleLdap() { + MapSettings settings = LdapSettingsFactory.generateSimpleAnonymousAccessSettings(exampleServer, infosupportServer); + settings.setProperty("ldap.example.group.request", "(&(|(objectClass=groupOfUniqueNames)(objectClass=posixGroup))(|(uniqueMember={dn})(memberUid={uid})))"); + settings.setProperty("ldap.infosupport.group.request", "(&(|(objectClass=groupOfUniqueNames)(objectClass=posixGroup))(|(uniqueMember={dn})(memberUid={uid})))"); + LdapSettingsManager settingsManager = new LdapSettingsManager(settings, new LdapAutodiscovery()); + LdapGroupsProvider groupsProvider = new LdapGroupsProvider(settingsManager.getContextFactories(), settingsManager.getUserMappings(), settingsManager.getGroupMappings()); + + Collection<String> groups; + + groups = groupsProvider.getGroups("godin"); + assertThat(groups).containsOnly("sonar-users", "sonar-developers", "linux-users"); + + groups = groupsProvider.getGroups("robby"); + assertThat(groups).containsOnly("sonar-users", "sonar-developers", "linux-users"); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapModuleTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapModuleTest.java new file mode 100644 index 00000000000..c231f765af2 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapModuleTest.java @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.auth.ldap; + +import org.junit.Test; +import org.sonar.core.platform.ComponentContainer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER; + +public class LdapModuleTest { + + @Test + public void verify_count_of_added_components() { + ComponentContainer container = new ComponentContainer(); + new LdapModule().configure(container); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 3); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapRealmTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapRealmTest.java new file mode 100644 index 00000000000..232269a4083 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapRealmTest.java @@ -0,0 +1,82 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import javax.servlet.http.HttpServletRequest; +import org.junit.ClassRule; +import org.junit.Test; +import org.mockito.Mockito; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.security.ExternalGroupsProvider; +import org.sonar.api.security.ExternalUsersProvider; +import org.sonar.auth.ldap.server.LdapServer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + +public class LdapRealmTest { + + @ClassRule + public static LdapServer server = new LdapServer("/users.example.org.ldif"); + + @Test + public void normal() { + MapSettings settings = new MapSettings() + .setProperty("ldap.url", server.getUrl()); + LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings, new LdapAutodiscovery())); + assertThat(realm.getName()).isEqualTo("LDAP"); + realm.init(); + assertThat(realm.doGetAuthenticator()).isInstanceOf(LdapAuthenticator.class); + assertThat(realm.getUsersProvider()).isInstanceOf(ExternalUsersProvider.class).isInstanceOf(LdapUsersProvider.class); + assertThat(realm.getGroupsProvider()).isNull(); + } + + @Test + public void noConnection() { + MapSettings settings = new MapSettings() + .setProperty("ldap.url", "ldap://no-such-host") + .setProperty("ldap.group.baseDn", "cn=groups,dc=example,dc=org"); + LdapRealm realm = new LdapRealm(new LdapSettingsManager(settings, new LdapAutodiscovery())); + assertThat(realm.getName()).isEqualTo("LDAP"); + try { + realm.init(); + fail("Since there is no connection, the init method has to throw an exception."); + } catch (LdapException e) { + assertThat(e).hasMessage("Unable to open LDAP connection"); + } + assertThat(realm.doGetAuthenticator()).isInstanceOf(LdapAuthenticator.class); + assertThat(realm.getUsersProvider()).isInstanceOf(ExternalUsersProvider.class).isInstanceOf(LdapUsersProvider.class); + assertThat(realm.getGroupsProvider()).isInstanceOf(ExternalGroupsProvider.class).isInstanceOf(LdapGroupsProvider.class); + + try { + realm.getUsersProvider().doGetUserDetails(new ExternalUsersProvider.Context("tester", Mockito.mock(HttpServletRequest.class))); + fail("Since there is no connection, the doGetUserDetails method has to throw an exception."); + } catch (LdapException e) { + assertThat(e.getMessage()).contains("Unable to retrieve details for user tester"); + } + try { + realm.getGroupsProvider().doGetGroups(new ExternalGroupsProvider.Context("tester", Mockito.mock(HttpServletRequest.class))); + fail("Since there is no connection, the doGetGroups method has to throw an exception."); + } catch (LdapException e) { + assertThat(e.getMessage()).contains("Unable to retrieve details for user tester"); + } + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapReferralsTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapReferralsTest.java new file mode 100644 index 00000000000..a635eea0a0f --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapReferralsTest.java @@ -0,0 +1,69 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import java.util.Map; +import javax.annotation.Nullable; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.api.config.Settings; +import org.sonar.auth.ldap.server.LdapServer; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LdapReferralsTest { + + @ClassRule + public static LdapServer server = new LdapServer("/users.example.org.ldif"); + + Map<String, LdapContextFactory> underTest; + + @Test + public void referral_is_set_to_follow_when_followReferrals_setting_is_set_to_true() { + underTest = createFactories("ldap.followReferrals", "true"); + + LdapContextFactory contextFactory = underTest.values().iterator().next(); + assertThat(contextFactory.getReferral()).isEqualTo("follow"); + } + + @Test + public void referral_is_set_to_ignore_when_followReferrals_setting_is_set_to_false() { + underTest = createFactories("ldap.followReferrals", "false"); + + LdapContextFactory contextFactory = underTest.values().iterator().next(); + assertThat(contextFactory.getReferral()).isEqualTo("ignore"); + } + + @Test + public void referral_is_set_to_follow_when_no_followReferrals_setting() { + underTest = createFactories(null, null); + + LdapContextFactory contextFactory = underTest.values().iterator().next(); + assertThat(contextFactory.getReferral()).isEqualTo("follow"); + } + + private static Map<String, LdapContextFactory> createFactories(@Nullable String propertyKey, @Nullable String propertyValue) { + Settings settings = LdapSettingsFactory.generateSimpleAnonymousAccessSettings(server, null); + if (propertyKey != null) { + settings.setProperty(propertyKey, propertyValue); + } + return new LdapSettingsManager(settings, new LdapAutodiscovery()).getContextFactories(); + } +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapSearchTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapSearchTest.java new file mode 100644 index 00000000000..d1b99d5169c --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapSearchTest.java @@ -0,0 +1,118 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Map; +import javax.naming.NamingException; +import javax.naming.directory.SearchControls; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.auth.ldap.server.LdapServer; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LdapSearchTest { + + @ClassRule + public static LdapServer server = new LdapServer("/users.example.org.ldif"); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private static Map<String, LdapContextFactory> contextFactories; + + @BeforeClass + public static void init() { + contextFactories = new LdapSettingsManager(LdapSettingsFactory.generateSimpleAnonymousAccessSettings(server, null), new LdapAutodiscovery()).getContextFactories(); + } + + @Test + public void subtreeSearch() throws Exception { + LdapSearch search = new LdapSearch(contextFactories.values().iterator().next()) + .setBaseDn("dc=example,dc=org") + .setRequest("(objectClass={0})") + .setParameters("inetOrgPerson") + .returns("objectClass"); + + assertThat(search.getBaseDn()).isEqualTo("dc=example,dc=org"); + assertThat(search.getScope()).isEqualTo(SearchControls.SUBTREE_SCOPE); + assertThat(search.getRequest()).isEqualTo("(objectClass={0})"); + assertThat(search.getParameters()).isEqualTo(new String[] {"inetOrgPerson"}); + assertThat(search.getReturningAttributes()).isEqualTo(new String[] {"objectClass"}); + assertThat(search.toString()).isEqualTo("LdapSearch{baseDn=dc=example,dc=org, scope=subtree, request=(objectClass={0}), parameters=[inetOrgPerson], attributes=[objectClass]}"); + assertThat(enumerationToArrayList(search.find()).size()).isEqualTo(3); + thrown.expect(NamingException.class); + thrown.expectMessage("Non unique result for " + search.toString()); + search.findUnique(); + } + + @Test + public void oneLevelSearch() throws Exception { + LdapSearch search = new LdapSearch(contextFactories.values().iterator().next()) + .setBaseDn("dc=example,dc=org") + .setScope(SearchControls.ONELEVEL_SCOPE) + .setRequest("(objectClass={0})") + .setParameters("inetOrgPerson") + .returns("cn"); + + assertThat(search.getBaseDn()).isEqualTo("dc=example,dc=org"); + assertThat(search.getScope()).isEqualTo(SearchControls.ONELEVEL_SCOPE); + assertThat(search.getRequest()).isEqualTo("(objectClass={0})"); + assertThat(search.getParameters()).isEqualTo(new String[] {"inetOrgPerson"}); + assertThat(search.getReturningAttributes()).isEqualTo(new String[] {"cn"}); + assertThat(search.toString()).isEqualTo("LdapSearch{baseDn=dc=example,dc=org, scope=onelevel, request=(objectClass={0}), parameters=[inetOrgPerson], attributes=[cn]}"); + assertThat(enumerationToArrayList(search.find()).size()).isEqualTo(0); + assertThat(search.findUnique()).isNull(); + } + + @Test + public void objectSearch() throws Exception { + LdapSearch search = new LdapSearch(contextFactories.values().iterator().next()) + .setBaseDn("cn=bind,ou=users,dc=example,dc=org") + .setScope(SearchControls.OBJECT_SCOPE) + .setRequest("(objectClass={0})") + .setParameters("uidObject") + .returns("uid"); + + assertThat(search.getBaseDn()).isEqualTo("cn=bind,ou=users,dc=example,dc=org"); + assertThat(search.getScope()).isEqualTo(SearchControls.OBJECT_SCOPE); + assertThat(search.getRequest()).isEqualTo("(objectClass={0})"); + assertThat(search.getParameters()).isEqualTo(new String[] {"uidObject"}); + assertThat(search.getReturningAttributes()).isEqualTo(new String[] {"uid"}); + assertThat(search.toString()).isEqualTo( + "LdapSearch{baseDn=cn=bind,ou=users,dc=example,dc=org, scope=object, request=(objectClass={0}), parameters=[uidObject], attributes=[uid]}"); + assertThat(enumerationToArrayList(search.find()).size()).isEqualTo(1); + assertThat(search.findUnique()).isNotNull(); + } + + private static <E> ArrayList<E> enumerationToArrayList(Enumeration<E> enumeration) { + ArrayList<E> result = new ArrayList<>(); + while (enumeration.hasMoreElements()) { + result.add(enumeration.nextElement()); + } + return result; + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapSettingsFactory.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapSettingsFactory.java new file mode 100644 index 00000000000..d08b3d8f407 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapSettingsFactory.java @@ -0,0 +1,95 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import javax.annotation.Nullable; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.auth.ldap.server.LdapServer; + +/** + * Create Settings for most used test cases. + */ +public class LdapSettingsFactory { + + /** + * Generate simple settings for 2 ldap servers that allows anonymous access. + * + * @return The specific settings. + */ + public static MapSettings generateSimpleAnonymousAccessSettings(LdapServer exampleServer, @Nullable LdapServer infosupportServer) { + MapSettings settings = new MapSettings(); + + if (infosupportServer != null) { + settings.setProperty("ldap.servers", "example,infosupport"); + + settings.setProperty("ldap.example.url", exampleServer.getUrl()) + .setProperty("ldap.example.user.baseDn", "ou=users,dc=example,dc=org") + .setProperty("ldap.example.group.baseDn", "ou=groups,dc=example,dc=org"); + settings.setProperty("ldap.infosupport.url", infosupportServer.getUrl()) + .setProperty("ldap.infosupport.user.baseDn", "ou=users,dc=infosupport,dc=com") + .setProperty("ldap.infosupport.group.baseDn", "ou=groups,dc=infosupport,dc=com"); + } else { + settings.setProperty("ldap.url", exampleServer.getUrl()) + .setProperty("ldap.user.baseDn", "ou=users,dc=example,dc=org") + .setProperty("ldap.group.baseDn", "ou=groups,dc=example,dc=org"); + } + return settings; + } + + /** + * Generate settings for 2 ldap servers. + * + * @param exampleServer The first ldap server. + * @param infosupportServer The second ldap server. + * @return The specific settings. + */ + public static MapSettings generateAuthenticationSettings(LdapServer exampleServer, @Nullable LdapServer infosupportServer, String authMethod) { + MapSettings settings = new MapSettings(); + + if (infosupportServer != null) { + settings.setProperty("ldap.servers", "example,infosupport"); + + settings.setProperty("ldap.example.url", exampleServer.getUrl()) + .setProperty("ldap.example.bindDn", LdapContextFactory.AUTH_METHOD_SIMPLE.equals(authMethod) ? "cn=bind,ou=users,dc=example,dc=org" : "bind") + .setProperty("ldap.example.bindPassword", "bindpassword") + .setProperty("ldap.example.authentication", authMethod) + .setProperty("ldap.example.realm", "example.org") + .setProperty("ldap.example.user.baseDn", "ou=users,dc=example,dc=org") + .setProperty("ldap.example.group.baseDn", "ou=groups,dc=example,dc=org"); + + settings.setProperty("ldap.infosupport.url", infosupportServer.getUrl()) + .setProperty("ldap.infosupport.bindDn", LdapContextFactory.AUTH_METHOD_SIMPLE.equals(authMethod) ? "cn=bind,ou=users,dc=infosupport,dc=com" : "bind") + .setProperty("ldap.infosupport.bindPassword", "bindpassword") + .setProperty("ldap.infosupport.authentication", authMethod) + .setProperty("ldap.infosupport.realm", "infosupport.com") + .setProperty("ldap.infosupport.user.baseDn", "ou=users,dc=infosupport,dc=com") + .setProperty("ldap.infosupport.group.baseDn", "ou=groups,dc=infosupport,dc=com"); + } else { + settings.setProperty("ldap.url", exampleServer.getUrl()) + .setProperty("ldap.bindDn", LdapContextFactory.AUTH_METHOD_SIMPLE.equals(authMethod) ? "cn=bind,ou=users,dc=example,dc=org" : "bind") + .setProperty("ldap.bindPassword", "bindpassword") + .setProperty("ldap.authentication", authMethod) + .setProperty("ldap.realm", "example.org") + .setProperty("ldap.user.baseDn", "ou=users,dc=example,dc=org") + .setProperty("ldap.group.baseDn", "ou=groups,dc=example,dc=org"); + } + return settings; + } +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapSettingsManagerTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapSettingsManagerTest.java new file mode 100644 index 00000000000..88d16dedec8 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapSettingsManagerTest.java @@ -0,0 +1,201 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import java.util.Arrays; +import java.util.Collections; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.config.Settings; +import org.sonar.api.config.internal.MapSettings; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.auth.ldap.LdapAutodiscovery.LdapSrvRecord; + +public class LdapSettingsManagerTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void shouldFailWhenNoLdapUrl() { + Settings settings = generateMultipleLdapSettingsWithUserAndGroupMapping(); + settings.removeProperty("ldap.example.url"); + LdapSettingsManager settingsManager = new LdapSettingsManager(settings, new LdapAutodiscovery()); + + thrown.expect(LdapException.class); + thrown.expectMessage("The property 'ldap.example.url' property is empty while it is mandatory."); + settingsManager.getContextFactories(); + } + + @Test + public void shouldFailWhenMixingSingleAndMultipleConfiguration() { + Settings settings = generateMultipleLdapSettingsWithUserAndGroupMapping(); + settings.setProperty("ldap.url", "ldap://foo"); + LdapSettingsManager settingsManager = new LdapSettingsManager(settings, new LdapAutodiscovery()); + + thrown.expect(LdapException.class); + thrown + .expectMessage( + "When defining multiple LDAP servers with the property 'ldap.servers', all LDAP properties must be linked to one of those servers. Please remove properties like 'ldap.url', 'ldap.realm', ..."); + settingsManager.getContextFactories(); + } + + @Test + public void testContextFactoriesWithSingleLdap() throws Exception { + LdapSettingsManager settingsManager = new LdapSettingsManager( + generateSingleLdapSettingsWithUserAndGroupMapping(), new LdapAutodiscovery()); + assertThat(settingsManager.getContextFactories().size()).isEqualTo(1); + } + + /** + * Test there are 2 @link{org.sonar.plugins.ldap.LdapContextFactory}s found. + * + * @throws Exception + * This is not expected. + */ + @Test + public void testContextFactoriesWithMultipleLdap() throws Exception { + LdapSettingsManager settingsManager = new LdapSettingsManager( + generateMultipleLdapSettingsWithUserAndGroupMapping(), new LdapAutodiscovery()); + assertThat(settingsManager.getContextFactories().size()).isEqualTo(2); + // We do it twice to make sure the settings keep the same. + assertThat(settingsManager.getContextFactories().size()).isEqualTo(2); + } + + @Test + public void testAutodiscover() throws Exception { + LdapAutodiscovery ldapAutodiscovery = mock(LdapAutodiscovery.class); + LdapSrvRecord ldap1 = new LdapSrvRecord("ldap://localhost:189", 1, 1); + LdapSrvRecord ldap2 = new LdapSrvRecord("ldap://localhost:1899", 1, 1); + when(ldapAutodiscovery.getLdapServers("example.org")).thenReturn(Arrays.asList(ldap1, ldap2)); + LdapSettingsManager settingsManager = new LdapSettingsManager( + generateAutodiscoverSettings(), ldapAutodiscovery); + assertThat(settingsManager.getContextFactories().size()).isEqualTo(2); + } + + @Test + public void testAutodiscoverFailed() throws Exception { + LdapAutodiscovery ldapAutodiscovery = mock(LdapAutodiscovery.class); + when(ldapAutodiscovery.getLdapServers("example.org")).thenReturn(Collections.<LdapSrvRecord>emptyList()); + LdapSettingsManager settingsManager = new LdapSettingsManager( + generateAutodiscoverSettings(), ldapAutodiscovery); + + thrown.expect(LdapException.class); + thrown.expectMessage("The property 'ldap.url' is empty and SonarQube is not able to auto-discover any LDAP server."); + + settingsManager.getContextFactories(); + } + + /** + * Test there are 2 @link{org.sonar.plugins.ldap.LdapUserMapping}s found. + * + * @throws Exception + * This is not expected. + */ + @Test + public void testUserMappings() throws Exception { + LdapSettingsManager settingsManager = new LdapSettingsManager( + generateMultipleLdapSettingsWithUserAndGroupMapping(), new LdapAutodiscovery()); + assertThat(settingsManager.getUserMappings().size()).isEqualTo(2); + // We do it twice to make sure the settings keep the same. + assertThat(settingsManager.getUserMappings().size()).isEqualTo(2); + } + + /** + * Test there are 2 @link{org.sonar.plugins.ldap.LdapGroupMapping}s found. + * + * @throws Exception + * This is not expected. + */ + @Test + public void testGroupMappings() throws Exception { + LdapSettingsManager settingsManager = new LdapSettingsManager( + generateMultipleLdapSettingsWithUserAndGroupMapping(), new LdapAutodiscovery()); + assertThat(settingsManager.getGroupMappings().size()).isEqualTo(2); + // We do it twice to make sure the settings keep the same. + assertThat(settingsManager.getGroupMappings().size()).isEqualTo(2); + } + + /** + * Test what happens when no configuration is set. + * Normally there will be a contextFactory, but the autodiscovery doesn't work for the test server. + * @throws Exception + */ + @Test + public void testEmptySettings() throws Exception { + LdapSettingsManager settingsManager = new LdapSettingsManager( + new MapSettings(), new LdapAutodiscovery()); + + thrown.expect(LdapException.class); + thrown.expectMessage("The property 'ldap.url' is empty and no realm configured to try auto-discovery."); + settingsManager.getContextFactories(); + } + + private MapSettings generateMultipleLdapSettingsWithUserAndGroupMapping() { + MapSettings settings = new MapSettings(); + + settings.setProperty("ldap.servers", "example,infosupport"); + + settings.setProperty("ldap.example.url", "/users.example.org.ldif") + .setProperty("ldap.example.user.baseDn", "ou=users,dc=example,dc=org") + .setProperty("ldap.example.group.baseDn", "ou=groups,dc=example,dc=org") + .setProperty("ldap.example.group.request", + "(&(objectClass=posixGroup)(memberUid={uid}))"); + + settings.setProperty("ldap.infosupport.url", "/users.infosupport.com.ldif") + .setProperty("ldap.infosupport.user.baseDn", + "ou=users,dc=infosupport,dc=com") + .setProperty("ldap.infosupport.group.baseDn", + "ou=groups,dc=infosupport,dc=com") + .setProperty("ldap.infosupport.group.request", + "(&(objectClass=posixGroup)(memberUid={uid}))"); + + return settings; + } + + private MapSettings generateSingleLdapSettingsWithUserAndGroupMapping() { + MapSettings settings = new MapSettings(); + + settings.setProperty("ldap.url", "/users.example.org.ldif") + .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=posixGroup)(memberUid={uid}))"); + + return settings; + } + + private MapSettings generateAutodiscoverSettings() { + MapSettings settings = new MapSettings(); + + settings.setProperty("ldap.realm", "example.org") + .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=posixGroup)(memberUid={uid}))"); + + return settings; + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapUserMappingTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapUserMappingTest.java new file mode 100644 index 00000000000..f0f1876e917 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapUserMappingTest.java @@ -0,0 +1,76 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import org.junit.Test; +import org.sonar.api.config.internal.MapSettings; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LdapUserMappingTest { + + @Test + public void defaults() { + LdapUserMapping userMapping = new LdapUserMapping(new MapSettings(), "ldap"); + assertThat(userMapping.getBaseDn()).isNull(); + assertThat(userMapping.getRequest()).isEqualTo("(&(objectClass=inetOrgPerson)(uid={0}))"); + assertThat(userMapping.getRealNameAttribute()).isEqualTo("cn"); + assertThat(userMapping.getEmailAttribute()).isEqualTo("mail"); + + assertThat(userMapping.toString()).isEqualTo("LdapUserMapping{" + + "baseDn=null," + + " request=(&(objectClass=inetOrgPerson)(uid={0}))," + + " realNameAttribute=cn," + + " emailAttribute=mail}"); + } + + @Test + public void activeDirectory() { + MapSettings settings = new MapSettings() + .setProperty("ldap.user.baseDn", "cn=users") + .setProperty("ldap.user.objectClass", "user") + .setProperty("ldap.user.loginAttribute", "sAMAccountName"); + + LdapUserMapping userMapping = new LdapUserMapping(settings, "ldap"); + LdapSearch search = userMapping.createSearch(null, "tester"); + assertThat(search.getBaseDn()).isEqualTo("cn=users"); + assertThat(search.getRequest()).isEqualTo("(&(objectClass=user)(sAMAccountName={0}))"); + assertThat(search.getParameters()).isEqualTo(new String[] {"tester"}); + assertThat(search.getReturningAttributes()).isNull(); + + assertThat(userMapping.toString()).isEqualTo("LdapUserMapping{" + + "baseDn=cn=users," + + " request=(&(objectClass=user)(sAMAccountName={0}))," + + " realNameAttribute=cn," + + " emailAttribute=mail}"); + } + + @Test + public void realm() { + MapSettings settings = new MapSettings() + .setProperty("ldap.realm", "example.org") + .setProperty("ldap.userObjectClass", "user") + .setProperty("ldap.loginAttribute", "sAMAccountName"); + + LdapUserMapping userMapping = new LdapUserMapping(settings, "ldap"); + assertThat(userMapping.getBaseDn()).isEqualTo("dc=example,dc=org"); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapUsersProviderTest.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapUsersProviderTest.java new file mode 100644 index 00000000000..90e61e59fea --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapUsersProviderTest.java @@ -0,0 +1,77 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap; + +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.api.config.Settings; +import org.sonar.api.security.UserDetails; +import org.sonar.auth.ldap.server.LdapServer; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LdapUsersProviderTest { + /** + * A reference to the original ldif file + */ + public static final String USERS_EXAMPLE_ORG_LDIF = "/users.example.org.ldif"; + /** + * A reference to an aditional ldif file. + */ + public static final String USERS_INFOSUPPORT_COM_LDIF = "/users.infosupport.com.ldif"; + + @ClassRule + public static LdapServer exampleServer = new LdapServer(USERS_EXAMPLE_ORG_LDIF); + @ClassRule + public static LdapServer infosupportServer = new LdapServer(USERS_INFOSUPPORT_COM_LDIF, "infosupport.com", "dc=infosupport,dc=com"); + + @Test + public void test() throws Exception { + Settings settings = LdapSettingsFactory.generateSimpleAnonymousAccessSettings(exampleServer, infosupportServer); + LdapSettingsManager settingsManager = new LdapSettingsManager(settings, new LdapAutodiscovery()); + LdapUsersProvider usersProvider = new LdapUsersProvider(settingsManager.getContextFactories(), settingsManager.getUserMappings()); + + UserDetails details; + + details = usersProvider.getUserDetails("godin"); + assertThat(details.getName()).isEqualTo("Evgeny Mandrikov"); + assertThat(details.getEmail()).isEqualTo("godin@example.org"); + + details = usersProvider.getUserDetails("tester"); + assertThat(details.getName()).isEqualTo("Tester Testerovich"); + assertThat(details.getEmail()).isEqualTo("tester@example.org"); + + details = usersProvider.getUserDetails("without_email"); + assertThat(details.getName()).isEqualTo("Without Email"); + assertThat(details.getEmail()).isEqualTo(""); + + details = usersProvider.getUserDetails("notfound"); + assertThat(details).isNull(); + + details = usersProvider.getUserDetails("robby"); + assertThat(details.getName()).isEqualTo("Robby Developer"); + assertThat(details.getEmail()).isEqualTo("rd@infosupport.com"); + + details = usersProvider.getUserDetails("testerInfo"); + assertThat(details.getName()).isEqualTo("Tester Testerovich"); + assertThat(details.getEmail()).isEqualTo("tester@infosupport.com"); + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/server/ApacheDS.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/server/ApacheDS.java new file mode 100644 index 00000000000..6f2f1f4d66f --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/server/ApacheDS.java @@ -0,0 +1,234 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap.server; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms; +import org.apache.directory.api.ldap.model.entry.DefaultEntry; +import org.apache.directory.api.ldap.model.entry.DefaultModification; +import org.apache.directory.api.ldap.model.entry.ModificationOperation; +import org.apache.directory.api.ldap.model.exception.LdapOperationException; +import org.apache.directory.api.ldap.model.ldif.ChangeType; +import org.apache.directory.api.ldap.model.ldif.LdifEntry; +import org.apache.directory.api.ldap.model.ldif.LdifReader; +import org.apache.directory.api.ldap.model.name.Dn; +import org.apache.directory.api.util.FileUtils; +import org.apache.directory.server.core.api.CoreSession; +import org.apache.directory.server.core.api.DirectoryService; +import org.apache.directory.server.core.api.InstanceLayout; +import org.apache.directory.server.core.factory.DefaultDirectoryServiceFactory; +import org.apache.directory.server.core.kerberos.KeyDerivationInterceptor; +import org.apache.directory.server.core.partition.impl.avl.AvlPartition; +import org.apache.directory.server.kerberos.KerberosConfig; +import org.apache.directory.server.kerberos.kdc.KdcServer; +import org.apache.directory.server.ldap.handlers.sasl.MechanismHandler; +import org.apache.directory.server.ldap.handlers.sasl.cramMD5.CramMd5MechanismHandler; +import org.apache.directory.server.ldap.handlers.sasl.digestMD5.DigestMd5MechanismHandler; +import org.apache.directory.server.ldap.handlers.sasl.gssapi.GssapiMechanismHandler; +import org.apache.directory.server.ldap.handlers.sasl.plain.PlainMechanismHandler; +import org.apache.directory.server.protocol.shared.transport.TcpTransport; +import org.apache.directory.server.protocol.shared.transport.UdpTransport; +import org.apache.directory.server.xdbm.impl.avl.AvlIndex; +import org.apache.mina.util.AvailablePortFinder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class ApacheDS { + + private static final Logger LOG = LoggerFactory.getLogger(ApacheDS.class); + + private final String realm; + private final String baseDn; + + private DirectoryService directoryService; + private org.apache.directory.server.ldap.LdapServer ldapServer; + private KdcServer kdcServer; + + private ApacheDS(String realm, String baseDn) { + this.realm = realm; + this.baseDn = baseDn; + ldapServer = new org.apache.directory.server.ldap.LdapServer(); + } + + public static ApacheDS start(String realm, String baseDn, String workDir) throws Exception { + return start(realm, baseDn, workDir + realm, null); + } + + static ApacheDS start(String realm, String baseDn) throws Exception { + return start(realm, baseDn, "target/ldap-work/" + realm, null); + } + + private static ApacheDS start(String realm, String baseDn, String workDir, Integer port) throws Exception { + return new ApacheDS(realm, baseDn) + .startDirectoryService(workDir) + .startKdcServer() + .startLdapServer(port == null ? AvailablePortFinder.getNextAvailable(1024) : port) + .activateNis(); + } + + void stop() throws Exception { + kdcServer.stop(); + kdcServer = null; + ldapServer.stop(); + ldapServer = null; + directoryService.shutdown(); + directoryService = null; + } + + public String getUrl() { + return "ldap://localhost:" + ldapServer.getPort(); + } + + /** + * Stream will be closed automatically. + */ + public void importLdif(InputStream is) throws Exception { + try (LdifReader reader = new LdifReader(is)) { + CoreSession coreSession = directoryService.getAdminSession(); + // see LdifFileLoader + for (LdifEntry ldifEntry : reader) { + String ldif = ldifEntry.toString(); + LOG.info(ldif); + if (ChangeType.Add == ldifEntry.getChangeType() || /* assume "add" by default */ ChangeType.None == ldifEntry.getChangeType()) { + coreSession.add(new DefaultEntry(coreSession.getDirectoryService().getSchemaManager(), ldifEntry.getEntry())); + } else if (ChangeType.Modify == ldifEntry.getChangeType()) { + coreSession.modify(ldifEntry.getDn(), ldifEntry.getModifications()); + } else if (ChangeType.Delete == ldifEntry.getChangeType()) { + coreSession.delete(ldifEntry.getDn()); + } else { + throw new IllegalStateException(); + } + } + } + } + + void disableAnonymousAccess() { + directoryService.setAllowAnonymousAccess(false); + } + + void enableAnonymousAccess() { + directoryService.setAllowAnonymousAccess(true); + } + + private ApacheDS startDirectoryService(String workDirStr) throws Exception { + DefaultDirectoryServiceFactory factory = new DefaultDirectoryServiceFactory(); + factory.init(realm); + + directoryService = factory.getDirectoryService(); + directoryService.getChangeLog().setEnabled(false); + directoryService.setShutdownHookEnabled(false); + directoryService.setAllowAnonymousAccess(true); + + File workDir = new File(workDirStr); + if (workDir.exists()) { + FileUtils.deleteDirectory(workDir); + } + InstanceLayout instanceLayout = new InstanceLayout(workDir); + directoryService.setInstanceLayout(instanceLayout); + + AvlPartition partition = new AvlPartition(directoryService.getSchemaManager()); + partition.setId("Test"); + partition.setSuffixDn(new Dn(directoryService.getSchemaManager(), baseDn)); + partition.addIndexedAttributes( + new AvlIndex<>("ou"), + new AvlIndex<>("uid"), + new AvlIndex<>("dc"), + new AvlIndex<>("objectClass")); + partition.initialize(); + directoryService.addPartition(partition); + directoryService.addLast(new KeyDerivationInterceptor()); + + directoryService.shutdown(); + directoryService.startup(); + + return this; + } + + private ApacheDS startLdapServer(int port) throws Exception { + ldapServer.setTransports(new TcpTransport(port)); + ldapServer.setDirectoryService(directoryService); + + // Setup SASL mechanisms + Map<String, MechanismHandler> mechanismHandlerMap = new HashMap<>(); + mechanismHandlerMap.put(SupportedSaslMechanisms.PLAIN, new PlainMechanismHandler()); + mechanismHandlerMap.put(SupportedSaslMechanisms.CRAM_MD5, new CramMd5MechanismHandler()); + mechanismHandlerMap.put(SupportedSaslMechanisms.DIGEST_MD5, new DigestMd5MechanismHandler()); + mechanismHandlerMap.put(SupportedSaslMechanisms.GSSAPI, new GssapiMechanismHandler()); + ldapServer.setSaslMechanismHandlers(mechanismHandlerMap); + + ldapServer.setSaslHost("localhost"); + ldapServer.setSaslRealms(Collections.singletonList(realm)); + // TODO ldapServer.setSaslPrincipal(); + // The base DN containing users that can be SASL authenticated. + ldapServer.setSearchBaseDn(baseDn); + + ldapServer.start(); + + return this; + } + + private ApacheDS startKdcServer() throws IOException, LdapOperationException { + int port = AvailablePortFinder.getNextAvailable(6088); + + KerberosConfig kdcConfig = new KerberosConfig(); + kdcConfig.setServicePrincipal("krbtgt/EXAMPLE.ORG@EXAMPLE.ORG"); + kdcConfig.setPrimaryRealm("EXAMPLE.ORG"); + kdcConfig.setPaEncTimestampRequired(false); + + kdcServer = new KdcServer(kdcConfig); + kdcServer.setSearchBaseDn("dc=example,dc=org"); + kdcServer.addTransports(new UdpTransport("localhost", port)); + kdcServer.setDirectoryService(directoryService); + kdcServer.start(); + + FileUtils.writeStringToFile(new File("target/krb5.conf"), "" + + "[libdefaults]\n" + + " default_realm = EXAMPLE.ORG\n" + + "\n" + + "[realms]\n" + + " EXAMPLE.ORG = {\n" + + " kdc = localhost:" + port + "\n" + + " }\n" + + "\n" + + "[domain_realm]\n" + + " .example.org = EXAMPLE.ORG\n" + + " example.org = EXAMPLE.ORG\n", + StandardCharsets.UTF_8.name()); + + return this; + } + + /** + * This seems to be required for objectClass posixGroup. + */ + private ApacheDS activateNis() throws Exception { + directoryService.getAdminSession().modify( + new Dn("cn=nis,ou=schema"), + new DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE, "m-disabled", "FALSE")); + return this; + } + +} diff --git a/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/server/LdapServer.java b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/server/LdapServer.java new file mode 100644 index 00000000000..6539ac5a662 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/server/LdapServer.java @@ -0,0 +1,68 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.auth.ldap.server; + +import org.junit.rules.ExternalResource; + +public class LdapServer extends ExternalResource { + + private ApacheDS server; + private String ldif; + private final String realm; + private final String baseDn; + + public LdapServer(String ldifResourceName) { + this(ldifResourceName, "example.org", "dc=example,dc=org"); + } + + public LdapServer(String ldifResourceName, String realm, String baseDn) { + this.ldif = ldifResourceName; + this.realm = realm; + this.baseDn = baseDn; + } + + @Override + protected void before() throws Throwable { + server = ApacheDS.start(realm, baseDn); + server.importLdif(LdapServer.class.getResourceAsStream(ldif)); + } + + @Override + protected void after() { + try { + server.stop(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + public String getUrl() { + return server.getUrl(); + } + + public void disableAnonymousAccess() { + server.disableAnonymousAccess(); + } + + public void enableAnonymousAccess() { + server.enableAnonymousAccess(); + } + +} diff --git a/server/sonar-auth-ldap/src/test/resources/conf/krb5.conf b/server/sonar-auth-ldap/src/test/resources/conf/krb5.conf new file mode 100644 index 00000000000..04fd9f9423a --- /dev/null +++ b/server/sonar-auth-ldap/src/test/resources/conf/krb5.conf @@ -0,0 +1,20 @@ +[libdefaults] + default_realm = EXAMPLE.ORG + +[realms] + EXAMPLE.ORG = { + kdc = localhost:6088 + } + INFOSUPPORT.COM = { + kdc = localhost:6089 + } + +[domain_realm] + .example.org = EXAMPLE.ORG + example.org = EXAMPLE.ORG + .infosupport.com = INFOSUPPORT.COM + infosupport.com = INFOSUPPORT.COM + +[login] + krb4_convert = true + krb4_get_tickets = false diff --git a/server/sonar-auth-ldap/src/test/resources/conf/sasl_mech.properties b/server/sonar-auth-ldap/src/test/resources/conf/sasl_mech.properties new file mode 100644 index 00000000000..f3d209e335c --- /dev/null +++ b/server/sonar-auth-ldap/src/test/resources/conf/sasl_mech.properties @@ -0,0 +1,23 @@ +# +# SonarQube +# Copyright (C) 2009-2019 SonarSource SA +# mailto:info AT sonarsource DOT com +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +ldap.url:ldap://localhost:1024 +# TODO don't work as expected +ldap.authentication:DIGEST-MD5 CRAM-MD5 +#ldap.realm: example.org diff --git a/server/sonar-auth-ldap/src/test/resources/krb.ldif b/server/sonar-auth-ldap/src/test/resources/krb.ldif new file mode 100644 index 00000000000..6c8235dc91e --- /dev/null +++ b/server/sonar-auth-ldap/src/test/resources/krb.ldif @@ -0,0 +1,55 @@ +dn: dc=example,dc=org +dc: example +objectClass: domain +objectClass: top + +dn: ou=Users,dc=example,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Users + +dn: uid=krbtgt,ou=Users,dc=example,dc=org +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: KDC Service +sn: Service +uid: krbtgt +userPassword: secret +krb5PrincipalName: krbtgt/EXAMPLE.ORG@EXAMPLE.ORG +krb5KeyVersionNumber: 0 + +dn: cn=SonarQube,ou=Users,dc=example,dc=org +objectClass: top +objectClass: organizationalRole +objectClass: simpleSecurityObject +objectClass: krb5principal +objectClass: krb5kdcentry +cn: SonarQube +userPassword: bind_password +krb5PrincipalName: SonarQube@EXAMPLE.ORG +krb5KeyVersionNumber: 0 + +dn: uid=godin,ou=Users,dc=example,dc=org +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: Evgeny Mandrikov +sn: Mandrikov +uid: godin +userPassword: user_password +krb5PrincipalName: Godin@EXAMPLE.ORG +krb5KeyVersionNumber: 0 + +dn: ou=Groups,dc=example,dc=org +objectclass:organizationalunit +ou: groups + +dn: cn=sonar-users,ou=Groups,dc=example,dc=org +objectclass: groupOfUniqueNames +cn: sonar-users +uniqueMember: uid=godin,ou=Users,dc=example,dc=org diff --git a/server/sonar-auth-ldap/src/test/resources/logback-test.xml b/server/sonar-auth-ldap/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..cc9519d939a --- /dev/null +++ b/server/sonar-auth-ldap/src/test/resources/logback-test.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + ~ SonarQube + ~ Copyright (C) 2009-2019 SonarSource SA + ~ mailto:info AT sonarsource DOT com + ~ + ~ This program is free software; you can redistribute it and/or + ~ modify it under the terms of the GNU Lesser General Public + ~ License as published by the Free Software Foundation; either + ~ version 3 of the License, or (at your option) any later version. + ~ + ~ This program is distributed in the hope that it will be useful, + ~ but WITHOUT ANY WARRANTY; without even the implied warranty of + ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + ~ Lesser General Public License for more details. + ~ + ~ You should have received a copy of the GNU Lesser General Public License + ~ along with this program; if not, write to the Free Software Foundation, + ~ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + --> + +<configuration> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern> + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + </pattern> + </encoder> + </appender> + + <logger name="org.sonar"> + <level value="DEBUG"/> + </logger> + + <logger name="org.apache.directory"> + <level value="ERROR"/> + </logger> + + <root> + <level value="INFO"/> + <appender-ref ref="STDOUT"/> + </root> + +</configuration> diff --git a/server/sonar-auth-ldap/src/test/resources/static-groups.example.org.ldif b/server/sonar-auth-ldap/src/test/resources/static-groups.example.org.ldif new file mode 100644 index 00000000000..857efc7c508 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/resources/static-groups.example.org.ldif @@ -0,0 +1,81 @@ +dn: dc=example,dc=org +objectClass: domain +objectClass: extensibleObject +objectClass: top +dc: example + +# +# USERS +# + +dn: ou=users,dc=example,dc=org +objectClass: organizationalUnit +objectClass: top +ou: users + +# Bind user +dn: cn=bind,ou=users,dc=example,dc=org +objectClass: organizationalRole +objectClass: simpleSecurityObject +objectClass: top +cn: bind +userpassword: bindpassword + +# Typical user +dn: cn=Evgeny Mandrikov,ou=users,dc=example,dc=org +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +cn: Evgeny Mandrikov +sn: Mandrikov +givenname: Evgeny +mail: godin@example.org +uid: godin +userpassword: secret1 + +# Just one more user +dn: cn=Tester Testerovich,ou=users,dc=example,dc=org +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +cn: Tester Testerovich +givenname: Tester +sn: Testerovich +mail: tester@example.org +uid: tester +userpassword: secret2 + +# +# GROUPS +# + +dn: ou=groups,dc=example,dc=org +objectclass:organizationalunit +ou: groups + +# sonar-users +dn: cn=sonar-users,ou=groups,dc=example,dc=org +objectclass: groupOfUniqueNames +cn: sonar-users +uniqueMember: cn=Tester Testerovich,ou=users,dc=example,dc=org +uniqueMember: cn=Evgeny Mandrikov,ou=users,dc=example,dc=org + +# sonar-developers +dn: cn=sonar-developers,ou=groups,dc=example,dc=org +objectclass: groupOfUniqueNames +cn: sonar-developers +uniqueMember: cn=Evgeny Mandrikov,ou=users,dc=example,dc=org + +# linux-users +dn: cn=linux-users,ou=groups,dc=example,dc=org +objectclass: posixGroup +objectclass: top +cn: linux-users +gidNumber: 10000 +memberUid: godin diff --git a/server/sonar-auth-ldap/src/test/resources/users-apacheds.ldif b/server/sonar-auth-ldap/src/test/resources/users-apacheds.ldif new file mode 100644 index 00000000000..d0231512459 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/resources/users-apacheds.ldif @@ -0,0 +1,88 @@ +dn: dc=example,dc=org +objectClass: domain +objectClass: extensibleObject +objectClass: top +dc: example + +# +# USERS +# + +dn: ou=users,dc=example,dc=org +objectClass: organizationalUnit +objectClass: top +ou: users + +dn: cn=bind,ou=users,dc=example,dc=org +objectClass: organizationalRole +objectClass: uidObject +objectClass: simpleSecurityObject +objectClass: top +cn: bind +uid: sonar +userpassword: bindpassword + +dn: cn=Evgeny Mandrikov,ou=users,dc=example,dc=org +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +objectClass: krb5principal +objectClass: krb5kdcentry +cn: Evgeny Mandrikov +givenname: Evgeny +mail: godin@example.org +sn: Mandrikov +uid: godin +userpassword: secret1 +krb5PrincipalName: godin@EXAMPLE.ORG +krb5KeyVersionNumber: 0 + +dn: cn=Tester Testerovich,ou=users,dc=example,dc=org +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +objectClass: krb5principal +objectClass: krb5kdcentry +cn: Tester Testerovich +givenname: Tester +mail: tester@example.org +sn: Testerovich +uid: tester +userpassword: secret2 +krb5PrincipalName: tester@EXAMPLE.ORG +krb5KeyVersionNumber: 0 + +#### +# For Krb5 +#### +dn: uid=krbtgt,ou=users,dc=example,dc=org +objectClass: person +objectClass: inetOrgPerson +objectClass: top +objectClass: krb5principal +objectClass: krb5kdcentry +sn: Service +cn: KDC Service +uid: krbtgt +userPassword: secret +krb5PrincipalName: krbtgt/EXAMPLE.ORG@EXAMPLE.ORG +krb5KeyVersionNumber: 0 + +dn: uid=ldap,ou=users,dc=example,dc=org +objectClass: person +objectClass: inetOrgPerson +objectClass: top +objectClass: krb5principal +objectClass: krb5kdcentry +sn: Service +cn: LDAP Service +uid: ldap +userPassword: randall +krb5PrincipalName: ldap/localhost@EXAMPLE.COM +krb5KeyVersionNumber: 0 diff --git a/server/sonar-auth-ldap/src/test/resources/users.example.org.ldif b/server/sonar-auth-ldap/src/test/resources/users.example.org.ldif new file mode 100644 index 00000000000..3dc462afbb0 --- /dev/null +++ b/server/sonar-auth-ldap/src/test/resources/users.example.org.ldif @@ -0,0 +1,98 @@ +dn: dc=example,dc=org +objectClass: domain +objectClass: extensibleObject +objectClass: top +dc: example + +# +# USERS +# + +dn: ou=users,dc=example,dc=org +objectClass: organizationalUnit +objectClass: top +ou: users + +# Bind user +dn: cn=bind,ou=users,dc=example,dc=org +objectClass: organizationalRole +objectClass: uidObject +objectClass: simpleSecurityObject +objectClass: top +cn: bind +uid: sonar +userpassword: bindpassword + +# Typical user +dn: cn=Evgeny Mandrikov,ou=users,dc=example,dc=org +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +cn: Evgeny Mandrikov +givenname: Evgeny +sn: Mandrikov +mail: godin@example.org +uid: godin +userpassword: secret1 + +# Just one more user +dn: cn=Tester Testerovich,ou=users,dc=example,dc=org +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +cn: Tester Testerovich +givenname: Tester +sn: Testerovich +mail: tester@example.org +uid: tester +userpassword: secret2 + +# Special case which can cause NPE +dn: cn=Without Email,ou=users,dc=example,dc=org +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +cn: Without Email +givenname: Without +sn: Email +uid: without_email +userpassword: secret3 + + +# +# GROUPS +# + +dn: ou=groups,dc=example,dc=org +objectclass:organizationalunit +ou: groups + +# sonar-users +dn: cn=sonar-users,ou=groups,dc=example,dc=org +objectclass: groupOfUniqueNames +cn: sonar-users +uniqueMember: cn=Tester Testerovich,ou=users,dc=example,dc=org +uniqueMember: cn=Evgeny Mandrikov,ou=users,dc=example,dc=org + +# sonar-developers +dn: cn=sonar-developers,ou=groups,dc=example,dc=org +objectclass: groupOfUniqueNames +cn: sonar-developers +uniqueMember: cn=Evgeny Mandrikov,ou=users,dc=example,dc=org + +# linux-users +dn: cn=linux-users,ou=groups,dc=example,dc=org +objectclass: posixGroup +objectclass: top +cn: linux-users +gidNumber: 10000 +memberUid: godin
\ No newline at end of file diff --git a/server/sonar-auth-ldap/src/test/resources/users.infosupport.com.ldif b/server/sonar-auth-ldap/src/test/resources/users.infosupport.com.ldif new file mode 100644 index 00000000000..a08174bf72b --- /dev/null +++ b/server/sonar-auth-ldap/src/test/resources/users.infosupport.com.ldif @@ -0,0 +1,98 @@ +dn: dc=infosupport,dc=com +objectClass: domain +objectClass: extensibleObject +objectClass: top +dc: infosupport + +# +# USERS +# + +dn: ou=users,dc=infosupport,dc=com +objectClass: organizationalUnit +objectClass: top +ou: users + +# Bind user +dn: cn=bind,ou=users,dc=infosupport,dc=com +objectClass: organizationalRole +objectClass: uidObject +objectClass: simpleSecurityObject +objectClass: top +cn: bind +uid: sonar +userpassword: bindpassword + +# Typical user +dn: cn=Robby Developer,ou=users,dc=infosupport,dc=com +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +cn: Robby Developer +givenname: Robby +sn: Developer +mail: rd@infosupport.com +uid: robby +userpassword: secret1 + +# Just one more user +dn: cn=Tester Testerovich,ou=users,dc=infosupport,dc=com +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +cn: Tester Testerovich +givenname: Tester +sn: Testerovich +mail: tester@infosupport.com +uid: testerInfo +userpassword: secret2 + +# Special case which can cause NPE +dn: cn=Without Email,ou=users,dc=infosupport,dc=com +objectClass: organizationalPerson +objectClass: person +objectClass: extensibleObject +objectClass: uidObject +objectClass: inetOrgPerson +objectClass: top +cn: Without Email +givenname: Without +sn: Email +uid: without_email +userpassword: secret3 + + +# +# GROUPS +# + +dn: ou=groups,dc=infosupport,dc=com +objectclass:organizationalunit +ou: groups + +# sonar-users +dn: cn=sonar-users,ou=groups,dc=infosupport,dc=com +objectclass: groupOfUniqueNames +cn: sonar-users +uniqueMember: cn=Robby Developer,ou=users,dc=infosupport,dc=com +uniqueMember: cn=Tester Testerovich,ou=users,dc=infosupport,dc=com + +# sonar-developers +dn: cn=sonar-developers,ou=groups,dc=infosupport,dc=com +objectclass: groupOfUniqueNames +cn: sonar-developers +uniqueMember: cn=Robby Developer,ou=users,dc=infosupport,dc=com + +# linux-users +dn: cn=linux-users,ou=groups,dc=infosupport,dc=com +objectclass: posixGroup +objectclass: top +cn: linux-users +gidNumber: 10000 +memberUid: robby
\ No newline at end of file |