diff options
author | Evgeny Mandrikov <mandrikov@gmail.com> | 2012-01-09 22:55:59 +0400 |
---|---|---|
committer | Evgeny Mandrikov <mandrikov@gmail.com> | 2012-01-10 02:26:54 +0400 |
commit | a3509a17ff32da47721d48c59768dacc2e86b3cd (patch) | |
tree | adfcf555497ad222d5dd93306965be182c3d3537 /sonar-server | |
parent | d9b0b6a9bce879a1831b457e75e529d78889db0c (diff) | |
download | sonarqube-a3509a17ff32da47721d48c59768dacc2e86b3cd.tar.gz sonarqube-a3509a17ff32da47721d48c59768dacc2e86b3cd.zip |
SONAR-3137,SONAR-2292 Complete API for external security systems
Diffstat (limited to 'sonar-server')
9 files changed, 404 insertions, 299 deletions
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 ba055fec7c9..a22f4f9593b 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 @@ -67,9 +67,9 @@ import org.sonar.server.qualitymodel.DefaultModelManager; import org.sonar.server.rules.ProfilesConsole; import org.sonar.server.rules.RulesConsole; import org.sonar.server.startup.*; -import org.sonar.server.ui.AuthenticatorFactory; import org.sonar.server.ui.CodeColorizers; import org.sonar.server.ui.JRubyI18n; +import org.sonar.server.ui.RealmFactory; import org.sonar.server.ui.Views; import javax.servlet.ServletContext; @@ -193,7 +193,7 @@ public final class Platform { servicesContainer.addComponent(DefaultRulesManager.class, false); servicesContainer.addComponent(ProfilesManager.class, false); servicesContainer.addComponent(Backup.class, false); - servicesContainer.addSingleton(AuthenticatorFactory.class); + servicesContainer.addSingleton(RealmFactory.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/AuthenticatorFactory.java b/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorFactory.java deleted file mode 100644 index 71b567cd00e..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorFactory.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2011 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.server.ui; - -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.CoreProperties; -import org.sonar.api.ServerComponent; -import org.sonar.api.config.Settings; -import org.sonar.api.security.ExternalUsersProvider; -import org.sonar.api.security.LoginPasswordAuthenticator; -import org.sonar.api.security.UserDetails; - -public class AuthenticatorFactory implements ServerComponent { - - private static final Logger LOG = LoggerFactory.getLogger(AuthenticatorFactory.class); - private static final Logger INFO = LoggerFactory.getLogger("org.sonar.INFO"); - - private LoginPasswordAuthenticator authenticator = null; - private String classname; - private boolean ignoreStartupFailure; - private LoginPasswordAuthenticator[] authenticators; - - public AuthenticatorFactory(Settings settings, LoginPasswordAuthenticator[] authenticators) { - classname = settings.getString(CoreProperties.CORE_AUTHENTICATOR_CLASS); - ignoreStartupFailure = settings.getBoolean(CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE); - this.authenticators = authenticators; - } - - /** - * This constructor is used when there aren't any authentication plugins. - */ - public AuthenticatorFactory(Settings settings) { - this(settings, null); - } - - /** - * Start the authenticator selected in sonar configuration. If no authentication plugin is selected, then - * the default authentication mechanism is used and null is returned. - * - * @throws AuthenticatorNotFoundException if authenticator can not be found - * @throws RuntimeException if authenticator can not be started - */ - public void start() { - // check authentication plugin at startup - if (StringUtils.isEmpty(classname)) { - // use sonar internal authenticator - return; - } - - authenticator = searchAuthenticator(); - if (authenticator == null) { - LOG.error("Authentication plugin not found. Please check the property '" + CoreProperties.CORE_AUTHENTICATOR_CLASS + "' in conf/sonar.properties"); - throw new AuthenticatorNotFoundException(classname); - } - - try { - INFO.info("Authentication plugin: class " + classname); - authenticator.init(); - INFO.info("Authentication plugin started"); - - } catch (RuntimeException e) { - if (ignoreStartupFailure) { - LOG.error("IGNORED - Authentication plugin fails to start: " + e.getMessage()); - } else { - LOG.error("Authentication plugin fails to start: " + e.getMessage()); - throw e; - } - } - } - - public LoginPasswordAuthenticator getAuthenticator() { - return authenticator; - } - - public ExternalUsersProvider getUsersProvider() { - if (authenticator != null) { - if (authenticator instanceof ExternalUsersProvider) { - return (ExternalUsersProvider) authenticator; - } - return new DefaultUsersProvider(); - } - return null; - } - - private static class DefaultUsersProvider implements ExternalUsersProvider { - public UserDetails doGetUserDetails(String login) { - UserDetails result = new UserDetails(); - result.setName(login); - result.setEmail(""); - return result; - } - } - - private LoginPasswordAuthenticator searchAuthenticator() { - if (authenticators != null) { - for (LoginPasswordAuthenticator lpa : authenticators) { - if (lpa.getClass().getName().equals(classname)) { - return lpa; - } - } - } - return null; - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorNotFoundException.java b/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorNotFoundException.java index 0e57e6bbfc5..5e22a0b2ad0 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorNotFoundException.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorNotFoundException.java @@ -19,6 +19,10 @@ */ package org.sonar.server.ui; +/** + * @deprecated in 2.14 and should be removed + */ +@Deprecated public class AuthenticatorNotFoundException extends RuntimeException { public AuthenticatorNotFoundException(String classname) { 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 new file mode 100644 index 00000000000..0e669791878 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/ui/CompatibilityRealm.java @@ -0,0 +1,52 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 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.server.ui; + +import org.sonar.api.CoreProperties; +import org.sonar.api.security.LoginPasswordAuthenticator; +import org.sonar.api.security.Realm; + +/** + * Provides backward compatibility for {@link CoreProperties#CORE_AUTHENTICATOR_CLASS}. + * + * @since 2.14 + */ +class CompatibilityRealm extends Realm { + private final LoginPasswordAuthenticator authenticator; + + public CompatibilityRealm(LoginPasswordAuthenticator authenticator) { + this.authenticator = authenticator; + } + + @Override + public void init() { + authenticator.init(); + } + + @Override + public String getName() { + return "CompatibilityRealm[" + authenticator.getClass().getName() + "]"; + } + + @Override + public LoginPasswordAuthenticator getAuthenticator() { + 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/RealmFactory.java new file mode 100644 index 00000000000..db3614281b3 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/ui/RealmFactory.java @@ -0,0 +1,121 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 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.server.ui; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +/** + * @since 2.14 + */ +public class RealmFactory implements ServerComponent { + + private static final Logger INFO = LoggerFactory.getLogger("org.sonar.INFO"); + private static final Logger LOG = LoggerFactory.getLogger(RealmFactory.class); + + private final boolean ignoreStartupFailure; + private final Realm realm; + + static final String REALM_PROPERTY = "sonar.security.realm"; + + public RealmFactory(Settings settings, Realm[] 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; + if (!StringUtils.isEmpty(realmName)) { + selectedRealm = selectRealm(realms, realmName); + if (selectedRealm == null) { + LOG.error("Realm not found. Please check the property '" + REALM_PROPERTY + "' in conf/sonar.properties"); + throw new AuthenticatorNotFoundException(realmName); + } + } + if (selectedRealm == null && !StringUtils.isEmpty(className)) { + LoginPasswordAuthenticator authenticator = selectAuthenticator(authenticators, className); + if (authenticator == null) { + LOG.error("Authenticator plugin not found. Please check the property '" + CoreProperties.CORE_AUTHENTICATOR_CLASS + + "' in conf/sonar.properties"); + throw new AuthenticatorNotFoundException(className); + } + selectedRealm = new CompatibilityRealm(authenticator); + } + realm = selectedRealm; + } + + public RealmFactory(Settings settings, LoginPasswordAuthenticator[] authenticators) { + this(settings, null, authenticators); + } + + public RealmFactory(Settings settings, Realm[] realms) { + this(settings, realms, null); + } + + public RealmFactory(Settings settings) { + this(settings, null, null); + } + + public void start() { + try { + INFO.info("Security realm: " + realm.getName()); + realm.init(); + INFO.info("Security realm started"); + } catch (RuntimeException e) { + if (ignoreStartupFailure) { + LOG.error("IGNORED - Realm fails to start: " + e.getMessage()); + } else { + LOG.error("Realm fails to start: " + e.getMessage()); + throw e; + } + } + } + + public Realm getRealm() { + return realm; + } + + private static Realm selectRealm(Realm[] realms, String realmName) { + if (realms != null) { + for (Realm realm : realms) { + if (StringUtils.equals(realmName, realm.getName())) { + return realm; + } + } + } + return null; + } + + private static LoginPasswordAuthenticator selectAuthenticator(LoginPasswordAuthenticator[] authenticators, String className) { + if (authenticators != null) { + for (LoginPasswordAuthenticator lpa : authenticators) { + if (lpa.getClass().getName().equals(className)) { + return lpa; + } + } + } + return null; + } + +} 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 e0abde1c172..a24eb6bf9ac 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 @@ -21,81 +21,70 @@ # # Use Sonar database (table USERS) to authenticate users. # -class DefaultAuthenticator +class DefaultRealm def authenticate?(login, password) return false if login.blank? || password.blank? - user=User.find_by_login(login) + user = User.find_by_login(login) user && user.authenticated?(password) end - def editable_password? - true - end -end - - -# -# Use an external system to authenticate users, for example LDAP. See the Java extension point org.sonar.api.security.LoginPasswordAuthenticator. -# -class PluginAuthenticator - def initialize(java_authenticator) - @java_authenticator=java_authenticator - end - - def authenticate?(login, password) - login.present? && password.present? && @java_authenticator.authenticate(login, password) + def synchronize(user, password) + # nothing to do end def editable_password? - false + true end end # -# Since 2.14 -# Experimental -# -# Use an external system to authenticate users with fallback to Sonar database. +# Use an external security system with fallback to Sonar database. +# See the Java extension point org.sonar.api.security.Realm # -class FallbackAuthenticator - def initialize(java_authenticator) - @java_authenticator = java_authenticator +class PluginRealm + def initialize(java_realm) + @java_authenticator = java_realm.getAuthenticator() + @java_users_provider = java_realm.getUsersProvider() end def authenticate?(login, password) return false if login.blank? || password.blank? + # TODO handle exceptions if @java_authenticator.authenticate(login, password) return true end - # Fallback to password in Sonar Database + # Fallback to password from Sonar Database user = User.find_by_login(login) return user && user.authenticated?(password) end + def synchronize(user, password) + if @java_users_provider + # TODO handle exceptions + details = @java_users_provider.doGetUserDetails(user.login) + user.update_attributes(:name => details.getName(), :email => details.getEmail(), :password => password, :password_confirmation => password) + user.save + end + end + def editable_password? - true + false end end # -# Load the authentication system to use. The server must be restarted when configuration is changed. +# Load the realm to use. The server must be restarted when configuration is changed. # -class AuthenticatorFactory - @@authenticator = nil - @@users_provider = nil - - def self.authenticator - if @@authenticator.nil? - authenticator_factory=Java::OrgSonarServerUi::JRubyFacade.new.getCoreComponentByClassname('org.sonar.server.ui.AuthenticatorFactory') - component=authenticator_factory.getAuthenticator() - @@authenticator=(component ? FallbackAuthenticator.new(component) : DefaultAuthenticator.new) - @@users_provider = (component ? authenticator_factory.getUsersProvider() : nil) +class RealmFactory + @@realm = nil + + def self.realm + if @@realm.nil? + realm_factory = Java::OrgSonarServerUi::JRubyFacade.new.getCoreComponentByClassname('org.sonar.server.ui.RealmFactory') + component = realm_factory.getRealm() + @@realm = component ? PluginRealm.new(component) : DefaultRealm.new end - @@authenticator - end - - def self.users_provider - @@users_provider + @@realm end end @@ -131,44 +120,38 @@ module NeedAuthentication user = User.find_by_login(login) if user # User exists - return nil if !AuthenticatorFactory.authenticator.authenticate?(login, password) + return nil if !RealmFactory.realm.authenticate?(login, password) # Password correct - users_provider = AuthenticatorFactory.users_provider - if users_provider - # Sync details - details = AuthenticatorFactory.users_provider.doGetUserDetails(login) - user.update_attributes(:name => details.getName(), :email => details.getEmail(), :password => password, :password_confirmation => password) - # TODO log if unable to save? - user.save - end + # Synchronize details + RealmFactory.realm.synchronize(user, password) else # User not found - return nil if !AuthenticatorFactory.authenticator.authenticate?(login, password) + return nil if !RealmFactory.realm.authenticate?(login, password) # Password correct # Automatically create a user in the sonar db if authentication has been successfully done create_user = java_facade.getSettings().getBoolean('sonar.authenticator.createUsers') - users_provider = AuthenticatorFactory.users_provider - if create_user && users_provider - details = users_provider.doGetUserDetails(login) - user = User.new(:login => login, :name => details.getName(), :email => details.getEmail(), :password => password, :password_confirmation => password) + if create_user + user = User.new(:login => login, :name => login, :email => '', :password => password, :password_confirmation => password) default_group_name = java_facade.getSettings().getString('sonar.defaultGroup') - default_group=Group.find_by_name(default_group_name) + default_group = Group.find_by_name(default_group_name) if default_group user.groups<<default_group user.save else logger.error("The default user group does not exist: #{default_group_name}. Please check the parameter 'Default user group' in general settings.") end + + # Synchronize details + RealmFactory.realm.synchronize(user, password) end end - return user end def editable_password? - AuthenticatorFactory.authenticator.editable_password? + RealmFactory.realm.editable_password? end end end diff --git a/sonar-server/src/test/java/org/sonar/server/ui/AuthenticatorFactoryTest.java b/sonar-server/src/test/java/org/sonar/server/ui/AuthenticatorFactoryTest.java deleted file mode 100644 index c36aa0f3ddb..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/ui/AuthenticatorFactoryTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2011 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.server.ui; - -import org.junit.Test; -import org.sonar.api.CoreProperties; -import org.sonar.api.config.Settings; -import org.sonar.api.security.LoginPasswordAuthenticator; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertThat; - -public class AuthenticatorFactoryTest { - - @Test - public void doNotFailIfNoAuthenticationPlugins() { - AuthenticatorFactory factory = new AuthenticatorFactory(new Settings()); - assertThat(factory.getAuthenticator(), nullValue()); - factory.start(); - } - - @Test - public void startSelectedAuthenticator() { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_CLASS, FakeAuthenticator.class.getName()); - - LoginPasswordAuthenticator authenticator = new FakeAuthenticator(); - AuthenticatorFactory factory = new AuthenticatorFactory(settings, new LoginPasswordAuthenticator[]{authenticator}); - factory.start(); - assertThat(factory.getAuthenticator(), is(authenticator)); - } - - @Test(expected = ConnectionException.class) - public void authenticatorDoesNotStart() { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_CLASS, FailAuthenticator.class.getName()); - - AuthenticatorFactory factory = new AuthenticatorFactory(settings, new LoginPasswordAuthenticator[]{new FakeAuthenticator(), new FailAuthenticator()}); - factory.start(); - factory.getAuthenticator(); - } - - @Test(expected = AuthenticatorNotFoundException.class) - public void authenticatorNotFound() { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_CLASS, "foo"); - - AuthenticatorFactory factory = new AuthenticatorFactory(settings, new LoginPasswordAuthenticator[]{new FakeAuthenticator(), new FailAuthenticator()}); - factory.start(); - factory.getAuthenticator(); - } - - @Test(expected = AuthenticatorNotFoundException.class) - public void noAuthenticators() { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_CLASS, "foo"); - - AuthenticatorFactory factory = new AuthenticatorFactory(settings, null); - factory.start(); - } - - @Test - public void ignoreStartupFailure() { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_CLASS, FailAuthenticator.class.getName()); - settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE, Boolean.TRUE); - - AuthenticatorFactory factory = new AuthenticatorFactory(settings, new LoginPasswordAuthenticator[]{new FakeAuthenticator(), new FailAuthenticator()}); - factory.start(); - assertThat(factory.getAuthenticator(), not(nullValue())); - } - - static class FakeAuthenticator implements LoginPasswordAuthenticator { - public void init() { - } - - public boolean authenticate(String login, String password) { - return false; - } - } - - static class ConnectionException extends RuntimeException { - } - - static class FailAuthenticator implements LoginPasswordAuthenticator { - public void init() { - throw new ConnectionException(); - } - - public boolean authenticate(String login, String password) { - return false; - } - } -} 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 new file mode 100644 index 00000000000..46c8aa6213b --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/ui/CompatibilityRealmTest.java @@ -0,0 +1,42 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 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.server.ui; + +import org.junit.Test; +import org.sonar.api.security.LoginPasswordAuthenticator; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class CompatibilityRealmTest { + + @Test + public void shouldDelegate() { + LoginPasswordAuthenticator authenticator = mock(LoginPasswordAuthenticator.class); + CompatibilityRealm realm = new CompatibilityRealm(authenticator); + realm.init(); + verify(authenticator).init(); + assertThat(realm.getAuthenticator(), 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/RealmFactoryTest.java new file mode 100644 index 00000000000..a0436ac9120 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/ui/RealmFactoryTest.java @@ -0,0 +1,139 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 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.server.ui; + +import org.junit.Before; +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 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 { + + private Settings settings; + + @Before + public void setUp() { + settings = new Settings(); + } + + /** + * Typical usage. + */ + @Test + public void shouldSelectRealmAndStart() { + Realm realm = spy(new FakeRealm()); + settings.setProperty(RealmFactory.REALM_PROPERTY, realm.getName()); + + RealmFactory factory = new RealmFactory(settings, new Realm[] {realm}); + factory.start(); + assertThat(factory.getRealm(), is(realm)); + verify(realm).init(); + } + + @Test + public void doNotFailIfNoRealms() { + RealmFactory factory = new RealmFactory(settings); + assertThat(factory.getRealm(), nullValue()); + } + + @Test(expected = AuthenticatorNotFoundException.class) + public void realmNotFound() { + settings.setProperty(RealmFactory.REALM_PROPERTY, "Fake"); + + new RealmFactory(settings); + } + + @Test + public void shouldProvideCompatibilityForAuthenticator() { + 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(); + assertThat(realm, instanceOf(CompatibilityRealm.class)); + } + + @Test + public void shouldTakePrecedenceOverAuthenticator() { + Realm realm = new FakeRealm(); + settings.setProperty(RealmFactory.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}); + assertThat(factory.getRealm(), is(realm)); + } + + @Test(expected = AuthenticatorNotFoundException.class) + public void authenticatorNotFound() { + settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_CLASS, "Fake"); + + new RealmFactory(settings); + } + + @Test + public void ignoreStartupFailure() { + Realm realm = spy(new AlwaysFailsRealm()); + settings.setProperty(RealmFactory.REALM_PROPERTY, realm.getName()); + settings.setProperty(CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE, true); + + new RealmFactory(settings, new Realm[] {realm}).start(); + verify(realm).init(); + } + + @Test(expected = IllegalStateException.class) + public void shouldFail() { + Realm realm = spy(new AlwaysFailsRealm()); + settings.setProperty(RealmFactory.REALM_PROPERTY, realm.getName()); + + new RealmFactory(settings, new Realm[] {realm}).start(); + } + + private static class AlwaysFailsRealm extends FakeRealm { + @Override + public void init() { + throw new IllegalStateException(); + } + } + + private static class FakeRealm extends Realm { + @Override + public LoginPasswordAuthenticator getAuthenticator() { + return null; + } + } + + private static class FakeAuthenticator implements LoginPasswordAuthenticator { + public void init() { + } + + public boolean authenticate(String login, String password) { + return false; + } + } + +} |