Author: angela
Date: Tue Oct 30 09:19:18 2018
New Revision: 1845206
URL: http://svn.apache.org/viewvc?rev=1845206&view=rev
Log:
OAK-7863 : Allow for admin password to expire
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryAdminTest.java
- copied, changed from r1844647,
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthentication.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryTest.java
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/user/expiry.md
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthentication.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthentication.java?rev=1845206&r1=1845205&r2=1845206&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthentication.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthentication.java
Tue Oct 30 09:19:18 2018
@@ -79,6 +79,8 @@ class UserAuthentication implements Auth
private static final Logger log =
LoggerFactory.getLogger(UserAuthentication.class);
+ public static final String PARAM_PASSWORD_EXPIRY_FOR_ADMIN =
"passwordExpiryForAdmin";
+
private final UserConfiguration config;
private final Root root;
private final String loginId;
@@ -242,13 +244,13 @@ class UserAuthentication implements Auth
}
private boolean isPasswordExpired(@NotNull User user) throws
RepositoryException {
- // the password of the "admin" user never expires
- if (user.isAdmin()) {
+ ConfigurationParameters params = config.getParameters();
+ // unless PARAM_PASSWORD_EXPIRY_FOR_ADMIN is enabled, the password of
the "admin" user never expires
+ if (!Utils.canHavePasswordExpired(user, params)) {
return false;
}
boolean expired = false;
- ConfigurationParameters params = config.getParameters();
int maxAge = params.getConfigValue(PARAM_PASSWORD_MAX_AGE,
DEFAULT_PASSWORD_MAX_AGE);
boolean forceInitialPwChange =
params.getConfigValue(PARAM_PASSWORD_INITIAL_CHANGE,
DEFAULT_PASSWORD_INITIAL_CHANGE);
if (maxAge > 0) {
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java?rev=1845206&r1=1845205&r2=1845206&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
Tue Oct 30 09:19:18 2018
@@ -151,6 +151,12 @@ public class UserConfigurationImpl exten
int passwordHistorySize() default
UserConstants.PASSWORD_HISTORY_DISABLED_SIZE;
@AttributeDefinition(
+ name = "Enable Password Expiry for Admin User",
+ description = "When enabled, the admin user will also be
subject to password expiry. The default value is false for backwards
compatibility."
+ )
+ boolean passwordExpiryForAdmin() default false;
+
+ @AttributeDefinition(
name = "Principal Cache Expiration",
description = "Optional configuration defining the number of
milliseconds " +
"until the principal cache expires (NOTE: currently
only respected for principal resolution " +
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java?rev=1845206&r1=1845205&r2=1845206&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java
Tue Oct 30 09:19:18 2018
@@ -471,7 +471,7 @@ public class UserManagerImpl implements
boolean forceInitialPwChange = forceInitialPasswordChangeEnabled();
boolean isNewUser = userTree.getStatus() == Tree.Status.NEW;
- if (!UserUtil.isAdmin(config, userId)
+ if (Utils.canHavePasswordExpired(userId, config)
// only expiry is enabled, set in all cases
&& ((expiryEnabled && !forceInitialPwChange)
// as soon as force initial pw is enabled, we set in all cases
except new users,
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java?rev=1845206&r1=1845205&r2=1845206&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java
Tue Oct 30 09:19:18 2018
@@ -18,13 +18,16 @@ package org.apache.jackrabbit.oak.securi
import javax.jcr.AccessDeniedException;
+import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.user.util.UserUtil;
import org.apache.jackrabbit.util.Text;
import org.jetbrains.annotations.NotNull;
-class Utils {
+final class Utils {
private Utils() {}
@@ -76,4 +79,20 @@ class Utils {
}
}
}
+
+ static boolean canHavePasswordExpired(@NotNull String userId, @NotNull
ConfigurationParameters config) {
+ if (UserUtil.isAdmin(config, userId) &&
!config.getConfigValue(UserAuthentication.PARAM_PASSWORD_EXPIRY_FOR_ADMIN,
false)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ static boolean canHavePasswordExpired(@NotNull User user, @NotNull
ConfigurationParameters config) {
+ if (user.isAdmin() &&
!config.getConfigValue(UserAuthentication.PARAM_PASSWORD_EXPIRY_FOR_ADMIN,
false)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
}
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java?rev=1845206&r1=1845205&r2=1845206&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
Tue Oct 30 09:19:18 2018
@@ -16,12 +16,9 @@
*/
package org.apache.jackrabbit.oak;
-import static com.google.common.collect.Lists.newArrayList;
-
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
-
import javax.jcr.Credentials;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.RepositoryException;
@@ -71,6 +68,8 @@ import org.jetbrains.annotations.Nullabl
import org.junit.After;
import org.junit.Before;
+import static com.google.common.collect.Lists.newArrayList;
+
/**
* AbstractOakTest is the base class for oak test execution.
*/
@@ -108,7 +107,7 @@ public abstract class AbstractSecurityTe
withEditors(oak);
contentRepository = oak.createContentRepository();
- adminSession = login(getAdminCredentials());
+ adminSession = createAdminSession(contentRepository);
root = adminSession.getLatestRoot();
Configuration.setConfiguration(getConfiguration());
@@ -177,6 +176,11 @@ public abstract class AbstractSecurityTe
return new SimpleCredentials(adminId, adminId.toCharArray());
}
+ @NotNull
+ protected ContentSession createAdminSession(@NotNull ContentRepository
repository) throws LoginException, NoSuchWorkspaceException {
+ return repository.login(getAdminCredentials(), null);
+ }
+
protected NamePathMapper getNamePathMapper() {
return namePathMapper;
}
Copied:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryAdminTest.java
(from r1844647,
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryTest.java)
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryAdminTest.java?p2=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryAdminTest.java&p1=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryTest.java&r1=1844647&r2=1845206&rev=1845206&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryAdminTest.java
Tue Oct 30 09:19:18 2018
@@ -16,23 +16,30 @@
*/
package org.apache.jackrabbit.oak.security.user;
-import java.util.UUID;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.SimpleCredentials;
+import javax.security.auth.Subject;
import javax.security.auth.login.CredentialExpiredException;
import javax.security.auth.login.LoginException;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.ContentSession;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
import org.apache.jackrabbit.oak.spi.security.authentication.Authentication;
+import org.apache.jackrabbit.oak.spi.security.authentication.SystemSubject;
import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
-import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
@@ -42,64 +49,67 @@ import static org.junit.Assert.assertNot
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-/**
- * @see <a href="https://issues.apache.org/jira/browse/OAK-1922">OAK-1922</a>
- */
-public class PasswordExpiryTest extends AbstractSecurityTest {
+public class PasswordExpiryAdminTest extends AbstractSecurityTest {
+ private User user;
private String userId;
@Before
public void before() throws Exception {
super.before();
- userId = getTestUser().getID();
+ user =
getUserManager(root).getAuthorizable(UserConstants.DEFAULT_ADMIN_ID,
User.class);
+ userId = user.getID();
}
+
@Override
protected ConfigurationParameters getSecurityConfigParameters() {
- ConfigurationParameters userConfig =
ConfigurationParameters.of(UserConstants.PARAM_PASSWORD_MAX_AGE, 10);
+ ConfigurationParameters userConfig = ConfigurationParameters.of(
+ UserConstants.PARAM_PASSWORD_MAX_AGE, 10,
+ UserAuthentication.PARAM_PASSWORD_EXPIRY_FOR_ADMIN, true);
return ConfigurationParameters.of(UserConfiguration.NAME, userConfig);
}
- @Test
- public void testCreateUser() throws Exception {
- String newUserId = "newuser" + UUID.randomUUID();
- User user = null;
-
+ @NotNull
+ @Override
+ protected ContentSession createAdminSession(@NotNull ContentRepository
repository) throws LoginException, NoSuchWorkspaceException {
try {
- user = getUserManager(root).createUser(newUserId, newUserId);
- root.commit();
-
- Tree pwdTree =
root.getTree(user.getPath()).getChild(UserConstants.REP_PWD);
- assertTrue(pwdTree.exists());
- assertTrue(TreeUtil.isNodeType(pwdTree,
UserConstants.NT_REP_PASSWORD,
root.getTree(NodeTypeConstants.NODE_TYPES_PATH)));
-
- ReadOnlyNodeTypeManager ntMgr =
ReadOnlyNodeTypeManager.getInstance(root, getNamePathMapper());
- assertTrue(ntMgr.getDefinition(pwdTree.getParent(),
pwdTree).isProtected());
-
- PropertyState property =
pwdTree.getProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED);
- assertNotNull(property);
- assertEquals(Type.LONG, property.getType());
- assertTrue(property.getValue(Type.LONG, 0) > 0);
-
- // protected properties must not be exposed by User#hasProperty
- assertFalse(user.hasProperty(UserConstants.REP_PWD + "/" +
UserConstants.REP_PASSWORD_LAST_MODIFIED));
- } finally {
- if (user != null) {
- user.remove();
- root.commit();
- }
+ return Subject.doAs(SystemSubject.INSTANCE, new
PrivilegedExceptionAction<ContentSession>() {
+ @Override
+ public ContentSession run() throws NoSuchWorkspaceException,
LoginException {
+ return repository.login(null, null);
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new RuntimeException(e);
}
}
@Test
+ public void testUserNode() throws Exception {
+ Tree pwdTree =
root.getTree(user.getPath()).getChild(UserConstants.REP_PWD);
+ assertTrue(pwdTree.exists());
+ assertTrue(TreeUtil.isNodeType(pwdTree, UserConstants.NT_REP_PASSWORD,
root.getTree(NodeTypeConstants.NODE_TYPES_PATH)));
+
+ ReadOnlyNodeTypeManager ntMgr =
ReadOnlyNodeTypeManager.getInstance(root, getNamePathMapper());
+ assertTrue(ntMgr.getDefinition(pwdTree.getParent(),
pwdTree).isProtected());
+
+ PropertyState property =
pwdTree.getProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED);
+ assertNotNull(property);
+ assertEquals(Type.LONG, property.getType());
+ assertTrue(property.getValue(Type.LONG, 0) > 0);
+
+ // protected properties must not be exposed by User#hasProperty
+ assertFalse(user.hasProperty(UserConstants.REP_PWD + "/" +
UserConstants.REP_PASSWORD_LAST_MODIFIED));
+ }
+
+ @Test
public void testChangePassword() throws Exception {
- User user = getTestUser();
PropertyState p1 =
root.getTree(user.getPath()).getChild(UserConstants.REP_PWD).getProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED);
long oldModTime = p1.getValue(Type.LONG, 0);
assertTrue(oldModTime > 0);
waitForSystemTimeIncrement(oldModTime);
- user.changePassword(userId);
+ user.changePassword(user.getID());
root.commit();
PropertyState p2 =
root.getTree(user.getPath()).getChild(UserConstants.REP_PWD).getProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED);
long newModTime = p2.getValue(Type.LONG, 0);
@@ -117,7 +127,7 @@ public class PasswordExpiryTest extends
public void testAuthenticatePasswordExpired() throws Exception {
Authentication a = new UserAuthentication(getUserConfiguration(),
root, userId);
// set password last modified to beginning of epoch
-
root.getTree(getTestUser().getPath()).getChild(UserConstants.REP_PWD).setProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED,
0);
+
root.getTree(user.getPath()).getChild(UserConstants.REP_PWD).setProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED,
0);
root.commit();
try {
a.authenticate(new SimpleCredentials(userId,
userId.toCharArray()));
@@ -131,7 +141,7 @@ public class PasswordExpiryTest extends
public void testAuthenticateBeforePasswordExpired() throws Exception {
Authentication a = new UserAuthentication(getUserConfiguration(),
root, userId);
// set password last modified to beginning of epoch
-
root.getTree(getTestUser().getPath()).getChild(UserConstants.REP_PWD).setProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED,
0);
+
root.getTree(user.getPath()).getChild(UserConstants.REP_PWD).setProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED,
0);
root.commit();
try {
a.authenticate(new SimpleCredentials(userId,
"wrong".toCharArray()));
@@ -146,11 +156,11 @@ public class PasswordExpiryTest extends
public void testAuthenticatePasswordExpiredChangePassword() throws
Exception {
Authentication a = new UserAuthentication(getUserConfiguration(),
root, userId);
// set password last modified to beginning of epoch
-
root.getTree(getTestUser().getPath()).getChild(UserConstants.REP_PWD).setProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED,
0);
+
root.getTree(user.getPath()).getChild(UserConstants.REP_PWD).setProperty(UserConstants.REP_PASSWORD_LAST_MODIFIED,
0);
root.commit();
// changing the password should reset the pw last mod and the pw no
longer be expired
- getTestUser().changePassword(userId);
+ user.changePassword(userId);
root.commit();
assertTrue(a.authenticate(new SimpleCredentials(userId,
userId.toCharArray())));
}
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryTest.java?rev=1845206&r1=1845205&r2=1845206&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/PasswordExpiryTest.java
Tue Oct 30 09:19:18 2018
@@ -154,4 +154,10 @@ public class PasswordExpiryTest extends
root.commit();
assertTrue(a.authenticate(new SimpleCredentials(userId,
userId.toCharArray())));
}
+
+ @Test
+ public void testByDefaultAdminHasNoPwNode() throws Exception {
+ User adminUser =
getUserManager(root).getAuthorizable(getUserConfiguration().getParameters().getConfigValue(UserConstants.PARAM_ADMIN_ID,
UserConstants.DEFAULT_ADMIN_ID), User.class);
+
assertFalse(root.getTree(adminUser.getPath()).getChild(UserConstants.REP_PWD).exists());
+ }
}
Modified: jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/user/expiry.md
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/user/expiry.md?rev=1845206&r1=1845205&r2=1845206&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/user/expiry.md
(original)
+++ jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/user/expiry.md Tue
Oct 30 09:19:18 2018
@@ -47,10 +47,11 @@ OSGi configuration. By default both feat
The following configuration options are supported:
-| Parameter | Type | Default | Description
|
-|------------------------------------- |--------
-|------------------------|
-| `PARAM_PASSWORD_MAX_AGE` | int | 0 | Number of days until
the password expires. |
-| `PARAM_PASSWORD_INITIAL_CHANGE` | boolean | false | boolean flag to
enable initial pw change. |
+| Parameter | Type | Default | Description
|
+|-----------------------------------|---------|----------|--------------------------------------------|
+| `PARAM_PASSWORD_MAX_AGE` | int | 0 | Number of days
until the password expires. |
+| `PARAM_PASSWORD_INITIAL_CHANGE` | boolean | false | boolean flag to
enable initial pw change. |
+| `PARAM_PASSWORD_EXPIRY_FOR_ADMIN` | boolean | false | flag to enable pw
expiry for admin user. |
Note: