diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2015-12-16 12:18:46 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-02-11 12:20:48 +0100 |
commit | 1d06608dbe0e02ce8ab12bf2116d7e6ae36d4657 (patch) | |
tree | eb500577cc95f1bb86ff5e293ecc159ea908bbd0 /it/it-plugins | |
parent | 393a139c493e8a58d3e52cbc0a5d27faf8b9c3bb (diff) | |
download | sonarqube-1d06608dbe0e02ce8ab12bf2116d7e6ae36d4657.tar.gz sonarqube-1d06608dbe0e02ce8ab12bf2116d7e6ae36d4657.zip |
Move ExternalAuthenticationTest ITs
Diffstat (limited to 'it/it-plugins')
8 files changed, 494 insertions, 0 deletions
diff --git a/it/it-plugins/pom.xml b/it/it-plugins/pom.xml index 9dd4d8459da..fa1df6e5231 100644 --- a/it/it-plugins/pom.xml +++ b/it/it-plugins/pom.xml @@ -42,6 +42,7 @@ <module>project-builder-plugin</module> <module>property-relocation-plugin</module> <module>property-sets-plugin</module> + <module>security-plugin</module> <module>server-plugin</module> <module>settings-encryption-plugin</module> <module>settings-plugin</module> diff --git a/it/it-plugins/security-plugin/pom.xml b/it/it-plugins/security-plugin/pom.xml new file mode 100644 index 00000000000..2243869854b --- /dev/null +++ b/it/it-plugins/security-plugin/pom.xml @@ -0,0 +1,59 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.sonarsource.sonarqube</groupId> + <artifactId>it-plugins</artifactId> + <version>5.5-SNAPSHOT</version> + </parent> + + <artifactId>security-plugin</artifactId> + <packaging>sonar-plugin</packaging> + <version>1.0-SNAPSHOT</version> + <description>Plugins :: Security</description> + + <dependencies> + <dependency> + <groupId>org.sonarsource.sonarqube</groupId> + <artifactId>sonar-plugin-api</artifactId> + <version>${apiVersion}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.6</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>2.0.0</version> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-guava</artifactId> + <version>1.3.1</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> + <artifactId>sonar-packaging-maven-plugin</artifactId> + <version>1.15</version> + <extensions>true</extensions> + <configuration> + <pluginClass>SecurityPlugin</pluginClass> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/it/it-plugins/security-plugin/src/main/java/FakeAuthenticator.java b/it/it-plugins/security-plugin/src/main/java/FakeAuthenticator.java new file mode 100644 index 00000000000..6455d260b89 --- /dev/null +++ b/it/it-plugins/security-plugin/src/main/java/FakeAuthenticator.java @@ -0,0 +1,157 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.Properties; +import org.sonar.api.Property; +import org.sonar.api.PropertyType; +import org.sonar.api.config.Settings; +import org.sonar.api.security.LoginPasswordAuthenticator; +import org.sonar.api.security.UserDetails; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; + +@Properties({ + @Property( + key = FakeAuthenticator.DATA_PROPERTY, + name = "Fake Users", type = PropertyType.TEXT + ) +}) +public class FakeAuthenticator implements LoginPasswordAuthenticator { + + private static final Logger LOG = Loggers.get(FakeAuthenticator.class); + + /** + * Example: + * <pre> + * evgeny.password=foo + * evgeny.name=Evgeny Mandrikov + * evgeny.email=evgeny@example.org + * evgeny.groups=sonar-users + * + * simon.password=bar + * simon.groups=sonar-users,sonar-developers + * </pre> + */ + public static final String DATA_PROPERTY = "sonar.fakeauthenticator.users"; + + private final Settings settings; + + private Map<String, String> data; + + public FakeAuthenticator(Settings settings) { + this.settings = settings; + } + + public boolean authenticate(String username, String password) { + // Never touch admin + if (isAdmin(username)) { + return true; + } + + reloadData(); + checkExistence(username); + + String expectedPassword = data.get(username + ".password"); + if (StringUtils.equals(password, expectedPassword)) { + LOG.info("user {} with password {}", username, password); + return true; + } else { + LOG.info("user " + username + " expected password " + expectedPassword + " , but was " + password); + return false; + } + } + + private void checkExistence(String username) { + if (!data.containsKey(username + ".password")) { + throw new RuntimeException("No such user"); + } + } + + public UserDetails doGetUserDetails(String username) { + // Never touch admin + if (isAdmin(username)) { + return null; + } + + reloadData(); + checkExistence(username); + + UserDetails result = new UserDetails(); + result.setName(Strings.nullToEmpty(data.get(username + ".name"))); + result.setEmail(Strings.nullToEmpty(data.get(username + ".email"))); + LOG.info("details for user {} : {}", username, result); + return result; + } + + public Collection<String> doGetGroups(String username) { + // Never touch admin + if (isAdmin(username)) { + return null; + } + + reloadData(); + checkExistence(username); + + Collection<String> result = parseList(data.get(username + ".groups")); + LOG.info("groups for user {} : {}", username, result); + return result; + } + + private static boolean isAdmin(String username) { + return StringUtils.equals(username, "admin"); + } + + private void reloadData() { + data = parse(settings.getString(DATA_PROPERTY)); + } + + private static final Splitter LIST_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults(); + private static final Splitter LINE_SPLITTER = Splitter.on(Pattern.compile("\r?\n")).omitEmptyStrings().trimResults(); + + @VisibleForTesting + static List<String> parseList(String data) { + return ImmutableList.copyOf(LIST_SPLITTER.split(Strings.nullToEmpty(data))); + } + + @VisibleForTesting + static Map<String, String> parse(String data) { + Map<String, String> result = Maps.newHashMap(); + for (String entry : LINE_SPLITTER.split(Strings.nullToEmpty(data))) { + Iterator<String> keyValue = Splitter.on('=').split(entry).iterator(); + result.put(keyValue.next(), keyValue.next()); + } + return result; + } + + public void init() { + // nothing to do + } + +} diff --git a/it/it-plugins/security-plugin/src/main/java/FakeGroupsProvider.java b/it/it-plugins/security-plugin/src/main/java/FakeGroupsProvider.java new file mode 100644 index 00000000000..9c1666c5423 --- /dev/null +++ b/it/it-plugins/security-plugin/src/main/java/FakeGroupsProvider.java @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +import java.util.Collection; +import org.sonar.api.security.ExternalGroupsProvider; + +public class FakeGroupsProvider extends ExternalGroupsProvider { + + private final FakeAuthenticator instance; + + public FakeGroupsProvider(FakeAuthenticator instance) { + this.instance = instance; + } + + @Override + public Collection<String> doGetGroups(String username) { + return instance.doGetGroups(username); + } + +} diff --git a/it/it-plugins/security-plugin/src/main/java/FakeRealm.java b/it/it-plugins/security-plugin/src/main/java/FakeRealm.java new file mode 100644 index 00000000000..4b4dd479836 --- /dev/null +++ b/it/it-plugins/security-plugin/src/main/java/FakeRealm.java @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +import org.sonar.api.config.Settings; +import org.sonar.api.security.ExternalGroupsProvider; +import org.sonar.api.security.ExternalUsersProvider; +import org.sonar.api.security.LoginPasswordAuthenticator; +import org.sonar.api.security.SecurityRealm; + +public class FakeRealm extends SecurityRealm { + + private FakeAuthenticator instance; + + public FakeRealm(Settings settings) { + this.instance = new FakeAuthenticator(settings); + } + + @Override + public LoginPasswordAuthenticator getLoginPasswordAuthenticator() { + return instance; + } + + @Override + public ExternalGroupsProvider getGroupsProvider() { + return new FakeGroupsProvider(instance); + } + + @Override + public ExternalUsersProvider getUsersProvider() { + return new FakeUsersProvider(instance); + } + +} diff --git a/it/it-plugins/security-plugin/src/main/java/FakeUsersProvider.java b/it/it-plugins/security-plugin/src/main/java/FakeUsersProvider.java new file mode 100644 index 00000000000..4ebae9deae1 --- /dev/null +++ b/it/it-plugins/security-plugin/src/main/java/FakeUsersProvider.java @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +import org.sonar.api.security.ExternalUsersProvider; +import org.sonar.api.security.UserDetails; + +public class FakeUsersProvider extends ExternalUsersProvider { + + private final FakeAuthenticator instance; + + public FakeUsersProvider(FakeAuthenticator instance) { + this.instance = instance; + } + + @Override + public UserDetails doGetUserDetails(String username) { + return instance.doGetUserDetails(username); + } + +} diff --git a/it/it-plugins/security-plugin/src/main/java/SecurityPlugin.java b/it/it-plugins/security-plugin/src/main/java/SecurityPlugin.java new file mode 100644 index 00000000000..c2582893c70 --- /dev/null +++ b/it/it-plugins/security-plugin/src/main/java/SecurityPlugin.java @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +import java.util.Arrays; +import java.util.List; +import org.sonar.api.SonarPlugin; + +public class SecurityPlugin extends SonarPlugin { + + public List getExtensions() { + return Arrays.asList(FakeRealm.class, FakeAuthenticator.class); + } + +} diff --git a/it/it-plugins/security-plugin/src/test/java/FakeAuthenticatorTest.java b/it/it-plugins/security-plugin/src/test/java/FakeAuthenticatorTest.java new file mode 100644 index 00000000000..6a0b1884a05 --- /dev/null +++ b/it/it-plugins/security-plugin/src/test/java/FakeAuthenticatorTest.java @@ -0,0 +1,126 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.config.Settings; +import org.sonar.api.security.UserDetails; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class FakeAuthenticatorTest { + + private Settings settings; + private FakeAuthenticator authenticator; + + @Before + public void setUp() { + settings = new Settings(); + authenticator = new FakeAuthenticator(settings); + authenticator.init(); + } + + @Test + public void shouldNeverTouchAdmin() { + assertThat(authenticator.authenticate("admin", "admin")).isTrue(); + assertThat(authenticator.doGetGroups("admin")).isNull(); + assertThat(authenticator.doGetUserDetails("admin")).isNull(); + } + + @Test + public void shouldAuthenticateFakeUsers() { + settings.setProperty(FakeAuthenticator.DATA_PROPERTY, "evgeny.password=foo"); + + assertThat(authenticator.authenticate("evgeny", "foo")).isTrue(); + assertThat(authenticator.authenticate("evgeny", "bar")).isFalse(); + } + + @Test(expected = RuntimeException.class) + public void shouldNotAuthenticateNotExistingUsers() { + authenticator.authenticate("evgeny", "foo"); + } + + @Test + public void shouldGetUserDetails() { + settings.setProperty(FakeAuthenticator.DATA_PROPERTY, "evgeny.password=foo\n" + + "evgeny.name=Tester Testerovich\n" + + "evgeny.email=evgeny@example.org"); + + UserDetails details = authenticator.doGetUserDetails("evgeny"); + assertThat(details.getName()).isEqualTo("Tester Testerovich"); + assertThat(details.getEmail()).isEqualTo("evgeny@example.org"); + } + + @Test(expected = RuntimeException.class) + public void shouldNotReturnDetailsForNotExistingUsers() { + authenticator.doGetUserDetails("evgeny"); + } + + @Test + public void shouldGetGroups() { + settings.setProperty(FakeAuthenticator.DATA_PROPERTY, "evgeny.password=foo\n" + + "evgeny.groups=sonar-users,sonar-developers"); + + assertThat(authenticator.doGetGroups("evgeny")).containsOnly("sonar-users", "sonar-developers"); + } + + @Test(expected = RuntimeException.class) + public void shouldNotReturnGroupsForNotExistingUsers() { + authenticator.doGetGroups("evgeny"); + } + + @Test + public void shouldParseList() { + assertThat(FakeAuthenticator.parseList(null)).isEmpty(); + assertThat(FakeAuthenticator.parseList("")).isEmpty(); + assertThat(FakeAuthenticator.parseList(",,,")).isEmpty(); + assertThat(FakeAuthenticator.parseList("a,b")).containsOnly("a", "b"); + } + + @Test + public void shouldParseMap() { + Map<String, String> map = FakeAuthenticator.parse(null); + assertThat(map).isEmpty(); + + map = FakeAuthenticator.parse(""); + assertThat(map).isEmpty(); + + map = FakeAuthenticator.parse("foo=bar"); + assertThat(map).hasSize(1); + assertThat(map.get("foo")).isEqualTo("bar"); + + map = FakeAuthenticator.parse("foo=bar\r\nbaz=qux"); + assertThat(map).hasSize(2); + assertThat(map.get("foo")).isEqualTo("bar"); + assertThat(map.get("baz")).isEqualTo("qux"); + + map = FakeAuthenticator.parse("foo=bar\nbaz=qux"); + assertThat(map).hasSize(2); + assertThat(map.get("foo")).isEqualTo("bar"); + assertThat(map.get("baz")).isEqualTo("qux"); + + map = FakeAuthenticator.parse("foo=bar\n\n\nbaz=qux"); + assertThat(map).hasSize(2); + assertThat(map.get("foo")).isEqualTo("bar"); + assertThat(map.get("baz")).isEqualTo("qux"); + } + +} |