This is an automated email from the ASF dual-hosted git repository.
enorman pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-jcr-mock.git
The following commit(s) were added to refs/heads/master by this push:
new a27a118 SLING-12190 provide more real MockUser password handling (#32)
a27a118 is described below
commit a27a11874d605793579a2f951a2097a5829d0073
Author: Eric Norman <[email protected]>
AuthorDate: Sun Dec 10 13:48:18 2023 -0800
SLING-12190 provide more real MockUser password handling (#32)
---
.../apache/sling/testing/mock/jcr/MockUser.java | 39 ++++++++++++++---
.../sling/testing/mock/jcr/MockUserManager.java | 6 ++-
.../testing/mock/jcr/MockUserManagerTest.java | 19 +++++++-
.../sling/testing/mock/jcr/MockUserTest.java | 51 ++++++++++++++++++++--
4 files changed, 103 insertions(+), 12 deletions(-)
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockUser.java
b/src/main/java/org/apache/sling/testing/mock/jcr/MockUser.java
index ad0f2bb..88ed311 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockUser.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockUser.java
@@ -16,8 +16,9 @@
*/
package org.apache.sling.testing.mock.jcr;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
import java.security.Principal;
-import java.util.Arrays;
import javax.jcr.Credentials;
import javax.jcr.Node;
@@ -27,6 +28,9 @@ import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.api.security.user.Impersonation;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.oak.spi.security.principal.SystemUserPrincipal;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.spi.security.user.UserIdCredentials;
+import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@@ -37,7 +41,6 @@ import org.slf4j.LoggerFactory;
*/
class MockUser extends MockAuthorizable implements User {
private Logger logger = LoggerFactory.getLogger(getClass());
- private char[] pwd = {};
private boolean disabled;
private String disabledReason;
@@ -68,7 +71,20 @@ class MockUser extends MockAuthorizable implements User {
@Override
public @NotNull Credentials getCredentials() throws RepositoryException {
- return new SimpleCredentials(id, pwd);
+ char[] pwd;
+ if (homeNode.hasProperty(UserConstants.REP_PASSWORD)) {
+ pwd =
homeNode.getProperty(UserConstants.REP_PASSWORD).getString().toCharArray();
+ } else {
+ pwd = null;
+ }
+
+ Credentials creds;
+ if (pwd == null) {
+ creds = new UserIdCredentials(id);
+ } else {
+ creds = new SimpleCredentials(id, pwd);
+ }
+ return creds;
}
@Override
@@ -81,13 +97,24 @@ class MockUser extends MockAuthorizable implements User {
if (password == null) {
throw new RepositoryException("Attempt to set 'null' password for
user " + getID());
}
-
- pwd = password.toCharArray();
+ try {
+ char[] hashedPwd =
PasswordUtil.buildPasswordHash(password).toCharArray();
+ homeNode.setProperty(UserConstants.REP_PASSWORD,
String.valueOf(hashedPwd));
+ } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
+ throw new RepositoryException("Failed to build the password hash",
e);
+ }
}
@Override
public void changePassword(@Nullable String password, @NotNull String
oldPassword) throws RepositoryException {
- if (Arrays.equals(pwd, oldPassword.toCharArray())) {
+ String hashedPwd;
+ if (homeNode.hasProperty(UserConstants.REP_PASSWORD)) {
+ String pwd =
homeNode.getProperty(UserConstants.REP_PASSWORD).getString();
+ hashedPwd = String.valueOf(pwd);
+ } else {
+ hashedPwd = null;
+ }
+ if (PasswordUtil.isSame(hashedPwd, oldPassword.toCharArray())) {
changePassword(password);
} else {
throw new RepositoryException("old password did not match");
diff --git
a/src/main/java/org/apache/sling/testing/mock/jcr/MockUserManager.java
b/src/main/java/org/apache/sling/testing/mock/jcr/MockUserManager.java
index f8bd17a..ca21b11 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockUserManager.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockUserManager.java
@@ -306,7 +306,11 @@ public class MockUserManager implements UserManager {
}
}
Node node = ensureAuthorizablePathExists(intermediatePath,
principalName, authorizableNodeType);
- return (User)authorizables.computeIfAbsent(userID, id -> new
MockUser(id, principal, node, this));
+ User user = (User)authorizables.computeIfAbsent(userID, id -> new
MockUser(id, principal, node, this));
+ if (password != null) {
+ user.changePassword(password);
+ }
+ return user;
}
@Override
diff --git
a/src/test/java/org/apache/sling/testing/mock/jcr/MockUserManagerTest.java
b/src/test/java/org/apache/sling/testing/mock/jcr/MockUserManagerTest.java
index bc03f2a..33278ea 100644
--- a/src/test/java/org/apache/sling/testing/mock/jcr/MockUserManagerTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockUserManagerTest.java
@@ -23,12 +23,15 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.ValueFactory;
@@ -40,6 +43,7 @@ import org.apache.jackrabbit.api.security.user.Query;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil;
import org.apache.jackrabbit.value.ValueFactoryImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -87,13 +91,19 @@ public class MockUserManagerTest {
}
@Test
- public void testLoadAlreadyExistingAuthorizables() throws
RepositoryException {
+ public void testLoadAlreadyExistingAuthorizables() throws
RepositoryException, NoSuchAlgorithmException, UnsupportedEncodingException {
Node homeNode = session.getRootNode()
.addNode("home", UserConstants.NT_REP_AUTHORIZABLE_FOLDER);
Node usersNode = homeNode.addNode("users",
UserConstants.NT_REP_AUTHORIZABLE_FOLDER);
Node testuser1 = usersNode.addNode("testuser1",
UserConstants.NT_REP_USER);
testuser1.setProperty(UserConstants.REP_AUTHORIZABLE_ID, "testuser1");
testuser1.setProperty(UserConstants.REP_PRINCIPAL_NAME, "testuser1");
+ testuser1.setProperty(UserConstants.REP_PASSWORD,
PasswordUtil.buildPasswordHash("testPwd"));
+
+ // user with no password set - for code coverage
+ Node testuser2 = usersNode.addNode("testuser2",
UserConstants.NT_REP_USER);
+ testuser2.setProperty(UserConstants.REP_AUTHORIZABLE_ID, "testuser2");
+ testuser2.setProperty(UserConstants.REP_PRINCIPAL_NAME, "testuser2");
Node testsystemuser1 = usersNode.addNode("testsystemuser1",
UserConstants.NT_REP_SYSTEM_USER);
testsystemuser1.setProperty(UserConstants.REP_AUTHORIZABLE_ID,
"testsystemuser1");
@@ -106,7 +116,12 @@ public class MockUserManagerTest {
userManager.loadAlreadyExistingAuthorizables();
- assertNotNull(userManager.getAuthorizable("testuser1"));
+ @Nullable Authorizable authorizable =
userManager.getAuthorizable("testuser1");
+ assertTrue(authorizable instanceof User);
+ // verify password state was stored
+ SimpleCredentials creds =
(SimpleCredentials)((User)authorizable).getCredentials();
+ assertTrue(PasswordUtil.isSame(String.valueOf(creds.getPassword()),
"testPwd"));
+ assertNotNull(userManager.getAuthorizable("testuser2"));
assertNotNull(userManager.getAuthorizable("testsystemuser1"));
assertNotNull(userManager.getAuthorizable("testgroup1"));
}
diff --git a/src/test/java/org/apache/sling/testing/mock/jcr/MockUserTest.java
b/src/test/java/org/apache/sling/testing/mock/jcr/MockUserTest.java
index 519d5fc..a53ba15 100644
--- a/src/test/java/org/apache/sling/testing/mock/jcr/MockUserTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockUserTest.java
@@ -16,13 +16,15 @@
*/
package org.apache.sling.testing.mock.jcr;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+
import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -31,8 +33,11 @@ import javax.jcr.UnsupportedRepositoryOperationException;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.spi.security.user.UserIdCredentials;
+import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
+import org.mockito.MockedStatic;
import org.mockito.Mockito;
import ch.qos.logback.classic.Level;
@@ -114,6 +119,15 @@ public class MockUserTest extends
MockAuthorizableTest<User> {
assertTrue(credentials instanceof SimpleCredentials);
assertEquals(authorizable.getID(),
((SimpleCredentials)credentials).getUserID());
}
+ @Test
+ public void testGetCredentialsWithNullPassword() throws
RepositoryException {
+ // create a user with no password
+ authorizable = userManager.createUser("user2", null);
+
+ @NotNull Credentials credentials = authorizable.getCredentials();
+ assertTrue(credentials instanceof UserIdCredentials);
+ assertEquals(authorizable.getID(),
((UserIdCredentials)credentials).getUserId());
+ }
/**
* Test method for {@link
org.apache.sling.testing.mock.jcr.MockUser#getImpersonation()}.
@@ -133,10 +147,33 @@ public class MockUserTest extends
MockAuthorizableTest<User> {
assertThrows(RepositoryException.class, () ->
authorizable.changePassword(null));
}
+ @Test
+ public void testChangePasswordStringFromNull() throws RepositoryException {
+ // start with a null password - for code coverage
+ authorizable = userManager.createUser("testuser2", null);
+ assertThrows(RepositoryException.class, () ->
authorizable.changePassword("changed", "oldPwd"));
+ }
+
+ @Test
+ public void testChangePasswordStringWithCaughtNoSuchAlgorithmException()
throws RepositoryException {
+ try (MockedStatic<PasswordUtil> passwordUtilMock =
Mockito.mockStatic(PasswordUtil.class);) {
+ passwordUtilMock.when(() ->
PasswordUtil.buildPasswordHash("changed"))
+ .thenThrow(NoSuchAlgorithmException.class);
+ assertThrows(RepositoryException.class, () ->
authorizable.changePassword("changed"));
+ }
+ }
+ @Test
+ public void
testChangePasswordStringWithCaughtUnsupportedEncodingExceptionException()
throws RepositoryException {
+ try (MockedStatic<PasswordUtil> passwordUtilMock =
Mockito.mockStatic(PasswordUtil.class);) {
+ passwordUtilMock.when(() ->
PasswordUtil.buildPasswordHash("changed"))
+ .thenThrow(UnsupportedEncodingException.class);
+ assertThrows(RepositoryException.class, () ->
authorizable.changePassword("changed"));
+ }
+ }
protected void assertPassword(char [] expectedPwd) throws
RepositoryException {
SimpleCredentials creds =
(SimpleCredentials)authorizable.getCredentials();
- assertArrayEquals(expectedPwd, creds.getPassword());
+ assertTrue(PasswordUtil.isSame(new String(creds.getPassword()),
expectedPwd));
}
/**
@@ -144,7 +181,7 @@ public class MockUserTest extends
MockAuthorizableTest<User> {
*/
@Test
public void testChangePasswordStringString() throws RepositoryException {
- authorizable.changePassword("changed", "");
+ authorizable.changePassword("changed", "pwd");
assertPassword("changed".toCharArray());
assertThrows(RepositoryException.class, () ->
authorizable.changePassword("changed2", "wrong"));
@@ -194,4 +231,12 @@ public class MockUserTest extends
MockAuthorizableTest<User> {
node.getProperty(UserConstants.REP_PRINCIPAL_NAME).getString());
}
+ @Test
+ @Override
+ public void testGetPropertyNames() throws RepositoryException {
+ // create a user with no password so there are no initial properties
+ authorizable = userManager.createUser("user2", null);
+ super.testGetPropertyNames();
+ }
+
}