summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalGroupsProvider.java15
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalUsersProvider.java15
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/LoginPasswordAuthenticator.java15
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/SecurityRealm.java (renamed from sonar-plugin-api/src/main/java/org/sonar/api/security/Realm.java)9
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/security/UserDetails.java17
-rw-r--r--sonar-server/src/dev/postgresql/conf/logback.xml28
-rw-r--r--sonar-server/src/main/java/org/sonar/server/platform/Platform.java4
-rw-r--r--sonar-server/src/main/java/org/sonar/server/ui/CompatibilityRealm.java6
-rw-r--r--sonar-server/src/main/java/org/sonar/server/ui/SecurityRealmFactory.java (renamed from sonar-server/src/main/java/org/sonar/server/ui/RealmFactory.java)24
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/lib/need_authentication.rb27
-rw-r--r--sonar-server/src/test/java/org/sonar/server/ui/CompatibilityRealmTest.java2
-rw-r--r--sonar-server/src/test/java/org/sonar/server/ui/SecurityRealmFactoryTest.java (renamed from sonar-server/src/test/java/org/sonar/server/ui/RealmFactoryTest.java)45
12 files changed, 125 insertions, 82 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalGroupsProvider.java b/sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalGroupsProvider.java
index c6f7c501f22..0410b66cc90 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalGroupsProvider.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/security/ExternalGroupsProvider.java
@@ -19,17 +19,20 @@
*/
package org.sonar.api.security;
-import com.google.common.annotations.Beta;
-import org.sonar.api.ServerExtension;
-
import java.util.Collection;
/**
+ * 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
*/
-@Beta
-public interface ExternalGroupsProvider extends ServerExtension {
+public abstract class ExternalGroupsProvider {
- Collection<String> doGetGroups(String username);
+ /**
+ * @return list of groups associated with specified user, or null if such user doesn't exist
+ * @throws RuntimeException in case of unexpected error such as connection failure
+ */
+ public abstract Collection<String> doGetGroups(String username);
}
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 5e49ef8116f..00f7dfb4dac 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,15 +19,18 @@
*/
package org.sonar.api.security;
-import com.google.common.annotations.Beta;
-import org.sonar.api.ServerExtension;
-
/**
+ * 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
*/
-@Beta
-public interface ExternalUsersProvider extends ServerExtension {
+public abstract class ExternalUsersProvider {
- UserDetails doGetUserDetails(String username);
+ /**
+ * @return details for specified user, or null if such user doesn't exist
+ * @throws RuntimeException in case of unexpected error such as connection failure
+ */
+ public abstract UserDetails doGetUserDetails(String username);
}
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 7160746c8e5..8ca6f97864f 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
@@ -23,14 +23,21 @@ import org.sonar.api.ServerExtension;
/**
* @since 1.12
+ * @see SecurityRealm
*/
public interface LoginPasswordAuthenticator extends ServerExtension {
/**
- * Throws a runtime exception if the authenticator can not be initialized at sonar server startup, eg. if the connection to LDAP server is refused.
+ * @throws RuntimeException if the authenticator can not be initialized at sonar server startup, eg. if the connection to LDAP server is refused
+ * @deprecated in 2.14, but was left for backward compatibility - when this authenticator is not a part of {@link SecurityRealm}, otherwise has no effect and not invoked
*/
+ @Deprecated
void init();
- boolean authenticate(String login, String password);
-
-} \ No newline at end of file
+ /**
+ * @return true, if user was successfully authenticated with specified username and password, false otherwise
+ * @throws RuntimeException in case of unexpected error such as connection failure
+ */
+ boolean authenticate(String username, String password);
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/security/Realm.java b/sonar-plugin-api/src/main/java/org/sonar/api/security/SecurityRealm.java
index 5ef15b9238c..f21d4d26946 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/security/Realm.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/security/SecurityRealm.java
@@ -19,14 +19,12 @@
*/
package org.sonar.api.security;
-import com.google.common.annotations.Beta;
import org.sonar.api.ServerExtension;
/**
* @since 2.14
*/
-@Beta
-public abstract class Realm implements ServerExtension {
+public abstract class SecurityRealm implements ServerExtension {
/**
* @return unique name of this realm, e.g. "LDAP"
@@ -35,13 +33,16 @@ public abstract class Realm implements ServerExtension {
return getClass().getSimpleName();
}
+ /**
+ * Invoked during server startup and can be used to initialize internal state.
+ */
public void init() {
}
/**
* @return {@link LoginPasswordAuthenticator} associated with this realm, never null
*/
- public abstract LoginPasswordAuthenticator getAuthenticator();
+ public abstract LoginPasswordAuthenticator getLoginPasswordAuthenticator();
/**
* @return {@link ExternalUsersProvider} associated with this realm, null if not supported
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 e5a4db4b40f..e3519866a13 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
@@ -19,18 +19,18 @@
*/
package org.sonar.api.security;
-import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
/**
* This class is not intended to be subclassed by clients.
*
* @since 2.14
+ * @see ExternalUsersProvider
*/
-@Beta
-public class UserDetails {
+public final class UserDetails {
- private String name;
- private String email;
+ private String name = "";
+ private String email = "";
public UserDetails() {
}
@@ -51,4 +51,11 @@ public class UserDetails {
return name;
}
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("name", name)
+ .add("email", email)
+ .toString();
+ }
}
diff --git a/sonar-server/src/dev/postgresql/conf/logback.xml b/sonar-server/src/dev/postgresql/conf/logback.xml
index 7605ec46890..3c2b26eb555 100644
--- a/sonar-server/src/dev/postgresql/conf/logback.xml
+++ b/sonar-server/src/dev/postgresql/conf/logback.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?>
-
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
@@ -9,34 +8,33 @@
</pattern>
</encoder>
</appender>
-
+
<logger name="org.hibernate.SQL">
- <level value="ERROR"/>
+ <level value="ERROR"/>
</logger>
-
+
<logger name="org.hibernate.cache.ReadWriteCache">
<!-- removing "An item was expired by the cache while it was locked (increase your cache timeout)" msg -->
- <level value="ERROR"/>
+ <level value="ERROR"/>
</logger>
-
+
<logger name="org.hibernate.cache.EhCacheProvider">
<!-- removing "org.hibernate.cache.EhCacheProvider - Could not find configuratio)" message -->
- <level value="ERROR"/>
+ <level value="ERROR"/>
</logger>
-
+
<logger name="org.sonar.INFO">
- <level value="INFO"/>
+ <level value="INFO"/>
</logger>
-
+
<logger name="net.sf.ehcache">
- <level value="INFO"/>
+ <level value="INFO"/>
</logger>
-
-
+
<logger name="rails.sonar">
- <level value="INFO"/>
+ <level value="INFO"/>
</logger>
-
+
<root>
<level value="INFO"/>
<appender-ref ref="STDOUT"/>
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
index 17049e551b1..f14f10043f7 100644
--- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
+++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
@@ -68,7 +68,7 @@ import org.sonar.server.rules.RulesConsole;
import org.sonar.server.startup.*;
import org.sonar.server.ui.CodeColorizers;
import org.sonar.server.ui.JRubyI18n;
-import org.sonar.server.ui.RealmFactory;
+import org.sonar.server.ui.SecurityRealmFactory;
import org.sonar.server.ui.Views;
import javax.servlet.ServletContext;
@@ -192,7 +192,7 @@ public final class Platform {
servicesContainer.addComponent(DefaultRulesManager.class, false);
servicesContainer.addComponent(ProfilesManager.class, false);
servicesContainer.addComponent(Backup.class, false);
- servicesContainer.addSingleton(RealmFactory.class);
+ servicesContainer.addSingleton(SecurityRealmFactory.class);
servicesContainer.addSingleton(ServerLifecycleNotifier.class);
servicesContainer.addSingleton(AnnotationProfileParser.class);
servicesContainer.addSingleton(XMLProfileParser.class);
diff --git a/sonar-server/src/main/java/org/sonar/server/ui/CompatibilityRealm.java b/sonar-server/src/main/java/org/sonar/server/ui/CompatibilityRealm.java
index 45d72239373..77ef6b6140f 100644
--- a/sonar-server/src/main/java/org/sonar/server/ui/CompatibilityRealm.java
+++ b/sonar-server/src/main/java/org/sonar/server/ui/CompatibilityRealm.java
@@ -21,14 +21,14 @@ package org.sonar.server.ui;
import org.sonar.api.CoreProperties;
import org.sonar.api.security.LoginPasswordAuthenticator;
-import org.sonar.api.security.Realm;
+import org.sonar.api.security.SecurityRealm;
/**
* Provides backward compatibility for {@link CoreProperties#CORE_AUTHENTICATOR_CLASS}.
*
* @since 2.14
*/
-class CompatibilityRealm extends Realm {
+class CompatibilityRealm extends SecurityRealm {
private final LoginPasswordAuthenticator authenticator;
public CompatibilityRealm(LoginPasswordAuthenticator authenticator) {
@@ -46,7 +46,7 @@ class CompatibilityRealm extends Realm {
}
@Override
- public LoginPasswordAuthenticator getAuthenticator() {
+ public LoginPasswordAuthenticator getLoginPasswordAuthenticator() {
return authenticator;
}
}
diff --git a/sonar-server/src/main/java/org/sonar/server/ui/RealmFactory.java b/sonar-server/src/main/java/org/sonar/server/ui/SecurityRealmFactory.java
index e3187b5929c..2761f575399 100644
--- a/sonar-server/src/main/java/org/sonar/server/ui/RealmFactory.java
+++ b/sonar-server/src/main/java/org/sonar/server/ui/SecurityRealmFactory.java
@@ -26,26 +26,26 @@ import org.sonar.api.CoreProperties;
import org.sonar.api.ServerComponent;
import org.sonar.api.config.Settings;
import org.sonar.api.security.LoginPasswordAuthenticator;
-import org.sonar.api.security.Realm;
+import org.sonar.api.security.SecurityRealm;
/**
* @since 2.14
*/
-public class RealmFactory implements ServerComponent {
+public class SecurityRealmFactory implements ServerComponent {
private static final Logger INFO = LoggerFactory.getLogger("org.sonar.INFO");
- private static final Logger LOG = LoggerFactory.getLogger(RealmFactory.class);
+ private static final Logger LOG = LoggerFactory.getLogger(SecurityRealmFactory.class);
private final boolean ignoreStartupFailure;
- private final Realm realm;
+ private final SecurityRealm realm;
static final String REALM_PROPERTY = "sonar.security.realm";
- public RealmFactory(Settings settings, Realm[] realms, LoginPasswordAuthenticator[] authenticators) {
+ public SecurityRealmFactory(Settings settings, SecurityRealm[] realms, LoginPasswordAuthenticator[] authenticators) {
ignoreStartupFailure = settings.getBoolean(CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE);
String realmName = settings.getString(REALM_PROPERTY);
String className = settings.getString(CoreProperties.CORE_AUTHENTICATOR_CLASS);
- Realm selectedRealm = null;
+ SecurityRealm selectedRealm = null;
if (!StringUtils.isEmpty(realmName)) {
selectedRealm = selectRealm(realms, realmName);
if (selectedRealm == null) {
@@ -65,15 +65,15 @@ public class RealmFactory implements ServerComponent {
realm = selectedRealm;
}
- public RealmFactory(Settings settings, LoginPasswordAuthenticator[] authenticators) {
+ public SecurityRealmFactory(Settings settings, LoginPasswordAuthenticator[] authenticators) {
this(settings, null, authenticators);
}
- public RealmFactory(Settings settings, Realm[] realms) {
+ public SecurityRealmFactory(Settings settings, SecurityRealm[] realms) {
this(settings, realms, null);
}
- public RealmFactory(Settings settings) {
+ public SecurityRealmFactory(Settings settings) {
this(settings, null, null);
}
@@ -94,13 +94,13 @@ public class RealmFactory implements ServerComponent {
}
}
- public Realm getRealm() {
+ public SecurityRealm getRealm() {
return realm;
}
- private static Realm selectRealm(Realm[] realms, String realmName) {
+ private static SecurityRealm selectRealm(SecurityRealm[] realms, String realmName) {
if (realms != null) {
- for (Realm realm : realms) {
+ for (SecurityRealm realm : realms) {
if (StringUtils.equals(realmName, realm.getName())) {
return realm;
}
diff --git a/sonar-server/src/main/webapp/WEB-INF/lib/need_authentication.rb b/sonar-server/src/main/webapp/WEB-INF/lib/need_authentication.rb
index 94e7d62223d..e7335d80369 100644
--- a/sonar-server/src/main/webapp/WEB-INF/lib/need_authentication.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/lib/need_authentication.rb
@@ -43,8 +43,9 @@ end
#
class PluginRealm
def initialize(java_realm)
- @java_authenticator = java_realm.getAuthenticator()
+ @java_authenticator = java_realm.getLoginPasswordAuthenticator()
@java_users_provider = java_realm.getUsersProvider()
+ @java_groups_provider = java_realm.getGroupsProvider()
end
def authenticate?(login, password)
@@ -70,12 +71,34 @@ class PluginRealm
else
if details
user.update_attributes(:name => details.getName(), :email => details.getEmail(), :password => password, :password_confirmation => password)
+ # Synchronize groups only when succeeded to synchronize details
+ synchronize_groups(user)
user.save
end
end
end
end
+ def synchronize_groups(user)
+ if @java_groups_provider
+ begin
+ groups = @java_groups_provider.doGetGroups(user.login)
+ rescue Exception => e
+ Java::OrgSonarServerUi::JRubyFacade.new.logError("Error from external groups provider: #{e.message}")
+ else
+ if groups
+ user.groups = []
+ for group_name in groups
+ group = Group.find_by_name(group_name)
+ if group
+ user.groups << group
+ end
+ end
+ end
+ end
+ end
+ end
+
def editable_password?
false
end
@@ -89,7 +112,7 @@ class RealmFactory
def self.realm
if @@realm.nil?
- realm_factory = Java::OrgSonarServerUi::JRubyFacade.new.getCoreComponentByClassname('org.sonar.server.ui.RealmFactory')
+ realm_factory = Java::OrgSonarServerUi::JRubyFacade.new.getCoreComponentByClassname('org.sonar.server.ui.SecurityRealmFactory')
component = realm_factory.getRealm()
@@realm = component ? PluginRealm.new(component) : DefaultRealm.new
end
diff --git a/sonar-server/src/test/java/org/sonar/server/ui/CompatibilityRealmTest.java b/sonar-server/src/test/java/org/sonar/server/ui/CompatibilityRealmTest.java
index 84febf3eb0e..136407aeb04 100644
--- a/sonar-server/src/test/java/org/sonar/server/ui/CompatibilityRealmTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/ui/CompatibilityRealmTest.java
@@ -35,7 +35,7 @@ public class CompatibilityRealmTest {
CompatibilityRealm realm = new CompatibilityRealm(authenticator);
realm.init();
verify(authenticator).init();
- assertThat(realm.getAuthenticator(), is(authenticator));
+ assertThat(realm.getLoginPasswordAuthenticator(), is(authenticator));
assertThat(realm.getName(), is("CompatibilityRealm[" + authenticator.getClass().getName() + "]"));
}
diff --git a/sonar-server/src/test/java/org/sonar/server/ui/RealmFactoryTest.java b/sonar-server/src/test/java/org/sonar/server/ui/SecurityRealmFactoryTest.java
index 9f27ba0ee7b..38ba8cd2662 100644
--- a/sonar-server/src/test/java/org/sonar/server/ui/RealmFactoryTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/ui/SecurityRealmFactoryTest.java
@@ -24,14 +24,14 @@ import org.junit.Test;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
import org.sonar.api.security.LoginPasswordAuthenticator;
-import org.sonar.api.security.Realm;
+import org.sonar.api.security.SecurityRealm;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-public class RealmFactoryTest {
+public class SecurityRealmFactoryTest {
private Settings settings;
@@ -45,10 +45,10 @@ public class RealmFactoryTest {
*/
@Test
public void shouldSelectRealmAndStart() {
- Realm realm = spy(new FakeRealm());
- settings.setProperty(RealmFactory.REALM_PROPERTY, realm.getName());
+ SecurityRealm realm = spy(new FakeRealm());
+ settings.setProperty(SecurityRealmFactory.REALM_PROPERTY, realm.getName());
- RealmFactory factory = new RealmFactory(settings, new Realm[] {realm});
+ SecurityRealmFactory factory = new SecurityRealmFactory(settings, new SecurityRealm[] {realm});
factory.start();
assertThat(factory.getRealm(), is(realm));
verify(realm).init();
@@ -56,16 +56,16 @@ public class RealmFactoryTest {
@Test
public void doNotFailIfNoRealms() {
- RealmFactory factory = new RealmFactory(settings);
+ SecurityRealmFactory factory = new SecurityRealmFactory(settings);
factory.start();
assertThat(factory.getRealm(), nullValue());
}
@Test(expected = AuthenticatorNotFoundException.class)
public void realmNotFound() {
- settings.setProperty(RealmFactory.REALM_PROPERTY, "Fake");
+ settings.setProperty(SecurityRealmFactory.REALM_PROPERTY, "Fake");
- new RealmFactory(settings);
+ new SecurityRealmFactory(settings);
}
@Test
@@ -73,19 +73,20 @@ public class RealmFactoryTest {
settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_CLASS, FakeAuthenticator.class.getName());
LoginPasswordAuthenticator authenticator = new FakeAuthenticator();
- RealmFactory factory = new RealmFactory(settings, new LoginPasswordAuthenticator[] {authenticator});
- Realm realm = factory.getRealm();
+ SecurityRealmFactory factory = new SecurityRealmFactory(settings, new LoginPasswordAuthenticator[] {authenticator});
+ SecurityRealm realm = factory.getRealm();
assertThat(realm, instanceOf(CompatibilityRealm.class));
}
@Test
public void shouldTakePrecedenceOverAuthenticator() {
- Realm realm = new FakeRealm();
- settings.setProperty(RealmFactory.REALM_PROPERTY, realm.getName());
+ SecurityRealm realm = new FakeRealm();
+ settings.setProperty(SecurityRealmFactory.REALM_PROPERTY, realm.getName());
LoginPasswordAuthenticator authenticator = new FakeAuthenticator();
settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_CLASS, FakeAuthenticator.class.getName());
- RealmFactory factory = new RealmFactory(settings, new Realm[] {realm}, new LoginPasswordAuthenticator[] {authenticator});
+ SecurityRealmFactory factory = new SecurityRealmFactory(settings, new SecurityRealm[] {realm},
+ new LoginPasswordAuthenticator[] {authenticator});
assertThat(factory.getRealm(), is(realm));
}
@@ -93,25 +94,25 @@ public class RealmFactoryTest {
public void authenticatorNotFound() {
settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_CLASS, "Fake");
- new RealmFactory(settings);
+ new SecurityRealmFactory(settings);
}
@Test
public void ignoreStartupFailure() {
- Realm realm = spy(new AlwaysFailsRealm());
- settings.setProperty(RealmFactory.REALM_PROPERTY, realm.getName());
+ SecurityRealm realm = spy(new AlwaysFailsRealm());
+ settings.setProperty(SecurityRealmFactory.REALM_PROPERTY, realm.getName());
settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE, true);
- new RealmFactory(settings, new Realm[] {realm}).start();
+ new SecurityRealmFactory(settings, new SecurityRealm[] {realm}).start();
verify(realm).init();
}
@Test(expected = IllegalStateException.class)
public void shouldFail() {
- Realm realm = spy(new AlwaysFailsRealm());
- settings.setProperty(RealmFactory.REALM_PROPERTY, realm.getName());
+ SecurityRealm realm = spy(new AlwaysFailsRealm());
+ settings.setProperty(SecurityRealmFactory.REALM_PROPERTY, realm.getName());
- new RealmFactory(settings, new Realm[] {realm}).start();
+ new SecurityRealmFactory(settings, new SecurityRealm[] {realm}).start();
}
private static class AlwaysFailsRealm extends FakeRealm {
@@ -121,9 +122,9 @@ public class RealmFactoryTest {
}
}
- private static class FakeRealm extends Realm {
+ private static class FakeRealm extends SecurityRealm {
@Override
- public LoginPasswordAuthenticator getAuthenticator() {
+ public LoginPasswordAuthenticator getLoginPasswordAuthenticator() {
return null;
}
}