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 2017/06/08 15:55:15 UTC
[3/4] syncope git commit: [SYNCOPE-1067] Core modifications
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 1b7374a..6cec27a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -28,6 +28,7 @@ import java.util.Set;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -165,6 +166,10 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
|| realm.equals(RealmUtils.getGroupOwnerRealm(group.getRealm().getFullPath(), group.getKey()));
}
});
+ if (!authorized) {
+ authorized = !CollectionUtils.intersection(findDynRealms(group.getKey()), authRealms).isEmpty();
+ }
+
if (authRealms == null || authRealms.isEmpty() || !authorized) {
throw new DelegatedAdministrationException(AnyTypeKind.GROUP, group.getKey());
}
@@ -315,11 +320,15 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
}
}
+ dynRealmDAO().refreshDynMemberships(merged);
+
return merged;
}
@Override
public void delete(final Group group) {
+ dynRealmDAO().removeDynMemberships(group.getKey());
+
for (AMembership membership : findAMemberships(group)) {
AnyObject leftEnd = membership.getLeftEnd();
leftEnd.getMemberships().remove(membership);
@@ -349,6 +358,9 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, leftEnd, AuthContextUtils.getDomain()));
}
+ clearUDynMembers(group);
+ clearADynMembers(group);
+
entityManager().remove(group);
publisher.publishEvent(
new AnyDeletedEvent(this, AnyTypeKind.GROUP, group.getKey(), AuthContextUtils.getDomain()));
@@ -427,7 +439,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
@Override
public void removeDynMemberships(final AnyObject anyObject) {
- List<Group> dynGroups = anyObjectDAO().findDynGroups(anyObject);
+ List<Group> dynGroups = anyObjectDAO().findDynGroups(anyObject.getKey());
Query delete = entityManager().createNativeQuery("DELETE FROM " + ADYNMEMB_TABLE + " WHERE any_id=?");
delete.setParameter(1, anyObject.getKey());
@@ -501,7 +513,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
@Override
public void removeDynMemberships(final User user) {
- List<Group> dynGroups = userDAO().findDynGroups(user);
+ List<Group> dynGroups = userDAO().findDynGroups(user.getKey());
Query delete = entityManager().createNativeQuery("DELETE FROM " + UDYNMEMB_TABLE + " WHERE any_id=?");
delete.setParameter(1, user.getKey());
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
index 9796f4d..367ee8d 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
@@ -121,6 +121,8 @@ public class JPARoleDAO extends AbstractDAO<Role> implements RoleDAO {
publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, user, AuthContextUtils.getDomain()));
}
+ clearDynMembers(role);
+
entityManager().remove(role);
}
@@ -183,9 +185,9 @@ public class JPARoleDAO extends AbstractDAO<Role> implements RoleDAO {
}
@Override
- public void removeDynMemberships(final User user) {
+ public void removeDynMemberships(final String key) {
Query delete = entityManager().createNativeQuery("DELETE FROM " + DYNMEMB_TABLE + " WHERE any_id=?");
- delete.setParameter(1, user.getKey());
+ delete.setParameter(1, key);
delete.executeUpdate();
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
index 40db0c4..afa83f4 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
@@ -186,6 +186,9 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
return user.getRealm().getFullPath().startsWith(realm);
}
});
+ if (!authorized) {
+ authorized = !CollectionUtils.intersection(findDynRealms(user.getKey()), authRealms).isEmpty();
+ }
if (authRealms == null || authRealms.isEmpty() || !authorized) {
throw new DelegatedAdministrationException(AnyTypeKind.USER, user.getKey());
}
@@ -448,14 +451,16 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
roleDAO.refreshDynMemberships(merged);
groupDAO().refreshDynMemberships(merged);
+ dynRealmDAO().refreshDynMemberships(merged);
return merged;
}
@Override
public void delete(final User user) {
- roleDAO.removeDynMemberships(user);
- groupDAO.removeDynMemberships(user);
+ roleDAO.removeDynMemberships(user.getKey());
+ groupDAO().removeDynMemberships(user);
+ dynRealmDAO().removeDynMemberships(user.getKey());
AccessToken accessToken = accessTokenDAO.findByOwner(user.getUsername());
if (accessToken != null) {
@@ -470,21 +475,21 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
@Override
public Collection<Role> findAllRoles(final User user) {
- return CollectionUtils.union(user.getRoles(), findDynRoles(user));
+ return CollectionUtils.union(user.getRoles(), findDynRoles(user.getKey()));
}
@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
@Override
- public List<Role> findDynRoles(final User user) {
+ public List<Role> findDynRoles(final String key) {
Query query = entityManager().createNativeQuery(
"SELECT role_id FROM " + JPARoleDAO.DYNMEMB_TABLE + " WHERE any_id=?");
- query.setParameter(1, user.getKey());
+ query.setParameter(1, key);
List<Role> result = new ArrayList<>();
- for (Object key : query.getResultList()) {
- String actualKey = key instanceof Object[]
- ? (String) ((Object[]) key)[0]
- : ((String) key);
+ for (Object resultKey : query.getResultList()) {
+ String actualKey = resultKey instanceof Object[]
+ ? (String) ((Object[]) resultKey)[0]
+ : ((String) resultKey);
Role role = roleDAO.find(actualKey);
if (role == null) {
@@ -498,16 +503,16 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
@Override
- public List<Group> findDynGroups(final User user) {
+ public List<Group> findDynGroups(final String key) {
Query query = entityManager().createNativeQuery(
"SELECT group_id FROM " + JPAGroupDAO.UDYNMEMB_TABLE + " WHERE any_id=?");
- query.setParameter(1, user.getKey());
+ query.setParameter(1, key);
List<Group> result = new ArrayList<>();
- for (Object key : query.getResultList()) {
- String actualKey = key instanceof Object[]
- ? (String) ((Object[]) key)[0]
- : ((String) key);
+ for (Object resultKey : query.getResultList()) {
+ String actualKey = resultKey instanceof Object[]
+ ? (String) ((Object[]) resultKey)[0]
+ : ((String) resultKey);
Group group = groupDAO().find(actualKey);
if (group == null) {
@@ -530,7 +535,7 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
return input.getRightEnd();
}
}, new ArrayList<Group>()),
- findDynGroups(user));
+ findDynGroups(user.getKey()));
}
@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
index fd40470..5cac5bb 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
@@ -135,6 +135,10 @@ class SearchSupport {
return new SearchView("svdr", JPARoleDAO.DYNMEMB_TABLE);
}
+ public SearchView dynrealmmembership() {
+ return new SearchView("svdrealm", JPADynRealmDAO.DYNMEMB_TABLE);
+ }
+
public SearchView nullAttr() {
return new SearchView("svna", field().name + "_null_attr");
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynRealm.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynRealm.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynRealm.java
new file mode 100644
index 0000000..3a0aaa1
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynRealm.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import org.apache.syncope.core.persistence.api.entity.DynRealm;
+import org.apache.syncope.core.persistence.jpa.validation.entity.DynRealmCheck;
+
+@Entity
+@Table(name = JPADynRealm.TABLE)
+@Cacheable
+@DynRealmCheck
+public class JPADynRealm extends AbstractProvidedKeyEntity implements DynRealm {
+
+ private static final long serialVersionUID = -6851035842423560341L;
+
+ public static final String TABLE = "DynRealm";
+
+ @NotNull
+ private String fiql;
+
+ @Override
+ public String getFIQLCond() {
+ return fiql;
+ }
+
+ @Override
+ public void setFIQLCond(final String fiql) {
+ this.fiql = fiql;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
index 7d9660c..daea67a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
@@ -124,6 +124,7 @@ import org.apache.syncope.core.persistence.api.entity.task.AnyTemplatePullTask;
import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
import org.apache.syncope.core.persistence.jpa.entity.resource.JPAOrgUnit;
+import org.apache.syncope.core.persistence.api.entity.DynRealm;
@Component
public class JPAEntityFactory implements EntityFactory {
@@ -137,6 +138,8 @@ public class JPAEntityFactory implements EntityFactory {
result = (E) new JPADomain();
} else if (reference.equals(Realm.class)) {
result = (E) new JPARealm();
+ } else if (reference.equals(DynRealm.class)) {
+ result = (E) new JPADynRealm();
} else if (reference.equals(AnyTemplateRealm.class)) {
result = (E) new JPAAnyTemplateRealm();
} else if (reference.equals(AccountPolicy.class)) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
index 919c3cb..30a1f47 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
@@ -41,6 +41,7 @@ import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.Role;
import org.apache.syncope.core.persistence.jpa.entity.user.JPADynRoleMembership;
import org.apache.syncope.core.persistence.jpa.validation.entity.RoleCheck;
+import org.apache.syncope.core.persistence.api.entity.DynRealm;
@Entity
@Table(name = JPARole.TABLE)
@@ -67,6 +68,14 @@ public class JPARole extends AbstractProvidedKeyEntity implements Role {
@Valid
private List<JPARealm> realms = new ArrayList<>();
+ @ManyToMany(fetch = FetchType.EAGER)
+ @JoinTable(joinColumns =
+ @JoinColumn(name = "role_id"),
+ inverseJoinColumns =
+ @JoinColumn(name = "dynamicRealm_id"))
+ @Valid
+ private List<JPADynRealm> dynRealms = new ArrayList<>();
+
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "role")
@Valid
private JPADynRoleMembership dynMembership;
@@ -91,6 +100,17 @@ public class JPARole extends AbstractProvidedKeyEntity implements Role {
}
@Override
+ public boolean add(final DynRealm dynamicRealm) {
+ checkType(dynamicRealm, JPADynRealm.class);
+ return dynRealms.add((JPADynRealm) dynamicRealm);
+ }
+
+ @Override
+ public List<? extends DynRealm> getDynRealms() {
+ return dynRealms;
+ }
+
+ @Override
public DynRoleMembership getDynMembership() {
return dynMembership;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/DynRealmCheck.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/DynRealmCheck.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/DynRealmCheck.java
new file mode 100644
index 0000000..567dc74
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/DynRealmCheck.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.validation.entity;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = DynRealmValidator.class)
+@Documented
+public @interface DynRealmCheck {
+
+ String message() default "{org.apache.syncope.core.persistence.validation.dynrealm}";
+
+ Class<?>[] groups() default {};
+
+ Class<? extends Payload>[] payload() default {};
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/DynRealmValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/DynRealmValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/DynRealmValidator.java
new file mode 100644
index 0000000..e97c122
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/DynRealmValidator.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.validation.entity;
+
+import java.util.regex.Pattern;
+import javax.validation.ConstraintValidatorContext;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.core.persistence.api.entity.DynRealm;
+
+public class DynRealmValidator extends AbstractValidator<DynRealmCheck, DynRealm> {
+
+ private static final Pattern REALM_KEY_PATTERN = Pattern.compile("^[A-Za-z0-9]+");
+
+ @Override
+ public boolean isValid(final DynRealm dynRealm, final ConstraintValidatorContext context) {
+ context.disableDefaultConstraintViolation();
+
+ boolean isValid = true;
+
+ if (dynRealm.getKey().startsWith("/") || !REALM_KEY_PATTERN.matcher(dynRealm.getKey()).matches()) {
+ isValid = false;
+
+ context.buildConstraintViolationWithTemplate(
+ getTemplate(EntityViolationType.InvalidDynRealm,
+ "Only letters and numbers are allowed in dynamic realm key, and must not start with /")).
+ addPropertyNode("key").addConstraintViolation();
+ }
+
+ return isValid;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
index e1bdf68..3b46f62 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
@@ -28,6 +28,7 @@ import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntit
import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.apache.syncope.core.persistence.api.entity.AnnotatedEntity;
import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.DynMembership;
import org.apache.syncope.core.persistence.api.entity.Entity;
import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
import org.apache.syncope.core.persistence.api.entity.Policy;
@@ -62,6 +63,7 @@ public class EntityValidationListener {
&& !Policy.class.equals(interf)
&& !GroupableRelatable.class.equals(interf)
&& !Any.class.equals(interf)
+ && !DynMembership.class.equals(interf)
&& Entity.class.isAssignableFrom(interf)) {
entityInt = interf;
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/resources/indexes.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/indexes.xml b/core/persistence-jpa/src/main/resources/indexes.xml
index 1dfa63d..ded4d52 100644
--- a/core/persistence-jpa/src/main/resources/indexes.xml
+++ b/core/persistence-jpa/src/main/resources/indexes.xml
@@ -29,6 +29,9 @@ under the License.
<entry key="DynRoleMembers_any_id">CREATE INDEX DynRoleMembers_any_id ON DynRoleMembers(any_id)</entry>
<entry key="DynRoleMembers_role_id">CREATE INDEX DynRoleMembers_role_id ON DynRoleMembers(role_id)</entry>
+ <entry key="DynRealmMembers_any_id">CREATE INDEX DynRealmMembers_any_id ON DynRealmMembers(any_id)</entry>
+ <entry key="DynRealmMembers_realm_id">CREATE INDEX DynRealmMembers_dynRealm_id ON DynRealmMembers(dynRealm_id)</entry>
+
<entry key="UPlainAttrValue_stringvalueIndex">CREATE INDEX UAttrValue_stringvalueIndex ON UPlainAttrValue(stringvalue)</entry>
<entry key="UPlainAttrValue_datevalueIndex">CREATE INDEX UAttrValue_datevalueIndex ON UPlainAttrValue(datevalue)</entry>
<entry key="UPlainAttrValue_longvalueIndex">CREATE INDEX UAttrValue_longvalueIndex ON UPlainAttrValue(longvalue)</entry>
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/main/resources/views.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/views.xml b/core/persistence-jpa/src/main/resources/views.xml
index fb68516..bcff6b9 100644
--- a/core/persistence-jpa/src/main/resources/views.xml
+++ b/core/persistence-jpa/src/main/resources/views.xml
@@ -39,6 +39,12 @@ under the License.
role_id CHAR(36),
UNIQUE(any_id, role_id))
</entry>
+ <entry key="DynRealmMembers">
+ CREATE TABLE DynRealmMembers(
+ any_id CHAR(36),
+ dynRealm_id CHAR(36),
+ UNIQUE(any_id, dynRealm_id))
+ </entry>
<!-- user -->
<entry key="user_search">
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
index c7e5c62..1ba9913 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
@@ -109,7 +109,7 @@ public class AnySearchTest extends AbstractTest {
assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(groupCond)));
RoleCond roleCond = new RoleCond();
- roleCond.setRoleKey("Other");
+ roleCond.setRole("Other");
assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(roleCond)));
user = userDAO.find("c9b2dec2-00a7-4855-97c0-d854842b4b24");
@@ -303,7 +303,7 @@ public class AnySearchTest extends AbstractTest {
@Test
public void searchByRole() {
RoleCond roleCond = new RoleCond();
- roleCond.setRoleKey("Other");
+ roleCond.setRole("Other");
List<User> users = searchDAO.search(SearchCond.getLeafCond(roleCond), AnyTypeKind.USER);
assertNotNull(users);
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/RoleTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/RoleTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/RoleTest.java
index 174eef2..55fbb19 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/RoleTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/RoleTest.java
@@ -18,7 +18,6 @@
*/
package org.apache.syncope.core.persistence.jpa.inner;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
index f91aa7e..f3d3203 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
@@ -100,7 +100,7 @@ public class AnySearchTest extends AbstractTest {
// 2. search user by this dynamic role
RoleCond roleCond = new RoleCond();
- roleCond.setRoleKey(role.getKey());
+ roleCond.setRole(role.getKey());
List<User> users = searchDAO.search(SearchCond.getLeafCond(roleCond), AnyTypeKind.USER);
assertNotNull(users);
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/DynRealmTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/DynRealmTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/DynRealmTest.java
new file mode 100644
index 0000000..307b865
--- /dev/null
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/DynRealmTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.outer;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.search.DynRealmCond;
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.DynRealm;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional("Master")
+public class DynRealmTest extends AbstractTest {
+
+ @Autowired
+ private DynRealmDAO dynRealmDAO;
+
+ @Autowired
+ private AnySearchDAO searchDAO;
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Test
+ public void misc() {
+ DynRealm dynRealm = entityFactory.newEntity(DynRealm.class);
+ dynRealm.setKey("/name");
+ dynRealm.setFIQLCond("cool==true");
+
+ // invalid key (starts with /)
+ try {
+ dynRealmDAO.save(dynRealm);
+ fail();
+ } catch (Exception e) {
+ assertNotNull(e);
+ }
+
+ dynRealm.setKey("name");
+ DynRealm actual = dynRealmDAO.save(dynRealm);
+ assertNotNull(actual);
+
+ dynRealmDAO.flush();
+
+ DynRealmCond dynRealmCond = new DynRealmCond();
+ dynRealmCond.setDynRealm(actual.getKey());
+ List<User> matching = searchDAO.search(SearchCond.getLeafCond(dynRealmCond), AnyTypeKind.USER);
+ assertNotNull(matching);
+ assertFalse(matching.isEmpty());
+
+ User user = matching.get(0);
+ assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(dynRealmCond)));
+
+ assertTrue(userDAO.findDynRealms(user.getKey()).contains(actual.getKey()));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/DynRealmDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/DynRealmDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/DynRealmDataBinder.java
new file mode 100644
index 0000000..5244b65
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/DynRealmDataBinder.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.api.data;
+
+import org.apache.syncope.common.lib.to.DynRealmTO;
+import org.apache.syncope.core.persistence.api.entity.DynRealm;
+
+public interface DynRealmDataBinder {
+
+ DynRealm create(DynRealmTO dynRealmTO);
+
+ DynRealm update(DynRealm dynRealm, DynRealmTO dynRealmTO);
+
+ DynRealmTO getDynRealmTO(DynRealm dynRealm);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
index 5428f5f..550f183 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -102,6 +102,9 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
details);
if (details) {
+ // dynamic realms
+ anyObjectTO.getDynRealms().addAll(userDAO.findDynRealms(anyObject.getKey()));
+
// relationships
CollectionUtils.collect(anyObject.getRelationships(), new Transformer<ARelationship, RelationshipTO>() {
@@ -126,7 +129,7 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
}, anyObjectTO.getMemberships());
// dynamic memberships
- CollectionUtils.collect(anyObjectDAO.findDynGroups(anyObject),
+ CollectionUtils.collect(anyObjectDAO.findDynGroups(anyObject.getKey()),
EntityUtils.<Group>keyTransformer(), anyObjectTO.getDynGroups());
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DynRealmDataBinderImpl.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..56d7903
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DynRealmDataBinderImpl.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java.data;
+
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.DynRealmTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.DynRealm;
+import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
+import org.apache.syncope.core.provisioning.api.data.DynRealmDataBinder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class DynRealmDataBinderImpl implements DynRealmDataBinder {
+
+ @Autowired
+ private DynRealmDAO dynRealmDAO;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ @Override
+ public DynRealm create(final DynRealmTO dynRealmTO) {
+ return update(entityFactory.newEntity(DynRealm.class), dynRealmTO);
+ }
+
+ @Override
+ public DynRealm update(final DynRealm dynRealm, final DynRealmTO dynRealmTO) {
+ dynRealm.setKey(dynRealmTO.getKey());
+
+ SearchCond cond = SearchCondConverter.convert(dynRealmTO.getCond());
+ if (!cond.isValid()) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSearchExpression);
+ sce.getElements().add(dynRealmTO.getCond());
+ throw sce;
+ }
+ dynRealm.setFIQLCond(dynRealmTO.getCond());
+
+ return dynRealmDAO.save(dynRealm);
+ }
+
+ @Override
+ public DynRealmTO getDynRealmTO(final DynRealm dynRealm) {
+ DynRealmTO dynRealmTO = new DynRealmTO();
+
+ dynRealmTO.setKey(dynRealm.getKey());
+ dynRealmTO.setCond(dynRealm.getFIQLCond());
+
+ return dynRealmTO;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
index 32206aa..c4f8c50 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
@@ -231,7 +231,7 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
}
group = groupDAO.save(group);
-
+
// dynamic membership
if (groupPatch.getUDynMembershipCond() == null) {
if (group.getUDynMembership() != null) {
@@ -345,6 +345,11 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
group.getResources(),
details);
+ if (details) {
+ // dynamic realms
+ groupTO.getDynRealms().addAll(groupDAO.findDynRealms(group.getKey()));
+ }
+
if (group.getUDynMembership() != null) {
groupTO.setUDynMembershipCond(group.getUDynMembership().getFIQLCond());
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
index 6ccb229..b907051 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
@@ -23,15 +23,18 @@ import org.apache.commons.collections4.Transformer;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.to.RoleTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.dao.RoleDAO;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.DynRealm;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.Role;
import org.apache.syncope.core.persistence.api.entity.user.DynRoleMembership;
import org.apache.syncope.core.provisioning.api.data.RoleDataBinder;
+import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -46,6 +49,9 @@ public class RoleDataBinderImpl implements RoleDataBinder {
private RealmDAO realmDAO;
@Autowired
+ private DynRealmDAO dynRealmDAO;
+
+ @Autowired
private RoleDAO roleDAO;
@Autowired
@@ -93,6 +99,16 @@ public class RoleDataBinderImpl implements RoleDataBinder {
}
}
+ role.getDynRealms().clear();
+ for (String key : roleTO.getDynRealms()) {
+ DynRealm dynRealm = dynRealmDAO.find(key);
+ if (dynRealm == null) {
+ LOG.debug("Invalid dynamic ream {}, ignoring", key);
+ } else {
+ role.add(dynRealm);
+ }
+ }
+
role = roleDAO.save(role);
// dynamic membership
@@ -127,6 +143,8 @@ public class RoleDataBinderImpl implements RoleDataBinder {
}
}, roleTO.getRealms());
+ CollectionUtils.collect(role.getDynRealms(), EntityUtils.keyTransformer(), roleTO.getDynRealms());
+
if (role.getDynMembership() != null) {
roleTO.setDynMembershipCond(role.getDynMembership().getFIQLCond());
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index 3cd52c3..54c9983 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -606,6 +606,9 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
details);
if (details) {
+ // dynamic realms
+ userTO.getDynRealms().addAll(userDAO.findDynRealms(user.getKey()));
+
// roles
CollectionUtils.collect(user.getRoles(),
EntityUtils.<Role>keyTransformer(), userTO.getRoles());
@@ -634,9 +637,9 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
}, userTO.getMemberships());
// dynamic memberships
- CollectionUtils.collect(userDAO.findDynRoles(user),
+ CollectionUtils.collect(userDAO.findDynRoles(user.getKey()),
EntityUtils.<Role>keyTransformer(), userTO.getDynRoles());
- CollectionUtils.collect(userDAO.findDynGroups(user),
+ CollectionUtils.collect(userDAO.findDynGroups(user.getKey()),
EntityUtils.<Group>keyTransformer(), userTO.getDynGroups());
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/DynRealmServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/DynRealmServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/DynRealmServiceImpl.java
new file mode 100644
index 0000000..41e3bad
--- /dev/null
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/DynRealmServiceImpl.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.rest.cxf.service;
+
+import java.net.URI;
+import java.util.List;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.to.DynRealmTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.DynRealmService;
+import org.apache.syncope.core.logic.DynRealmLogic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DynRealmServiceImpl extends AbstractServiceImpl implements DynRealmService {
+
+ @Autowired
+ private DynRealmLogic logic;
+
+ @Override
+ public List<DynRealmTO> list() {
+ return logic.list();
+ }
+
+ @Override
+ public DynRealmTO read(final String key) {
+ return logic.read(key);
+ }
+
+ @Override
+ public Response create(final DynRealmTO roleTO) {
+ DynRealmTO created = logic.create(roleTO);
+ URI location = uriInfo.getAbsolutePathBuilder().path(created.getKey()).build();
+ return Response.created(location).
+ header(RESTHeaders.RESOURCE_KEY, created.getKey()).
+ build();
+ }
+
+ @Override
+ public void update(final DynRealmTO roleTO) {
+ logic.update(roleTO);
+ }
+
+ @Override
+ public void delete(final String key) {
+ logic.delete(key);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
----------------------------------------------------------------------
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
index aba2e50..79ba01b 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
@@ -19,7 +19,6 @@
package org.apache.syncope.core.spring.security;
import com.fasterxml.jackson.core.type.TypeReference;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -29,11 +28,10 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
-import org.apache.commons.collections4.Closure;
import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.SetUtils;
import org.apache.commons.collections4.Transformer;
+import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.SyncopeConstants;
@@ -65,6 +63,7 @@ import org.apache.syncope.core.provisioning.api.ConnectorFactory;
import org.apache.syncope.core.provisioning.api.EntitlementsHolder;
import org.apache.syncope.core.provisioning.api.MappingManager;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
import org.identityconnectors.framework.common.objects.Uid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -92,6 +91,10 @@ public class AuthDataAccessor {
protected static final Set<SyncopeGrantedAuthority> ANONYMOUS_AUTHORITIES =
Collections.singleton(new SyncopeGrantedAuthority(StandardEntitlement.ANONYMOUS));
+ protected static final String[] GROUP_OWNER_ENTITLEMENTS = new String[] {
+ StandardEntitlement.GROUP_READ, StandardEntitlement.GROUP_UPDATE, StandardEntitlement.GROUP_DELETE
+ };
+
@Resource(name = "adminUser")
protected String adminUser;
@@ -282,39 +285,35 @@ public class AuthDataAccessor {
if (user.isMustChangePassword()) {
authorities.add(new SyncopeGrantedAuthority(StandardEntitlement.MUST_CHANGE_PASSWORD));
} else {
- final Map<String, Set<String>> entForRealms = new HashMap<>();
-
- // Give entitlements as assigned by roles (with realms, where applicable) - assigned either
- // statically and dynamically
- for (final Role role : userDAO.findAllRoles(user)) {
- IterableUtils.forEach(role.getEntitlements(), new Closure<String>() {
-
- @Override
- public void execute(final String entitlement) {
- Set<String> realms = entForRealms.get(entitlement);
- if (realms == null) {
- realms = new HashSet<>();
- entForRealms.put(entitlement, realms);
- }
+ Map<String, Set<String>> entForRealms = new HashMap<>();
+
+ // Give entitlements as assigned by roles (with static or dynamic realms, where applicable) - assigned
+ // either statically and dynamically
+ for (Role role : userDAO.findAllRoles(user)) {
+ for (String entitlement : role.getEntitlements()) {
+ Set<String> realms = entForRealms.get(entitlement);
+ if (realms == null) {
+ realms = new HashSet<>();
+ entForRealms.put(entitlement, realms);
+ }
+
+ CollectionUtils.collect(role.getRealms(), new Transformer<Realm, String>() {
- CollectionUtils.collect(role.getRealms(), new Transformer<Realm, String>() {
+ @Override
+ public String transform(final Realm realm) {
+ return realm.getFullPath();
+ }
+ }, realms);
- @Override
- public String transform(final Realm realm) {
- return realm.getFullPath();
- }
- }, realms);
+ if (!entitlement.endsWith("_CREATE") && !entitlement.endsWith("_DELETE")) {
+ CollectionUtils.collect(role.getDynRealms(), EntityUtils.keyTransformer(), realms);
}
- });
+ }
}
// Give group entitlements for owned groups
for (Group group : groupDAO.findOwnedByUser(user.getKey())) {
- for (String entitlement : Arrays.asList(
- StandardEntitlement.GROUP_READ,
- StandardEntitlement.GROUP_UPDATE,
- StandardEntitlement.GROUP_DELETE)) {
-
+ for (String entitlement : GROUP_OWNER_ENTITLEMENTS) {
Set<String> realms = entForRealms.get(entitlement);
if (realms == null) {
realms = new HashSet<>();
@@ -376,7 +375,7 @@ public class AuthDataAccessor {
+ " for JWT " + authentication.getClaims().getTokenId());
}
- if (user.isSuspended() != null && user.isSuspended()) {
+ if (BooleanUtils.isTrue(user.isSuspended())) {
throw new DisabledException("User " + user.getUsername() + " is suspended");
}
@@ -385,13 +384,9 @@ public class AuthDataAccessor {
throw new DisabledException("User " + user.getUsername() + " not allowed to authenticate");
}
- if (user.isMustChangePassword()) {
+ if (BooleanUtils.isTrue(user.isMustChangePassword())) {
authorities = Collections.singleton(
new SyncopeGrantedAuthority(StandardEntitlement.MUST_CHANGE_PASSWORD));
- } else if (accessToken.getAuthorities() == null) {
- LOG.debug("No authorities found in JWT, calculating...");
-
- authorities = getUserAuthorities(user);
} else {
LOG.debug("Authorities found in JWT, fetching...");
@@ -400,8 +395,8 @@ public class AuthDataAccessor {
ENCRYPTOR.decode(new String(accessToken.getAuthorities()), CipherAlgorithm.AES),
new TypeReference<Set<SyncopeGrantedAuthority>>() {
});
- } catch (Exception e) {
- LOG.error("Could not read stored authorities", e);
+ } catch (Throwable t) {
+ LOG.error("Could not read stored authorities", t);
authorities = Collections.emptySet();
}
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
----------------------------------------------------------------------
diff --git a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
index 47bcf9d..d9ce84f 100644
--- a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
+++ b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
@@ -103,7 +103,13 @@ public class ElasticsearchUtils {
? userDAO.findAllResourceKeys(any.getKey())
: any instanceof AnyObject
? anyObjectDAO.findAllResourceKeys(any.getKey())
- : any.getResourceKeys());
+ : any.getResourceKeys()).
+ field("dynRealms",
+ any instanceof User
+ ? userDAO.findDynRealms(any.getKey())
+ : any instanceof AnyObject
+ ? anyObjectDAO.findDynRealms(any.getKey())
+ : groupDAO.findDynRealms(any.getKey()));
if (any instanceof AnyObject) {
AnyObject anyObject = ((AnyObject) any);
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
----------------------------------------------------------------------
diff --git a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
index 0318bc5..82b7c6f 100644
--- a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
+++ b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
@@ -18,9 +18,12 @@
*/
package org.apache.syncope.core.persistence.jpa.dao;
+import static org.apache.syncope.core.persistence.jpa.dao.AbstractDAO.LOG;
+
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections4.CollectionUtils;
@@ -34,6 +37,7 @@ import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
import org.apache.syncope.core.persistence.api.dao.search.AnyTypeCond;
import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
+import org.apache.syncope.core.persistence.api.dao.search.DynRealmCond;
import org.apache.syncope.core.persistence.api.dao.search.MemberCond;
import org.apache.syncope.core.persistence.api.dao.search.MembershipCond;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
@@ -44,6 +48,7 @@ import org.apache.syncope.core.persistence.api.dao.search.RoleCond;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.DynRealm;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.persistence.api.entity.Realm;
@@ -75,21 +80,37 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
@Autowired
private ElasticsearchUtils elasticsearchUtils;
- private DisMaxQueryBuilder adminRealmsFilter(final Set<String> adminRealms) {
+ private Pair<DisMaxQueryBuilder, Set<String>> adminRealmsFilter(final Set<String> adminRealms) {
DisMaxQueryBuilder builder = QueryBuilders.disMaxQuery();
+ Set<String> dynRealmKeys = new HashSet<>();
for (String realmPath : RealmUtils.normalize(adminRealms)) {
- Realm realm = realmDAO.findByFullPath(realmPath);
- if (realm == null) {
- LOG.warn("Ignoring invalid realm {}", realmPath);
+ if (realmPath.startsWith("/")) {
+ Realm realm = realmDAO.findByFullPath(realmPath);
+ if (realm == null) {
+ LOG.warn("Ignoring invalid realm {}", realmPath);
+ } else {
+ for (Realm descendant : realmDAO.findDescendants(realm)) {
+ builder.add(QueryBuilders.termQuery("realm", descendant.getFullPath()));
+ }
+ }
} else {
- for (Realm descendant : realmDAO.findDescendants(realm)) {
- builder.add(QueryBuilders.termQuery("realm", descendant.getFullPath()));
+ DynRealm dynRealm = dynRealmDAO.find(realmPath);
+ if (dynRealm == null) {
+ LOG.warn("Ignoring invalid dynamic realm {}", realmPath);
+ } else {
+ dynRealmKeys.add(dynRealm.getKey());
+ builder.add(QueryBuilders.termQuery("dynRealm", dynRealm.getKey()));
}
}
}
+ if (!dynRealmKeys.isEmpty()) {
+ for (Realm descendant : realmDAO.findAll()) {
+ builder.add(QueryBuilders.termQuery("realm", descendant.getFullPath()));
+ }
+ }
- return builder;
+ return Pair.of(builder, dynRealmKeys);
}
private SearchRequestBuilder searchRequestBuilder(
@@ -97,14 +118,16 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
final SearchCond cond,
final AnyTypeKind kind) {
+ Pair<DisMaxQueryBuilder, Set<String>> filter = adminRealmsFilter(adminRealms);
+
return client.prepareSearch(AuthContextUtils.getDomain().toLowerCase()).
setTypes(kind.name()).
setSearchType(SearchType.QUERY_THEN_FETCH).
setQuery(SyncopeConstants.FULL_ADMIN_REALMS.equals(adminRealms)
? getQueryBuilder(cond, kind)
: QueryBuilders.boolQuery().
- must(adminRealmsFilter(adminRealms)).
- must(getQueryBuilder(cond, kind)));
+ must(filter.getLeft()).
+ must(getQueryBuilder(buildEffectiveCond(cond, filter.getRight()), kind)));
}
@Override
@@ -196,6 +219,8 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
builder = getQueryBuilder(cond.getAssignableCond());
} else if (cond.getRoleCond() != null && AnyTypeKind.USER == kind) {
builder = getQueryBuilder(cond.getRoleCond());
+ } else if (cond.getDynRealmCond() != null) {
+ builder = getQueryBuilder(cond.getDynRealmCond());
} else if (cond.getMemberCond() != null && AnyTypeKind.GROUP == kind) {
builder = getQueryBuilder(cond.getMemberCond());
} else if (cond.getResourceCond() != null) {
@@ -286,7 +311,11 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
}
private QueryBuilder getQueryBuilder(final RoleCond cond) {
- return QueryBuilders.termQuery("roles", cond.getRoleKey());
+ return QueryBuilders.termQuery("roles", cond.getRole());
+ }
+
+ private QueryBuilder getQueryBuilder(final DynRealmCond cond) {
+ return QueryBuilders.termQuery("dynRealms", cond.getDynRealm());
}
private QueryBuilder getQueryBuilder(final MemberCond cond) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index 1ef0d32..f22a045 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -66,6 +66,7 @@ import org.apache.syncope.common.rest.api.service.CamelRouteService;
import org.apache.syncope.common.rest.api.service.ConfigurationService;
import org.apache.syncope.common.rest.api.service.ConnectorService;
import org.apache.syncope.common.rest.api.service.DomainService;
+import org.apache.syncope.common.rest.api.service.DynRealmService;
import org.apache.syncope.common.rest.api.service.LoggerService;
import org.apache.syncope.common.rest.api.service.NotificationService;
import org.apache.syncope.common.rest.api.service.PolicyService;
@@ -182,6 +183,8 @@ public abstract class AbstractITCase {
protected static RoleService roleService;
+ protected static DynRealmService dynRealmService;
+
protected static UserService userService;
protected static UserSelfService userSelfService;
@@ -262,6 +265,7 @@ public abstract class AbstractITCase {
realmService = adminClient.getService(RealmService.class);
anyObjectService = adminClient.getService(AnyObjectService.class);
roleService = adminClient.getService(RoleService.class);
+ dynRealmService = adminClient.getService(DynRealmService.class);
userService = adminClient.getService(UserService.class);
userSelfService = adminClient.getService(UserSelfService.class);
userWorkflowService = adminClient.getService(UserWorkflowService.class);
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..e773716
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.fit.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.patch.AttrPatch;
+import org.apache.syncope.common.lib.patch.GroupPatch;
+import org.apache.syncope.common.lib.patch.StringPatchItem;
+import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.to.DynRealmTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.PagedResult;
+import org.apache.syncope.common.lib.to.ProvisioningResult;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.syncope.common.rest.api.beans.AnyQuery;
+import org.apache.syncope.common.rest.api.service.DynRealmService;
+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.junit.Test;
+
+public class DynRealmITCase extends AbstractITCase {
+
+ @Test
+ public void misc() {
+ DynRealmTO dynRealm = null;
+ try {
+ dynRealm = new DynRealmTO();
+ dynRealm.setKey("/name" + getUUIDString());
+ dynRealm.setCond("cool==true");
+
+ // invalid key (starts with /)
+ try {
+ dynRealmService.create(dynRealm);
+ fail();
+ } catch (SyncopeClientException e) {
+ assertEquals(ClientExceptionType.InvalidDynRealm, e.getType());
+ }
+ dynRealm.setKey("name" + getUUIDString());
+
+ Response response = dynRealmService.create(dynRealm);
+ dynRealm = getObject(response.getLocation(), DynRealmService.class, DynRealmTO.class);
+ assertNotNull(dynRealm);
+
+ PagedResult<UserTO> matching = userService.search(new AnyQuery.Builder().fiql("cool==true").build());
+ assertNotNull(matching);
+ assertNotEquals(0, matching.getSize());
+
+ UserTO user = matching.getResult().get(0);
+
+ assertTrue(user.getDynRealms().contains(dynRealm.getKey()));
+ } finally {
+ if (dynRealm != null) {
+ dynRealmService.delete(dynRealm.getKey());
+ }
+ }
+ }
+
+ @Test
+ public void delegatedAdmin() {
+ DynRealmTO dynRealm = null;
+ RoleTO role = null;
+ try {
+ // 1. create dynamic realm for all users and groups having resource-ldap assigned
+ dynRealm = new DynRealmTO();
+ dynRealm.setKey("LDAPLovers" + getUUIDString());
+ dynRealm.setCond("$resources==resource-ldap");
+
+ Response response = dynRealmService.create(dynRealm);
+ dynRealm = getObject(response.getLocation(), DynRealmService.class, DynRealmTO.class);
+ assertNotNull(dynRealm);
+
+ // 2. create role for such dynamic realm
+ role = new RoleTO();
+ role.setKey("Administer LDAP" + getUUIDString());
+ role.getEntitlements().add(StandardEntitlement.USER_SEARCH);
+ role.getEntitlements().add(StandardEntitlement.USER_READ);
+ role.getEntitlements().add(StandardEntitlement.USER_UPDATE);
+ role.getEntitlements().add(StandardEntitlement.GROUP_READ);
+ role.getEntitlements().add(StandardEntitlement.GROUP_UPDATE);
+ role.getDynRealms().add(dynRealm.getKey());
+
+ role = createRole(role);
+ assertNotNull(role);
+
+ // 3. assign the new role to vivaldi
+ UserPatch userPatch = new UserPatch();
+ userPatch.setKey("b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee");
+ userPatch.getRoles().add(new StringPatchItem.Builder().value(role.getKey()).build());
+ UserTO vivaldi = updateUser(userPatch).getEntity();
+ assertNotNull(vivaldi);
+ assertTrue(vivaldi.getRoles().contains(role.getKey()));
+
+ // 4. create new user and group, assign resource-ldap
+ UserTO user = UserITCase.getUniqueSampleTO("dynRealmUser@apache.org");
+ user.setRealm("/even/two");
+ user.getResources().clear();
+ user.getResources().add(RESOURCE_NAME_LDAP);
+ user = createUser(user).getEntity();
+ assertNotNull(user);
+ final String userKey = user.getKey();
+
+ GroupTO group = GroupITCase.getSampleTO("dynRealmGroup");
+ group.setRealm("/odd");
+ group.getResources().clear();
+ group.getResources().add(RESOURCE_NAME_LDAP);
+ group = createGroup(group).getEntity();
+ assertNotNull(group);
+ final String groupKey = group.getKey();
+
+ // 5. verify that the new user and group are found when searching by dynamic realm
+ PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm("/").fiql(
+ SyncopeClient.getUserSearchConditionBuilder().inDynRealms(dynRealm.getKey()).query()).build());
+ assertTrue(IterableUtils.matchesAny(matchingUsers.getResult(), new Predicate<UserTO>() {
+
+ @Override
+ public boolean evaluate(final UserTO object) {
+ return object.getKey().equals(userKey);
+ }
+ }));
+ PagedResult<GroupTO> matchingGroups = groupService.search(new AnyQuery.Builder().realm("/").fiql(
+ SyncopeClient.getGroupSearchConditionBuilder().inDynRealms(dynRealm.getKey()).query()).build());
+ assertTrue(IterableUtils.matchesAny(matchingGroups.getResult(), new Predicate<GroupTO>() {
+
+ @Override
+ public boolean evaluate(final GroupTO object) {
+ return object.getKey().equals(groupKey);
+ }
+ }));
+
+ // 6. perpare to act as vivaldi
+ SyncopeClient vivaldiClient = clientFactory.create("vivaldi", ADMIN_PWD);
+ UserService vivaldiUserService = vivaldiClient.getService(UserService.class);
+ GroupService vivaldiGroupService = vivaldiClient.getService(GroupService.class);
+
+ // 7. verify delegated administration
+ // USER_READ
+ assertNotNull(vivaldiUserService.read(userKey));
+
+ // GROUP_READ
+ assertNotNull(vivaldiGroupService.read(groupKey));
+
+ // USER_SEARCH
+ matchingUsers = vivaldiUserService.search(new AnyQuery.Builder().realm("/").build());
+ assertTrue(IterableUtils.matchesAny(matchingUsers.getResult(), new Predicate<UserTO>() {
+
+ @Override
+ public boolean evaluate(final UserTO object) {
+ return object.getKey().equals(userKey);
+ }
+ }));
+
+ // USER_UPDATE
+ userPatch = new UserPatch();
+ userPatch.setKey(userKey);
+ userPatch.getResources().add(new StringPatchItem.Builder().value(RESOURCE_NAME_NOPROPAGATION).build());
+ user = vivaldiUserService.update(userPatch).
+ readEntity(new GenericType<ProvisioningResult<UserTO>>() {
+ }).getEntity();
+ assertNotNull(user);
+ assertTrue(user.getResources().contains(RESOURCE_NAME_NOPROPAGATION));
+
+ // GROUP_UPDATE
+ GroupPatch groupPatch = new GroupPatch();
+ groupPatch.setKey(groupKey);
+ groupPatch.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO("icon", "modified")).build());
+ group = vivaldiGroupService.update(groupPatch).
+ readEntity(new GenericType<ProvisioningResult<GroupTO>>() {
+ }).getEntity();
+ assertNotNull(group);
+ assertEquals("modified", group.getPlainAttrMap().get("icon").getValues().get(0));
+ } finally {
+ if (role != null) {
+ roleService.delete(role.getKey());
+ }
+ if (dynRealm != null) {
+ dynRealmService.delete(dynRealm.getKey());
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/a1bb6723/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ExceptionMapperITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ExceptionMapperITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ExceptionMapperITCase.java
index 8a8e6a2..9db9031 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ExceptionMapperITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ExceptionMapperITCase.java
@@ -125,7 +125,7 @@ public class ExceptionMapperITCase extends AbstractITCase {
fail();
} catch (Exception e) {
String message = ERROR_MESSAGES.getProperty("errMessage.UniqueConstraintViolation");
- assertEquals(e.getMessage(), "DataIntegrityViolation [" + message + "]");
+ assertEquals("EntityExists [" + message + "]", e.getMessage());
}
}