You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2021/07/13 15:16:42 UTC
[syncope] branch 2_1_X updated: LDAP password pull and propagation
improvements
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/2_1_X by this push:
new 874fd6e LDAP password pull and propagation improvements
874fd6e is described below
commit 874fd6e770946e6fdd2dfab0714b1f30ebecb1e0
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Tue Jul 13 15:37:25 2021 +0200
LDAP password pull and propagation improvements
---
.../LDAPPasswordPropagationActions.java | 29 +++----
.../java/pushpull/LDAPPasswordPullActions.java | 71 ++++++++---------
.../java/pushpull/LDAPPasswordPullActionsTest.java | 90 ++++++++--------------
3 files changed, 73 insertions(+), 117 deletions(-)
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java
index 8d79c7c..21e5e0c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java
@@ -20,12 +20,10 @@ package org.apache.syncope.core.provisioning.java.propagation;
import java.util.Base64;
import java.util.HashSet;
-import java.util.Optional;
import java.util.Set;
import javax.xml.bind.DatatypeConverter;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
-import org.apache.syncope.common.lib.types.ConnConfProperty;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.ConnInstance;
import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
@@ -89,33 +87,26 @@ public class LDAPPasswordPropagationActions implements PropagationActions {
}
}
- private String getCipherAlgorithm(final ConnInstance connInstance) {
- Optional<ConnConfProperty> cipherAlgorithm = connInstance.getConf().stream().
+ private static String getCipherAlgorithm(final ConnInstance connInstance) {
+ return connInstance.getConf().stream().
filter(property -> "passwordHashAlgorithm".equals(property.getSchema().getName())
- && property.getValues() != null && !property.getValues().isEmpty()).findFirst();
-
- return cipherAlgorithm.isPresent()
- ? (String) cipherAlgorithm.get().getValues().get(0)
- : CLEARTEXT;
+ && property.getValues() != null && !property.getValues().isEmpty()).findFirst().
+ map(cipherAlgorithm -> (String) cipherAlgorithm.getValues().get(0)).
+ orElse(CLEARTEXT);
}
- private boolean cipherAlgorithmMatches(final String connectorAlgorithm, final CipherAlgorithm userAlgorithm) {
- if (userAlgorithm == null) {
+ private static boolean cipherAlgorithmMatches(final String connectorAlgo, final CipherAlgorithm userAlgo) {
+ if (userAlgo == null) {
return false;
}
- if (connectorAlgorithm.equals(userAlgorithm.name())) {
+ if (connectorAlgo.equals(userAlgo.name())) {
return true;
}
// Special check for "SHA" and "SSHA" (user pulled from LDAP)
- if (("SHA".equals(connectorAlgorithm) && userAlgorithm.name().startsWith("SHA"))
- || ("SSHA".equals(connectorAlgorithm) && userAlgorithm.name().startsWith("SSHA"))) {
-
- return true;
- }
-
- return false;
+ return ("SHA".equals(connectorAlgo) && userAlgo.name().startsWith("SHA"))
+ || ("SSHA".equals(connectorAlgo) && userAlgo.name().startsWith("SSHA"));
}
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActions.java
index a3d6818..85236f5 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActions.java
@@ -19,10 +19,11 @@
package org.apache.syncope.core.provisioning.java.pushpull;
import java.util.Base64;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.Set;
import javax.xml.bind.DatatypeConverter;
-import org.apache.syncope.common.lib.patch.AnyPatch;
-import org.apache.syncope.common.lib.patch.PasswordPatch;
-import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
@@ -30,7 +31,13 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
import org.apache.syncope.common.lib.to.ProvisioningReport;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
+import org.identityconnectors.common.security.GuardedString;
+import org.identityconnectors.common.security.SecurityUtil;
+import org.identityconnectors.framework.common.objects.AttributeUtil;
+import org.identityconnectors.framework.common.objects.OperationalAttributes;
import org.identityconnectors.framework.common.objects.SyncDelta;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
@@ -49,49 +56,28 @@ public class LDAPPasswordPullActions implements PullActions {
@Autowired
protected UserDAO userDAO;
- protected String encodedPassword;
-
- protected CipherAlgorithm cipher;
-
- @Transactional(readOnly = true)
- @Override
- public void beforeProvision(
- final ProvisioningProfile<?, ?> profile,
- final SyncDelta delta,
- final EntityTO entity) throws JobExecutionException {
-
- if (entity instanceof UserTO) {
- String password = ((UserTO) entity).getPassword();
- parseEncodedPassword(password);
- }
- }
-
- @Transactional(readOnly = true)
@Override
- public <M extends AnyPatch> void beforeUpdate(
- final ProvisioningProfile<?, ?> profile,
- final SyncDelta delta,
- final EntityTO entityTO,
- final M anyPatch) throws JobExecutionException {
-
- if (anyPatch instanceof UserPatch) {
- PasswordPatch modPassword = ((UserPatch) anyPatch).getPassword();
- parseEncodedPassword(modPassword == null ? null : modPassword.getValue());
+ public Set<String> moreAttrsToGet(final ProvisioningProfile<?, ?> profile, final Provision provision) {
+ if (AnyTypeKind.USER == provision.getAnyType().getKind()) {
+ return Collections.singleton(OperationalAttributes.PASSWORD_NAME);
}
+ return PullActions.super.moreAttrsToGet(profile, provision);
}
- protected void parseEncodedPassword(final String password) {
+ private static Optional<Pair<String, CipherAlgorithm>> parseEncodedPassword(final String password) {
if (password != null && password.startsWith("{")) {
+ String digest = Optional.ofNullable(
+ password.substring(1, password.indexOf('}'))).map(String::toUpperCase).
+ orElse(null);
int closingBracketIndex = password.indexOf('}');
- String digest = password.substring(1, closingBracketIndex).toUpperCase();
try {
- encodedPassword = password.substring(closingBracketIndex + 1);
- cipher = CipherAlgorithm.valueOf(digest);
+ return Optional.of(
+ Pair.of(password.substring(closingBracketIndex + 1), CipherAlgorithm.valueOf(digest)));
} catch (IllegalArgumentException e) {
LOG.error("Cipher algorithm not allowed: {}", digest, e);
- encodedPassword = null;
}
}
+ return Optional.empty();
}
@Transactional
@@ -102,16 +88,19 @@ public class LDAPPasswordPullActions implements PullActions {
final EntityTO entity,
final ProvisioningReport result) throws JobExecutionException {
- if (entity instanceof UserTO && encodedPassword != null && cipher != null) {
+ if (entity instanceof UserTO) {
User user = userDAO.find(entity.getKey());
if (user != null) {
- byte[] encodedPasswordBytes = Base64.getDecoder().decode(encodedPassword.getBytes());
- String encodedHexStr = DatatypeConverter.printHexBinary(encodedPasswordBytes).toUpperCase();
+ GuardedString passwordAttr = AttributeUtil.getPasswordValue(delta.getObject().getAttributes());
+ if (passwordAttr != null) {
+ parseEncodedPassword(SecurityUtil.decrypt(passwordAttr)).ifPresent(encoded -> {
+ byte[] encodedPasswordBytes = Base64.getDecoder().decode(encoded.getLeft().getBytes());
+ String encodedHexStr = DatatypeConverter.printHexBinary(encodedPasswordBytes).toUpperCase();
- user.setEncodedPassword(encodedHexStr, cipher);
+ user.setEncodedPassword(encodedHexStr, encoded.getRight());
+ });
+ }
}
- encodedPassword = null;
- cipher = null;
}
}
}
diff --git a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActionsTest.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActionsTest.java
index 5754603..02ae4bb 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActionsTest.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActionsTest.java
@@ -18,15 +18,15 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
-import org.apache.syncope.common.lib.patch.PasswordPatch;
-import org.apache.syncope.common.lib.patch.UserPatch;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
import org.apache.syncope.common.lib.to.ProvisioningReport;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
@@ -34,20 +34,25 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
import org.apache.syncope.core.provisioning.java.AbstractTest;
+import org.identityconnectors.common.security.GuardedString;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.Name;
+import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.SyncDelta;
-import org.junit.jupiter.api.BeforeEach;
+import org.identityconnectors.framework.common.objects.SyncDeltaBuilder;
+import org.identityconnectors.framework.common.objects.SyncDeltaType;
+import org.identityconnectors.framework.common.objects.SyncToken;
+import org.identityconnectors.framework.common.objects.Uid;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.quartz.JobExecutionException;
-import org.springframework.test.util.ReflectionTestUtils;
public class LDAPPasswordPullActionsTest extends AbstractTest {
@Mock
- private SyncDelta syncDelta;
-
- @Mock
private ProvisioningProfile<?, ?> profile;
@Mock
@@ -57,66 +62,37 @@ public class LDAPPasswordPullActionsTest extends AbstractTest {
private ProvisioningReport result;
@InjectMocks
- private LDAPPasswordPullActions ldapPasswordPullActions;
-
- private UserTO userTO;
-
- private UserPatch userPatch;
-
- private String encodedPassword;
-
- private CipherAlgorithm cipher;
-
- @BeforeEach
- public void initTest() {
- userTO = new UserTO();
- encodedPassword = "s3cureP4ssw0rd";
- cipher = CipherAlgorithm.SHA512;
-
- ReflectionTestUtils.setField(ldapPasswordPullActions, "encodedPassword", encodedPassword);
- ReflectionTestUtils.setField(ldapPasswordPullActions, "cipher", cipher);
- }
-
- @Test
- public void beforeProvision() throws JobExecutionException {
- String digest = "SHA256";
- String password = "t3stPassw0rd";
- userTO.setPassword(String.format("{%s}%s", digest, password));
-
- ldapPasswordPullActions.beforeProvision(profile, syncDelta, userTO);
-
- assertEquals(CipherAlgorithm.valueOf(digest), ReflectionTestUtils.getField(ldapPasswordPullActions, "cipher"));
- assertEquals(password, ReflectionTestUtils.getField(ldapPasswordPullActions, "encodedPassword"));
- }
-
- @Test
- public void beforeUpdate() throws JobExecutionException {
- userPatch = new UserPatch();
- userPatch.setPassword(new PasswordPatch.Builder().value("{MD5}an0therTestP4ss").build());
-
- ldapPasswordPullActions.beforeUpdate(profile, syncDelta, userTO, userPatch);
-
- assertNull(ReflectionTestUtils.getField(ldapPasswordPullActions, "encodedPassword"));
- }
+ private LDAPPasswordPullActions actions;
@Test
public void afterWithNullUser() throws JobExecutionException {
+ UserTO userTO = new UserTO();
+ userTO.setKey(UUID.randomUUID().toString());
when(userDAO.find(userTO.getKey())).thenReturn(null);
- ldapPasswordPullActions.after(profile, syncDelta, userTO, result);
-
- assertNull(ReflectionTestUtils.getField(ldapPasswordPullActions, "encodedPassword"));
- assertNull(ReflectionTestUtils.getField(ldapPasswordPullActions, "cipher"));
+ assertDoesNotThrow(() -> actions.after(profile, null, userTO, result));
}
@Test
public void after(@Mock User user) throws JobExecutionException {
+ UserTO userTO = new UserTO();
+ userTO.setKey(UUID.randomUUID().toString());
when(userDAO.find(userTO.getKey())).thenReturn(user);
- ldapPasswordPullActions.after(profile, syncDelta, userTO, result);
+ Set<Attribute> attributes = new HashSet<>();
+ attributes.add(new Uid(UUID.randomUUID().toString()));
+ attributes.add(new Name(UUID.randomUUID().toString()));
+ attributes.add(AttributeBuilder.buildPassword(
+ new GuardedString("{SSHA}4AwQq1UVDwubSXmR4pnmLsoVR6U2Z7R55kwxRA==".toCharArray())));
+ SyncDelta delta = new SyncDeltaBuilder().
+ setToken(new SyncToken("sample-token")).
+ setDeltaType(SyncDeltaType.CREATE_OR_UPDATE).
+ setUid(new Uid(UUID.randomUUID().toString())).
+ setObject(new ConnectorObject(ObjectClass.ACCOUNT, attributes)).
+ build();
+
+ actions.after(profile, delta, userTO, result);
verify(user).setEncodedPassword(anyString(), any(CipherAlgorithm.class));
- assertNull(ReflectionTestUtils.getField(ldapPasswordPullActions, "encodedPassword"));
- assertNull(ReflectionTestUtils.getField(ldapPasswordPullActions, "cipher"));
}
}