Index: oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java (revision 1869538) +++ oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java (date 1573114535000) @@ -187,19 +187,19 @@ 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. @@ -217,15 +217,15 @@ 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 @@ -233,6 +233,8 @@ syncUser(externalUser); + // login successful -> remember credentials for commit/logout + credentials = creds; return true; } else { debug("IDP {} returned null for {}", idp.getName(), logId.toString()); @@ -449,6 +451,12 @@ return credentialsSupport.getCredentialClasses(); } + @Nullable + @Override + protected Credentials getCommittedCredentials() { + return credentials; + } + //----------------------------------------------< public setters (JAAS) >--- public void setSyncManager(@NotNull SyncManager syncManager) { Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModule.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModule.java (revision 1869538) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModule.java (date 1573114354000) @@ -193,6 +193,12 @@ return Collections.singleton(TokenCredentials.class); } + @Nullable + @Override + protected Credentials getCommittedCredentials() { + return tokenCredentials; + } + @Override protected void clearState() { super.clearState(); Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImpl.java (revision 1869538) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImpl.java (date 1573114315000) @@ -182,6 +182,12 @@ return SUPPORTED_CREDENTIALS; } + @Nullable + @Override + protected Credentials getCommittedCredentials() { + return credentials; + } + @Override protected void clearState() { super.clearState(); Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.java (revision 1869538) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.java (date 1573140640000) @@ -16,23 +16,7 @@ */ package org.apache.jackrabbit.oak.spi.security.authentication; -import java.io.IOException; -import java.security.Principal; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import javax.jcr.Credentials; -import javax.jcr.NoSuchWorkspaceException; -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 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; @@ -52,10 +36,27 @@ import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.osgi.annotation.versioning.ProviderType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.osgi.annotation.versioning.ProviderType; +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; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; +import java.io.IOException; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Collections; +import java.util.Map; +import java.util.Set; /** * Abstract implementation of the {@link LoginModule} interface that can act @@ -175,6 +176,7 @@ private ContentSession systemSession; private Root root; + private Set principals; //--------------------------------------------------------< LoginModule >--- @Override @@ -186,18 +188,34 @@ } @Override - public boolean logout() { - boolean success = false; - if (!subject.getPrincipals().isEmpty() && !subject.getPublicCredentials(Credentials.class).isEmpty()) { - // clear subject if not readonly + public boolean logout() throws LoginException { + Credentials creds = getCommittedCredentials(); + if (creds != null && principals != null) { if (!subject.isReadOnly()) { - subject.getPrincipals().clear(); - subject.getPublicCredentials().clear(); + subject.getPublicCredentials().remove(creds); + subject.getPrincipals().removeAll(principals); + } else { + destroyCredentials(creds); } - success = true; + return true; + } else { + // this login module didn't add credentials/principals to the subject upon commit + // -> logout of this LoginModule should be ignored + return false; } - return success; } + + private static void destroyCredentials(@NotNull Credentials credentials) throws LoginException { + if (credentials instanceof Destroyable) { + try { + ((Destroyable) credentials).destroy(); + } catch (DestroyFailedException e) { + throw new LoginException(e.getMessage()); + } + } else { + throw new LoginException("Unable to destroy credentials of read-only subject."); + } + } @Override public boolean abort() throws LoginException { @@ -300,6 +318,11 @@ return shared; } + @Nullable + protected Credentials getCommittedCredentials() { + return null; + } + /** * @return The login name passed to this login module with the shared state. * @see #SHARED_KEY_LOGIN_NAME @@ -485,10 +508,11 @@ PrincipalProvider principalProvider = getPrincipalProvider(); if (principalProvider == null) { log.debug("Cannot retrieve principals. No principal provider configured."); - return Collections.emptySet(); + principals = Collections.emptySet(); } else { - return principalProvider.getPrincipals(userId); + principals = ImmutableSet.builder().addAll(principalProvider.getPrincipals(userId)).build(); } + return principals; } @NotNull @@ -496,13 +520,13 @@ PrincipalProvider principalProvider = getPrincipalProvider(); if (principalProvider == null) { log.debug("Cannot retrieve principals. No principal provider configured."); - return Collections.emptySet(); + principals = Collections.emptySet(); } else { - Set principals = new HashSet<>(); - principals.add(userPrincipal); - principals.addAll(principalProvider.getMembershipPrincipals(userPrincipal)); - return principals; - } + principals = ImmutableSet.builder(). + add(userPrincipal). + addAll(principalProvider.getMembershipPrincipals(userPrincipal)).build(); + } + return principals; } protected static void setAuthInfo(@NotNull AuthInfo authInfo, @NotNull Subject subject) { Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModule.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModule.java (revision 1869538) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModule.java (date 1573132232000) @@ -24,6 +24,7 @@ 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; @@ -131,8 +132,19 @@ } @Override - public boolean logout() { - return authenticationSucceeded(); + public boolean logout() throws LoginException { + if (authenticationSucceeded()) { + if (!subject.isReadOnly()) { + subject.getPublicCredentials().remove(guestCredentials); + subject.getPrincipals().remove(EveryonePrincipal.getInstance()); + return true; + } else { + throw new LoginException("Cannot destroy GuestCredentials"); + } + } else { + // ignore this login module + return false; + } } private boolean authenticationSucceeded() { Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java (revision 1869538) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java (date 1573123343000) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.3.1") +@Version("1.4.0") package org.apache.jackrabbit.oak.spi.security.authentication; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModuleTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModuleTest.java (revision 1869538) +++ oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModuleTest.java (date 1573208466000) @@ -18,7 +18,6 @@ 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.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 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,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Test; -import org.mockito.Mockito; +import org.mockito.Answers; +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 +78,51 @@ 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.doAnswer; 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 sharedState) { - AbstractLoginModule lm = new TestLoginModule(supportedCredentials); - lm.initialize(new Subject(), null, sharedState, null); - return lm; - } - - private static AbstractLoginModule initLoginModule(Class supportedCredentials, CallbackHandler cbh) { + private static AbstractLoginModule initLoginModule(@NotNull Class supportedCredentials, @NotNull Map sharedState) { AbstractLoginModule lm = new TestLoginModule(supportedCredentials); - lm.initialize(new Subject(), cbh, Collections.emptyMap(), null); + initialize(lm, new Subject(), null, sharedState); 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(@Nullable CallbackHandler cbh) { + AbstractLoginModule lm = new TestLoginModule(TestCredentials.class); + initialize(lm, new Subject(), cbh, Collections.emptyMap()); return lm; } - private static AbstractLoginModule initLoginModule(Subject subject, CallbackHandler cbh, LoginModuleMonitor monitor) { + private static AbstractLoginModule initLoginModule(@NotNull CallbackHandler cbh, @NotNull LoginModuleMonitor monitor) { AbstractLoginModule lm = new TestLoginModule(TestCredentials.class, monitor); - lm.initialize(subject, cbh, Collections.emptyMap(), null); + initialize(lm, new Subject(), cbh, Collections.emptyMap()); + return lm; + } + + 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 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,74 +139,147 @@ } @Test - public void testLogout() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, ImmutableMap.of()); - + public void testLogoutIgnored() throws LoginException { + AbstractLoginModule loginModule = initLoginModule(new Subject()); assertFalse(loginModule.logout()); } @Test - public void testLogoutSuccessClearsSubject() { - Subject subject = new Subject(false, ImmutableSet.of(new PrincipalImpl("pName")), ImmutableSet.of(new TestCredentials()), ImmutableSet.of()); - AbstractLoginModule loginModule = initLoginModule(subject, null, null); + public void testLogoutSuccess() throws LoginException { + PrincipalProvider pp = new TestPrincipalProvider("user"); + Principal p = pp.getPrincipal("user"); + Principal foreignPrincipal = TestPrincipalProvider.UNKNOWN; + + String userId = TestPrincipalProvider.getIDFromPrincipal(p); + + Credentials creds = new SimpleCredentials(userId, new char[0]); + Credentials foreign1 = new GuestCredentials(); + Credentials foreign2 = new TokenCredentials("token"); + + Subject subject = new Subject(false, + ImmutableSet.of(foreignPrincipal), + ImmutableSet.of(creds, foreign1, foreign2), ImmutableSet.of()); + + TestLoginModule loginModule = new TestLoginModule(SimpleCredentials.class); + loginModule.initialize(subject, new TestCallbackHandler(pp), Collections.emptyMap(), null); + + assertFalse(loginModule.logout()); + + loginModule.loginAndCommit(userId); + assertTrue(subject.getPrincipals().contains(p)); assertTrue(loginModule.logout()); - assertTrue(subject.getPublicCredentials().isEmpty()); - assertTrue(subject.getPrincipals().isEmpty()); + Set publicCreds = subject.getPublicCredentials(); + assertFalse(publicCreds.contains(creds)); + assertTrue(publicCreds.contains(foreign1)); + assertTrue(publicCreds.contains(foreign2)); + + Set principals = subject.getPrincipals(); + assertFalse(principals.contains(p)); + assertTrue(principals.contains(foreignPrincipal)); } @Test - public void testLogoutSuccessReadOnlySubject() { - Subject subject = new Subject(true, ImmutableSet.of(new PrincipalImpl("pName")), ImmutableSet.of(new TestCredentials()), ImmutableSet.of()); - AbstractLoginModule loginModule = initLoginModule(subject, null, null); + public void testLogoutDestroyable() 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.of(new PrincipalImpl("pName")), + ImmutableSet.of(creds, foreign1, foreign2), ImmutableSet.of()); + TestLoginModule loginModule = new TestLoginModule(TestCredentials.class); + loginModule.initialize(subject, null, Collections.emptyMap(), null); + assertFalse(loginModule.logout()); + + loginModule.loginAndCommit("userId"); assertTrue(loginModule.logout()); - assertFalse(subject.getPublicCredentials().isEmpty()); - assertFalse(subject.getPrincipals().isEmpty()); + verify(((Destroyable) creds), times(1)).destroy(); + } + + @Test(expected = LoginException.class) + public void testLogoutDestroyFails() 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()); + TestLoginModule loginModule = new TestLoginModule(TestCredentials.class); + loginModule.initialize(subject, null, Collections.emptyMap(), null); + + loginModule.loginAndCommit("userId"); + assertTrue(loginModule.logout()); } - @Test - public void testLogoutSubjectWithoutCredentials() { - Subject subject = new Subject(false, ImmutableSet.of(new PrincipalImpl("pName")), ImmutableSet.of("stringNotCredentials"), ImmutableSet.of()); - AbstractLoginModule loginModule = initLoginModule(subject, null, null); + @Test(expected = LoginException.class) + public void testLogoutNotDestroyable() throws LoginException { + Credentials creds = new TestCredentials(); + Subject subject = new Subject(true, + ImmutableSet.of(), + ImmutableSet.of(creds), ImmutableSet.of()); + + TestLoginModule loginModule = (TestLoginModule) initLoginModule(subject); + loginModule.loginAndCommit("userId"); + + // logout must fail loginModule.logout(); + } - assertFalse(subject.getPublicCredentials().isEmpty()); - assertFalse(subject.getPrincipals().isEmpty()); + @Test + public void testLogoutInvalidCredentials() throws LoginException { + // subject with invalid credentials + Subject subject = new Subject(false, ImmutableSet.of(new PrincipalImpl("pName")), ImmutableSet.of("stringNotCredentials"), ImmutableSet.of()); + AbstractLoginModule loginModule = initLoginModule(subject); - subject = new Subject(false, ImmutableSet.of(new PrincipalImpl("pName")), ImmutableSet.of(), ImmutableSet.of()); - loginModule = initLoginModule(subject, null, null); - loginModule.logout(); - - assertTrue(subject.getPublicCredentials().isEmpty()); - assertFalse(subject.getPrincipals().isEmpty()); + assertFalse(loginModule.logout()); } @Test - public void testLogoutSubjectWithoutPrincipals() { - Subject subject = new Subject(false, ImmutableSet.of(), ImmutableSet.of(new TestCredentials()), ImmutableSet.of()); - AbstractLoginModule loginModule = initLoginModule(subject, null, null); - loginModule.logout(); + public void testLogoutMissingCredentials() throws LoginException { + Credentials creds = new TestCredentials(); + Principal principal = TestPrincipalProvider.UNKNOWN; + TestPrincipalProvider pp = new TestPrincipalProvider("principal"); + + Subject subject = new Subject(false, ImmutableSet.of(principal), ImmutableSet.of(creds), ImmutableSet.of()); + + TestLoginModule loginModule = new TestLoginModule(SimpleCredentials.class); + loginModule.initialize(subject, new TestCallbackHandler(pp), Collections.emptyMap(), null); + loginModule.getPrincipals(pp.getTestPrincipals().iterator().next()); + + assertFalse(loginModule.logout()); + // subject must not be altered by logout + assertTrue(subject.getPublicCredentials().contains(creds)); + assertTrue(subject.getPrincipals().contains(principal)); + } + + @Test + public void testLogoutMissingPrincipals() throws LoginException { + Credentials creds = new TestCredentials(); + Principal preExisting = new PrincipalImpl("pName"); - assertFalse(subject.getPublicCredentials().isEmpty()); - assertTrue(subject.getPrincipals().isEmpty()); + Subject subject = new Subject(false, ImmutableSet.of(preExisting), ImmutableSet.of(creds), ImmutableSet.of()); + TestLoginModule loginModule = (TestLoginModule) initLoginModule(subject); + loginModule.credentials = creds; + + assertFalse(loginModule.logout()); + + assertTrue(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,17 +288,18 @@ @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 @@ -232,18 +319,18 @@ public void testGetSharedCredentials() { Map 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()); @@ -255,21 +342,24 @@ @Test public void testGetCredentialsFromSharedState() { Map 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); sharedState.clear(); + lm = initLoginModule(TestCredentials.class, sharedState); assertNull(lm.getCredentials()); } @@ -277,8 +367,6 @@ @Test public void testGetCredentialsFromSubject() { Subject subject = new Subject(); - - subject.getPublicCredentials().add(new TestCredentials()); AbstractLoginModule lm = new TestLoginModule(TestCredentials.class); @@ -293,7 +381,7 @@ subject.getPublicCredentials().add(new SimpleCredentials("userid", new char[0])); AbstractLoginModule lm = new TestLoginModule(TestCredentials.class); - lm.initialize(subject, null, ImmutableMap.of(), null); + lm.initialize(subject, null, Collections.emptyMap(), null); assertNull(lm.getCredentials()); } @@ -308,17 +396,18 @@ } }; - 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(); } @@ -326,7 +415,7 @@ @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(); } @@ -340,10 +429,17 @@ } } }; - AbstractLoginModule lm = initLoginModule(TestCredentials.class, cbh); + AbstractLoginModule lm = initLoginModule(cbh); assertNull(lm.getCredentials()); } + @Test + public void testGetCommitedCredentials() { + AbstractLoginModule lm = mock(AbstractLoginModule.class); + when(lm.getCommittedCredentials()).thenAnswer(Answers.CALLS_REAL_METHODS); + assertNull(lm.getCommittedCredentials()); + } + @Test public void testGetSharedPreAuthLoginEmptySharedState() { AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, ImmutableMap.of()); @@ -373,15 +469,15 @@ @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); @@ -398,7 +494,7 @@ @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()); } @@ -406,20 +502,20 @@ @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); @@ -429,27 +525,27 @@ @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); @@ -460,34 +556,34 @@ @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); @@ -497,21 +593,21 @@ @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()); } @@ -525,14 +621,14 @@ 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()); } @@ -540,8 +636,8 @@ 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()); } @@ -550,14 +646,14 @@ 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()); @@ -569,21 +665,21 @@ @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()); } @@ -597,14 +693,14 @@ 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()); } @@ -612,8 +708,8 @@ 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()); } @@ -622,8 +718,8 @@ 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()); } @@ -631,7 +727,7 @@ 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); @@ -644,7 +740,7 @@ @Test public void testGetPrincipalsMissingProvider() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler()); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler()); Set principals = loginModule.getPrincipals("userId"); assertTrue(principals.isEmpty()); @@ -654,7 +750,7 @@ 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 expected = new HashSet<>(); @@ -669,7 +765,7 @@ @Test public void testGetPrincipalsFromPrincipalMissingProvider() { - AbstractLoginModule loginModule = initLoginModule(TestCredentials.class, new TestCallbackHandler()); + AbstractLoginModule loginModule = initLoginModule(new TestCallbackHandler()); Set principals = loginModule.getPrincipals(new PrincipalImpl("principalName")); assertTrue(principals.isEmpty()); @@ -710,7 +806,7 @@ } }; - AbstractLoginModule lm = initLoginModule(TestCredentials.class, cbh, null); + AbstractLoginModule lm = initLoginModule(cbh); assertTrue(lm.getLoginModuleMonitor() instanceof LoginModuleStats); lm.onError(); assertEquals(1, stats.getLoginErrors()); @@ -719,7 +815,7 @@ @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()); @@ -728,7 +824,7 @@ @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(); @@ -737,37 +833,55 @@ //-------------------------------------------------------------------------- - 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 Credentials credentials; - 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; } + private void loginAndCommit(@NotNull String userId) { + credentials = getCredentials(); + Set principals = getPrincipals(userId); + + if (!subject.isReadOnly()) { + if (credentials != null) { + subject.getPublicCredentials().add(credentials); + } + subject.getPrincipals().addAll(principals); + } + } + @NotNull @Override protected Set getSupportedCredentials() { return Collections.singleton(supportedCredentialsClass); } + @Override + protected @Nullable Credentials getCommittedCredentials() { + return credentials; + } + @Override public boolean login() { - return true; + throw new UnsupportedOperationException(); } @Override public boolean commit() { - return true; + throw new UnsupportedOperationException(); } @Override @@ -787,7 +901,6 @@ private PrincipalProvider principalProvider = null; private ContentRepository contentRepository = null; private SecurityProvider securityProvider = null; - private String workspaceName = null; private TestCallbackHandler() { } @@ -804,7 +917,7 @@ 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; } @@ -824,33 +937,11 @@ 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(); } } } Index: oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModuleTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModuleTest.java (revision 1869538) +++ oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModuleTest.java (date 1573133685000) @@ -49,7 +49,7 @@ @Test public void testNullLogin() throws LoginException { CallbackHandler cbh = new TestCallbackHandler(null); - guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); + guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); assertTrue(guestLoginModule.login()); Object sharedCreds = sharedState.get(AbstractLoginModule.SHARED_KEY_CREDENTIALS); @@ -63,10 +63,29 @@ assertTrue(guestLoginModule.logout()); } + @Test(expected = LoginException.class) + public void testNullLoginReadOnlySubject() throws LoginException { + CallbackHandler cbh = new TestCallbackHandler(null); + Subject readOnly = new Subject(true, Collections.emptySet(), Collections.emptySet(), Collections.emptySet()); + guestLoginModule.initialize(readOnly, cbh, sharedState, Collections.emptyMap()); + + assertTrue(guestLoginModule.login()); + Object sharedCreds = sharedState.get(AbstractLoginModule.SHARED_KEY_CREDENTIALS); + assertNotNull(sharedCreds); + assertTrue(sharedCreds instanceof GuestCredentials); + + assertTrue(guestLoginModule.commit()); + assertTrue(subject.getPrincipals(EveryonePrincipal.class).isEmpty()); + assertTrue(subject.getPublicCredentials(GuestCredentials.class).isEmpty()); + + // subject is readonly and credentials cannot be destroyed => loginexception required + guestLoginModule.logout(); + } + @Test public void testGuestCredentials() throws LoginException { CallbackHandler cbh = new TestCallbackHandler(new GuestCredentials()); - guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); + guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); assertFalse(guestLoginModule.login()); assertFalse(sharedState.containsKey(AbstractLoginModule.SHARED_KEY_CREDENTIALS)); @@ -81,7 +100,7 @@ @Test public void testSimpleCredentials() throws LoginException { CallbackHandler cbh = new TestCallbackHandler(new SimpleCredentials("test", new char[0])); - guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); + guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); assertFalse(guestLoginModule.login()); assertFalse(sharedState.containsKey(AbstractLoginModule.SHARED_KEY_CREDENTIALS)); @@ -96,7 +115,7 @@ @Test public void testThrowingCallbackhandler() throws LoginException { CallbackHandler cbh = new ThrowingCallbackHandler(true); - guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); + guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); assertFalse(guestLoginModule.login()); assertFalse(sharedState.containsKey(AbstractLoginModule.SHARED_KEY_CREDENTIALS)); @@ -110,7 +129,7 @@ @Test public void testThrowingCallbackhandler2() throws LoginException { CallbackHandler cbh = new ThrowingCallbackHandler(false); - guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); + guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); assertFalse(guestLoginModule.login()); assertFalse(sharedState.containsKey(AbstractLoginModule.SHARED_KEY_CREDENTIALS)); @@ -123,7 +142,7 @@ @Test public void testMissingCallbackhandler() throws LoginException { - guestLoginModule.initialize(subject, null, sharedState, Collections.emptyMap()); + guestLoginModule.initialize(subject, null, sharedState, Collections.emptyMap()); assertFalse(guestLoginModule.login()); assertFalse(sharedState.containsKey(AbstractLoginModule.SHARED_KEY_CREDENTIALS)); @@ -143,7 +162,7 @@ public void testCommitWithReadOnlySubject() throws Exception { subject.setReadOnly(); CallbackHandler cbh = new TestCallbackHandler(null); - guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); + guestLoginModule.initialize(subject, cbh, sharedState, Collections.emptyMap()); assertTrue(guestLoginModule.login()); assertTrue(guestLoginModule.commit());