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 2019/09/11 15:14:27 UTC

[syncope] branch master updated (3d9fa58 -> d4b50ba)

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

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


    from 3d9fa58  [SYNCOPE-1478] Now allowing to reset uidOnCreate to null
     new ff9cb07  [SYNCOPE-1480] Ensure dynRealms is properly updated
     new d4b50ba  Upgrading bcpkix-jdk15on

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../core/persistence/api/dao/DynRealmDAO.java      |   3 -
 .../core/persistence/jpa/dao/JPADynRealmDAO.java   |  76 +++++++++++----
 .../jpa/dao/JPAExternalResourceDAO.java            |  20 ++--
 .../java/data/DynRealmDataBinderImpl.java          |   1 -
 fit/core-reference/pom.xml                         |   5 +
 .../apache/syncope/fit/core/DynRealmITCase.java    | 106 +++++++++++++++++++++
 pom.xml                                            |   8 +-
 7 files changed, 186 insertions(+), 33 deletions(-)


[syncope] 02/02: Upgrading bcpkix-jdk15on

Posted by il...@apache.org.
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

commit d4b50ba683f0cc7b5b03cf609040bcc8455f2dc4
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Wed Sep 11 17:13:43 2019 +0200

    Upgrading bcpkix-jdk15on
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index b6d24e6..1c21393 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1802,7 +1802,7 @@ under the License.
       <dependency>
         <groupId>org.bouncycastle</groupId>
         <artifactId>bcpkix-jdk15on</artifactId>
-        <version>1.62</version>
+        <version>1.63</version>
         <scope>test</scope>
       </dependency>
       <dependency>


[syncope] 01/02: [SYNCOPE-1480] Ensure dynRealms is properly updated

Posted by il...@apache.org.
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

commit ff9cb07abf411cfdaa7ba3fe020062e75cf4cc8f
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Wed Sep 11 16:21:17 2019 +0200

    [SYNCOPE-1480] Ensure dynRealms is properly updated
---
 .../core/persistence/api/dao/DynRealmDAO.java      |   3 -
 .../core/persistence/jpa/dao/JPADynRealmDAO.java   |  76 +++++++++++----
 .../jpa/dao/JPAExternalResourceDAO.java            |  20 ++--
 .../java/data/DynRealmDataBinderImpl.java          |   1 -
 fit/core-reference/pom.xml                         |   5 +
 .../apache/syncope/fit/core/DynRealmITCase.java    | 106 +++++++++++++++++++++
 pom.xml                                            |   6 ++
 7 files changed, 185 insertions(+), 32 deletions(-)

diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/DynRealmDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/DynRealmDAO.java
index 6268318..e7f4279 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/DynRealmDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/DynRealmDAO.java
@@ -34,10 +34,7 @@ public interface DynRealmDAO extends DAO<DynRealm> {
 
     void delete(String key);
 
-    void clearDynMembers(DynRealm dynRealm);
-
     void refreshDynMemberships(Any<?> any);
 
     void removeDynMemberships(String anyKey);
-
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADynRealmDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADynRealmDAO.java
index 0a63f16..7302d3e 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADynRealmDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADynRealmDAO.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
+import java.util.ArrayList;
 import java.util.List;
 import javax.persistence.Query;
 import javax.persistence.TypedQuery;
@@ -34,6 +35,9 @@ import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 import org.apache.syncope.core.persistence.api.dao.AnyMatchDAO;
+import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
+import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
 
 @Repository
 public class JPADynRealmDAO extends AbstractDAO<DynRealm> implements DynRealmDAO {
@@ -44,6 +48,15 @@ public class JPADynRealmDAO extends AbstractDAO<DynRealm> implements DynRealmDAO
     private ApplicationEventPublisher publisher;
 
     @Autowired
+    private UserDAO userDAO;
+
+    @Autowired
+    private GroupDAO groupDAO;
+
+    @Autowired
+    private AnyObjectDAO anyObjectDAO;
+
+    @Autowired
     private AnySearchDAO searchDAO;
 
     @Autowired
@@ -66,24 +79,60 @@ public class JPADynRealmDAO extends AbstractDAO<DynRealm> implements DynRealmDAO
         return entityManager().merge(dynRealm);
     }
 
+    private List<String> clearDynMembers(final DynRealm dynRealm) {
+        Query find = entityManager().createNativeQuery(
+                "SELECT any_id FROM " + DYNMEMB_TABLE + " WHERE dynRealm_id=?");
+        find.setParameter(1, dynRealm.getKey());
+
+        List<String> cleared = new ArrayList<>();
+        find.getResultList().stream().map(key -> key instanceof Object[]
+                ? (String) ((Object[]) key)[0]
+                : ((String) key)).
+                forEach(key -> cleared.add((String) key));
+
+        Query delete = entityManager().createNativeQuery("DELETE FROM " + DYNMEMB_TABLE + " WHERE dynRealm_id=?");
+        delete.setParameter(1, dynRealm.getKey());
+        delete.executeUpdate();
+
+        return cleared;
+    }
+
+    private void notifyDynMembershipRemoval(final List<String> anyKeys) {
+        anyKeys.forEach(key -> {
+            Any<?> any = userDAO.find(key);
+            if (any == null) {
+                any = groupDAO.find(key);
+            }
+            if (any == null) {
+                any = anyObjectDAO.find(key);
+            }
+            if (any != null) {
+                publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, any, AuthContextUtils.getDomain()));
+            }
+        });
+    }
+
     @Override
     public DynRealm saveAndRefreshDynMemberships(final DynRealm dynRealm) {
         DynRealm merged = save(dynRealm);
 
         // refresh dynamic memberships
-        clearDynMembers(merged);
+        List<String> cleared = clearDynMembers(merged);
 
         merged.getDynMemberships().stream().map(memb -> searchDAO.search(
                 SearchCondConverter.convert(memb.getFIQLCond()), memb.getAnyType().getKind())).
                 forEach(matching -> matching.forEach(any -> {
-                    Query insert = entityManager().createNativeQuery(
-                            "INSERT INTO " + DYNMEMB_TABLE + " VALUES(?, ?)");
-                    insert.setParameter(1, any.getKey());
-                    insert.setParameter(2, merged.getKey());
-                    insert.executeUpdate();
 
-                    publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, any, AuthContextUtils.getDomain()));
-                }));
+            Query insert = entityManager().createNativeQuery("INSERT INTO " + DYNMEMB_TABLE + " VALUES(?, ?)");
+            insert.setParameter(1, any.getKey());
+            insert.setParameter(2, merged.getKey());
+            insert.executeUpdate();
+
+            publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, any, AuthContextUtils.getDomain()));
+            cleared.remove(any.getKey());
+        }));
+
+        notifyDynMembershipRemoval(cleared);
 
         return merged;
     }
@@ -95,18 +144,11 @@ public class JPADynRealmDAO extends AbstractDAO<DynRealm> implements DynRealmDAO
             return;
         }
 
-        clearDynMembers(dynRealm);
+        notifyDynMembershipRemoval(clearDynMembers(dynRealm));
 
         entityManager().remove(dynRealm);
     }
 
-    @Override
-    public void clearDynMembers(final DynRealm dynRealm) {
-        Query delete = entityManager().createNativeQuery("DELETE FROM " + DYNMEMB_TABLE + " WHERE dynRealm_id=?");
-        delete.setParameter(1, dynRealm.getKey());
-        delete.executeUpdate();
-    }
-
     @Transactional
     @Override
     public void refreshDynMemberships(final Any<?> any) {
@@ -114,7 +156,7 @@ public class JPADynRealmDAO extends AbstractDAO<DynRealm> implements DynRealmDAO
             boolean matches = anyMatchDAO.matches(any, SearchCondConverter.convert(memb.getFIQLCond()));
 
             Query find = entityManager().createNativeQuery(
-                    "SELECT dynRealm_id FROM " + JPADynRealmDAO.DYNMEMB_TABLE + " WHERE any_id=?");
+                    "SELECT dynRealm_id FROM " + DYNMEMB_TABLE + " WHERE any_id=?");
             find.setParameter(1, any.getKey());
             boolean existing = !find.getResultList().isEmpty();
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
index 6e07589..7e45b0d 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
-import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -38,6 +37,7 @@ import org.apache.syncope.core.persistence.api.dao.TaskDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
+import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.policy.AccountPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
@@ -213,16 +213,14 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource> implem
                 + " m WHERE m.intAttrName=:intAttrName", MappingItem.class);
         query.setParameter("intAttrName", intAttrName);
 
-        Set<String> itemKeys = new HashSet<>();
-        query.getResultList().forEach(item -> itemKeys.add(item.getKey()));
-        itemKeys.stream().map(itemKey -> entityManager().find(JPAMappingItem.class, itemKey)).
-                filter(Objects::nonNull).map(item -> {
-            item.getMapping().getItems().remove(item);
-            return item;
-        }).map(item -> {
-            item.setMapping(null);
-            return item;
-        }).forEachOrdered(item -> entityManager().remove(item));
+        query.getResultList().stream().
+                map(Entity::getKey).
+                map(itemKey -> entityManager().find(JPAMappingItem.class, itemKey)).filter(Objects::nonNull).
+                forEach(item -> {
+                    item.getMapping().getItems().remove(item);
+                    item.setMapping(null);
+                    entityManager().remove(item);
+                });
 
         // Make empty query cache for *MappingItem and related *Mapping
         entityManager().getEntityManagerFactory().getCache().evict(JPAMappingItem.class);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DynRealmDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DynRealmDataBinderImpl.java
index 8c9ff61..0f00911 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DynRealmDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DynRealmDataBinderImpl.java
@@ -85,7 +85,6 @@ public class DynRealmDataBinderImpl implements DynRealmDataBinder {
             memb.setDynRealm(null);
             itor.remove();
         }
-        dynRealmDAO.clearDynMembers(dynRealm);
 
         dynRealmTO.getDynMembershipConds().forEach((type, fiql) -> {
             AnyType anyType = anyTypeDAO.find(type);
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 52f9663..d46c33f 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -204,6 +204,11 @@ under the License.
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-client</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter</artifactId>
       <scope>test</scope>
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
index cca1f43..2a0e71b 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
@@ -24,7 +24,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
 import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
@@ -34,6 +37,7 @@ import org.apache.syncope.common.lib.request.GroupUR;
 import org.apache.syncope.common.lib.request.StringPatchItem;
 import org.apache.syncope.common.lib.request.UserCR;
 import org.apache.syncope.common.lib.request.UserUR;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.DynRealmTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.PagedResult;
@@ -50,10 +54,19 @@ import org.apache.syncope.common.rest.api.service.GroupService;
 import org.apache.syncope.common.rest.api.service.UserService;
 import org.apache.syncope.fit.AbstractITCase;
 import org.apache.syncope.fit.ElasticsearchDetector;
+import org.apache.tika.io.IOUtils;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.util.InputStreamContentProvider;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
 import org.junit.jupiter.api.Test;
 
 public class DynRealmITCase extends AbstractITCase {
 
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
     @Test
     public void misc() {
         DynRealmTO dynRealm = null;
@@ -211,4 +224,97 @@ public class DynRealmITCase extends AbstractITCase {
             }
         }
     }
+
+    private ArrayNode fetchDynRealmsFromElasticsearch(final String userKey) throws Exception {
+        String body =
+                "{"
+                + "    \"query\": {"
+                + "        \"match\": {\"_id\": \"" + userKey + "\"}"
+                + "    }"
+                + "}";
+
+        HttpClient httpClient = new HttpClient();
+        httpClient.start();
+        ContentResponse response = httpClient.newRequest("http://localhost:9200/master_user/_search").
+                method(HttpMethod.GET).
+                header(HttpHeader.CONTENT_TYPE, MediaType.APPLICATION_JSON).
+                content(new InputStreamContentProvider(IOUtils.toInputStream(body))).
+                send();
+        assertEquals(HttpStatus.OK_200, response.getStatus());
+
+        return (ArrayNode) MAPPER.readTree(response.getContent()).
+                get("hits").get("hits").get(0).get("_source").get("dynRealms");
+    }
+
+    @Test
+    public void issueSYNCOPE1480() throws Exception {
+        String ctype = getUUIDString();
+
+        DynRealmTO dynRealm = null;
+        try {
+            // 1. create new dyn realm matching a very specific attribute value
+            dynRealm = new DynRealmTO();
+            dynRealm.setKey("name" + getUUIDString());
+            dynRealm.getDynMembershipConds().put(AnyTypeKind.USER.name(), "ctype==" + ctype);
+            dynRealmService.create(dynRealm);
+
+            Response response = dynRealmService.create(dynRealm);
+            dynRealm = getObject(response.getLocation(), DynRealmService.class, DynRealmTO.class);
+            assertNotNull(dynRealm);
+
+            // 2. no dyn realm members
+            PagedResult<UserTO> matching = userService.search(new AnyQuery.Builder().realm("/").fiql(
+                    SyncopeClient.getUserSearchConditionBuilder().inDynRealms(dynRealm.getKey()).query()).build());
+            assertEquals(0, matching.getSize());
+
+            // 3. create user with that attribute value
+            UserCR userCR = UserITCase.getUniqueSample("syncope1480@syncope.apache.org");
+            userCR.getPlainAttr("ctype").get().getValues().set(0, ctype);
+            UserTO user = createUser(userCR).getEntity();
+            assertNotNull(user.getKey());
+
+            // 4a. check that Elasticsearch index was updated correctly
+            if (ElasticsearchDetector.isElasticSearchEnabled(syncopeService)) {
+                try {
+                    Thread.sleep(2000);
+                } catch (InterruptedException ex) {
+                    // ignore
+                }
+
+                ArrayNode dynRealms = fetchDynRealmsFromElasticsearch(user.getKey());
+                assertEquals(1, dynRealms.size());
+                assertEquals(dynRealm.getKey(), dynRealms.get(0).asText());
+            }
+
+            // 4b. now there is 1 realm member
+            matching = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).fiql(
+                    SyncopeClient.getUserSearchConditionBuilder().inDynRealms(dynRealm.getKey()).query()).build());
+            assertEquals(1, matching.getSize());
+
+            // 5. change dyn realm condition
+            dynRealm.getDynMembershipConds().put(AnyTypeKind.USER.name(), "ctype==ANY");
+            dynRealmService.update(dynRealm);
+
+            // 6a. check that Elasticsearch index was updated correctly
+            if (ElasticsearchDetector.isElasticSearchEnabled(syncopeService)) {
+                try {
+                    Thread.sleep(2000);
+                } catch (InterruptedException ex) {
+                    // ignore
+                }
+
+                ArrayNode dynRealms = fetchDynRealmsFromElasticsearch(user.getKey());
+                assertTrue(dynRealms.isEmpty());
+            }
+
+            // 6b. no more dyn realm members
+            matching = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).fiql(
+                    SyncopeClient.getUserSearchConditionBuilder().inDynRealms(dynRealm.getKey()).query()).build());
+            assertEquals(0, matching.getSize());
+        } finally {
+            if (dynRealm != null) {
+                dynRealmService.delete(dynRealm.getKey());
+            }
+        }
+    }
 }
diff --git a/pom.xml b/pom.xml
index b8f61a8..b6d24e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1806,6 +1806,12 @@ under the License.
         <scope>test</scope>
       </dependency>
       <dependency>
+        <groupId>org.eclipse.jetty</groupId>
+        <artifactId>jetty-client</artifactId>
+        <version>9.4.20.v20190813</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-test</artifactId>
         <version>${spring.version}</version>