@@ -0,0 +1,35 @@ | |||
/* | |||
* 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.api.security; | |||
import com.google.common.annotations.Beta; | |||
import org.sonar.api.ServerExtension; | |||
import java.util.Collection; | |||
/** | |||
* @since 2.14 | |||
*/ | |||
@Beta | |||
public interface ExternalGroupsProvider extends ServerExtension { | |||
Collection<String> doGetGroups(String username); | |||
} |
@@ -19,9 +19,8 @@ | |||
*/ | |||
package org.sonar.api.security; | |||
import org.sonar.api.ServerExtension; | |||
import com.google.common.annotations.Beta; | |||
import org.sonar.api.ServerExtension; | |||
/** | |||
* @since 2.14 | |||
@@ -29,6 +28,6 @@ import com.google.common.annotations.Beta; | |||
@Beta | |||
public interface ExternalUsersProvider extends ServerExtension { | |||
UserDetails doGetUserDetails(String login); | |||
UserDetails doGetUserDetails(String username); | |||
} |
@@ -0,0 +1,60 @@ | |||
/* | |||
* 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.api.security; | |||
import com.google.common.annotations.Beta; | |||
import org.sonar.api.ServerExtension; | |||
/** | |||
* @since 2.14 | |||
*/ | |||
@Beta | |||
public abstract class Realm implements ServerExtension { | |||
/** | |||
* @return unique name of this realm, e.g. "LDAP" | |||
*/ | |||
public String getName() { | |||
return getClass().getSimpleName(); | |||
} | |||
public void init() { | |||
} | |||
/** | |||
* @return {@link LoginPasswordAuthenticator} associated with this realm, never null | |||
*/ | |||
public abstract LoginPasswordAuthenticator getAuthenticator(); | |||
/** | |||
* @return {@link ExternalUsersProvider} associated with this realm, null if not supported | |||
*/ | |||
public ExternalUsersProvider getUsersProvider() { | |||
return null; | |||
} | |||
/** | |||
* @return {@link ExternalGroupsProvider} associated with this realm, null if not supported | |||
*/ | |||
public ExternalGroupsProvider getGroupsProvider() { | |||
return null; | |||
} | |||
} |
@@ -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); |
@@ -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; | |||
} | |||
} |
@@ -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) { |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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 |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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() + "]")); | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |