Author: angela Date: Thu Nov 28 15:37:42 2019 New Revision: 1870559 URL: http://svn.apache.org/viewvc?rev=1870559&view=rev Log: OAK-8710 : AbstractLoginModule#logout() must not remove 'foreign' principals/credentials
Modified: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/PreAuthLoginModule.java jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleTest.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModule.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImpl.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestLoginModule.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModuleTest.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImplTest.java jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.groovy jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.groovy jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.java jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModule.java jackrabbit/oak/trunk/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModuleTest.java jackrabbit/oak/trunk/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModuleTest.java Modified: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java (original) +++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java Thu Nov 28 15:37:42 2019 @@ -57,7 +57,10 @@ import javax.security.auth.login.LoginEx import java.security.Principal; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * {@code ExternalLoginModule} implements a {@code LoginModule} that uses an @@ -190,19 +193,19 @@ public class ExternalLoginModule extends if (idp == null || syncHandler == null) { return false; } - credentials = getCredentials(); + Credentials creds = getCredentials(); // check if we have a pre authenticated login from a previous login module final PreAuthenticatedLogin preAuthLogin = getSharedPreAuthLogin(); - final String userId = getUserId(preAuthLogin, credentials); + final String userId = getUserId(preAuthLogin, creds); - if (userId == null && credentials == null) { + if (userId == null && creds == null) { log.debug("No credentials|userId found for external login module. ignoring."); return false; } // remember identification for log-output - Object logId = (userId != null) ? userId : credentials; + Object logId = (userId != null) ? userId : creds; try { // check if there exists a user with the given ID that has been synchronized // before into the repository. @@ -220,15 +223,15 @@ public class ExternalLoginModule extends if (preAuthLogin != null) { externalUser = idp.getUser(preAuthLogin.getUserId()); } else { - externalUser = idp.authenticate(credentials); + externalUser = idp.authenticate(creds); } if (externalUser != null) { log.debug("IDP {} returned valid user {}", idp.getName(), externalUser); - if (credentials != null) { + if (creds != null) { //noinspection unchecked - sharedState.put(SHARED_KEY_CREDENTIALS, credentials); + sharedState.put(SHARED_KEY_CREDENTIALS, creds); } //noinspection unchecked @@ -236,6 +239,8 @@ public class ExternalLoginModule extends syncUser(externalUser); + // login successful -> remember credentials for commit/logout + credentials = creds; return true; } else { debug("IDP {} returned null for {}", idp.getName(), logId.toString()); @@ -293,6 +298,12 @@ public class ExternalLoginModule extends return true; } + @Override + public boolean logout() throws LoginException { + Set creds = Stream.of(credentials, authInfo).filter(Objects::nonNull).collect(Collectors.toSet()); + return logout((creds.isEmpty() ? null : creds), principals); + } + //------------------------------------------------------------< private >--- @Nullable Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/PreAuthLoginModule.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/PreAuthLoginModule.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/PreAuthLoginModule.java (original) +++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/PreAuthLoginModule.java Thu Nov 28 15:37:42 2019 @@ -58,4 +58,9 @@ public final class PreAuthLoginModule ex public boolean commit() { return false; } + + @Override + public boolean logout() { + return false; + } } Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleTest.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleTest.java (original) +++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleTest.java Thu Nov 28 15:37:42 2019 @@ -121,12 +121,16 @@ public class ExternalLoginModuleTest ext verify(extIPMgr, never()).getProvider("idp"); verify(syncManager, never()).getSyncHandler("syncHandler"); assertFalse(loginModule.login()); + assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test public void testInitializeMissingIdpSyncHandler() throws LoginException { loginModule.initialize(new Subject(), createCallbackHandler(wb, null, null, null), Collections.emptyMap(), ImmutableMap.of(PARAM_IDP_NAME, "idp", PARAM_SYNC_HANDLER_NAME, "syncHandler")); assertFalse(loginModule.login()); + assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -139,6 +143,8 @@ public class ExternalLoginModuleTest ext verify(extIPMgr, times(1)).getProvider("idp"); verify(syncManager, times(1)).getSyncHandler("syncHandler"); assertFalse(loginModule.login()); + assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -161,6 +167,8 @@ public class ExternalLoginModuleTest ext @Test public void testLoginWithoutInit() throws Exception { assertFalse(loginModule.login()); + assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -170,6 +178,8 @@ public class ExternalLoginModuleTest ext loginModule.initialize(new Subject(), createCallbackHandler(wb, null, null, null), Collections.emptyMap(), Collections.singletonMap(PARAM_IDP_NAME, "idpName")); assertFalse(loginModule.login()); + assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -189,6 +199,8 @@ public class ExternalLoginModuleTest ext loginModule.initialize(new Subject(), cbh, new HashMap<>(), ImmutableMap.of(PARAM_IDP_NAME, DEFAULT_IDP_NAME, PARAM_SYNC_HANDLER_NAME, "syncHandler")); assertFalse(loginModule.login()); + assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -215,6 +227,9 @@ public class ExternalLoginModuleTest ext root.refresh(); assertNotNull(getUserManager(root).getAuthorizable(ID_TEST_USER)); + + assertTrue(loginModule.logout()); + assertTrue(subject.getPublicCredentials().isEmpty()); } @Test @@ -247,6 +262,13 @@ public class ExternalLoginModuleTest ext assertFalse(subject.getPublicCredentials(AuthInfo.class).isEmpty()); AuthInfo info = subject.getPublicCredentials(AuthInfo.class).iterator().next(); assertTrue(info.getPrincipals().contains(principal)); + + assertTrue(loginModule.logout()); + + // authinfo must be removed upon logout + assertTrue(subject.getPublicCredentials(AuthInfo.class).isEmpty()); + // predefined principal must _not_ be removed + assertTrue(subject.getPrincipals().contains(principal)); } @Test @@ -277,6 +299,10 @@ public class ExternalLoginModuleTest ext AuthInfo authInfo = subject.getPublicCredentials(AuthInfo.class).iterator().next(); assertNull(authInfo.getAttribute("attr")); + + assertTrue(loginModule.logout()); + assertTrue(subject.getPublicCredentials().isEmpty()); + assertTrue(subject.getPrincipals().isEmpty()); } @Test @@ -300,6 +326,8 @@ public class ExternalLoginModuleTest ext root.refresh(); assertNotNull(getUserManager(root).getAuthorizable(ID_TEST_USER)); + + assertTrue(loginModule.logout()); } @Test(expected = LoginException.class) @@ -398,6 +426,9 @@ public class ExternalLoginModuleTest ext assertFalse(loginModule.login()); root.refresh(); assertNull(getUserManager(root).getAuthorizable("local")); + + assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test(expected = LoginException.class) Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModule.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModule.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModule.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModule.java Thu Nov 28 15:37:42 2019 @@ -21,7 +21,10 @@ import java.security.Principal; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.jcr.Credentials; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; @@ -191,6 +194,12 @@ public final class TokenLoginModule exte return false; } + @Override + public boolean logout() throws LoginException { + Set creds = Stream.of(tokenCredentials, authInfo).filter(Objects::nonNull).collect(Collectors.toSet()); + return logout((creds.isEmpty() ? null : creds), principals); + } + //------------------------------------------------< AbstractLoginModule >--- @NotNull @Override Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImpl.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImpl.java Thu Nov 28 15:37:42 2019 @@ -44,7 +44,10 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Default login module implementation that authenticates JCR {@code Credentials} @@ -181,6 +184,12 @@ public final class LoginModuleImpl exten } } + @Override + public boolean logout() throws LoginException { + Set creds = Stream.of(credentials, authInfo).filter(Objects::nonNull).collect(Collectors.toSet()); + return logout((creds.isEmpty() ? null : creds), principals); + } + //------------------------------------------------< AbstractLoginModule >--- @NotNull @Override Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestLoginModule.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestLoginModule.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestLoginModule.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestLoginModule.java Thu Nov 28 15:37:42 2019 @@ -16,23 +16,29 @@ */ package org.apache.jackrabbit.oak.security.authentication.token; -import java.util.Map; -import java.util.Set; -import javax.jcr.Credentials; -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; - +import com.google.common.collect.ImmutableSet; +import org.apache.jackrabbit.oak.api.AuthInfo; import org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule; import org.apache.jackrabbit.oak.spi.security.authentication.AuthInfoImpl; import org.apache.jackrabbit.oak.spi.security.authentication.credentials.CredentialsSupport; import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal; import org.jetbrains.annotations.NotNull; +import javax.jcr.Credentials; +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.login.LoginException; +import java.security.Principal; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + public class TestLoginModule extends AbstractLoginModule { private CredentialsSupport credentialsSupport; private Credentials credentials; private String userId; + private AuthInfo info; @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { @@ -48,6 +54,16 @@ public class TestLoginModule extends Abs } @Override + public boolean logout() throws LoginException { + if (credentials != null) { + Set<? extends Principal> s = Collections.singleton(EveryonePrincipal.getInstance()); + return logout(ImmutableSet.of(credentials), s); + } else { + return false; + } + } + + @Override public boolean login() { credentials = getCredentials(); if (credentials != null) { @@ -64,9 +80,11 @@ public class TestLoginModule extends Abs public boolean commit() { if (userId != null) { subject.getPrincipals().add(EveryonePrincipal.getInstance()); - setAuthInfo(new AuthInfoImpl(userId, credentialsSupport.getAttributes(credentials), subject.getPrincipals()), subject); + info = new AuthInfoImpl(userId, credentialsSupport.getAttributes(credentials), subject.getPrincipals()); + setAuthInfo(info, subject); return true; } else { + clearState(); return false; } } Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModuleTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModuleTest.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModuleTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModuleTest.java Thu Nov 28 15:37:42 2019 @@ -59,7 +59,6 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -196,6 +195,8 @@ public class TokenLoginModuleTest extend lm.initialize(new Subject(), null, ImmutableMap.<String, Object>of(), ImmutableMap.<String, Object>of()); assertFalse(lm.login()); + assertFalse(lm.commit()); + assertFalse(lm.logout()); } @Test @@ -204,6 +205,8 @@ public class TokenLoginModuleTest extend lm.initialize(new Subject(), new TestCallbackHandler(null), ImmutableMap.<String, Object>of(), ImmutableMap.<String, Object>of()); assertFalse(lm.login()); + assertFalse(lm.commit()); + assertFalse(lm.logout()); } @@ -216,6 +219,7 @@ public class TokenLoginModuleTest extend assertFalse(lm.login()); assertFalse(lm.commit()); + assertFalse(lm.logout()); } @Test @@ -226,6 +230,8 @@ public class TokenLoginModuleTest extend lm.initialize(new Subject(), new TestCallbackHandler(tp), ImmutableMap.<String, Object>of(), ImmutableMap.<String, Object>of()); assertFalse(lm.login()); + assertFalse(lm.commit()); + assertFalse(lm.logout()); } @Test @@ -234,6 +240,8 @@ public class TokenLoginModuleTest extend lm.initialize(new Subject(), new ThrowingCallbackHandler(UnsupportedCallbackException.class), ImmutableMap.<String, Object>of(), ImmutableMap.<String, Object>of()); assertFalse(lm.login()); + assertFalse(lm.commit()); + assertFalse(lm.logout()); } @Test @@ -242,6 +250,8 @@ public class TokenLoginModuleTest extend lm.initialize(new Subject(), new ThrowingCallbackHandler(IOException.class), ImmutableMap.<String, Object>of(), ImmutableMap.<String, Object>of()); assertFalse(lm.login()); + assertFalse(lm.commit()); + assertFalse(lm.logout()); } @Test(expected = LoginException.class) @@ -261,6 +271,7 @@ public class TokenLoginModuleTest extend lm.commit(); } finally { verify(tp, times(1)).doCreateToken(any(Credentials.class)); + assertFalse(lm.logout()); } } @@ -288,6 +299,12 @@ public class TokenLoginModuleTest extend assertTrue(lm.commit()); assertEquals(ImmutableSet.of(getTestUser().getPrincipal(), EveryonePrincipal.getInstance()), subject.getPrincipals()); + assertFalse(subject.getPublicCredentials(AuthInfo.class).isEmpty()); + assertFalse(subject.getPublicCredentials(TokenCredentials.class).isEmpty()); + + assertTrue(lm.logout()); + assertTrue(subject.getPublicCredentials().isEmpty()); + assertTrue(subject.getPrincipals().isEmpty()); } @Test @@ -311,6 +328,8 @@ public class TokenLoginModuleTest extend assertFalse(lm.commit()); verify(tp, times(1)).createToken(sc); assertTrue(subject.getPublicCredentials(TokenCredentials.class).isEmpty()); + + assertFalse(lm.logout()); } @Test @@ -325,6 +344,7 @@ public class TokenLoginModuleTest extend assertFalse(lm.login()); assertFalse(lm.commit()); verify(tp, never()).createToken(any(Credentials.class)); + assertFalse(lm.logout()); } @Test @@ -339,6 +359,7 @@ public class TokenLoginModuleTest extend assertFalse(lm.login()); assertFalse(lm.commit()); verify(tp, never()).doCreateToken(any(Credentials.class)); + assertFalse(lm.logout()); } @Test @@ -365,6 +386,7 @@ public class TokenLoginModuleTest extend assertFalse(lm.login()); assertFalse(lm.commit()); verify(tp, times(1)).createToken(sc); + assertFalse(lm.logout()); } @Test @@ -391,6 +413,7 @@ public class TokenLoginModuleTest extend assertFalse(lm.login()); assertFalse(lm.commit()); verify(tp, times(1)).createToken(sc); + assertFalse(lm.logout()); } @Test Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImplTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImplTest.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImplTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImplTest.java Thu Nov 28 15:37:42 2019 @@ -19,7 +19,6 @@ package org.apache.jackrabbit.oak.securi import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials; import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.User; import org.apache.jackrabbit.api.security.user.UserManager; @@ -28,8 +27,8 @@ import org.apache.jackrabbit.oak.api.Aut import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.api.ContentSession; import org.apache.jackrabbit.oak.api.Root; -import org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule; -import org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModuleTest; +import org.apache.jackrabbit.oak.commons.junit.LogCustomizer; +import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.security.internal.SecurityProviderBuilder; import org.apache.jackrabbit.oak.security.user.UserAuthenticationFactoryImpl; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; @@ -42,6 +41,7 @@ import org.apache.jackrabbit.oak.spi.sec import org.apache.jackrabbit.oak.spi.security.authentication.PreAuthenticatedLogin; import org.apache.jackrabbit.oak.spi.security.authentication.callback.CredentialsCallback; import org.apache.jackrabbit.oak.spi.security.authentication.callback.RepositoryCallback; +import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration; import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl; import org.apache.jackrabbit.oak.spi.security.user.UserAuthenticationFactory; import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration; @@ -50,6 +50,7 @@ import org.apache.jackrabbit.oak.spi.sec import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Test; +import org.slf4j.event.Level; import javax.jcr.Credentials; import javax.jcr.GuestCredentials; @@ -63,11 +64,13 @@ import javax.security.auth.login.Configu import javax.security.auth.login.LoginException; import java.lang.reflect.Field; import java.security.Principal; +import java.security.PrivilegedExceptionAction; import java.util.Arrays; -import java.util.HashMap; +import java.util.Collections; import java.util.Map; import java.util.Set; +import static org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule.SHARED_KEY_CREDENTIALS; import static org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule.SHARED_KEY_PRE_AUTH_LOGIN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -76,13 +79,8 @@ import static org.junit.Assert.assertNul import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class LoginModuleImplTest extends AbstractSecurityTest { @@ -292,27 +290,43 @@ public class LoginModuleImplTest extends @Test public void testLoginPreAuthenticated() throws Exception { + User testUser = getTestUser(); + Set<? extends Principal> principals = getConfig(PrincipalConfiguration.class).getPrincipalProvider(root, NamePathMapper.DEFAULT).getPrincipals(testUser.getID()); + Authentication authentication = mock(Authentication.class); when(authentication.authenticate(any(Credentials.class))).thenReturn(true).getMock(); - when(authentication.getUserId()).thenReturn("uid"); // but getUserPrincipal returns null + when(authentication.getUserId()).thenReturn(testUser.getID()); // but getUserPrincipal returns null + + Principal foreignPrincipal = new PrincipalImpl("foreign"); UserAuthenticationFactory uaf = when(mock(UserAuthenticationFactory.class).getAuthentication(any(UserConfiguration.class), any(Root.class), anyString())).thenReturn(authentication).getMock(); Map<String, Object> sharedState = Maps.newHashMap(); sharedState.put(SHARED_KEY_PRE_AUTH_LOGIN, new PreAuthenticatedLogin("uid")); - Subject subject = new Subject(); + Subject subject = new Subject(false, ImmutableSet.of(foreignPrincipal), ImmutableSet.of(), ImmutableSet.of()); LoginModuleImpl lm = new LoginModuleImpl(); lm.initialize(subject, new TestCallbackHandler(uaf), sharedState, Maps.newHashMap()); assertTrue(lm.login()); assertTrue(lm.commit()); - assertTrue(subject.getPrincipals().isEmpty()); + // verify subject has been updated with test-user principals + Set<Principal> expected = new ImmutableSet.Builder().add(foreignPrincipal).addAll(principals).build(); + assertEquals(expected, subject.getPrincipals()); // no other public credentials than the AuthInfo assertEquals(1, subject.getPublicCredentials().size()); + // verify AuthInfo Set<AuthInfo> authInfos = subject.getPublicCredentials(AuthInfo.class); assertFalse(authInfos.isEmpty()); - assertEquals("uid", authInfos.iterator().next().getUserID()); + AuthInfo ai = authInfos.iterator().next(); + assertEquals(testUser.getID(), ai.getUserID()); + assertEquals(expected, ai.getPrincipals()); + + // verify logout only removes credentials/principals associated with this very login module + assertTrue(lm.logout()); + assertTrue(subject.getPublicCredentials().isEmpty()); + assertTrue(subject.getPrincipals().contains(foreignPrincipal)); + assertFalse(subject.getPrincipals().containsAll(principals)); } @Test @@ -332,6 +346,31 @@ public class LoginModuleImplTest extends assertTrue(subject.getPrincipals().isEmpty()); assertTrue(subject.getPublicCredentials().isEmpty()); + + assertTrue(lm.logout()); + } + + @Test + public void testLoginWithReadOnlySubject() throws Exception { + Map<String, Object> sharedState = Maps.newHashMap(); + sharedState.put(SHARED_KEY_CREDENTIALS, getAdminCredentials()); + + Principal unknownPrincipal = new PrincipalImpl("unknown"); + Subject subject = new Subject(true, Collections.singleton(unknownPrincipal), Collections.emptySet(), Collections.emptySet()); + + LoginModuleImpl lm = new LoginModuleImpl(); + lm.initialize(subject, new TestCallbackHandler(new UserAuthenticationFactoryImpl()), sharedState, Maps.newHashMap()); + + assertTrue(lm.login()); + assertTrue(lm.commit()); + + assertFalse(subject.getPrincipals().isEmpty()); + assertTrue(subject.getPublicCredentials().isEmpty()); + + assertTrue(lm.logout()); + + assertFalse(subject.getPrincipals().isEmpty()); + assertTrue(subject.getPublicCredentials().isEmpty()); } @Test @@ -342,6 +381,7 @@ public class LoginModuleImplTest extends assertFalse(loginModule.login()); assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -364,6 +404,7 @@ public class LoginModuleImplTest extends assertFalse(loginModule.login()); assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -384,6 +425,7 @@ public class LoginModuleImplTest extends assertFalse(loginModule.login()); assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -404,6 +446,7 @@ public class LoginModuleImplTest extends assertFalse(loginModule.login()); assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -424,6 +467,7 @@ public class LoginModuleImplTest extends assertFalse(loginModule.login()); assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -433,6 +477,7 @@ public class LoginModuleImplTest extends assertFalse(loginModule.login()); assertFalse(loginModule.commit()); + assertFalse(loginModule.logout()); } @Test @@ -468,6 +513,10 @@ public class LoginModuleImplTest extends // authinfo falls back to loginId because Authentication.getUserId returned null AuthInfo authInfo = subject.getPublicCredentials(AuthInfo.class).iterator().next(); assertEquals("loginId", authInfo.getUserID()); + + assertTrue(loginModule.logout()); + assertTrue(subject.getPrincipals().isEmpty()); + assertTrue(subject.getPublicCredentials().isEmpty()); } @Test @@ -502,6 +551,10 @@ public class LoginModuleImplTest extends AuthInfo authInfo = subject.getPublicCredentials(AuthInfo.class).iterator().next(); assertNull(authInfo.getUserID()); assertTrue(subject.getPrincipals().isEmpty()); + + assertTrue(loginModule.logout()); + assertTrue(subject.getPublicCredentials().isEmpty()); + assertTrue(subject.getPrincipals().isEmpty()); } @Test @@ -527,6 +580,28 @@ public class LoginModuleImplTest extends assertTrue(ai.getPrincipals().contains(getTestUser().getPrincipal())); } + @Test + public void testLoginLogoutPreexistingReadonlySubject() throws Exception { + createTestUser(); + Subject subject = new Subject(true, Collections.singleton(() -> "JMXPrincipal: foo"), Collections.EMPTY_SET, Collections.EMPTY_SET); + Subject.doAs(subject, (PrivilegedExceptionAction<Void>) () -> { + LogCustomizer logCustomizer = LogCustomizer + .forLogger("org.apache.jackrabbit.oak.core.ContentSessionImpl") + .enable(Level.ERROR) + .create(); + + ContentSession cs = login(new SimpleCredentials(USER_ID, USER_PW.toCharArray())); + try { + logCustomizer.starting(); + cs.close(); + } finally { + //verify that ContentSessionImpl.close() did not log anything + assertEquals(0, logCustomizer.getLogs().size()); + logCustomizer.finished(); + } + return null; + }); + } private class TestCallbackHandler implements CallbackHandler { Modified: jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.groovy URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.groovy?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.groovy (original) +++ jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.groovy Thu Nov 28 15:37:42 2019 @@ -122,5 +122,10 @@ class JaasConfigSpiTest extends Abstract } return false; } + + @Override + boolean logout() throws LoginException { + return super.logout(ImmutableSet.of(credentials), principals); + } } } \ No newline at end of file Modified: jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.groovy URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.groovy?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.groovy (original) +++ jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.groovy Thu Nov 28 15:37:42 2019 @@ -105,7 +105,12 @@ class TokenAuthenticationTest extends Ab if(sharedCreds instanceof SimpleCredentials) { credential.setAttribute(".token", ((SimpleCredentials)sharedCreds).getAttribute(".token")) } - return false + return false; + } + + @Override + boolean logout() { + return false; } } Modified: jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.java (original) +++ jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.java Thu Nov 28 15:37:42 2019 @@ -26,6 +26,8 @@ import java.util.Map; import java.util.Set; import javax.jcr.Credentials; import javax.jcr.NoSuchWorkspaceException; +import javax.security.auth.DestroyFailedException; +import javax.security.auth.Destroyable; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -33,6 +35,7 @@ import javax.security.auth.callback.Unsu import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; +import com.google.common.collect.ImmutableSet; import org.apache.jackrabbit.api.security.user.UserManager; import org.apache.jackrabbit.oak.api.AuthInfo; import org.apache.jackrabbit.oak.api.ContentRepository; @@ -185,14 +188,36 @@ public abstract class AbstractLoginModul this.options = (options == null) ? ConfigurationParameters.EMPTY : ConfigurationParameters.of(options); } + /** + * Besteffort default implementation of {@link LoginModule#logout()}, which removes all principals and all public + * credentials of type {@link Credentials} and {@link AuthInfo} from the subject. + * It will return {@code false}, if either principal set or credentials set is empty. + * + * Note, that this implementation is not able to only remove those principals/credentials that have been added + * by {@code this} very login module instance. Therefore subclasses should overwrite this method to provide a fully + * compliant solution of {@link #logout()}. They may however take advantage of {@link #logout(Set, Set)} + * in order to simplify the implementation of a logout that is compatible with the {@link LoginModule#logout()} + * contract incorporating the additional recommendations highlighted at + * <a href="https://docs.oracle.com/en/java/javase/13/security/java-authentication-and-authorization-service-jaas-loginmodule-developers-guide1.html#GUID-E9C5810B-ADB6-4454-869D-B269ECA8145F__LOGINMODULE.LOGOUTMETHOD-21144F6A">JAAS LoginModule Dev Guide</a> + * + * @return {@code true} if neither principals nor public credentials of type {@link Credentials} or {@link AuthInfo} + * stored in the {@link Subject} are empty; {@code false} otherwise + * @throws {@code LoginException} if the subject is readonly and destroying {@link Destroyable} credentials fails + * with {@link DestroyFailedException}. + */ @Override - public boolean logout() { + public boolean logout() throws LoginException { boolean success = false; - if (!subject.getPrincipals().isEmpty() && !subject.getPublicCredentials(Credentials.class).isEmpty()) { + Set<Object> creds = ImmutableSet.builder() + .addAll(subject.getPublicCredentials(Credentials.class)) + .addAll(subject.getPublicCredentials(AuthInfo.class)).build(); + if (!subject.getPrincipals().isEmpty() && !creds.isEmpty()) { // clear subject if not readonly if (!subject.isReadOnly()) { subject.getPrincipals().clear(); - subject.getPublicCredentials().clear(); + subject.getPublicCredentials().removeAll(creds); + } else { + destroyCredentials(creds); } success = true; } @@ -234,6 +259,51 @@ public abstract class AbstractLoginModul } /** + * General logout-helper that will return {@code false} if both {@code credentials} and {@code principals} are {@code null}. + * Note, that this implementation will only throw {@code LoginException} if the {@code subject} is marked readonly + * and destroying {@link Destroyable} credentials fails. + * + * @param credentials The set of credentials extracted by this instance during login/commit to be removed from {@link Subject#getPublicCredentials()} + * @param principals A set of principals extracted by this instance during login/commit to be removed from {@link Subject#getPrincipals()} + * @return {@code true} if either the credential set or the principal set is not {@code null}, {@code false} otherwise. + * @throws LoginException If the subject is readonly and an error occurs while destroying any of the given credentials. + * @see <a href="https://docs.oracle.com/en/java/javase/13/security/java-authentication-and-authorization-service-jaas-loginmodule-developers-guide1.html#GUID-E9C5810B-ADB6-4454-869D-B269ECA8145F__LOGINMODULE.LOGOUTMETHOD-21144F6A">JAASLMDevGuide</a> + */ + protected boolean logout(@Nullable Set<Object> credentials, @Nullable Set<? extends Principal> principals) throws LoginException { + if (credentials != null || principals != null) { + if (!subject.isReadOnly()) { + if (credentials != null) { + subject.getPublicCredentials().removeAll(credentials); + } + if (principals != null) { + subject.getPrincipals().removeAll(principals); + } + } else if (credentials != null) { + destroyCredentials(credentials); + } + return true; + } else { + // this login module didn't add credentials/authinfo/principals to the subject upon commit + // -> logout of this LoginModule should be ignored + return false; + } + } + + private static void destroyCredentials(@NotNull Iterable<Object> credentials) throws LoginException { + for (Object cred : credentials) { + if (cred instanceof Destroyable) { + try { + ((Destroyable) cred).destroy(); + } catch (DestroyFailedException e) { + throw new LoginException(e.getMessage()); + } + } else { + log.debug("Unable to destroy credentials ({}) of read-only subject.", credentials.getClass().getName()); + } + } + } + + /** * @return A set of supported credential classes. */ @NotNull @@ -410,7 +480,7 @@ public abstract class AbstractLoginModul }); root = systemSession.getLatestRoot(); } else { - log.debug("Unable to retrieve the Root via RepositoryCallback; ContentRepository not available."); + log.error("Unable to retrieve the Root via RepositoryCallback; ContentRepository not available."); } } catch (IOException | UnsupportedCallbackException | PrivilegedActionException e) { onError(); Modified: jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModule.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModule.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModule.java (original) +++ jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModule.java Thu Nov 28 15:37:42 2019 @@ -24,6 +24,7 @@ import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import org.apache.jackrabbit.oak.spi.security.authentication.callback.CredentialsCallback; @@ -132,7 +133,18 @@ public final class GuestLoginModule impl @Override public boolean logout() { - return authenticationSucceeded(); + if (authenticationSucceeded()) { + if (!subject.isReadOnly()) { + subject.getPublicCredentials().remove(guestCredentials); + subject.getPrincipals().remove(EveryonePrincipal.getInstance()); + } else { + log.debug("Cannot destroy GuestCredentials"); + } + return true; + } else { + // ignore this login module + return false; + } } private boolean authenticationSucceeded() { Modified: jackrabbit/oak/trunk/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModuleTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModuleTest.java?rev=1870559&r1=1870558&r2=1870559&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModuleTest.java (original) +++ jackrabbit/oak/trunk/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModuleTest.java Thu Nov 28 15:37:42 2019 @@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.spi.se import java.io.IOException; import java.security.Principal; -import java.security.PrivilegedActionException; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -28,7 +27,10 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import javax.jcr.Credentials; +import javax.jcr.GuestCredentials; import javax.jcr.SimpleCredentials; +import javax.security.auth.DestroyFailedException; +import javax.security.auth.Destroyable; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -37,12 +39,12 @@ import javax.security.auth.login.LoginEx import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials; import org.apache.jackrabbit.api.security.principal.PrincipalManager; import org.apache.jackrabbit.api.security.user.UserManager; import org.apache.jackrabbit.oak.api.AuthInfo; import org.apache.jackrabbit.oak.api.ContentRepository; import org.apache.jackrabbit.oak.api.ContentSession; -import org.apache.jackrabbit.oak.api.Descriptors; import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; @@ -66,8 +68,8 @@ import org.apache.jackrabbit.oak.stats.S import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Test; -import org.mockito.Mockito; +import static org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule.SHARED_KEY_CREDENTIALS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -75,41 +77,50 @@ import static org.junit.Assert.assertNot import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; public class AbstractLoginModuleTest { - private static AbstractLoginModule initLoginModule(Class<?> supportedCredentials, Map<String, ?> sharedState) { + private static AbstractLoginModule initLoginModule(@NotNull Class<?> supportedCredentials, @NotNull Map<String, ?> sharedState) { AbstractLoginModule lm = new TestLoginModule(supportedCredentials); - lm.initialize(new Subject(), null, sharedState, null); + initialize(lm, new Subject(), null, sharedState); return lm; } - private static AbstractLoginModule initLoginModule(Class<?> supportedCredentials, CallbackHandler cbh) { - AbstractLoginModule lm = new TestLoginModule(supportedCredentials); - lm.initialize(new Subject(), cbh, Collections.<String, Object>emptyMap(), null); + private static AbstractLoginModule initLoginModule(@Nullable CallbackHandler cbh) { + AbstractLoginModule lm = new TestLoginModule(TestCredentials.class); + initialize(lm, new Subject(), cbh, Collections.emptyMap()); return lm; } - private static AbstractLoginModule initLoginModule(Class<?> supportedCredentials, CallbackHandler cbh, LoginModuleMonitor monitor) { - AbstractLoginModule lm = new TestLoginModule(supportedCredentials, monitor); - lm.initialize(new Subject(), cbh, Collections.emptyMap(), null); + private static AbstractLoginModule initLoginModule(@NotNull CallbackHandler cbh, @NotNull LoginModuleMonitor monitor) { + AbstractLoginModule lm = new TestLoginModule(TestCredentials.class, monitor); + initialize(lm, new Subject(), cbh, Collections.emptyMap()); return lm; } - private static AbstractLoginModule initLoginModule(Subject subject, CallbackHandler cbh, LoginModuleMonitor monitor) { - AbstractLoginModule lm = new TestLoginModule(TestCredentials.class, monitor); - lm.initialize(subject, cbh, Collections.emptyMap(), null); + private static AbstractLoginModule initLoginModule(@NotNull Subject subject) { + AbstractLoginModule lm = new TestLoginModule(TestCredentials.class, null); + initialize(lm, subject, mock(CallbackHandler.class), Collections.emptyMap()); return lm; } + private static void initialize(@NotNull AbstractLoginModule loginModule, @NotNull Subject subject, @Nullable CallbackHandler cbh, @NotNull Map<String, ?> sharedState) { + loginModule.initialize(subject, cbh, sharedState, null); + } + + private static ContentRepository mockContentRepository(@Nullable ContentSession contentSession) throws Exception { + ContentSession cs = (contentSession == null) ? mock(ContentSession.class) : contentSession; + Root r = when(mock(Root.class).getContentSession()).thenReturn(cs).getMock(); + when(cs.getLatestRoot()).thenReturn(r); + return when(mock(ContentRepository.class).login(null, null)).thenReturn(cs).getMock(); + } + @Test public void testInitializeWithOptions() { AbstractLoginModule lm = new TestLoginModule(TestCredentials.class); @@ -126,16 +137,16 @@ public class AbstractLoginModuleTest { } @Test - public void testLogout() { + public void testLogout() throws Exception { AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, ImmutableMap.of()); assertFalse(loginModule.logout()); } @Test - public void testLogoutSuccessClearsSubject() { + public void testLogoutSuccessClearsSubject() throws Exception { Subject subject = new Subject(false, ImmutableSet.<Principal>of(new PrincipalImpl("pName")), ImmutableSet.of(new TestCredentials()), ImmutableSet.of()); - AbstractLoginModule loginModule = initLoginModule(subject, null, null); + AbstractLoginModule loginModule = initLoginModule(subject); assertTrue(loginModule.logout()); @@ -144,9 +155,9 @@ public class AbstractLoginModuleTest { } @Test - public void testLogoutSuccessReadOnlySubject() { + public void testLogoutSuccessReadOnlySubject() throws Exception { Subject subject = new Subject(true, ImmutableSet.<Principal>of(new PrincipalImpl("pName")), ImmutableSet.of(new TestCredentials()), ImmutableSet.of()); - AbstractLoginModule loginModule = initLoginModule(subject, null, null); + AbstractLoginModule loginModule = initLoginModule(subject); assertTrue(loginModule.logout()); @@ -155,16 +166,16 @@ public class AbstractLoginModuleTest { } @Test - public void testLogoutSubjectWithoutCredentials() { + public void testLogoutSubjectWithoutCredentials() throws Exception { Subject subject = new Subject(false, ImmutableSet.<Principal>of(new PrincipalImpl("pName")), ImmutableSet.of("stringNotCredentials"), ImmutableSet.of()); - AbstractLoginModule loginModule = initLoginModule(subject, null, null); + AbstractLoginModule loginModule = initLoginModule(subject); loginModule.logout(); assertFalse(subject.getPublicCredentials().isEmpty()); assertFalse(subject.getPrincipals().isEmpty()); subject = new Subject(false, ImmutableSet.<Principal>of(new PrincipalImpl("pName")), ImmutableSet.of(), ImmutableSet.of()); - loginModule = initLoginModule(subject, null, null); + loginModule = initLoginModule(subject); loginModule.logout(); assertTrue(subject.getPublicCredentials().isEmpty()); @@ -172,9 +183,9 @@ public class AbstractLoginModuleTest { } @Test - public void testLogoutSubjectWithoutPrincipals() { + public void testLogoutSubjectWithoutPrincipals() throws Exception { Subject subject = new Subject(false, ImmutableSet.<Principal>of(), ImmutableSet.of(new TestCredentials()), ImmutableSet.of()); - AbstractLoginModule loginModule = initLoginModule(subject, null, null); + AbstractLoginModule loginModule = initLoginModule(subject); loginModule.logout(); assertFalse(subject.getPublicCredentials().isEmpty()); @@ -182,18 +193,164 @@ public class AbstractLoginModuleTest { } @Test + public void testLogoutCPIgnored() throws LoginException { + AbstractLoginModule loginModule = initLoginModule(new Subject()); + assertFalse(loginModule.logout(null, null)); + } + + @Test + public void testLogoutCPSuccess() throws LoginException { + PrincipalProvider pp = new TestPrincipalProvider("user"); + Principal p = pp.getPrincipal("user"); + Principal foreignPrincipal = TestPrincipalProvider.UNKNOWN; + + String userId = TestPrincipalProvider.getIDFromPrincipal(p); + Set<? extends Principal> principals = pp.getPrincipals(userId); + Set<Principal> all = ImmutableSet.<Principal>builder().add(p).add(foreignPrincipal).addAll(principals).build(); + + + AuthInfo authInfo = new AuthInfoImpl(userId, null, all); + Credentials foreign1 = new GuestCredentials(); + Credentials foreign2 = new TokenCredentials("token"); + + Subject subject = new Subject(false, + ImmutableSet.of(foreignPrincipal, p), + ImmutableSet.of(authInfo, foreign1, foreign2), ImmutableSet.of()); + + TestLoginModule loginModule = new TestLoginModule(SimpleCredentials.class); + loginModule.initialize(subject, new TestCallbackHandler(pp), Collections.emptyMap(), null); + + assertTrue(loginModule.logout(ImmutableSet.of(authInfo), principals)); + + Set publicCreds = subject.getPublicCredentials(); + assertFalse(publicCreds.contains(authInfo)); + assertTrue(publicCreds.contains(foreign1)); + assertTrue(publicCreds.contains(foreign2)); + + assertFalse(subject.getPrincipals().contains(p)); + assertTrue(Collections.disjoint(subject.getPrincipals(), principals)); + assertTrue(subject.getPrincipals().contains(foreignPrincipal)); + } + + @Test + public void testLogoutCPDestroyable() throws Exception { + Credentials creds = mock(TestCredentials.class, withSettings().extraInterfaces(Destroyable.class)); + Credentials foreign1 = new GuestCredentials(); + Credentials foreign2 = new TokenCredentials("token"); + + Subject subject = new Subject(true, + ImmutableSet.<Principal>of(new PrincipalImpl("pName")), + ImmutableSet.of(creds, foreign1, foreign2), ImmutableSet.of()); + + AbstractLoginModule loginModule = initLoginModule(subject); + assertTrue(loginModule.logout(ImmutableSet.of(creds), Collections.emptySet())); + + verify(((Destroyable) creds), times(1)).destroy(); + } + + @Test(expected = LoginException.class) + public void testLogoutCPDestroyFails() throws Exception { + Credentials creds = mock(TestCredentials.class, withSettings().extraInterfaces(Destroyable.class)); + doThrow(new DestroyFailedException()).when((Destroyable)creds).destroy(); + + Subject subject = new Subject(true, ImmutableSet.of(), ImmutableSet.of(creds), ImmutableSet.of()); + AbstractLoginModule loginModule = initLoginModule(subject); + loginModule.logout(ImmutableSet.of(creds), null); + } + + @Test + public void testLogoutCPNotDestroyable() throws LoginException { + Credentials creds = new TestCredentials(); + Subject subject = new Subject(true, + ImmutableSet.of(), + ImmutableSet.of(creds), ImmutableSet.of()); + + TestLoginModule loginModule = (TestLoginModule) initLoginModule(subject); + assertTrue(loginModule.logout(null, Collections.emptySet())); + } + + @Test + public void testLogoutCPNullParams() throws LoginException { + Credentials creds = new TestCredentials(); + Principal unknownPrincipal = TestPrincipalProvider.UNKNOWN; + TestPrincipalProvider pp = new TestPrincipalProvider("principal"); + + Subject subject = new Subject(false, ImmutableSet.of(unknownPrincipal), ImmutableSet.of(creds), ImmutableSet.of()); + + TestLoginModule loginModule = new TestLoginModule(SimpleCredentials.class); + loginModule.initialize(subject, new TestCallbackHandler(pp), Collections.emptyMap(), null); + + assertFalse(loginModule.logout(null, null)); + // subject must not be altered by logout + assertTrue(subject.getPublicCredentials().contains(creds)); + assertTrue(subject.getPrincipals().contains(unknownPrincipal)); + } + + @Test + public void testLogoutCPMissingCredentials() throws LoginException { + Credentials creds = new TestCredentials(); + Principal unknownPrincipal = TestPrincipalProvider.UNKNOWN; + TestPrincipalProvider pp = new TestPrincipalProvider("principal"); + Principal p = pp.getPrincipal("principal"); + + Subject subject = new Subject(false, ImmutableSet.of(unknownPrincipal, p), ImmutableSet.of(creds), ImmutableSet.of()); + + TestLoginModule loginModule = new TestLoginModule(SimpleCredentials.class); + loginModule.initialize(subject, new TestCallbackHandler(pp), Collections.emptyMap(), null); + + assertTrue(loginModule.logout(null, ImmutableSet.of(p))); + + // only credentials/principals passed to logout must be removed + assertTrue(subject.getPublicCredentials().contains(creds)); + assertTrue(subject.getPrincipals().contains(unknownPrincipal)); + assertFalse(subject.getPrincipals().contains(p)); + } + + @Test + public void testLogoutCPMissingCredentialsReadOnly() throws LoginException { + Credentials creds = new TestCredentials(); + Principal unknownPrincipal = TestPrincipalProvider.UNKNOWN; + TestPrincipalProvider pp = new TestPrincipalProvider("principal"); + Principal p = pp.getPrincipal("principal"); + + Set<? extends Principal> principals = ImmutableSet.of(unknownPrincipal, p); + AuthInfo authInfo = new AuthInfoImpl(null, null, principals); + Subject subject = new Subject(true, principals, ImmutableSet.of(creds, authInfo), ImmutableSet.of()); + + TestLoginModule loginModule = new TestLoginModule(SimpleCredentials.class); + loginModule.initialize(subject, new TestCallbackHandler(pp), Collections.emptyMap(), null); + + assertTrue(loginModule.logout(ImmutableSet.of(creds, authInfo), Collections.singleton(p))); + // read-only subject must not be altered by logout + assertTrue(subject.getPublicCredentials().contains(creds)); + assertTrue(subject.getPrincipals().contains(unknownPrincipal)); + assertTrue(subject.getPrincipals().contains(p)); + } + + @Test + public void testLogoutCPMissingPrincipals() throws LoginException { + Credentials creds = new TestCredentials(); + Principal preExisting = new PrincipalImpl("pName"); + + Subject subject = new Subject(false, ImmutableSet.of(preExisting), ImmutableSet.of(creds), ImmutableSet.of()); + TestLoginModule loginModule = (TestLoginModule) initLoginModule(subject); + assertTrue(loginModule.logout(ImmutableSet.of(creds), null)); + + assertFalse(subject.getPublicCredentials().contains(creds)); + assertTrue(subject.getPrincipals().contains(preExisting)); + } + + @Test public void testAbort() throws LoginException { AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, ImmutableMap.of()); assertTrue(loginModule.abort()); - - loginModule.login(); - assertTrue(loginModule.abort()); } @Test - public void testAbortWithFailedSystemLogout() throws LoginException { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler(new TestContentRepository(), null, null)); + public void testAbortWithFailedSystemLogout() throws Exception { + ContentRepository cr = mockContentRepository(null); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler(cr, null)); // trigger creation of system-session loginModule.getRoot(); @@ -202,29 +359,31 @@ public class AbstractLoginModuleTest { @Test public void testClearStateWithSessionCloseFailing() throws Exception { - TestContentRepository cr = new TestContentRepository(); - doThrow(IOException.class).when(cr.cs).close(); + ContentSession cs = mock(ContentSession.class); + ContentRepository cr = mockContentRepository(cs); + doThrow(IOException.class).when(cs).close(); LoginModuleStats stats = newLoginModuleStats(); - CallbackHandler cbh = new TestCallbackHandler(cr, mock(SecurityProvider.class), null); + CallbackHandler cbh = new TestCallbackHandler(cr, mock(SecurityProvider.class)); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, cbh, stats); + AbstractLoginModule loginModule = initLoginModule(cbh, stats); loginModule.getRoot(); loginModule.clearState(); assertEquals(1, stats.getLoginErrors()); - verify(cr.cs, times(1)).close(); + verify(cs, times(1)).close(); } @Test public void testCloseSystemSession() throws Exception { - TestContentRepository cr = new TestContentRepository(); + ContentSession cs = mock(ContentSession.class); + ContentRepository cr = mockContentRepository(cs); - CallbackHandler cbh = new TestCallbackHandler(cr, mock(SecurityProvider.class), null); + CallbackHandler cbh = new TestCallbackHandler(cr, mock(SecurityProvider.class)); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, cbh); + AbstractLoginModule loginModule = initLoginModule(cbh); loginModule.getRoot(); loginModule.closeSystemSession(); - verify(cr.cs, times(1)).close(); + verify(cs, times(1)).close(); } @Test @@ -244,18 +403,18 @@ public class AbstractLoginModuleTest { public void testGetSharedCredentials() { Map<String, Object> sharedState = new HashMap<>(); - sharedState.put(AbstractLoginModule.SHARED_KEY_CREDENTIALS, new TestCredentials()); + sharedState.put(SHARED_KEY_CREDENTIALS, new TestCredentials()); AbstractLoginModule lm = initLoginModule(TestCredentials.class, sharedState); assertTrue(lm.getSharedCredentials() instanceof TestCredentials); - sharedState.put(AbstractLoginModule.SHARED_KEY_CREDENTIALS, new SimpleCredentials("test", "test".toCharArray())); + sharedState.put(SHARED_KEY_CREDENTIALS, new SimpleCredentials("test", "test".toCharArray())); lm = initLoginModule(TestCredentials.class, sharedState); assertTrue(lm.getSharedCredentials() instanceof SimpleCredentials); lm = initLoginModule(SimpleCredentials.class, sharedState); assertTrue(lm.getSharedCredentials() instanceof SimpleCredentials); - sharedState.put(AbstractLoginModule.SHARED_KEY_CREDENTIALS, "no credentials object"); + sharedState.put(SHARED_KEY_CREDENTIALS, "no credentials object"); lm = initLoginModule(TestCredentials.class, sharedState); assertNull(lm.getSharedCredentials()); @@ -267,17 +426,17 @@ public class AbstractLoginModuleTest { @Test public void testGetCredentialsFromSharedState() { Map<String, Credentials> sharedState = new HashMap<>(); + sharedState.put(SHARED_KEY_CREDENTIALS, new TestCredentials()); - sharedState.put(AbstractLoginModule.SHARED_KEY_CREDENTIALS, new TestCredentials()); AbstractLoginModule lm = initLoginModule(TestCredentials.class, sharedState); assertTrue(lm.getCredentials() instanceof TestCredentials); SimpleCredentials sc = new SimpleCredentials("test", "test".toCharArray()); - sharedState.put(AbstractLoginModule.SHARED_KEY_CREDENTIALS, sc); + sharedState.put(SHARED_KEY_CREDENTIALS, sc); lm = initLoginModule(TestCredentials.class, sharedState); assertNull(lm.getCredentials()); - sharedState.put(AbstractLoginModule.SHARED_KEY_CREDENTIALS, sc); + sharedState.put(SHARED_KEY_CREDENTIALS, sc); lm = initLoginModule(SimpleCredentials.class, sharedState); assertTrue(lm.getCredentials() instanceof SimpleCredentials); @@ -289,8 +448,6 @@ public class AbstractLoginModuleTest { @Test public void testGetCredentialsFromSubject() { Subject subject = new Subject(); - - subject.getPublicCredentials().add(new TestCredentials()); AbstractLoginModule lm = new TestLoginModule(TestCredentials.class); @@ -305,7 +462,7 @@ public class AbstractLoginModuleTest { subject.getPublicCredentials().add(new SimpleCredentials("userid", new char[0])); AbstractLoginModule lm = new TestLoginModule(TestCredentials.class); - lm.initialize(subject, null, ImmutableMap.<String, Object>of(), null); + lm.initialize(subject, null, Collections.emptyMap(), null); assertNull(lm.getCredentials()); } @@ -320,17 +477,18 @@ public class AbstractLoginModuleTest { } }; - AbstractLoginModule lm = initLoginModule(TestCredentials.class, cbh); + AbstractLoginModule lm = initLoginModule(cbh); assertTrue(lm.getCredentials() instanceof TestCredentials); - lm = initLoginModule(SimpleCredentials.class, cbh); + lm = new TestLoginModule(SimpleCredentials.class); + lm.initialize(new Subject(), cbh, Collections.emptyMap(), null); assertNull(lm.getCredentials()); } @Test public void testGetCredentialsIOException() { LoginModuleMonitor monitor = mock(LoginModuleMonitor.class); - AbstractLoginModule lm = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(true), monitor); + AbstractLoginModule lm = initLoginModule(new ThrowingCallbackHandler(true), monitor); assertNull(lm.getCredentials()); verify(monitor, times(1)).loginError(); } @@ -338,7 +496,7 @@ public class AbstractLoginModuleTest { @Test public void testGetCredentialsUnsupportedCallbackException() { LoginModuleMonitor monitor = mock(LoginModuleMonitor.class); - AbstractLoginModule lm = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(false), monitor); + AbstractLoginModule lm = initLoginModule(new ThrowingCallbackHandler(false), monitor); assertNull(lm.getCredentials()); verify(monitor, times(1)).loginError(); } @@ -352,7 +510,7 @@ public class AbstractLoginModuleTest { } } }; - AbstractLoginModule lm = initLoginModule(TestCredentials.class, cbh); + AbstractLoginModule lm = initLoginModule(cbh); assertNull(lm.getCredentials()); } @@ -385,15 +543,15 @@ public class AbstractLoginModuleTest { @Test public void testIncompleteRepositoryCallback() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler()); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler()); assertNull(loginModule.getSecurityProvider()); assertNull(loginModule.getRoot()); } @Test - public void testGetRoot() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler(new TestContentRepository(), null, null)); + public void testGetRoot() throws Exception { + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler(mockContentRepository(null), null)); Root root = loginModule.getRoot(); assertNotNull(root); @@ -410,7 +568,7 @@ public class AbstractLoginModuleTest { @Test public void testGetRootIOException() { LoginModuleStats stats = newLoginModuleStats(); - AbstractLoginModule lm = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(true), stats); + AbstractLoginModule lm = initLoginModule(new ThrowingCallbackHandler(true), stats); assertNull(lm.getRoot()); assertEquals(1, stats.getLoginErrors()); } @@ -418,20 +576,20 @@ public class AbstractLoginModuleTest { @Test public void testGetRootUnsupportedCallbackException() { LoginModuleStats stats = newLoginModuleStats(); - AbstractLoginModule lm = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(false), stats); + AbstractLoginModule lm = initLoginModule(new ThrowingCallbackHandler(false), stats); assertNull(lm.getRoot()); assertEquals(1, stats.getLoginErrors()); } @Test public void testGetRootMissingCallbackHandler() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, null, null); + AbstractLoginModule loginModule = initLoginModule((CallbackHandler) null); assertNull(loginModule.getRoot()); } @Test public void testGetSecurityProvider() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler(null, new OpenSecurityProvider(), null)); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler(null, new OpenSecurityProvider())); SecurityProvider securityProvider = loginModule.getSecurityProvider(); assertNotNull(securityProvider); @@ -441,27 +599,27 @@ public class AbstractLoginModuleTest { @Test public void testGetSecurityProviderIOException() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(true)); + AbstractLoginModule loginModule = initLoginModule(new ThrowingCallbackHandler(true)); assertNull(loginModule.getSecurityProvider()); } @Test public void testGetSecurityProviderUnsupportedCallbackException() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(false)); + AbstractLoginModule loginModule = initLoginModule(new ThrowingCallbackHandler(false)); assertNull(loginModule.getRoot()); } @Test public void testGetSecurityProviderMissingCallbackHandler() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, null, null); + AbstractLoginModule loginModule = initLoginModule((CallbackHandler) null); assertNull(loginModule.getSecurityProvider()); } @Test public void testGetWhiteboardFromCallback() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler(new DefaultWhiteboard())); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler(new DefaultWhiteboard())); Whiteboard wb = loginModule.getWhiteboard(); assertNotNull(wb); @@ -472,34 +630,34 @@ public class AbstractLoginModuleTest { @Test public void testGetWhiteboardFromIncompleteCallback() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler()); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler()); assertNull(loginModule.getWhiteboard()); } @Test public void testGetWhiteboardIOException() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(true)); + AbstractLoginModule loginModule = initLoginModule(new ThrowingCallbackHandler(true)); assertNull(loginModule.getWhiteboard()); } @Test public void testGetWhiteboardUnsupportedCallbackException() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(false)); + AbstractLoginModule loginModule = initLoginModule(new ThrowingCallbackHandler(false)); assertNull(loginModule.getWhiteboard()); } @Test public void testGetWhiteBoardMissingCallbackHandler() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, null, null); + AbstractLoginModule loginModule = initLoginModule((CallbackHandler) null); assertNull(loginModule.getWhiteboard()); } @Test public void testGetUserManagerFromCallback() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler(mock(UserManager.class))); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler(mock(UserManager.class))); UserManager userManager = loginModule.getUserManager(); assertNotNull(userManager); @@ -509,21 +667,21 @@ public class AbstractLoginModuleTest { @Test public void testGetUserManagerFromIncompleteCallback() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler()); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler()); assertNull(loginModule.getUserManager()); } @Test public void testGetUserManagerIOException() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(true)); + AbstractLoginModule loginModule = initLoginModule(new ThrowingCallbackHandler(true)); assertNull(loginModule.getUserManager()); } @Test public void testGetUserManagerUnsupportedCallbackException() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(false)); + AbstractLoginModule loginModule = initLoginModule(new ThrowingCallbackHandler(false)); assertNull(loginModule.getUserManager()); } @@ -537,14 +695,14 @@ public class AbstractLoginModuleTest { UserConfiguration uc = when(mock(UserConfiguration.class).getUserManager(r, NamePathMapper.DEFAULT)).thenReturn(um).getMock(); SecurityProvider sp = when(mock(SecurityProvider.class).getConfiguration(UserConfiguration.class)).thenReturn(uc).getMock(); - CallbackHandler cbh = new TestCallbackHandler(cp, sp, null); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, cbh, null); + CallbackHandler cbh = new TestCallbackHandler(cp, sp); + AbstractLoginModule loginModule = initLoginModule(cbh); assertEquals(um, loginModule.getUserManager()); } @Test public void testGetUserManagerMissingCallbackHandler() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, null, null); + AbstractLoginModule loginModule = initLoginModule((CallbackHandler) null); assertNull(loginModule.getUserManager()); } @@ -552,8 +710,8 @@ public class AbstractLoginModuleTest { public void testGetUserManagerMissingRoot() throws Exception { ContentRepository cp = when(mock(ContentRepository.class).login(null, null)).thenReturn(mock(ContentSession.class)).getMock(); - CallbackHandler cbh = new TestCallbackHandler(cp, mock(SecurityProvider.class), null); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, cbh, null); + CallbackHandler cbh = new TestCallbackHandler(cp, mock(SecurityProvider.class)); + AbstractLoginModule loginModule = initLoginModule(cbh); assertNull(loginModule.getUserManager()); } @@ -562,14 +720,14 @@ public class AbstractLoginModuleTest { ContentSession cs = when(mock(ContentSession.class).getLatestRoot()).thenReturn(mock(Root.class)).getMock(); ContentRepository cp = when(mock(ContentRepository.class).login(null, null)).thenReturn(cs).getMock(); - CallbackHandler cbh = new TestCallbackHandler(cp, null, null); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, cbh, null); + CallbackHandler cbh = new TestCallbackHandler(cp, null); + AbstractLoginModule loginModule = initLoginModule(cbh); assertNull(loginModule.getUserManager()); } @Test public void testGetPrincipalProviderFromCallback() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler(new TestPrincipalProvider())); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler(new TestPrincipalProvider())); assertNotNull(loginModule.getPrincipalProvider()); @@ -581,21 +739,21 @@ public class AbstractLoginModuleTest { @Test public void testGetPrincipalProviderFromIncompleteCallback() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler()); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler()); assertNull(loginModule.getPrincipalProvider()); } @Test public void testGetPrincipalProviderIOException() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(true)); + AbstractLoginModule loginModule = initLoginModule(new ThrowingCallbackHandler(true)); assertNull(loginModule.getPrincipalProvider()); } @Test public void testGetPrincipalProviderUnsupportedCallbackException() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(false)); + AbstractLoginModule loginModule = initLoginModule(new ThrowingCallbackHandler(false)); assertNull(loginModule.getPrincipalProvider()); } @@ -609,14 +767,14 @@ public class AbstractLoginModuleTest { PrincipalConfiguration pc = when(mock(PrincipalConfiguration.class).getPrincipalProvider(r, NamePathMapper.DEFAULT)).thenReturn(pp).getMock(); SecurityProvider sp = when(mock(SecurityProvider.class).getConfiguration(PrincipalConfiguration.class)).thenReturn(pc).getMock(); - CallbackHandler cbh = new TestCallbackHandler(cp, sp, null); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, cbh, null); + CallbackHandler cbh = new TestCallbackHandler(cp, sp); + AbstractLoginModule loginModule = initLoginModule(cbh); assertEquals(pp, loginModule.getPrincipalProvider()); } @Test public void testGetPrincipalProviderMissingCallbackHandler() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, null, null); + AbstractLoginModule loginModule = initLoginModule((CallbackHandler) null); assertNull(loginModule.getPrincipalProvider()); } @@ -624,8 +782,8 @@ public class AbstractLoginModuleTest { public void testGetPrincipalProviderMissingRoot() throws Exception { ContentRepository cp = when(mock(ContentRepository.class).login(null, null)).thenReturn(mock(ContentSession.class)).getMock(); - CallbackHandler cbh = new TestCallbackHandler(cp, mock(SecurityProvider.class), null); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, cbh, null); + CallbackHandler cbh = new TestCallbackHandler(cp, mock(SecurityProvider.class)); + AbstractLoginModule loginModule = initLoginModule(cbh); assertNull(loginModule.getPrincipalProvider()); } @@ -634,8 +792,8 @@ public class AbstractLoginModuleTest { ContentSession cs = when(mock(ContentSession.class).getLatestRoot()).thenReturn(mock(Root.class)).getMock(); ContentRepository cp = when(mock(ContentRepository.class).login(null, null)).thenReturn(cs).getMock(); - CallbackHandler cbh = new TestCallbackHandler(cp, null, null); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, cbh, null); + CallbackHandler cbh = new TestCallbackHandler(cp, null); + AbstractLoginModule loginModule = initLoginModule(cbh); assertNull(loginModule.getPrincipalProvider()); } @@ -643,7 +801,7 @@ public class AbstractLoginModuleTest { public void testGetPrincipals() { PrincipalProvider principalProvider = new TestPrincipalProvider(); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler(principalProvider)); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler(principalProvider)); Principal principal = principalProvider.findPrincipals(PrincipalManager.SEARCH_TYPE_NOT_GROUP).next(); String userId = TestPrincipalProvider.getIDFromPrincipal(principal); @@ -656,7 +814,7 @@ public class AbstractLoginModuleTest { @Test public void testGetPrincipalsMissingProvider() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler()); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler()); Set<? extends Principal> principals = loginModule.getPrincipals("userId"); assertTrue(principals.isEmpty()); @@ -666,7 +824,7 @@ public class AbstractLoginModuleTest { public void testGetPrincipalsFromPrincipal() { PrincipalProvider principalProvider = new TestPrincipalProvider(); - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler(principalProvider)); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler(principalProvider)); Principal principal = principalProvider.findPrincipals(PrincipalManager.SEARCH_TYPE_NOT_GROUP).next(); Set<Principal> expected = new HashSet<>(); @@ -681,7 +839,7 @@ public class AbstractLoginModuleTest { @Test public void testGetPrincipalsFromPrincipalMissingProvider() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler()); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler()); Set<? extends Principal> principals = loginModule.getPrincipals(new PrincipalImpl("principalName")); assertTrue(principals.isEmpty()); @@ -722,7 +880,7 @@ public class AbstractLoginModuleTest { } }; - AbstractLoginModule lm = initLoginModule(TestCredentials.class, cbh, null); + AbstractLoginModule lm = initLoginModule(cbh); assertTrue(lm.getLoginModuleMonitor() instanceof LoginModuleStats); lm.onError(); assertEquals(1, stats.getLoginErrors()); @@ -731,7 +889,7 @@ public class AbstractLoginModuleTest { @Test public void testNullLoginModuleMonitor() { LoginModuleStats stats = newLoginModuleStats(); - AbstractLoginModule lm = initLoginModule(TestCredentials.class, null, null); + AbstractLoginModule lm = initLoginModule((CallbackHandler) null); assertNull(lm.getLoginModuleMonitor()); lm.onError(); assertEquals(0, stats.getLoginErrors()); @@ -740,7 +898,7 @@ public class AbstractLoginModuleTest { @Test public void testErrorOnGetLoginModuleMonitor() { LoginModuleStats stats = newLoginModuleStats(); - AbstractLoginModule lm = initLoginModule(TestCredentials.class, new ThrowingCallbackHandler(true), null); + AbstractLoginModule lm = initLoginModule(new ThrowingCallbackHandler(true)); assertNull(lm.getLoginModuleMonitor()); lm.onError(); @@ -749,19 +907,18 @@ public class AbstractLoginModuleTest { //-------------------------------------------------------------------------- - private final class TestCredentials implements Credentials {} + private class TestCredentials implements Credentials {} private static final class TestLoginModule extends AbstractLoginModule { private final Class supportedCredentialsClass; + private final LoginModuleMonitor mon; - private LoginModuleMonitor mon; - - private TestLoginModule(Class supportedCredentialsClass) { - this.supportedCredentialsClass = supportedCredentialsClass; + private TestLoginModule(@NotNull Class supportedCredentialsClass) { + this(supportedCredentialsClass, null); } - private TestLoginModule(Class supportedCredentialsClass, LoginModuleMonitor mon) { + private TestLoginModule(@NotNull Class supportedCredentialsClass, @Nullable LoginModuleMonitor mon) { this.supportedCredentialsClass = supportedCredentialsClass; this.mon = mon; } @@ -774,12 +931,12 @@ public class AbstractLoginModuleTest { @Override public boolean login() { - return true; + throw new UnsupportedOperationException(); } @Override public boolean commit() { - return true; + throw new UnsupportedOperationException(); } @Override @@ -799,7 +956,6 @@ public class AbstractLoginModuleTest { private PrincipalProvider principalProvider = null; private ContentRepository contentRepository = null; private SecurityProvider securityProvider = null; - private String workspaceName = null; private TestCallbackHandler() { } @@ -816,7 +972,7 @@ public class AbstractLoginModuleTest { this.principalProvider = principalProvider; } - private TestCallbackHandler(@Nullable ContentRepository contentRepository, @Nullable SecurityProvider securityProvider, @Nullable String workspaceName) { + private TestCallbackHandler(@Nullable ContentRepository contentRepository, @Nullable SecurityProvider securityProvider) { this.contentRepository = contentRepository; this.securityProvider = securityProvider; } @@ -836,33 +992,11 @@ public class AbstractLoginModuleTest { RepositoryCallback rcb = (RepositoryCallback) cb; rcb.setContentRepository(contentRepository); rcb.setSecurityProvider(securityProvider); - rcb.setWorkspaceName(workspaceName); rcb.setLoginModuleMonitor(LoginModuleMonitor.NOOP); } else { throw new UnsupportedCallbackException(cb); } } - - } - - } - - private final class TestContentRepository implements ContentRepository { - - private ContentSession cs = Mockito.mock(ContentSession.class); - - @NotNull - @Override - public ContentSession login(@Nullable Credentials credentials, @Nullable String workspaceName) { - Mockito.when(cs.getLatestRoot()).thenReturn(Mockito.mock(Root.class)); - return cs; - - } - - @NotNull - @Override - public Descriptors getDescriptors() { - throw new UnsupportedOperationException(); } } }