This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/master by this push:
     new 9ae236d  LDAP password pull and propagation improvements
9ae236d is described below

commit 9ae236d46f719b5b87df2d158548f29c989fb3b3
Author: Francesco Chicchiriccò <ilgro...@apache.org>
AuthorDate: Tue Jul 13 15:37:25 2021 +0200

    LDAP password pull and propagation improvements
---
 .../LDAPPasswordPropagationActions.java            |  29 ++----
 .../java/pushpull/LDAPPasswordPullActions.java     |  74 ++++++---------
 .../java/pushpull/LDAPPasswordPullActionsTest.java | 102 +++++++--------------
 .../wa/src/main/resources/application.properties   |   2 +-
 .../src/main/resources/application.properties      |   2 +-
 5 files changed, 75 insertions(+), 134 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 50bb663..6852268 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;
@@ -90,33 +88,24 @@ public class LDAPPasswordPropagationActions implements 
PropagationActions {
     }
 
     private static String getCipherAlgorithm(final ConnInstance connInstance) {
-        Optional<ConnConfProperty> cipherAlgorithm = 
connInstance.getConf().stream().
+        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 static 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 a408fb9..1796334 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
@@ -20,21 +20,23 @@ package org.apache.syncope.core.provisioning.java.pushpull;
 
 import java.util.Base64;
 import java.util.Optional;
+import java.util.Set;
 import javax.xml.bind.DatatypeConverter;
-import org.apache.syncope.common.lib.request.AbstractPatchItem;
-import org.apache.syncope.common.lib.request.AnyCR;
-import org.apache.syncope.common.lib.request.AnyUR;
-import org.apache.syncope.common.lib.request.PasswordPatch;
-import org.apache.syncope.common.lib.request.UserCR;
-import org.apache.syncope.common.lib.request.UserUR;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.to.EntityTO;
-import org.apache.syncope.common.lib.to.ProvisioningReport;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 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;
@@ -53,49 +55,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 AnyCR anyCR) throws JobExecutionException {
-
-        if (anyCR instanceof UserCR) {
-            String password = ((UserCR) anyCR).getPassword();
-            parseEncodedPassword(password);
-        }
-    }
-
-    @Transactional(readOnly = true)
     @Override
-    public void beforeUpdate(
-            final ProvisioningProfile<?, ?> profile,
-            final SyncDelta delta,
-            final EntityTO entityTO,
-            final AnyUR anyUR) throws JobExecutionException {
-
-        if (anyUR instanceof UserUR) {
-            PasswordPatch modPassword = ((UserUR) anyUR).getPassword();
-            
parseEncodedPassword(Optional.ofNullable(modPassword).map(AbstractPatchItem::getValue).orElse(null));
+    public Set<String> moreAttrsToGet(final ProvisioningProfile<?, ?> profile, 
final Provision provision) {
+        if (AnyTypeKind.USER == provision.getAnyType().getKind()) {
+            return Set.of(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, 
password.indexOf('}')).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
@@ -106,16 +87,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 1b833eb..736b678 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,20 +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.SyncopeConstants;
-import org.apache.syncope.common.lib.request.AnyCR;
-import org.apache.syncope.common.lib.request.AnyUR;
-import org.apache.syncope.common.lib.request.PasswordPatch;
-import org.apache.syncope.common.lib.request.UserCR;
-import org.apache.syncope.common.lib.request.UserUR;
-import org.apache.syncope.common.lib.to.EntityTO;
+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;
@@ -39,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
@@ -62,70 +62,38 @@ public class LDAPPasswordPullActionsTest extends 
AbstractTest {
     private ProvisioningReport result;
 
     @InjectMocks
-    private LDAPPasswordPullActions ldapPasswordPullActions;
-
-    private AnyCR anyCR;
-
-    private AnyUR anyUR;
-
-    private EntityTO entity;
-
-    private String encodedPassword;
-
-    private CipherAlgorithm cipher;
-
-    @BeforeEach
-    public void initTest() {
-        entity = 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";
-        anyCR = new UserCR.Builder(SyncopeConstants.ROOT_REALM, "username").
-                password(String.format("{%s}%s", digest, password)).build();
-
-        ldapPasswordPullActions.beforeProvision(profile, syncDelta, anyCR);
 
-        assertEquals(CipherAlgorithm.valueOf(digest), 
ReflectionTestUtils.getField(ldapPasswordPullActions, "cipher"));
-        assertEquals(password, 
ReflectionTestUtils.getField(ldapPasswordPullActions, "encodedPassword"));
-    }
-
-    @Test
-    public void beforeUpdate() throws JobExecutionException {
-        anyUR = new UserUR.Builder(null).
-                password(new 
PasswordPatch.Builder().value("{MD5}an0therTestP4ss").build()).
-                build();
-
-        ldapPasswordPullActions.beforeUpdate(profile, syncDelta, entity, 
anyUR);
-
-        assertNull(ReflectionTestUtils.getField(ldapPasswordPullActions, 
"encodedPassword"));
-    }
+    private LDAPPasswordPullActions actions;
 
     @Test
     public void afterWithNullUser() throws JobExecutionException {
-        when(userDAO.find(entity.getKey())).thenReturn(null);
+        UserTO userTO = new UserTO();
+        userTO.setKey(UUID.randomUUID().toString());
+        when(userDAO.find(userTO.getKey())).thenReturn(null);
 
-        ldapPasswordPullActions.after(profile, syncDelta, entity, 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 {
-        when(userDAO.find(entity.getKey())).thenReturn(user);
+        UserTO userTO = new UserTO();
+        userTO.setKey(UUID.randomUUID().toString());
+        when(userDAO.find(userTO.getKey())).thenReturn(user);
+
+        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();
 
-        ldapPasswordPullActions.after(profile, syncDelta, entity, result);
+        actions.after(profile, delta, userTO, result);
 
         verify(user).setEncodedPassword(anyString(), 
any(CipherAlgorithm.class));
-        assertNull(ReflectionTestUtils.getField(ldapPasswordPullActions, 
"encodedPassword"));
-        assertNull(ReflectionTestUtils.getField(ldapPasswordPullActions, 
"cipher"));
     }
 }
diff --git a/docker/wa/src/main/resources/application.properties 
b/docker/wa/src/main/resources/application.properties
index 8446992..b8b2171 100644
--- a/docker/wa/src/main/resources/application.properties
+++ b/docker/wa/src/main/resources/application.properties
@@ -34,7 +34,7 @@ 
spring.web.resources.static-locations=classpath:/thymeleaf/static,classpath:/syn
 
 cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED
 management.endpoints.enabled-by-default=true
-management.endpoints.web.exposure.include=info,health,loggers,ssoSessions
+management.endpoints.web.exposure.include=info,health,loggers,ssoSessions,registeredServices
 management.endpoint.health.show-details=ALWAYS
 spring.cloud.discovery.client.health-indicator.enabled=false
 
diff --git a/wa/starter/src/main/resources/application.properties 
b/wa/starter/src/main/resources/application.properties
index 8a714d9..4e1b1c2 100644
--- a/wa/starter/src/main/resources/application.properties
+++ b/wa/starter/src/main/resources/application.properties
@@ -34,7 +34,7 @@ 
spring.web.resources.static-locations=classpath:/thymeleaf/static,classpath:/syn
 
 cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED
 management.endpoints.enabled-by-default=true
-management.endpoints.web.exposure.include=info,health,loggers,ssoSessions
+management.endpoints.web.exposure.include=info,health,loggers,ssoSessions,registeredServices
 management.endpoint.health.show-details=ALWAYS
 spring.cloud.discovery.client.health-indicator.enabled=false
 

Reply via email to