diff --git a/pom.xml b/pom.xml index 9cf2da6d0b..a4d1254af4 100644 --- a/pom.xml +++ b/pom.xml @@ -434,8 +434,8 @@ 1.5.3 - 1.7.5 - 1.0.13 + 1.7.6 + 1.1.1 2.5 3.0 1.18 diff --git a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java index 521f955e0f..338424d824 100644 --- a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java +++ b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java @@ -42,6 +42,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.event.ScmEventBus; +import sonia.scm.util.HttpUtil; import sonia.scm.xml.XmlSetStringAdapter; //~--- JDK imports ------------------------------------------------------------ @@ -114,6 +115,7 @@ public class ScmConfiguration */ public void load(ScmConfiguration other) { + this.realmDescription = other.realmDescription; this.dateFormat = other.dateFormat; this.pluginUrl = other.pluginUrl; this.anonymousAccessEnabled = other.anonymousAccessEnabled; @@ -129,6 +131,7 @@ public class ScmConfiguration this.baseUrl = other.baseUrl; this.disableGroupingGrid = other.disableGroupingGrid; this.enableRepositoryArchive = other.enableRepositoryArchive; + this.skipFailedAuthenticators = other.skipFailedAuthenticators; this.loginAttemptLimit = other.loginAttemptLimit; this.loginAttemptLimitTimeout = other.loginAttemptLimitTimeout; } @@ -287,6 +290,18 @@ public class ScmConfiguration return proxyUser; } + /** + * Returns the realm description. + * + * + * @return realm description + */ + public String getRealmDescription() + { + return realmDescription; + } + + /** * Returns true if the anonymous access to the SCM-Manager is enabled. * @@ -343,6 +358,19 @@ public class ScmConfiguration return forceBaseUrl; } + /** + * Returns true if failed authenticators are skipped. + * + * + * @return true if failed authenticators are skipped + * + * @since 1.36 + */ + public boolean isSkipFailedAuthenticators() + { + return skipFailedAuthenticators; + } + //~--- set methods ---------------------------------------------------------- /** @@ -544,6 +572,30 @@ public class ScmConfiguration this.proxyUser = proxyUser; } + /** + * Sets the realm description. + * + * + * @param realmDescription + */ + public void setRealmDescription(String realmDescription) + { + this.realmDescription = realmDescription; + } + + /** + * If set to true the authentication chain is not stopped, if an + * authenticator finds the user but fails to authenticate the user. + * + * @param skipFailedAuthenticators true to skip failed authenticators + * + * @since 1.36 + */ + public void setSkipFailedAuthenticators(boolean skipFailedAuthenticators) + { + this.skipFailedAuthenticators = skipFailedAuthenticators; + } + //~--- fields --------------------------------------------------------------- /** Field description */ @@ -572,21 +624,6 @@ public class ScmConfiguration @XmlElement(name = "login-attempt-limit") private int loginAttemptLimit = -1; - /** - * Login attempt timeout. - * - * @since 1.34 - */ - @XmlElement(name = "login-attempt-limit-timeout") - private long loginAttemptLimitTimeout = TimeUnit.MINUTES.toSeconds(5l); - - /** Field description */ - private boolean enableProxy = false; - - /** Field description */ - @XmlElement(name = "plugin-url") - private String pluginUrl = DEFAULT_PLUGINURL; - /** glob patterns for urls which are excluded from proxy */ @XmlElement(name = "proxy-excludes") @XmlJavaTypeAdapter(XmlSetStringAdapter.class) @@ -604,6 +641,36 @@ public class ScmConfiguration /** Field description */ private String proxyUser; + /** + * Skip failed authenticators. + * + * @since 1.36 + */ + @XmlElement(name = "skip-failed-authenticators") + private boolean skipFailedAuthenticators = false; + + /** Field description */ + @XmlElement(name = "plugin-url") + private String pluginUrl = DEFAULT_PLUGINURL; + + /** + * Login attempt timeout. + * + * @since 1.34 + */ + @XmlElement(name = "login-attempt-limit-timeout") + private long loginAttemptLimitTimeout = TimeUnit.MINUTES.toSeconds(5l); + + /** Field description */ + private boolean enableProxy = false; + + /** + * + * Authentication realm for basic authentication. + * + */ + private String realmDescription = HttpUtil.AUTHENTICATION_REALM; + /** Field description */ private boolean enableRepositoryArchive = false; diff --git a/scm-core/src/main/java/sonia/scm/util/HttpUtil.java b/scm-core/src/main/java/sonia/scm/util/HttpUtil.java index f1ce453cc1..69f913d74d 100644 --- a/scm-core/src/main/java/sonia/scm/util/HttpUtil.java +++ b/scm-core/src/main/java/sonia/scm/util/HttpUtil.java @@ -416,7 +416,7 @@ public final class HttpUtil throws IOException { - sendUnauthorized(null, response); + sendUnauthorized(null, response, AUTHENTICATION_REALM); } /** @@ -427,17 +427,50 @@ public final class HttpUtil * @param response http response * * @throws IOException - * - * @since 1.19 */ public static void sendUnauthorized(HttpServletRequest request, HttpServletResponse response) throws IOException + { + sendUnauthorized(request, response, AUTHENTICATION_REALM); + } + + /** + * Send an unauthorized header back to the client + * + * + * @param response - the http response + * @param realmDescription - realm description + * + * @throws IOException + */ + public static void sendUnauthorized(HttpServletResponse response, String realmDescription) + throws IOException + { + sendUnauthorized(null, response, realmDescription); + } + + /** + * Send an unauthorized header back to the client + * + * + * @param request http request + * @param response http response + * @param realmDescription realm description + * + * @throws IOException + * + * @since 1.19 + */ + public static void sendUnauthorized(HttpServletRequest request, + HttpServletResponse response, + String realmDescription) + throws IOException { if ((request == null) ||!isWUIRequest(request)) { response.setHeader(HEADER_WWW_AUTHENTICATE, - "Basic realm=\"".concat(AUTHENTICATION_REALM).concat("\"")); + "Basic realm=\"".concat(realmDescription).concat("\"")); } else if (logger.isTraceEnabled()) diff --git a/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java index 21ad28b6ea..5992fd4cf7 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java @@ -203,7 +203,7 @@ public class BasicAuthenticationFilter extends AutoLoginFilter if (Strings.isNullOrEmpty(authentication)) { - HttpUtil.sendUnauthorized(request, response); + HttpUtil.sendUnauthorized(request, response, configuration.getRealmDescription()); } else { diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java index 1b8b4dce11..9767f1d43e 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java @@ -245,7 +245,7 @@ public abstract class PermissionFilter extends HttpFilter } else { - HttpUtil.sendUnauthorized(response); + HttpUtil.sendUnauthorized(response, configuration.getRealmDescription()); } } diff --git a/scm-dao-xml/src/main/java/sonia/scm/xml/AbstractXmlDAO.java b/scm-dao-xml/src/main/java/sonia/scm/xml/AbstractXmlDAO.java index 33765ce8a0..a0baa41034 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/xml/AbstractXmlDAO.java +++ b/scm-dao-xml/src/main/java/sonia/scm/xml/AbstractXmlDAO.java @@ -34,6 +34,7 @@ package sonia.scm.xml; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -229,7 +230,8 @@ public abstract class AbstractXmlDAO getAll() { - return db.values(); + // avoid concurrent modification exceptions + return ImmutableList.copyOf(db.values()); } /** diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/DBFormatHealthCheck.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/DBFormatHealthCheck.java index c9958f24fb..1f90943e6f 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/DBFormatHealthCheck.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/DBFormatHealthCheck.java @@ -77,7 +77,7 @@ public class DBFormatHealthCheck extends DirectoryHealthCheck /** Field description */ private static final HealthCheckFailure INCOMPATIBLE_DB_FORMAT = new HealthCheckFailure("AnOTx99ex1", "Incompatible DB Format", - "https://bitbucket.org/sdorra/scm-manager/wiki/healtchecks/svn-incompatible-dbformat", + "https://bitbucket.org/sdorra/scm-manager/wiki/healthchecks/svn-incompatible-dbformat", "The subversion db format is incompatible with the svn version used within scm-manager."); /** Field description */ diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/IllegalArgumentExceptionMapper.java b/scm-webapp/src/main/java/sonia/scm/api/rest/IllegalArgumentExceptionMapper.java new file mode 100644 index 0000000000..32b6a02bc6 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/IllegalArgumentExceptionMapper.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.api.rest; + +//~--- JDK imports ------------------------------------------------------------ + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * + * @author Sebastian Sdorra + * @since 1.36 + */ +@Provider +public class IllegalArgumentExceptionMapper + implements ExceptionMapper +{ + + /** + * Method description + * + * + * @param exception + * + * @return + */ + @Override + public Response toResponse(IllegalArgumentException exception) + { + return Response.status(Status.BAD_REQUEST).build(); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java index 507ab86b1f..29e47ef737 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java @@ -35,6 +35,8 @@ package sonia.scm.api.rest.resources; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.inject.Inject; @@ -153,6 +155,7 @@ public class AuthenticationResource *
* @@ -172,6 +175,11 @@ public class AuthenticationResource @FormParam("password") String password, @FormParam("rememberMe") @DefaultValue("false") boolean rememberMe) { + Preconditions.checkArgument(!Strings.isNullOrEmpty(username), + "username parameter is required"); + Preconditions.checkArgument(!Strings.isNullOrEmpty(password), + "password parameter is required"); + Response response; Subject subject = SecurityUtils.getSubject(); diff --git a/scm-webapp/src/main/java/sonia/scm/security/DefaultKeyGenerator.java b/scm-webapp/src/main/java/sonia/scm/security/DefaultKeyGenerator.java index 2ed55e4487..149840b106 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/DefaultKeyGenerator.java +++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultKeyGenerator.java @@ -30,6 +30,7 @@ */ + package sonia.scm.security; //~--- non-JDK imports -------------------------------------------------------- @@ -68,6 +69,17 @@ public class DefaultKeyGenerator implements KeyGenerator //~--- methods -------------------------------------------------------------- + /** + * Method description + * + * + * @param args + */ + public static void main(String[] args) + { + System.out.println(new DefaultKeyGenerator().createKey()); + } + /** * Method description * @@ -107,8 +119,8 @@ public class DefaultKeyGenerator implements KeyGenerator //~--- fields --------------------------------------------------------------- /** Field description */ - private AtomicLong sessionKey = new AtomicLong(); + private final AtomicLong sessionKey = new AtomicLong(); /** Field description */ - private Random random = new Random(); + private final Random random = new Random(); } diff --git a/scm-webapp/src/main/java/sonia/scm/security/ScmRealm.java b/scm-webapp/src/main/java/sonia/scm/security/ScmRealm.java index 6fff389a3d..68a58cb124 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/ScmRealm.java +++ b/scm-webapp/src/main/java/sonia/scm/security/ScmRealm.java @@ -361,7 +361,10 @@ public class ScmRealm extends AuthorizingRealm // modify existing user, copy properties except password and admin if (user.copyProperties(dbUser, false)) { - userManager.modify(dbUser); + user.setLastModified(System.currentTimeMillis()); + UserEventHack.fireEvent(userManager, HandlerEventType.BEFORE_MODIFY, user); + userDAO.modify(user); + UserEventHack.fireEvent(userManager, HandlerEventType.MODIFY, user); } } diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java b/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java index ff1310f22e..eeade3f1a2 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java @@ -47,6 +47,7 @@ import org.slf4j.LoggerFactory; import sonia.scm.SCMContextProvider; import sonia.scm.cache.Cache; import sonia.scm.cache.CacheManager; +import sonia.scm.config.ScmConfiguration; import sonia.scm.security.EncryptionHandler; import sonia.scm.user.User; import sonia.scm.user.UserManager; @@ -85,19 +86,21 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager * Constructs ... * * - * + * @param configuration * @param userManager * @param authenticationHandlerSet * @param encryptionHandler * @param cacheManager */ @Inject - public ChainAuthenticatonManager(UserManager userManager, + public ChainAuthenticatonManager(ScmConfiguration configuration, + UserManager userManager, Set authenticationHandlerSet, EncryptionHandler encryptionHandler, CacheManager cacheManager) { AssertUtil.assertIsNotEmpty(authenticationHandlerSet); AssertUtil.assertIsNotNull(cacheManager); + this.configuration = configuration; this.authenticationHandlers = sort(userManager, authenticationHandlerSet); this.encryptionHandler = encryptionHandler; this.cache = cacheManager.getCache(CACHE_NAME); @@ -190,6 +193,22 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager } } + /** + * Method description + * + * + * @param result + * + * @return + */ + boolean stopChain(AuthenticationResult result) + { + return (result != null) && (result.getState() != null) + && (result.getState().isSuccessfully() + || ((result.getState() == AuthenticationState.FAILED) + &&!configuration.isSkipFailedAuthenticators())); + } + /** * Method description * @@ -230,9 +249,7 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager authenticator.getClass().getName(), result); } - if ((result != null) && (result.getState() != null) - && (result.getState().isSuccessfully() - || (result.getState() == AuthenticationState.FAILED))) + if (stopChain(result)) { if (result.getState().isSuccessfully() && (result.getUser() != null)) { @@ -372,7 +389,10 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager /** authentication cache */ private final Cache cache; - + + /** Field description */ + private final ScmConfiguration configuration; + /** encryption handler */ private final EncryptionHandler encryptionHandler; } diff --git a/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js b/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js index 72b85e2e8a..29efa3fa00 100644 --- a/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/config/sonia.config.scmconfigpanel.js @@ -34,6 +34,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ titleText: 'General Settings', servnameText: 'Servername', + realmDescriptionText: 'Realm description', dateFormatText: 'Date format', enableForwardingText: 'Enable forwarding (mod_proxy)', forwardPortText: 'Forward Port', @@ -50,6 +51,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ errorSubmitMsgText: 'Could not submit config.', // TODO i18n + skipFailedAuthenticatorsText: 'Skip failed authenticators', loginAttemptLimitText: 'Login Attempt Limit', loginAttemptLimitTimeoutText: 'Login Attempt Limit Timeout', @@ -67,6 +69,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ // help servernameHelpText: 'The name of this server. This name will be part of the repository url.', + realmDescriptionHelpText: 'Enter authentication realm description', // TODO i18n dateFormatHelpText: 'Moments date format. Please have a look at \n\ http://momentjs.com/docs/#/displaying/format/.
\n\ @@ -83,6 +86,8 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ adminUsersHelpText: 'Comma seperated list of users with admin permissions.', // TODO i18n + skipFailedAuthenticatorsHelpText: 'Do not stop the authentication chain, \n\ + if an authenticator finds the user but fails to authenticate the user.', loginAttemptLimitHelpText: 'Maximum allowed login attempts. Use -1 to disable the login attempt limit.', loginAttemptLimitTimeoutHelpText: 'Timeout in seconds for users which are temporary disabled,\ because of too many failed login attempts.', @@ -129,6 +134,12 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ name: 'enableRepositoryArchive', inputValue: 'true', helpText: this.enableRepositoryArchiveHelpText + },{ + xtype: 'textfield', + fieldLabel: this.realmDescriptionText, + name: 'realmDescription', + allowBlank: false, + helpText: this.realmDescriptionHelpText },{ xtype: 'textfield', fieldLabel: this.dateFormatText, @@ -149,6 +160,12 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{ name: 'anonymousAccessEnabled', inputValue: 'true', helpText: this.allowAnonymousAccessHelpText + },{ + xtype: 'checkbox', + fieldLabel: this.skipFailedAuthenticatorsText, + name: 'skip-failed-authenticators', + inputValue: 'true', + helpText: this.skipFailedAuthenticatorsHelpText },{ xtype: 'numberfield', fieldLabel: this.loginAttemptLimitText, diff --git a/scm-webapp/src/main/webapp/resources/js/i18n/de.js b/scm-webapp/src/main/webapp/resources/js/i18n/de.js index 40b6b6dca6..6c8e00f8e4 100644 --- a/scm-webapp/src/main/webapp/resources/js/i18n/de.js +++ b/scm-webapp/src/main/webapp/resources/js/i18n/de.js @@ -40,7 +40,7 @@ if (Ext.form.VTypes){ passwordText: 'Die Passwörter stimmen nicht überein!', nameTest: 'Der Name ist invalid.', usernameText: 'Der Benutzername ist invalid.', - repositoryNameText: 'Der Name des Repositorys ist ungültig.', + repositoryNameText: 'Der Name des Repositorys ist ungültig.' }); } @@ -349,6 +349,10 @@ if (Sonia.config.ScmConfigPanel){ adminGroupsHelpText: 'Komma getrennte Liste von Gruppen mit Administrationsrechten.', adminUsersHelpText: 'Komma getrennte Liste von Benutzern mit Administrationsrechten.', + skipFailedAuthenticatorsText: 'Überspringe fehlgeschlagene Authentifizierer', + skipFailedAuthenticatorsHelpText: 'Setzt die Authentifizierungs-Kette fort,\n\ + auch wenn ein ein Authentifizierer einen Benutzer gefunden hat,\n\ + diesen aber nicht Authentifizieren kann.', loginAttemptLimitText: 'Login Attempt Limit', loginAttemptLimitTimeoutText: 'Login Attempt Limit Timeout', loginAttemptLimitHelpText: 'Maximale Anzahl gescheiterte Loginversuche. Der Wert -1 deaktiviert die Begrenzung.', diff --git a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js index b6db7fb59f..99293a225d 100644 --- a/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js +++ b/scm-webapp/src/main/webapp/resources/js/repository/sonia.repository.grid.js @@ -99,7 +99,8 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, { },{ name: 'archived' },{ - name: 'healthCheckFailures' + name: 'healthCheckFailures', + defaultValue: null }] }), sortInfo: { diff --git a/scm-webapp/src/test/java/sonia/scm/web/security/ChainAuthenticationManagerTest.java b/scm-webapp/src/test/java/sonia/scm/web/security/ChainAuthenticationManagerTest.java index 1de9959a7b..1fa0ff384a 100644 --- a/scm-webapp/src/test/java/sonia/scm/web/security/ChainAuthenticationManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/web/security/ChainAuthenticationManagerTest.java @@ -42,6 +42,7 @@ import org.junit.Test; import sonia.scm.AbstractTestBase; import sonia.scm.SCMContextProvider; import sonia.scm.cache.MapCacheManager; +import sonia.scm.config.ScmConfiguration; import sonia.scm.security.MessageDigestEncryptionHandler; import sonia.scm.user.User; import sonia.scm.user.UserManager; @@ -136,7 +137,7 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase SingleUserAuthenticaionHandler a2 = new SingleUserAuthenticaionHandler("a2", trillian); - manager = createManager("a2", a1, a2); + manager = createManager("a2", false, a1, a2); AuthenticationResult result = manager.authenticate(request, response, trillian.getName(), "trillian123"); @@ -146,6 +147,24 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase assertEquals("a2", result.getUser().getType()); } + /** + * Method description + * + */ + @Test + public void testStopChain() + { + ChainAuthenticatonManager cam = createManager("", false); + + assertTrue(cam.stopChain(new AuthenticationResult(perfect))); + assertTrue(cam.stopChain(AuthenticationResult.FAILED)); + assertFalse(cam.stopChain(AuthenticationResult.NOT_FOUND)); + cam = createManager("", true); + assertTrue(cam.stopChain(new AuthenticationResult(perfect))); + assertFalse(cam.stopChain(AuthenticationResult.FAILED)); + assertFalse(cam.stopChain(AuthenticationResult.NOT_FOUND)); + } + /** * Method description * @@ -198,7 +217,7 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase trillian = UserTestData.createTrillian(); trillian.setPassword("trillian123"); - return createManager("", + return createManager("", false, new SingleUserAuthenticaionHandler("perfectsType", perfect), new SingleUserAuthenticaionHandler("trilliansType", trillian)); } @@ -208,20 +227,33 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase * * * @param defaultType + * @param skipFailedAuthenticators * @param handlers * * @return */ private ChainAuthenticatonManager createManager(String defaultType, - AuthenticationHandler... handlers) + boolean skipFailedAuthenticators, AuthenticationHandler... handlers) { + if ( handlers == null || handlers.length == 0 ){ + //J- + handlers = new AuthenticationHandler[]{ + new SingleUserAuthenticaionHandler("perfectsType", perfect), + new SingleUserAuthenticaionHandler("trilliansType", trillian) + }; + //J+ + } + ScmConfiguration configuration = new ScmConfiguration(); + + configuration.setSkipFailedAuthenticators(skipFailedAuthenticators); + Set handlerSet = ImmutableSet.copyOf(handlers); UserManager userManager = mock(UserManager.class); when(userManager.getDefaultType()).thenReturn(defaultType); - manager = new ChainAuthenticatonManager(userManager, handlerSet, - new MessageDigestEncryptionHandler(), new MapCacheManager()); + manager = new ChainAuthenticatonManager(configuration, userManager, + handlerSet, new MessageDigestEncryptionHandler(), new MapCacheManager()); manager.init(contextProvider); return manager; @@ -326,10 +358,10 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase //~--- fields ------------------------------------------------------------- /** Field description */ - private String type; + private final String type; /** Field description */ - private User user; + private final User user; }