aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-plugin-api
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2012-05-08 09:14:29 +0200
committerSimon Brandhof <simon.brandhof@gmail.com>2012-05-08 10:23:02 +0200
commit9e46b4bb203a60742f0cb58cd621a58496b7ed33 (patch)
treece4a6aac43db33c25c4bf48b6c22a9f63e88e42c /sonar-plugin-api
parentbd0abcb3f754f4c123f9ce3145e2cf814210b91e (diff)
downloadsonarqube-9e46b4bb203a60742f0cb58cd621a58496b7ed33.tar.gz
sonarqube-9e46b4bb203a60742f0cb58cd621a58496b7ed33.zip
SONAR-2950 Single Sign On with external authentication mechanism
Diffstat (limited to 'sonar-plugin-api')
-rw-r--r--sonar-plugin-api/pom.xml15
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/Authenticator.java70
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalUsersProvider.java44
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/LoginPasswordAuthenticator.java1
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/SecurityRealm.java22
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/UserDetails.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/package-info.java23
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/web/ServletFilter.java84
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/security/ExternalUsersProviderTest.java67
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/security/SecurityRealmTest.java59
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/web/ServletFilterTest.java61
11 files changed, 443 insertions, 5 deletions
diff --git a/sonar-plugin-api/pom.xml b/sonar-plugin-api/pom.xml
index 22a6a4fdef2..93e5a4a7522 100644
--- a/sonar-plugin-api/pom.xml
+++ b/sonar-plugin-api/pom.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<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/xsd/maven-4.0.0.xsd">
+<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.codehaus.sonar</groupId>
@@ -131,6 +132,12 @@
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
</dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.4</version>
+ <optional>true</optional>
+ </dependency>
<!-- unit tests -->
<dependency>
@@ -169,6 +176,12 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.easytesting</groupId>
+ <artifactId>fest-assert</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-servlet-tester</artifactId>
<scope>test</scope>
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/security/Authenticator.java b/sonar-plugin-api/src/main/java/org/sonar/api/security/Authenticator.java
new file mode 100644
index 00000000000..2420eaf3d8f
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/security/Authenticator.java
@@ -0,0 +1,70 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.security;
+
+import com.google.common.base.Preconditions;
+import org.sonar.api.ServerExtension;
+
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @see SecurityRealm
+ * @since 3.1
+ */
+public abstract class Authenticator implements ServerExtension {
+
+ /**
+ * @return true if user was successfully authenticated with specified credentials, false otherwise
+ * @throws RuntimeException in case of unexpected error such as connection failure
+ */
+ public abstract boolean doAuthenticate(Context context);
+
+ public static final class Context {
+ private String username;
+ private String password;
+ private HttpServletRequest request;
+
+ public Context(@Nullable String username, @Nullable String password, HttpServletRequest request) {
+ Preconditions.checkNotNull(request);
+ this.request = request;
+ this.username = username;
+ this.password = password;
+ }
+
+ /**
+ * Username can be null, for example when using <a href="http://www.jasig.org/cas">CAS</a>.
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Password can be null, for example when using <a href="http://www.jasig.org/cas">CAS</a>.
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ public HttpServletRequest getRequest() {
+ return request;
+ }
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalUsersProvider.java b/sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalUsersProvider.java
index 00f7dfb4dac..b7c93c59fb2 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalUsersProvider.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalUsersProvider.java
@@ -19,18 +19,58 @@
*/
package org.sonar.api.security;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
/**
* Note that prefix "do" for names of methods is reserved for future enhancements, thus should not be used in subclasses.
*
- * @since 2.14
* @see SecurityRealm
+ * @since 2.14
*/
public abstract class ExternalUsersProvider {
/**
+ * This method is overridden by old versions of plugins such as LDAP 1.1. It should be overridden anymore.
+ *
* @return details for specified user, or null if such user doesn't exist
* @throws RuntimeException in case of unexpected error such as connection failure
+ * @deprecated replaced by {@link #doGetUserDetails(org.sonar.api.security.ExternalUsersProvider.Context)} since v. 3.1
*/
- public abstract UserDetails doGetUserDetails(String username);
+ @Deprecated
+ public UserDetails doGetUserDetails(@Nullable String username) {
+ return null;
+ }
+
+ /**
+ * Override this method in order load user information.
+ *
+ * @return the user, or null if user doesn't exist
+ * @throws RuntimeException in case of unexpected error such as connection failure
+ * @since 3.1
+ */
+ public UserDetails doGetUserDetails(Context context) {
+ return doGetUserDetails(context.getUsername());
+ }
+
+ public static final class Context {
+ private String username;
+ private HttpServletRequest request;
+
+ public Context(@Nullable String username, HttpServletRequest request) {
+ this.username = username;
+ this.request = request;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+ public HttpServletRequest getRequest() {
+ return request;
+ }
+ }
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/security/LoginPasswordAuthenticator.java b/sonar-plugin-api/src/main/java/org/sonar/api/security/LoginPasswordAuthenticator.java
index 8ca6f97864f..2883275a24e 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/security/LoginPasswordAuthenticator.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/security/LoginPasswordAuthenticator.java
@@ -24,6 +24,7 @@ import org.sonar.api.ServerExtension;
/**
* @since 1.12
* @see SecurityRealm
+ * @deprecated replaced by Authenticator in version 3.1
*/
public interface LoginPasswordAuthenticator extends ServerExtension {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/security/SecurityRealm.java b/sonar-plugin-api/src/main/java/org/sonar/api/security/SecurityRealm.java
index f21d4d26946..16a122933ef 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/security/SecurityRealm.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/security/SecurityRealm.java
@@ -41,8 +41,27 @@ public abstract class SecurityRealm implements ServerExtension {
/**
* @return {@link LoginPasswordAuthenticator} associated with this realm, never null
+ * @deprecated replaced by doGetAuthenticator in version 3.1
*/
- public abstract LoginPasswordAuthenticator getLoginPasswordAuthenticator();
+ @Deprecated
+ public LoginPasswordAuthenticator getLoginPasswordAuthenticator() {
+ return null;
+ }
+
+ /**
+ * @since 3.1
+ */
+ public Authenticator doGetAuthenticator() {
+ if (getLoginPasswordAuthenticator() == null) {
+ return null;
+ }
+ return new Authenticator() {
+ @Override
+ public boolean doAuthenticate(Context context) {
+ return getLoginPasswordAuthenticator().authenticate(context.getUsername(), context.getPassword());
+ }
+ };
+ }
/**
* @return {@link ExternalUsersProvider} associated with this realm, null if not supported
@@ -57,5 +76,4 @@ public abstract class SecurityRealm implements ServerExtension {
public ExternalGroupsProvider getGroupsProvider() {
return null;
}
-
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/security/UserDetails.java b/sonar-plugin-api/src/main/java/org/sonar/api/security/UserDetails.java
index e3519866a13..2d4afc0524c 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/security/UserDetails.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/security/UserDetails.java
@@ -21,6 +21,8 @@ package org.sonar.api.security;
import com.google.common.base.Objects;
+import javax.annotation.Nullable;
+
/**
* This class is not intended to be subclassed by clients.
*
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/security/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/security/package-info.java
new file mode 100644
index 00000000000..8658aba99c6
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/security/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.security;
+
+import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/web/ServletFilter.java b/sonar-plugin-api/src/main/java/org/sonar/api/web/ServletFilter.java
new file mode 100644
index 00000000000..983f7fcfcfc
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/web/ServletFilter.java
@@ -0,0 +1,84 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.web;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import org.sonar.api.ServerExtension;
+
+import javax.servlet.Filter;
+
+/**
+ * @since 3.1
+ */
+@Beta
+public abstract class ServletFilter implements ServerExtension, Filter {
+
+ /**
+ * Override to change URL. Default is /*
+ */
+ public UrlPattern doGetPattern() {
+ return UrlPattern.create("/*");
+ }
+
+ public static final class UrlPattern {
+ private int code;
+ private String url;
+ private String urlToMatch;
+
+ public static UrlPattern create(String pattern) {
+ return new UrlPattern(pattern);
+ }
+
+ private UrlPattern(String url) {
+ Preconditions.checkArgument(!Strings.isNullOrEmpty(url), "Empty url");
+ this.url = url;
+ this.urlToMatch = url.replaceAll("/?\\*", "");
+ if ("/*".equals(url)) {
+ code = 1;
+ } else if (url.startsWith("*")) {
+ code = 2;
+ } else if (url.endsWith("*")) {
+ code = 3;
+ } else {
+ code = 4;
+ }
+ }
+
+ public boolean matches(String path) {
+ switch (code) {
+ case 1:
+ return true;
+ case 2:
+ return path.endsWith(urlToMatch);
+ case 3:
+ return path.startsWith(urlToMatch);
+ default:
+ return path.equals(urlToMatch);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return url;
+ }
+ }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/security/ExternalUsersProviderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/security/ExternalUsersProviderTest.java
new file mode 100644
index 00000000000..f1ed1a023e1
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/security/ExternalUsersProviderTest.java
@@ -0,0 +1,67 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.security;
+
+import com.google.common.base.Preconditions;
+import org.junit.Test;
+
+import javax.servlet.http.HttpServletRequest;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class ExternalUsersProviderTest {
+
+ @Test
+ public void doGetUserDetails() {
+ ExternalUsersProvider provider = new ExternalUsersProvider() {
+ @Override
+ public UserDetails doGetUserDetails(Context context) {
+ Preconditions.checkNotNull(context.getUsername());
+ Preconditions.checkNotNull(context.getRequest());
+ UserDetails user = new UserDetails();
+ user.setName(context.getUsername());
+ user.setEmail("foo@bar.com");
+ return user;
+ }
+ };
+ UserDetails user = provider.doGetUserDetails(new ExternalUsersProvider.Context("foo", mock(HttpServletRequest.class)));
+
+ assertThat(user.getName()).isEqualTo("foo");
+ assertThat(user.getEmail()).isEqualTo("foo@bar.com");
+ }
+
+ @Test
+ public void doGetUserDetails_deprecated_api() {
+ ExternalUsersProvider provider = new ExternalUsersProvider() {
+ @Override
+ public UserDetails doGetUserDetails(String username) {
+ UserDetails user = new UserDetails();
+ user.setName(username);
+ user.setEmail("foo@bar.com");
+ return user;
+ }
+ };
+ UserDetails user = provider.doGetUserDetails(new ExternalUsersProvider.Context("foo", mock(HttpServletRequest.class)));
+
+ assertThat(user.getName()).isEqualTo("foo");
+ assertThat(user.getEmail()).isEqualTo("foo@bar.com");
+ }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/security/SecurityRealmTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/security/SecurityRealmTest.java
new file mode 100644
index 00000000000..e22eabc34a2
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/security/SecurityRealmTest.java
@@ -0,0 +1,59 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.security;
+
+import org.junit.Test;
+
+import javax.servlet.http.HttpServletRequest;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class SecurityRealmTest {
+
+ @Test
+ public void doGetAuthenticator() {
+ final Authenticator authenticator = mock(Authenticator.class);
+ SecurityRealm realm = new SecurityRealm() {
+ @Override
+ public Authenticator doGetAuthenticator() {
+ return authenticator;
+ }
+ };
+ assertThat(realm.doGetAuthenticator()).isSameAs(authenticator);
+ }
+
+ @Test
+ public void getLoginPasswordAuthenticator_deprecated_method_replaced_by_getAuthenticator() {
+ final LoginPasswordAuthenticator deprecatedAuthenticator = mock(LoginPasswordAuthenticator.class);
+ SecurityRealm realm = new SecurityRealm() {
+ @Override
+ public LoginPasswordAuthenticator getLoginPasswordAuthenticator() {
+ return deprecatedAuthenticator;
+ }
+ };
+ Authenticator proxy = realm.doGetAuthenticator();
+ Authenticator.Context context = new Authenticator.Context("foo", "bar", mock(HttpServletRequest.class));
+ proxy.doAuthenticate(context);
+
+ verify(deprecatedAuthenticator).authenticate("foo", "bar");
+ }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/web/ServletFilterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/web/ServletFilterTest.java
new file mode 100644
index 00000000000..398cbb6d247
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/web/ServletFilterTest.java
@@ -0,0 +1,61 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.web;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class ServletFilterTest {
+ @Test
+ public void matchAll() {
+ ServletFilter.UrlPattern pattern = ServletFilter.UrlPattern.create("/*");
+ assertThat(pattern.matches("/")).isTrue();
+ assertThat(pattern.matches("/foo/ooo")).isTrue();
+ }
+
+ @Test
+ public void matchEndOfUrl() {
+ ServletFilter.UrlPattern pattern = ServletFilter.UrlPattern.create("*foo");
+ assertThat(pattern.matches("/")).isFalse();
+ assertThat(pattern.matches("/hello/foo")).isTrue();
+ assertThat(pattern.matches("/hello/bar")).isFalse();
+ assertThat(pattern.matches("/foo")).isTrue();
+ assertThat(pattern.matches("/foo2")).isFalse();
+ }
+
+ @Test
+ public void matchBeginningOfUrl() {
+ ServletFilter.UrlPattern pattern = ServletFilter.UrlPattern.create("/foo/*");
+ assertThat(pattern.matches("/")).isFalse();
+ assertThat(pattern.matches("/foo")).isTrue();
+ assertThat(pattern.matches("/foo/bar")).isTrue();
+ assertThat(pattern.matches("/bar")).isFalse();
+ }
+
+ @Test
+ public void matchExactUrl() {
+ ServletFilter.UrlPattern pattern = ServletFilter.UrlPattern.create("/foo");
+ assertThat(pattern.matches("/")).isFalse();
+ assertThat(pattern.matches("/foo")).isTrue();
+ assertThat(pattern.matches("/foo/")).isFalse();
+ assertThat(pattern.matches("/bar")).isFalse();
+ }
+}