You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2016/08/11 13:11:18 UTC
svn commit: r1755975 - in /jackrabbit/oak/trunk:
oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/
oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/
oak-core/src/main/java...
Author: angela
Date: Thu Aug 11 13:11:18 2016
New Revision: 1755975
URL: http://svn.apache.org/viewvc?rev=1755975&view=rev
Log:
OAK-4129 : Use CredentialsSupport in TokenConfigurationImpl and TokenProviderImpl
Added:
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/TokenExternalLoginModuleTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestCredentialsSupport.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/TokenLoginModuleCredentialsSupportTest.java
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/token/
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/token/default.md
Modified:
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/CredentialsSupport.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupport.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/package-info.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImplOSGiTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupportTest.java
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/tokenmanagement.md
Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.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/CustomCredentialsSupportTest.java?rev=1755975&r1=1755974&r2=1755975&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/CustomCredentialsSupportTest.java Thu Aug 11 13:11:18 2016
@@ -31,6 +31,7 @@ import javax.security.auth.login.LoginEx
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
import org.apache.jackrabbit.oak.api.AuthInfo;
import org.apache.jackrabbit.oak.api.ContentSession;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalGroup;
@@ -67,7 +68,7 @@ public class CustomCredentialsSupportTes
try {
AuthInfo info = cs.getAuthInfo();
assertEquals("testUser", info.getUserID());
- assertAttributes(((IDP) idp).getAttributes(creds), info);
+ assertAttributes(getCredentialsSupport().getAttributes(creds), info);
} finally {
cs.close();
}
@@ -94,6 +95,14 @@ public class CustomCredentialsSupportTes
return new IDP();
}
+ static Credentials createTestCredentials() {
+ return new TestCredentials(USER_ID);
+ }
+
+ protected CredentialsSupport getCredentialsSupport() {
+ return (IDP) idp;
+ }
+
private static final class TestCredentials implements Credentials {
private final String uid;
@@ -103,7 +112,10 @@ public class CustomCredentialsSupportTes
}
}
- private static final class IDP implements ExternalIdentityProvider, CredentialsSupport {
+ static final class IDP implements ExternalIdentityProvider, CredentialsSupport {
+
+ private final Map attributes = Maps.newHashMap(ImmutableMap.of("a", "a"));
+
@Nonnull
@Override
public String getName() {
@@ -207,10 +219,20 @@ public class CustomCredentialsSupportTes
@Override
public Map<String, ?> getAttributes(@Nonnull Credentials credentials) {
if (credentials instanceof TestCredentials) {
- return ImmutableMap.of("a", "a");
+ return attributes;
} else {
return ImmutableMap.of();
}
}
+
+ @Override
+ public boolean setAttributes(@Nonnull Credentials credentials, @Nonnull Map<String, ?> attributes) {
+ if (credentials instanceof TestCredentials) {
+ this.attributes.putAll(attributes);
+ return true;
+ } else {
+ return false;
+ }
+ }
}
}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/TokenExternalLoginModuleTest.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/TokenExternalLoginModuleTest.java?rev=1755975&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/TokenExternalLoginModuleTest.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/TokenExternalLoginModuleTest.java Thu Aug 11 13:11:18 2016
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.spi.security.authentication.external.impl;
+
+import java.util.Collections;
+import java.util.Map;
+import javax.jcr.Credentials;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.security.authentication.token.TokenConfigurationImpl;
+import org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule;
+import org.apache.jackrabbit.oak.spi.security.authentication.credentials.CredentialsSupport;
+import org.apache.jackrabbit.oak.spi.security.authentication.token.CompositeTokenConfiguration;
+import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration;
+import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class TokenExternalLoginModuleTest extends CustomCredentialsSupportTest {
+
+ private CredentialsSupport credentialsSupport;
+ private Registration registration;
+ private TokenConfigurationImpl tc;
+
+ @Before
+ public void before() throws Exception {
+ super.before();
+
+ credentialsSupport = getCredentialsSupport();
+
+ // NOTE: should be replaced by proper OSGi setup
+ CompositeTokenConfiguration composite = ((CompositeTokenConfiguration) getSecurityProvider().getConfiguration(TokenConfiguration.class));
+ tc = (TokenConfigurationImpl) composite.getDefaultConfig();
+ tc.bindCredentialsSupport(credentialsSupport);
+ }
+
+ @Override
+ public void after() throws Exception {
+ try {
+ tc.unbindCredentialsSupport(credentialsSupport);
+ } finally {
+ root.refresh();
+ super.after();
+ }
+ }
+
+ @Override
+ protected Configuration getConfiguration() {
+ return new Configuration() {
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String s) {
+ return new AppConfigurationEntry[]{
+ new AppConfigurationEntry(
+ TokenLoginModule.class.getName(),
+ AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT,
+ Collections.<String, Object>emptyMap()),
+
+ new AppConfigurationEntry(
+ ExternalLoginModule.class.getName(),
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ options)
+ };
+ }
+ };
+ }
+
+ @Test
+ public void testTokenCreation() throws Exception {
+ Credentials creds = createTestCredentials();
+ assertTrue(credentialsSupport.setAttributes(creds, ImmutableMap.<String, Object>of(".token", "")));
+
+ String expectedUserId = credentialsSupport.getUserId(creds);
+
+ ContentSession cs = login(creds);
+ try {
+ assertEquals(expectedUserId, cs.getAuthInfo().getUserID());
+
+ Map<String, ?> attributes = credentialsSupport.getAttributes(creds);
+ String token = attributes.get(".token").toString();
+ assertFalse(token.isEmpty());
+
+ root.refresh();
+ User user = getUserManager(root).getAuthorizable(expectedUserId, User.class);
+
+ Tree tokenParent = root.getTree(user.getPath()).getChild(".tokens");
+ assertTrue(tokenParent.exists());
+ assertEquals(1, tokenParent.getChildrenCount(100));
+ } finally {
+ cs.close();
+ }
+ }
+
+ @Test
+ public void testTokenLogin() throws Exception {
+ Credentials creds = createTestCredentials();
+ assertTrue(credentialsSupport.setAttributes(creds, ImmutableMap.<String, Object>of(".token", "")));
+
+ String expectedUserId = credentialsSupport.getUserId(creds);
+
+ ContentSession cs = login(creds);
+ try {
+ String token = credentialsSupport.getAttributes(creds).get(".token").toString();
+ cs.close();
+
+ cs = login(new TokenCredentials(token));
+ assertEquals(expectedUserId, cs.getAuthInfo().getUserID());
+ } finally {
+ cs.close();
+ }
+ }
+}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java?rev=1755975&r1=1755974&r2=1755975&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java Thu Aug 11 13:11:18 2016
@@ -27,6 +27,9 @@ import org.apache.felix.scr.annotations.
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
@@ -35,6 +38,8 @@ import org.apache.jackrabbit.oak.spi.sec
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
import org.apache.jackrabbit.oak.spi.security.SecurityConfiguration;
import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import org.apache.jackrabbit.oak.spi.security.authentication.credentials.CredentialsSupport;
+import org.apache.jackrabbit.oak.spi.security.authentication.credentials.SimpleCredentialsSupport;
import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration;
import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenProvider;
import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
@@ -72,6 +77,12 @@ import org.apache.jackrabbit.oak.spi.sec
})
public class TokenConfigurationImpl extends ConfigurationBase implements TokenConfiguration {
+ @Reference(
+ cardinality = ReferenceCardinality.OPTIONAL_UNARY,
+ policy = ReferencePolicy.DYNAMIC)
+ private CredentialsSupport credentialsSupport = SimpleCredentialsSupport.getInstance();
+
+ @SuppressWarnings("UnusedDeclaration")
public TokenConfigurationImpl() {
super();
}
@@ -80,12 +91,26 @@ public class TokenConfigurationImpl exte
super(securityProvider, securityProvider.getParameters(NAME));
}
+ //----------------------------------------------------------------< SCR >---
@SuppressWarnings("UnusedDeclaration")
@Activate
private void activate(Map<String, Object> properties) {
setParameters(ConfigurationParameters.of(properties));
}
+ @SuppressWarnings("UnusedDeclaration")
+ public void bindCredentialsSupport(CredentialsSupport credentialsSupport) {
+ this.credentialsSupport = credentialsSupport;
+ }
+
+ @SuppressWarnings("UnusedDeclaration")
+ public void unbindCredentialsSupport(CredentialsSupport credentialsSupport) {
+ if (credentialsSupport == this.credentialsSupport) {
+ // reset to default implementation
+ this.credentialsSupport = SimpleCredentialsSupport.getInstance();
+ }
+ }
+
//----------------------------------------------< SecurityConfiguration >---
@Nonnull
@Override
@@ -111,6 +136,6 @@ public class TokenConfigurationImpl exte
@Override
public TokenProvider getTokenProvider(Root root) {
UserConfiguration uc = getSecurityProvider().getConfiguration(UserConfiguration.class);
- return new TokenProviderImpl(root, getParameters(), uc);
+ return new TokenProviderImpl(root, getParameters(), uc, credentialsSupport);
}
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java?rev=1755975&r1=1755974&r2=1755975&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java Thu Aug 11 13:11:18 2016
@@ -33,8 +33,8 @@ import javax.annotation.Nonnull;
import javax.jcr.AccessDeniedException;
import javax.jcr.Credentials;
import javax.jcr.RepositoryException;
-import javax.jcr.SimpleCredentials;
+import com.google.common.collect.ImmutableMap;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials;
import org.apache.jackrabbit.api.security.user.Authorizable;
@@ -49,6 +49,8 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.name.NamespaceConstants;
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
import org.apache.jackrabbit.oak.spi.security.authentication.ImpersonationCredentials;
+import org.apache.jackrabbit.oak.spi.security.authentication.credentials.CredentialsSupport;
+import org.apache.jackrabbit.oak.spi.security.authentication.credentials.SimpleCredentialsSupport;
import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenInfo;
import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenProvider;
import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
@@ -104,14 +106,20 @@ class TokenProviderImpl implements Token
private final Root root;
private final ConfigurationParameters options;
+ private final CredentialsSupport credentialsSupport;
private final long tokenExpiration;
private final UserManager userManager;
private final IdentifierManager identifierManager;
- TokenProviderImpl(Root root, ConfigurationParameters options, UserConfiguration userConfiguration) {
+ TokenProviderImpl(@Nonnull Root root, @Nonnull ConfigurationParameters options, @Nonnull UserConfiguration userConfiguration) {
+ this(root, options, userConfiguration, SimpleCredentialsSupport.getInstance());
+ }
+
+ TokenProviderImpl(@Nonnull Root root, @Nonnull ConfigurationParameters options, @Nonnull UserConfiguration userConfiguration, @Nonnull CredentialsSupport credentialsSupport) {
this.root = root;
this.options = options;
+ this.credentialsSupport = credentialsSupport;
this.tokenExpiration = options.getConfigValue(PARAM_TOKEN_EXPIRATION, DEFAULT_TOKEN_EXPIRATION);
this.userManager = userConfiguration.getUserManager(root, NamePathMapper.DEFAULT);
@@ -126,18 +134,18 @@ class TokenProviderImpl implements Token
* a {@link #TOKEN_ATTRIBUTE} attribute with an empty value.
*
* @param credentials The current credentials.
- * @return {@code true} if the specified credentials are {@link SimpleCredentials}
- * or {@link ImpersonationCredentials} and if the (extracted) simple credentials
- * object contain a {@link #TOKEN_ATTRIBUTE} attribute with an empty value;
- * {@code false} otherwise.
+ * @return {@code true} if the specified credentials or those extracted from
+ * {@link ImpersonationCredentials} are supported and and if the (extracted)
+ * credentials object contain a {@link #TOKEN_ATTRIBUTE} attribute with an
+ * empty value; {@code false} otherwise.
*/
@Override
public boolean doCreateToken(@Nonnull Credentials credentials) {
- SimpleCredentials sc = extractSimpleCredentials(credentials);
- if (sc == null) {
+ Credentials creds = extractCredentials(credentials);
+ if (creds == null) {
return false;
} else {
- Object attr = sc.getAttribute(TOKEN_ATTRIBUTE);
+ Object attr = credentialsSupport.getAttributes(creds).get(TOKEN_ATTRIBUTE);
return (attr != null && "".equals(attr.toString()));
}
}
@@ -155,18 +163,18 @@ class TokenProviderImpl implements Token
@CheckForNull
@Override
public TokenInfo createToken(@Nonnull Credentials credentials) {
- SimpleCredentials sc = extractSimpleCredentials(credentials);
+ Credentials creds = extractCredentials(credentials);
+ String uid = (creds != null) ? credentialsSupport.getUserId(creds) : null;
+
TokenInfo tokenInfo = null;
- if (sc != null) {
- String[] attrNames = sc.getAttributeNames();
- Map<String, String> attributes = new HashMap<String, String>(attrNames.length);
- for (String attrName : sc.getAttributeNames()) {
- attributes.put(attrName, sc.getAttribute(attrName).toString());
- }
- tokenInfo = createToken(sc.getUserID(), attributes);
+ if (uid != null) {
+ Map<String, ?> attributes = credentialsSupport.getAttributes(creds);
+ tokenInfo = createToken(uid, attributes);
if (tokenInfo != null) {
- // also set the new token to the simple credentials.
- sc.setAttribute(TOKEN_ATTRIBUTE, tokenInfo.getToken());
+ // also set the new token to the credentials.
+ if (!credentialsSupport.setAttributes(creds, ImmutableMap.of(TOKEN_ATTRIBUTE, tokenInfo.getToken()))) {
+ log.debug("Cannot set token attribute to " + creds);
+ }
}
}
@@ -267,20 +275,17 @@ class TokenProviderImpl implements Token
}
@CheckForNull
- private static SimpleCredentials extractSimpleCredentials(Credentials credentials) {
- if (credentials instanceof SimpleCredentials) {
- return (SimpleCredentials) credentials;
- }
-
+ private Credentials extractCredentials(@Nonnull Credentials credentials) {
+ Credentials creds = credentials;
if (credentials instanceof ImpersonationCredentials) {
- Credentials base = ((ImpersonationCredentials) credentials).getBaseCredentials();
- if (base instanceof SimpleCredentials) {
- return (SimpleCredentials) base;
- }
+ creds = ((ImpersonationCredentials) credentials).getBaseCredentials();
}
- // cannot extract SimpleCredentials
- return null;
+ if (credentialsSupport.getCredentialClasses().contains(creds.getClass())) {
+ return creds;
+ } else {
+ return null;
+ }
}
@Nonnull
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/CredentialsSupport.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/CredentialsSupport.java?rev=1755975&r1=1755974&r2=1755975&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/CredentialsSupport.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/CredentialsSupport.java Thu Aug 11 13:11:18 2016
@@ -21,7 +21,6 @@ import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.jcr.Credentials;
-import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule;
@@ -64,4 +63,15 @@ public interface CredentialsSupport {
*/
@Nonnull
Map<String, ?> getAttributes(@Nonnull Credentials credentials);
+
+ /**
+ * Writes the attributes to the specified {@code Credentials}.
+ * If the specified credentials are not supported or doesn't allow to write
+ * attributes this method will return {@code false}.
+ *
+ * @param credentials The credentials as passed to the repository login.
+ * @param attributes The attributes to be written to the given credentials.
+ * @return {@code true}, if the attributes were set; {@code false} otherwise.
+ */
+ boolean setAttributes(@Nonnull Credentials credentials, @Nonnull Map<String, ?> attributes);
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupport.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupport.java?rev=1755975&r1=1755974&r2=1755975&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupport.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupport.java Thu Aug 11 13:11:18 2016
@@ -74,4 +74,17 @@ public final class SimpleCredentialsSupp
return Collections.emptyMap();
}
}
+
+ @Override
+ public boolean setAttributes(@Nonnull Credentials credentials, @Nonnull Map<String, ?> attributes) {
+ if (credentials instanceof SimpleCredentials) {
+ SimpleCredentials sc = (SimpleCredentials) credentials;
+ for (Map.Entry<String, ?> entry : attributes.entrySet()) {
+ sc.setAttribute(entry.getKey(), entry.getValue());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/package-info.java?rev=1755975&r1=1755974&r2=1755975&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/package-info.java Thu Aug 11 13:11:18 2016
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("1.0.0")
+@Version("2.0.0")
package org.apache.jackrabbit.oak.spi.security.authentication.credentials;
import aQute.bnd.annotation.Version;
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestCredentialsSupport.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestCredentialsSupport.java?rev=1755975&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestCredentialsSupport.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestCredentialsSupport.java Thu Aug 11 13:11:18 2016
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.authentication.token;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.jcr.Credentials;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.oak.spi.security.authentication.credentials.CredentialsSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Dummy implementation of {@link CredentialsSupport} that only supports
+ * {@link org.apache.jackrabbit.oak.security.authentication.token.TestCredentialsSupport.Creds}
+ * and always returns the same user ID upon {@link CredentialsSupport#getUserId(Credentials)}.
+ */
+public class TestCredentialsSupport implements CredentialsSupport {
+
+ private final String uid;
+
+ TestCredentialsSupport() {
+ this.uid = null;
+ }
+
+ TestCredentialsSupport(@Nonnull String uid) {
+ this.uid = uid;
+ }
+
+ @Nonnull
+ @Override
+ public Set<Class> getCredentialClasses() {
+ return ImmutableSet.<Class>of(Creds.class);
+ }
+
+ @CheckForNull
+ @Override
+ public String getUserId(@Nonnull Credentials credentials) {
+ if (credentials instanceof Creds) {
+ return uid;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ @Nonnull
+ @Override
+ public Map<String, ?> getAttributes(@Nonnull Credentials credentials) {
+ if (credentials instanceof Creds) {
+ return ((Creds) credentials).attributes;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ @Override
+ public boolean setAttributes(@Nonnull Credentials credentials, @Nonnull Map<String, ?> attributes) {
+ if (credentials instanceof Creds) {
+ ((Creds) credentials).attributes.putAll(attributes);
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ static final class Creds implements Credentials {
+
+ private final Map attributes;
+
+ Creds() {
+ attributes = new HashMap();
+ attributes.put(TokenConstants.TOKEN_ATTRIBUTE, "");
+ }
+ }
+}
Added: 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=1755975&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestLoginModule.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TestLoginModule.java Thu Aug 11 13:11:18 2016
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.authentication.token;
+
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.jcr.Credentials;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+
+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;
+
+public class TestLoginModule extends AbstractLoginModule {
+
+ private CredentialsSupport credentialsSupport;
+ private Credentials credentials;
+ private String userId;
+
+ @Override
+ public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
+ super.initialize(subject, callbackHandler, sharedState, options);
+
+ credentialsSupport = (CredentialsSupport) options.get("credsSupport");
+ }
+
+ @Nonnull
+ @Override
+ protected Set<Class> getSupportedCredentials() {
+ return new TestCredentialsSupport().getCredentialClasses();
+ }
+
+ @Override
+ public boolean login() throws LoginException {
+ credentials = getCredentials();
+ if (credentials != null) {
+ userId = credentialsSupport.getUserId(credentials);
+ sharedState.put(SHARED_KEY_CREDENTIALS, credentials);
+ sharedState.put(SHARED_KEY_LOGIN_NAME, credentialsSupport.getUserId(credentials));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean commit() throws LoginException {
+ if (userId != null) {
+ subject.getPrincipals().add(EveryonePrincipal.getInstance());
+ setAuthInfo(new AuthInfoImpl(userId, credentialsSupport.getAttributes(credentials), subject.getPrincipals()), subject);
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImplOSGiTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImplOSGiTest.java?rev=1755975&r1=1755974&r2=1755975&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImplOSGiTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImplOSGiTest.java Thu Aug 11 13:11:18 2016
@@ -16,15 +16,22 @@
*/
package org.apache.jackrabbit.oak.security.authentication.token;
+import java.util.Hashtable;
+import javax.jcr.SimpleCredentials;
+
import com.google.common.collect.ImmutableMap;
import org.apache.jackrabbit.oak.AbstractSecurityTest;
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.authentication.credentials.CredentialsSupport;
import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenProvider;
import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
import org.junit.Rule;
import org.junit.Test;
+import org.osgi.framework.ServiceRegistration;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
public class TokenConfigurationImplOSGiTest extends AbstractSecurityTest {
@@ -33,13 +40,20 @@ public class TokenConfigurationImplOSGiT
private final TokenConfigurationImpl tokenConfiguration = new TokenConfigurationImpl();
+ private SimpleCredentials sc;
+
@Override
public void before() throws Exception {
super.before();
+ tokenConfiguration.setSecurityProvider(getSecurityProvider());
+
context.registerInjectActivateService(tokenConfiguration, ImmutableMap.<String, Object>of(
TokenProvider.PARAM_TOKEN_EXPIRATION, 25,
TokenProvider.PARAM_TOKEN_LENGTH, 4));
+
+ sc = new SimpleCredentials(getTestUser().getID(), new char[0]);
+ sc.setAttribute(TokenConstants.TOKEN_ATTRIBUTE, "");
}
@Test
@@ -48,4 +62,37 @@ public class TokenConfigurationImplOSGiT
assertEquals(25, params.getConfigValue(TokenProvider.PARAM_TOKEN_EXPIRATION, TokenProviderImpl.DEFAULT_TOKEN_EXPIRATION).longValue());
assertEquals(4, params.getConfigValue(TokenProvider.PARAM_TOKEN_LENGTH, TokenProviderImpl.DEFAULT_KEY_SIZE).intValue());
}
+
+ @Test
+ public void testDefaultCredentialsSupport() throws Exception {
+ TokenProvider tp = tokenConfiguration.getTokenProvider(root);
+ assertTrue(tp.doCreateToken(sc));
+ }
+
+ @Test
+ public void testBindCredentialsSupport() {
+ context.registerService(CredentialsSupport.class, new TestCredentialsSupport(sc.getUserID()));
+
+ TokenProvider tp = tokenConfiguration.getTokenProvider(root);
+
+ assertFalse(tp.doCreateToken(sc));
+ assertTrue(tp.doCreateToken(new TestCredentialsSupport.Creds()));
+ }
+
+ @Test
+ public void testUnbindCredentialsSupport() {
+ CredentialsSupport testSupport = new TestCredentialsSupport(sc.getUserID());
+ ServiceRegistration registration = context.bundleContext().registerService(CredentialsSupport.class.getName(), testSupport, new Hashtable());
+
+ TokenProvider tp = tokenConfiguration.getTokenProvider(root);
+ assertFalse(tp.doCreateToken(sc));
+ assertTrue(tp.doCreateToken(new TestCredentialsSupport.Creds()));
+
+ registration.unregister();
+
+ tp = tokenConfiguration.getTokenProvider(root);
+ assertTrue(tp.doCreateToken(sc));
+ assertFalse(tp.doCreateToken(new TestCredentialsSupport.Creds()));
+
+ }
}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModuleCredentialsSupportTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModuleCredentialsSupportTest.java?rev=1755975&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModuleCredentialsSupportTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModuleCredentialsSupportTest.java Thu Aug 11 13:11:18 2016
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.authentication.token;
+
+import java.util.Collections;
+import java.util.Map;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl;
+import org.apache.jackrabbit.oak.spi.security.authentication.credentials.CredentialsSupport;
+import org.apache.jackrabbit.oak.spi.security.authentication.token.CompositeTokenConfiguration;
+import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+public class TokenLoginModuleCredentialsSupportTest extends AbstractSecurityTest {
+
+ private String userId;
+ private TokenConfigurationImpl tc;
+ private CredentialsSupport credentialsSupport;
+
+ @Before
+ public void before() throws Exception {
+ super.before();
+
+ userId = getTestUser().getID();
+ credentialsSupport = new TestCredentialsSupport(userId);
+
+ CompositeTokenConfiguration composite = ((CompositeTokenConfiguration) getSecurityProvider().getConfiguration(TokenConfiguration.class));
+ tc = (TokenConfigurationImpl) composite.getDefaultConfig();
+ tc.bindCredentialsSupport(credentialsSupport);
+ }
+
+ @Override
+ public void after() throws Exception {
+ try {
+ tc.unbindCredentialsSupport(credentialsSupport);
+ } finally {
+ root.refresh();
+ super.after();
+ }
+ }
+
+ @Override
+ protected Configuration getConfiguration() {
+ return new Configuration() {
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String s) {
+ AppConfigurationEntry tokenEntry = new AppConfigurationEntry(
+ TokenLoginModule.class.getName(),
+ AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT,
+ Collections.<String, Object>emptyMap());
+
+ AppConfigurationEntry testEntry = new AppConfigurationEntry(
+ TestLoginModule.class.getName(),
+ AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT,
+ ImmutableMap.of("credsSupport", credentialsSupport));
+
+ AppConfigurationEntry defaultEntry = new AppConfigurationEntry(
+ LoginModuleImpl.class.getName(),
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ Collections.<String, Object>emptyMap());
+
+ return new AppConfigurationEntry[] {tokenEntry, testEntry, defaultEntry};
+ }
+ };
+ }
+
+ @Test
+ public void testCustomCredentials() throws Exception {
+ TestCredentialsSupport.Creds credentials = new TestCredentialsSupport.Creds();
+
+ ContentSession cs = login(credentials);
+ try {
+ assertEquals(userId, cs.getAuthInfo().getUserID());
+
+ Map<String, ?> attributes = credentialsSupport.getAttributes(credentials);
+ String token = attributes.get(TokenConstants.TOKEN_ATTRIBUTE).toString();
+ assertFalse(token.isEmpty());
+
+ cs.close();
+
+ cs = login(new TokenCredentials(token));
+ assertEquals(userId, cs.getAuthInfo().getUserID());
+ } finally {
+ cs.close();
+ }
+ }
+}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupportTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupportTest.java?rev=1755975&r1=1755974&r2=1755975&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupportTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupportTest.java Thu Aug 11 13:11:18 2016
@@ -71,5 +71,26 @@ public class SimpleCredentialsSupportTes
assertEquals(expected, attributes);
}
+ @Test
+ public void testSetAttributes() {
+ Map<String, ?> attributes = credentialsSupport.getAttributes(new TestCredentials());
+ assertNotNull(attributes);
+ assertTrue(attributes.isEmpty());
+
+ SimpleCredentials sc = new SimpleCredentials("uid", new char[0]);
+
+ Map<String, ?> expected = ImmutableMap.of("a", "a", "b", Boolean.TRUE, "c", new TestCredentials());
+ credentialsSupport.setAttributes(sc, expected);
+
+ for (Map.Entry<String, ?> entry : expected.entrySet()) {
+ assertEquals(entry.getValue(), sc.getAttribute(entry.getKey()));
+ }
+
+ attributes = credentialsSupport.getAttributes(sc);
+ assertNotNull(attributes);
+ assertEquals(3, attributes.size());
+ assertEquals(expected, attributes);
+ }
+
private static final class TestCredentials implements Credentials {}
}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/token/default.md
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/token/default.md?rev=1755975&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/token/default.md (added)
+++ jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/token/default.md Thu Aug 11 13:11:18 2016
@@ -0,0 +1,300 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+Token Management : The Default Implementation
+---------------------------------------------
+
+### General Notes
+
+The default implementation of the token management API stores login tokens along
+with the user's home directory in the repository. Along with the hash of the
+login token separated properties defining the expiration time of the token
+as well as as additional properties associated with the login tokens. This
+additional information may be mandatory (thus validated during the login) or
+optional. The optional properties are meant to have informative value only and
+will be transferred to public attributes as exposed by the [AuthInfo] present
+with each [ContentSession].
+
+### Token Management Operations
+
+#### Token Creation
+
+The creation of a new token is triggered by valid and supported `Credentials`
+passed to the login module chain that contain an additional, empty `.token` attribute.
+
+The [TokenLoginModule] will obtain these `Credentials` from the shared state
+during the commit phase (i.e. phase 2 of the JAAS authentication) and will pass
+them to the configured [TokenProvider] implementation the following sequence:
+
+ Credentials shared = getSharedCredentials();
+ if (shared != null && tokenProvider.doCreateToken(shared)) {
+ [...]
+ TokenInfo ti = tokenProvider.createToken(shared);
+ [...]
+ }
+
+In case of success these steps will have generated a new token and stored
+it's hash along with all mandatory and informative attributes to the new
+content node representing the token.
+
+##### Supported Credentials for Token Creation
+
+By default the implementation deals with shared `SimpleCredentials`.
+
+With Oak 1.5.8 the token management has been extended in order to allow
+for custom `Credentials` implementations. This is achieved by registering
+a custom implementation of the [CredentialsSupport] interface.
+The default the token management uses [SimpleCredentialsSupport].
+
+See also [OAK-4129] and section [Pluggability](#pluggability) below) for
+additional information.
+
+#### Token Validation
+
+Once a token has been created it can be used for subsequent repository
+logins with [TokenCredentials]. This time the [TokenLoginModule] will
+attempt to perform the login phase (i.e. phase 1 of the JAAS authentication).
+
+This includes resolving the login token (`TokenProvider.getTokenInfo`) and
+asserting it's validity in case it exists. The validation consists of following steps:
+
+- check that the token has not expired (`TokenInfo.isExpired`)
+- verify that all mandatory attributes are present and match the expectations (`TokenInfo.matches`)
+
+Only if these steps have been successfully completed the login of the
+[TokenLoginModule] will succeed.
+
+#### Token Removal
+
+A given login token (and the node associated with it) will be removed if
+the authentication fails due to an expired token or with an explicit API call
+i.e. `TokenInfo.remove`.
+
+#### Resetting Expiration Time
+
+The default `TokenProvider` implementation will automatically reset the expiration
+time of a given token upon successful authentication.
+
+This behavior can be disabled by setting the `tokenRefresh` configuration parameter
+to `false` (see `PARAM_TOKEN_REFRESH` below). In this case expiration time will
+not be reset and an attempt to do so using the API (e.g. calling `
+TokenInfo.resetExpiration(long loginTime)`) will return `false` indicating
+that the expiration time has not been reset. The token will consequently expire
+and the user will need to login again using the configured login
+mechanism (e.g. using the credentials support for token creation).
+
+<a name="representation"/>
+### Representation in the Repository
+
+#### Content Structure
+
+The login tokens issued for a given user are all located underneath a node
+named `.tokens` that will be created by the `TokenProvider` once the first token
+is created. The default implementation creates a distinct node for each login
+token as described below
+
+ testUser {
+ "jcr:primaryType": "rep:User",
+ ...
+ ".tokens" {
+ "jcr:primaryType": "rep:Unstructured",
+ "2014-04-10T16.09.07.159+02.00" {
+ "jcr:primaryType": "rep:Token",
+ ...
+ "2014-05-07T12.08.57.683+02.00" {
+ "jcr:primaryType": "rep:Token",
+ ...
+ }
+ "2014-06-25T16.00.13.018+02.00" {
+ "jcr:primaryType": "rep:Token",
+ ...
+ }
+ }
+ }
+
+#### Token Nodes
+
+As of Oak 1.0 the login token are represented in the repository as follows:
+
+- the token node is referenceable with the dedicated node type `rep:Token` (used to be unstructured in Jackrabbit 2.x)
+- expiration and key properties are defined to be mandatory and protected
+- expiration time is obtained from `PARAM_TOKEN_EXPIRATION` specified in the
+ login attributes and falls back to the configuration parameter with the same
+ name as specified in the configuration options of the `TokenConfiguration`.
+
+The definition of the new built-in node type `rep:Token`:
+
+ [rep:Token] > mix:referenceable
+ - rep:token.key (STRING) protected mandatory
+ - rep:token.exp (DATE) protected mandatory
+ - * (UNDEFINED) protected
+ - * (UNDEFINED) multiple protected
+
+The following example illustrates the token nodes resulting from this node type
+definition:
+
+ testUser {
+ "jcr:primaryType": "rep:User",
+ ...
+ ".tokens" {
+ "2014-04-10T16.09.07.159+02.00" {
+ "jcr:primaryType": "rep:Token",
+ "jcr:uuid": "30c1f361-35a2-421a-9ebc-c781eb8a08f0",
+ "rep:token.key": "{SHA-256}afaf64dba5d862f9-1000-3e2d4e58ac16189b9f2ac95d8d5b692e61cb06db437bcd9be5c10bdf3792356a",
+ "rep:token.exp": "2014-04-11T04:09:07.159+02:00",
+ ".token.ip": "0:0:0:0:0:0:0:1%0"
+ ".token.otherMandatoryProperty": "expectedValue",
+ "referer": "http://localhost:4502/crx/explorer/login.jsp"
+ "otherInformalProperty": "somevalue"
+ },
+ "2014-05-07T12.08.57.683+02.00" {
+ "jcr:primaryType": "rep:Token",
+ "jcr:uuid": "c95c91e2-2e08-48ab-93db-6e7c8cdd6469",
+ "rep:token.key": "{SHA-256}b1d268c55abda258-1000-62e4c368972260576d37e6ba14a10f9f02897e42992624890e22c522220f7e54",
+ "rep:token.exp": "2014-05-08T00:08:57.683+02:00"
+ },
+ ...
+ }
+ }
+ }
+
+<a name="validation"/>
+### Validation
+
+The consistency of this content structure both on creation and modification is
+asserted by a dedicated `TokenValidator`. The corresponding errors are
+all of type `Constraint` with the following codes:
+
+| Code | Message |
+|-------------------|----------------------------------------------------------|
+| 0060 | Attempt to create reserved token property in other ctx |
+| 0061 | Attempt to change existing token key |
+| 0062 | Change primary type of existing node to rep:Token |
+| 0063 | Creation/Manipulation of tokens without using provider |
+| 0064 | Create a token outside of configured scope |
+| 0065 | Invalid location of token node |
+| 0066 | Invalid token key |
+| 0067 | Mandatory token expiration missing |
+| 0068 | Invalid location of .tokens node |
+| 0069 | Change type of .tokens parent node |
+
+<a name="configuration"/>
+### Configuration
+
+The default Oak [TokenConfiguration] allows to define the following configuration
+options for the `TokenProvider`:
+
+#### Configuration Parameters
+
+| Parameter | Type | Default |
+|-------------------------------------|---------|--------------------------|
+| PARAM_TOKEN_EXPIRATION | long | 2 * 3600 * 1000 (2 hours)|
+| PARAM_TOKEN_LENGTH | int | 8 |
+| PARAM_TOKEN_REFRESH | boolean | true |
+| PARAM_PASSWORD_HASH_ALGORITHM | String | SHA-256 |
+| PARAM_PASSWORD_HASH_ITERATIONS | int | 1000 |
+| PARAM_PASSWORD_SALT_SIZE | int | 8 |
+| | | |
+
+
+<a name="pluggability"/>
+### Pluggability
+
+In an OSGi-based setup the default `TokenConfiguration` you can bind a
+custom implementation of the [CredentialsSupport] interface. Doing so
+allows to support any type of custom credentials, which do not reveal
+the ID of the user logging into repository.
+
+In particular when chaining the `TokenLoginModule` and the `ExternalLoginModule`
+the [CredentialsSupport] can be used to authenticate and synchronize
+users provided by third party systems during phase 1 (login) and generate
+a login token during phase 2 (commit). See section
+[Authentication with the External Login Module](../externalloginmodule.html)
+for additional details. For this to work the same [CredentialsSupport]
+must be configured with the [ExternalIdentityProvider] and the `TokenConfiguration`
+and `CredentialsSupport.getUserId` must reveal the ID of the synced user (i.e. `ExternalUser.getId`).
+
+In general the following steps are required in order to plug a different `CredentialsSupport`
+into the default `TokenConfiguration`:
+
+- implement the `CredentialsSupport` interface (e.g. as extension to the `ExternalIdentityProvider`)
+- make sure the implementation is an OSGi service and deploy it to the Oak repository.
+
+##### Examples
+
+###### Example CredentialsSupport
+
+In an OSGi-based setup it's sufficient to make the service available to the repository
+in order to enable a custom `CredentialsSupport`.
+
+ @Component
+ @Service(value = {CredentialsSupport.class})
+ /**
+ * Custom implementation of the {@code CredentialsSupport} interface.
+ */
+ final class MyCredentialsSupport implements CredentialsSupport {
+
+ @Nonnull
+ @Override
+ public Set<Class> getCredentialClasses() {
+ return ImmutableSet.<Class>of(MyCredentials.class);
+ }
+
+ @CheckForNull
+ @Override
+ public String getUserId(@Nonnull Credentials credentials) {
+ if (credentials instanceof MyCredentials) {
+ // TODO: resolve user id
+ return resolveUserId(credentials);
+ } else {
+ return null;
+ }
+ }
+
+ @Nonnull
+ @Override
+ public Map<String, ?> getAttributes(@Nonnull Credentials credentials) {
+ // TODO: optional implementation
+ return ImmutableMap.of();
+ }
+
+ @Override
+ public boolean setAttributes(@Nonnull Credentials credentials, @Nonnull Map<String, ?> attributes) {
+ // TODO: optional implementation
+ return false;
+ }
+
+ [...]
+ }
+
+###### Example CredentialsSupport in Combination with External Authentication
+
+See section [Authentication with the External Login Module](../externalloginmodule.html#pluggability)
+for an example.
+
+<!-- references -->
+
+[TokenCredentials]: http://svn.apache.org/repos/asf/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authentication/token/TokenCredentials.java
+[AuthInfo]: /oak/docs/apidocs/org/apache/jackrabbit/oak/api/AuthInfo.html
+[ContentSession]: /oak/docs/apidocs/org/apache/jackrabbit/oak/api/ContentSession.html
+[TokenProvider]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/token/TokenProvider.html
+[TokenInfo]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/token/TokenInfo.html
+[TokenLoginModule]: /oak/docs/apidocs/org/apache/jackrabbit/oak/security/authentication/token/TokenLoginModule.html
+[CredentialsSupport]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/credentials/CredentialsSupport.html
+[SimpleCredentialsSupport]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupport.html
+[OAK-4129]: https://issues.apache.org/jira/browse/OAK-4129
+[ExternalIdentityProvider]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProvider.html
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/tokenmanagement.md
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/tokenmanagement.md?rev=1755975&r1=1755974&r2=1755975&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/tokenmanagement.md (original)
+++ jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/tokenmanagement.md Thu Aug 11 13:11:18 2016
@@ -59,7 +59,16 @@ authentication phases behave as follows:
create a new instance of `TokenCredentials`, push the public attributes to the
shared stated and update the subject with the new credentials;
finally the commit call **returns `false`**
+
+##### Example JAAS Configuration
+
+ jackrabbit.oak {
+ org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule sufficient;
+ org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl required;
+ };
+
+<a name="api_extensions"/>
### Token Management API
Oak 1.0 defines the following interfaces used to manage login tokens:
@@ -71,174 +80,32 @@ Oak 1.0 defines the following interfaces
In addition Oak comes with a default implementation of the provider interface
that is able to aggregate multiple `TokenProvider`s:
-- [CompositeTokenProvider]
-
-
-### Characteristics of the TokenProvider Implementation
-
-The default implementation of the token management API stores login tokens along
-with the user's home directory in the repository. Along with the hash of the
-login token separated properties defining the expiration time of the token
-as well as as additional properties associated with the login tokens. This
-additional information may be mandatory (thus validated during the login) or
-optional. The optional properties are meant to have informative value only and
-will be transferred to public attributes as exposed by the [AuthInfo] present
-with each [ContentSession].
-
-#### Token Creation
-
-The creation of a new token is triggered by valid `SimpleCredentials` passed
-to the login module chain that contain an additional, empty `.token` attribute.
-The default `TokenProvider` implementation will consequently generate a new
-token and store it's hash along with all mandatory and informative attributes
-to the new content node representing the new token.
-
-#### Token Removal
-
-In the default implementation a given login token (and the node associated with it)
-will be removed if the authentication fails due to an expired token.
-
-#### Resetting Expiration Time
-
-The default `TokenProvider` implementation will automatically reset the expiration
-time of a given token upon successful authentication.
-
-This behavior can be disabled by setting the `tokenRefresh` configuration parameter
-to `false` (see `PARAM_TOKEN_REFRESH` below). In this case expiration time will
-not be reset and an attempt to do so using the API (e.g. calling `
-TokenInfo.resetExpiration(long loginTime)`) will return `false` indicating
-that the expiration time has not been reset. The token will consequently expire
-and the user will need to login again using the configured default login
-mechanism (e.g. using `SimpleCredentials`).
-
-#### Token Representation in the Repository
-
-##### Content Structure
-
-The login tokens issued for a given user are all located underneath a node
-named `.tokens` that will be created by the `TokenProvider` once the first token
-is created. The default implementation creates a distinct node for each login
-token as described below
-
- testUser {
- "jcr:primaryType": "rep:User",
- ...
- ".tokens" {
- "jcr:primaryType": "rep:Unstructured",
- "2014-04-10T16.09.07.159+02.00" {
- "jcr:primaryType": "rep:Token",
- ...
- "2014-05-07T12.08.57.683+02.00" {
- "jcr:primaryType": "rep:Token",
- ...
- }
- "2014-06-25T16.00.13.018+02.00" {
- "jcr:primaryType": "rep:Token",
- ...
- }
- }
- }
-
-##### Token Nodes
-
-As of Oak 1.0 the login token are represented in the repository as follows:
+- [CompositeTokenConfiguration]: Extension of the `CompositeConfiguration` to combined different token management implementations.
+- [CompositeTokenProvider]: Aggregation of the `TokenProvider` implementations defined by the configurations contained the `CompositeTokenConfiguration`
-- the token node is referenceable with the dedicated node type `rep:Token` (used to be unstructured in Jackrabbit 2.x)
-- expiration and key properties are defined to be mandatory and protected
-- expiration time is obtained from `PARAM_TOKEN_EXPIRATION` specified in the
- login attributes and falls back to the configuration parameter with the same
- name as specified in the configuration options of the `TokenConfiguration`.
-
-The definition of the new built-in node type `rep:Token`:
-
- [rep:Token] > mix:referenceable
- - rep:token.key (STRING) protected mandatory
- - rep:token.exp (DATE) protected mandatory
- - * (UNDEFINED) protected
- - * (UNDEFINED) multiple protected
-
-The following example illustrates the token nodes resulting from this node type
-definition:
-
- testUser {
- "jcr:primaryType": "rep:User",
- ...
- ".tokens" {
- "2014-04-10T16.09.07.159+02.00" {
- "jcr:primaryType": "rep:Token",
- "jcr:uuid": "30c1f361-35a2-421a-9ebc-c781eb8a08f0",
- "rep:token.key": "{SHA-256}afaf64dba5d862f9-1000-3e2d4e58ac16189b9f2ac95d8d5b692e61cb06db437bcd9be5c10bdf3792356a",
- "rep:token.exp": "2014-04-11T04:09:07.159+02:00",
- ".token.ip": "0:0:0:0:0:0:0:1%0"
- ".token.otherMandatoryProperty": "expectedValue",
- "referer": "http://localhost:4502/crx/explorer/login.jsp"
- "otherInformalProperty": "somevalue"
- },
- "2014-05-07T12.08.57.683+02.00" {
- "jcr:primaryType": "rep:Token",
- "jcr:uuid": "c95c91e2-2e08-48ab-93db-6e7c8cdd6469",
- "rep:token.key": "{SHA-256}b1d268c55abda258-1000-62e4c368972260576d37e6ba14a10f9f02897e42992624890e22c522220f7e54",
- "rep:token.exp": "2014-05-08T00:08:57.683+02:00"
- },
- ...
- }
- }
- }
+See section [Pluggability](#pluggability) for an example.
-<a name="validation"/>
-##### Validation
+<a href="default_implementation"/>
+### Characteristics of the Default Implementation
-The consistency of this content structure both on creation and modification is
-asserted by a dedicated `TokenValidator`. The corresponding errors are
-all of type `Constraint` with the following codes:
-
-| Code | Message |
-|-------------------|----------------------------------------------------------|
-| 0060 | Attempt to create reserved token property in other ctx |
-| 0061 | Attempt to change existing token key |
-| 0062 | Change primary type of existing node to rep:Token |
-| 0063 | Creation/Manipulation of tokens without using provider |
-| 0064 | Create a token outside of configured scope |
-| 0065 | Invalid location of token node |
-| 0066 | Invalid token key |
-| 0067 | Mandatory token expiration missing |
-| 0068 | Invalid location of .tokens node |
-| 0069 | Change type of .tokens parent node |
+The characteristics of the default token management implementation is
+described in section [Token Management : The Default Implementation](token/default.html).
+<a name="configuration"/>
### Configuration
-The Oak token management comes with it's own [TokenConfiguration] which allows
-to obtain a new `TokenProvider` instance with the specified configuration options.
-
-Apart from the default configuration implementation Oak provides a public
-[CompositeTokenConfiguration], which is used to combined different implementations
-plugged at runtime.
-
-#### Configuration Parameters
-
-| Parameter | Type | Default |
-|-------------------------------------|---------|--------------------------|
-| PARAM_TOKEN_EXPIRATION | long | 2 * 3600 * 1000 (2 hours)|
-| PARAM_TOKEN_LENGTH | int | 8 |
-| PARAM_TOKEN_REFRESH | boolean | true |
-| | | |
-
-
-#### Examples
-
-##### Example JAAS Configuration
-
- jackrabbit.oak {
- org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule sufficient;
- org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl required;
- };
+The configuration options of the default implementation are described in
+the [Configuration](token/default.html#configuration) section.
+<a name="pluggability"/>
### Pluggability
-The default security setup as present with Oak 1.0 is able to provide custom
-`TokenProvider` implementations and will automatically combine the
-different implementations using the `CompositeTokenProvider`.
+The default security setup as present with Oak 1.0 is able to deal with
+custom token management implementations and will collect multiple
+implementations within `CompositeTokenConfiguration` present with the
+`SecurityProvider`. The `CompositeTokenConfiguration` itself will
+combine the different `TokenProvider` implementations using the `CompositeTokenProvider`.
In an OSGi setup the following steps are required in order to add a custom
token provider implementation:
@@ -291,4 +158,5 @@ token provider implementation:
[ContentSession]: /oak/docs/apidocs/org/apache/jackrabbit/oak/api/ContentSession.html
[TokenProvider]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/token/TokenProvider.html
[TokenInfo]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/token/TokenInfo.html
+[CompositeTokenConfiguration]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/token/CompositeTokenConfiguration.html
[CompositeTokenProvider]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/token/CompositeTokenProvider.html
\ No newline at end of file