You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2015/10/30 12:35:03 UTC
[24/50] [abbrv] syncope git commit: [SYNCOPE-717] Merge from 1_2_X
[SYNCOPE-717] Merge from 1_2_X
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/e486aaf3
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/e486aaf3
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/e486aaf3
Branch: refs/heads/SYNCOPE-156
Commit: e486aaf3a1ac1b5a3281a2c93598cc38cca4073e
Parents: 0211410 5954e2e
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 29 10:37:23 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 29 10:39:43 2015 +0100
----------------------------------------------------------------------
.../syncope/core/misc/utils/FormatUtils.java | 6 +-
.../syncope/fit/core/reference/GroupITCase.java | 59 ++++++++++++++++++++
2 files changed, 64 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/e486aaf3/core/misc/src/main/java/org/apache/syncope/core/misc/utils/FormatUtils.java
----------------------------------------------------------------------
diff --cc core/misc/src/main/java/org/apache/syncope/core/misc/utils/FormatUtils.java
index ec5250a,0000000..131f310
mode 100644,000000..100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/utils/FormatUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/FormatUtils.java
@@@ -1,117 -1,0 +1,121 @@@
+/*
+ * 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.misc.utils;
+
+import java.text.DecimalFormat;
++import java.text.DecimalFormatSymbols;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
++import java.util.Locale;
+import org.apache.commons.lang3.time.DateUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
+
+/**
+ * Utility class for parsing / formatting date and numbers.
+ */
+public final class FormatUtils {
+
+ private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
+
+ @Override
+ protected SimpleDateFormat initialValue() {
+ SimpleDateFormat sdf = new SimpleDateFormat();
+ sdf.applyPattern(SyncopeConstants.DEFAULT_DATE_PATTERN);
+ return sdf;
+ }
+ };
+
+ private static final ThreadLocal<DecimalFormat> DECIMAL_FORMAT = new ThreadLocal<DecimalFormat>() {
+
+ @Override
+ protected DecimalFormat initialValue() {
- return new DecimalFormat();
++ DecimalFormat df = new DecimalFormat();
++ df.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ENGLISH));
++ return df;
+ }
+ };
+
+ public static String format(final Date date) {
+ return format(date, true);
+ }
+
+ public static String format(final Date date, final boolean lenient) {
+ return format(date, lenient, null);
+ }
+
+ public static String format(final Date date, final boolean lenient, final String conversionPattern) {
+ SimpleDateFormat sdf = DATE_FORMAT.get();
+ if (conversionPattern != null) {
+ sdf.applyPattern(conversionPattern);
+ }
+ sdf.setLenient(lenient);
+ return sdf.format(date);
+ }
+
+ public static String format(final long number) {
+ return format(number, null);
+ }
+
+ public static String format(final long number, final String conversionPattern) {
+ DecimalFormat df = DECIMAL_FORMAT.get();
+ if (conversionPattern != null) {
+ df.applyPattern(conversionPattern);
+ }
+ return df.format(number);
+ }
+
+ public static String format(final double number) {
+ return format(number, null);
+ }
+
+ public static String format(final double number, final String conversionPattern) {
+ DecimalFormat df = DECIMAL_FORMAT.get();
+ if (conversionPattern != null) {
+ df.applyPattern(conversionPattern);
+ }
+ return df.format(number);
+ }
+
+ public static Date parseDate(final String source) throws ParseException {
+ return DateUtils.parseDate(source, SyncopeConstants.DATE_PATTERNS);
+ }
+
+ public static Date parseDate(final String source, final String conversionPattern) throws ParseException {
+ SimpleDateFormat sdf = DATE_FORMAT.get();
+ sdf.applyPattern(conversionPattern);
+ sdf.setLenient(false);
+ return sdf.parse(source);
+ }
+
+ public static Number parseNumber(final String source, final String conversionPattern) throws ParseException {
+ DecimalFormat df = DECIMAL_FORMAT.get();
+ df.applyPattern(conversionPattern);
+ return df.parse(source);
+ }
+
+ public static void clear() {
+ DATE_FORMAT.remove();
+ DECIMAL_FORMAT.remove();
+ }
+
+ private FormatUtils() {
+ // private empty constructor
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e486aaf3/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
----------------------------------------------------------------------
diff --cc fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
index db12a2b,0000000..17ba8c8
mode 100644,000000..100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
@@@ -1,806 -1,0 +1,865 @@@
+/*
+ * 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.reference;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessControlException;
+import java.util.List;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.ws.rs.core.Response;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.patch.AssociationPatch;
+import org.apache.syncope.common.lib.patch.AttrPatch;
+import org.apache.syncope.common.lib.patch.DeassociationPatch;
+import org.apache.syncope.common.lib.patch.GroupPatch;
+import org.apache.syncope.common.lib.patch.LongReplacePatchItem;
+import org.apache.syncope.common.lib.patch.StringReplacePatchItem;
+import org.apache.syncope.common.lib.to.AnyTypeClassTO;
+import org.apache.syncope.common.lib.to.AnyTypeTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.ConnInstanceTO;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.PagedResult;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.MappingTO;
+import org.apache.syncope.common.lib.to.ProvisionTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
++import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ConnectorCapability;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.common.lib.types.PatchOperation;
+import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
+import org.apache.syncope.common.lib.types.ResourceAssociationAction;
+import org.apache.syncope.common.lib.types.ResourceDeassociationAction;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.common.rest.api.Preference;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.GroupService;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.JVM)
+public class GroupITCase extends AbstractITCase {
+
+ public static GroupTO getBasicSampleTO(final String name) {
+ GroupTO groupTO = new GroupTO();
+ groupTO.setRealm("/");
+ groupTO.setName(name + getUUIDString());
+ return groupTO;
+ }
+
+ public static GroupTO getSampleTO(final String name) {
+ GroupTO groupTO = getBasicSampleTO(name);
+
+ groupTO.getPlainAttrs().add(attrTO("icon", "anIcon"));
+
+ groupTO.getResources().add(RESOURCE_NAME_LDAP);
+ return groupTO;
+ }
+
+ @Test
+ public void create() {
+ GroupTO groupTO = getSampleTO("lastGroup");
+ groupTO.getVirAttrs().add(attrTO("rvirtualdata", "rvirtualvalue"));
+ groupTO.setGroupOwner(8L);
+
+ groupTO = createGroup(groupTO);
+ assertNotNull(groupTO);
+
+ assertNotNull(groupTO.getVirAttrMap());
+ assertNotNull(groupTO.getVirAttrMap().get("rvirtualdata").getValues());
+ assertFalse(groupTO.getVirAttrMap().get("rvirtualdata").getValues().isEmpty());
+ assertEquals("rvirtualvalue", groupTO.getVirAttrMap().get("rvirtualdata").getValues().get(0));
+
+ assertTrue(groupTO.getResources().contains(RESOURCE_NAME_LDAP));
+
+ ConnObjectTO connObjectTO =
+ resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), groupTO.getKey());
+ assertNotNull(connObjectTO);
+ assertNotNull(connObjectTO.getPlainAttrMap().get("owner"));
+
+ // SYNCOPE-515: remove ownership
+ GroupPatch groupPatch = new GroupPatch();
+ groupPatch.setKey(groupTO.getKey());
+ groupPatch.setGroupOwner(new LongReplacePatchItem());
+
+ assertNull(updateGroup(groupPatch).getGroupOwner());
+ }
+
+ @Test
+ public void delete() {
+ try {
+ groupService.delete(0L);
+ } catch (SyncopeClientException e) {
+ assertEquals(Response.Status.NOT_FOUND, e.getType().getResponseStatus());
+ }
+
+ GroupTO groupTO = new GroupTO();
+ groupTO.setName("toBeDeleted" + getUUIDString());
+ groupTO.setRealm("/even");
+
+ groupTO.getResources().add(RESOURCE_NAME_LDAP);
+
+ groupTO = createGroup(groupTO);
+ assertNotNull(groupTO);
+
+ GroupTO deletedGroup = deleteGroup(groupTO.getKey());
+ assertNotNull(deletedGroup);
+
+ try {
+ groupService.read(deletedGroup.getKey());
+ } catch (SyncopeClientException e) {
+ assertEquals(Response.Status.NOT_FOUND, e.getType().getResponseStatus());
+ }
+ }
+
+ @Test
+ public void list() {
+ PagedResult<GroupTO> groupTOs =
+ groupService.list(SyncopeClient.getAnyListQueryBuilder().realm(SyncopeConstants.ROOT_REALM).build());
+ assertNotNull(groupTOs);
+ assertTrue(groupTOs.getResult().size() >= 8);
+ for (GroupTO groupTO : groupTOs.getResult()) {
+ assertNotNull(groupTO);
+ }
+ }
+
+ @Test
+ public void read() {
+ GroupTO groupTO = groupService.read(1L);
+
+ assertNotNull(groupTO);
+ assertNotNull(groupTO.getPlainAttrs());
+ assertFalse(groupTO.getPlainAttrs().isEmpty());
+ }
+
+ @Test
+ public void selfRead() {
+ UserTO userTO = userService.read(1L);
+ assertNotNull(userTO);
+
+ assertTrue(userTO.getMembershipMap().containsKey(1L));
+ assertFalse(userTO.getMembershipMap().containsKey(3L));
+
+ GroupService groupService2 = clientFactory.create("rossini", ADMIN_PWD).getService(GroupService.class);
+
+ try {
+ groupService2.read(3L);
+ fail();
+ } catch (SyncopeClientException e) {
+ assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
+ }
+
+ List<GroupTO> groups = groupService2.own();
+ assertNotNull(groups);
+ assertTrue(CollectionUtils.exists(groups, new Predicate<GroupTO>() {
+
+ @Override
+ public boolean evaluate(final GroupTO group) {
+ return 1L == group.getKey();
+ }
+ }));
+ }
+
+ @Test
+ public void update() {
+ GroupTO groupTO = getSampleTO("latestGroup" + getUUIDString());
+ groupTO = createGroup(groupTO);
+
+ assertEquals(1, groupTO.getPlainAttrs().size());
+
+ GroupPatch groupPatch = new GroupPatch();
+ groupPatch.setKey(groupTO.getKey());
+ String modName = "finalGroup" + getUUIDString();
+ groupPatch.setName(new StringReplacePatchItem.Builder().value(modName).build());
+ groupPatch.getPlainAttrs().add(attrAddReplacePatch("show", "FALSE"));
+
+ groupTO = updateGroup(groupPatch);
+
+ assertEquals(modName, groupTO.getName());
+ assertEquals(2, groupTO.getPlainAttrs().size());
+ }
+
+ @Test
+ public void updateRemovingDerAttribute() {
+ GroupTO groupTO = getBasicSampleTO("withderived" + getUUIDString());
+ groupTO.getDerAttrs().add(attrTO("rderivedschema", null));
+
+ groupTO = createGroup(groupTO);
+
+ assertNotNull(groupTO);
+ assertEquals(1, groupTO.getDerAttrs().size());
+
+ GroupPatch groupPatch = new GroupPatch();
+ groupPatch.setKey(groupTO.getKey());
+ groupPatch.getDerAttrs().add(new AttrPatch.Builder().operation(PatchOperation.DELETE).
+ attrTO(new AttrTO.Builder().schema("rderivedschema").build()).
+ build());
+
+ groupTO = updateGroup(groupPatch);
+ assertNotNull(groupTO);
+ assertTrue(groupTO.getDerAttrs().isEmpty());
+ }
+
+ @Test
+ public void updateAsGroupOwner() {
+ // 1. read group as admin
+ GroupTO groupTO = groupService.read(6L);
+
+ // issue SYNCOPE-15
+ assertNotNull(groupTO.getCreationDate());
+ assertNotNull(groupTO.getLastChangeDate());
+ assertEquals("admin", groupTO.getCreator());
+ assertEquals("admin", groupTO.getLastModifier());
+
+ // 2. prepare update
+ GroupPatch groupPatch = new GroupPatch();
+ groupPatch.setKey(groupTO.getKey());
+ groupPatch.setName(new StringReplacePatchItem.Builder().value("Director").build());
+
+ // 3. try to update as verdi, not owner of group 6 - fail
+ GroupService groupService2 = clientFactory.create("verdi", ADMIN_PWD).getService(GroupService.class);
+
+ try {
+ groupService2.update(groupPatch);
+ fail();
+ } catch (SyncopeClientException e) {
+ assertEquals(Response.Status.UNAUTHORIZED, e.getType().getResponseStatus());
+ } catch (AccessControlException e) {
+ assertNotNull(e);
+ }
+
+ // 4. update as puccini, owner of group 6 - success
+ GroupService groupService3 = clientFactory.create("puccini", ADMIN_PWD).getService(GroupService.class);
+
+ groupTO = groupService3.update(groupPatch).readEntity(GroupTO.class);
+ assertEquals("Director", groupTO.getName());
+
+ // issue SYNCOPE-15
+ assertNotNull(groupTO.getCreationDate());
+ assertNotNull(groupTO.getLastChangeDate());
+ assertEquals("admin", groupTO.getCreator());
+ assertEquals("puccini", groupTO.getLastModifier());
+ assertTrue(groupTO.getCreationDate().before(groupTO.getLastChangeDate()));
+ }
+
+ @Test
+ public void issue178() {
+ GroupTO groupTO = new GroupTO();
+ String groupName = "torename" + getUUIDString();
+ groupTO.setName(groupName);
+ groupTO.setRealm("/");
+
+ GroupTO actual = createGroup(groupTO);
+
+ assertNotNull(actual);
+ assertEquals(groupName, actual.getName());
+
+ GroupPatch groupPatch = new GroupPatch();
+ groupPatch.setKey(actual.getKey());
+ String renamedGroup = "renamed" + getUUIDString();
+ groupPatch.setName(new StringReplacePatchItem.Builder().value(renamedGroup).build());
+
+ actual = updateGroup(groupPatch);
+ assertNotNull(actual);
+ assertEquals(renamedGroup, actual.getName());
+ }
+
+ @Test
+ public void unlink() {
+ GroupTO actual = createGroup(getSampleTO("unlink"));
+ assertNotNull(actual);
+
+ assertNotNull(resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey()));
+
+ DeassociationPatch deassociationPatch = new DeassociationPatch();
+ deassociationPatch.setKey(actual.getKey());
+ deassociationPatch.setAction(ResourceDeassociationAction.UNLINK);
+ deassociationPatch.getResources().add(RESOURCE_NAME_LDAP);
+
+ assertNotNull(groupService.deassociate(deassociationPatch).readEntity(BulkActionResult.class));
+
+ actual = groupService.read(actual.getKey());
+ assertNotNull(actual);
+ assertTrue(actual.getResources().isEmpty());
+
+ assertNotNull(resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey()));
+ }
+
+ @Test
+ public void link() {
+ GroupTO groupTO = getSampleTO("link");
+ groupTO.getResources().clear();
+
+ GroupTO actual = createGroup(groupTO);
+ assertNotNull(actual);
+
+ try {
+ resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey());
+ fail();
+ } catch (Exception e) {
+ assertNotNull(e);
+ }
+
+ AssociationPatch associationPatch = new AssociationPatch();
+ associationPatch.setKey(actual.getKey());
+ associationPatch.setAction(ResourceAssociationAction.LINK);
+ associationPatch.getResources().add(RESOURCE_NAME_LDAP);
+
+ assertNotNull(groupService.associate(associationPatch).readEntity(BulkActionResult.class));
+
+ actual = groupService.read(actual.getKey());
+ assertFalse(actual.getResources().isEmpty());
+
+ try {
+ resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey());
+ fail();
+ } catch (Exception e) {
+ assertNotNull(e);
+ }
+ }
+
+ @Test
+ public void unassign() {
+ GroupTO actual = createGroup(getSampleTO("unassign"));
+ assertNotNull(actual);
+
+ assertNotNull(resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey()));
+
+ DeassociationPatch deassociationPatch = new DeassociationPatch();
+ deassociationPatch.setKey(actual.getKey());
+ deassociationPatch.setAction(ResourceDeassociationAction.UNASSIGN);
+ deassociationPatch.getResources().add(RESOURCE_NAME_LDAP);
+
+ assertNotNull(groupService.deassociate(deassociationPatch).readEntity(BulkActionResult.class));
+
+ actual = groupService.read(actual.getKey());
+ assertNotNull(actual);
+ assertTrue(actual.getResources().isEmpty());
+
+ try {
+ resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey());
+ fail();
+ } catch (Exception e) {
+ assertNotNull(e);
+ }
+ }
+
+ @Test
+ public void assign() {
+ GroupTO groupTO = getSampleTO("assign");
+ groupTO.getResources().clear();
+
+ GroupTO actual = createGroup(groupTO);
+ assertNotNull(actual);
+
+ try {
+ resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey());
+ fail();
+ } catch (Exception e) {
+ assertNotNull(e);
+ }
+
+ AssociationPatch associationPatch = new AssociationPatch();
+ associationPatch.setKey(actual.getKey());
+ associationPatch.setAction(ResourceAssociationAction.ASSIGN);
+ associationPatch.getResources().add(RESOURCE_NAME_LDAP);
+
+ assertNotNull(groupService.associate(associationPatch).readEntity(BulkActionResult.class));
+
+ actual = groupService.read(actual.getKey());
+ assertFalse(actual.getResources().isEmpty());
+ assertNotNull(resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey()));
+ }
+
+ @Test
+ public void deprovision() {
+ GroupTO actual = createGroup(getSampleTO("deprovision"));
+ assertNotNull(actual);
+ assertNotNull(actual.getKey());
+
+ assertNotNull(resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey()));
+
+ DeassociationPatch deassociationPatch = new DeassociationPatch();
+ deassociationPatch.setKey(actual.getKey());
+ deassociationPatch.setAction(ResourceDeassociationAction.DEPROVISION);
+ deassociationPatch.getResources().add(RESOURCE_NAME_LDAP);
+
+ assertNotNull(groupService.deassociate(deassociationPatch).readEntity(BulkActionResult.class));
+
+ actual = groupService.read(actual.getKey());
+ assertNotNull(actual);
+ assertFalse(actual.getResources().isEmpty());
+
+ try {
+ resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey());
+ fail();
+ } catch (Exception e) {
+ assertNotNull(e);
+ }
+ }
+
+ @Test
+ public void provision() {
+ GroupTO groupTO = getSampleTO("assign" + getUUIDString());
+ groupTO.getResources().clear();
+
+ GroupTO actual = createGroup(groupTO);
+ assertNotNull(actual);
+
+ try {
+ resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey());
+ fail();
+ } catch (Exception e) {
+ assertNotNull(e);
+ }
+
+ AssociationPatch associationPatch = new AssociationPatch();
+ associationPatch.setKey(actual.getKey());
+ associationPatch.setAction(ResourceAssociationAction.PROVISION);
+ associationPatch.getResources().add(RESOURCE_NAME_LDAP);
+
+ assertNotNull(groupService.associate(associationPatch).readEntity(BulkActionResult.class));
+
+ actual = groupService.read(actual.getKey());
+ assertTrue(actual.getResources().isEmpty());
+
+ assertNotNull(resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey()));
+ }
+
+ @Test
+ public void deprovisionUnlinked() {
+ GroupTO groupTO = getSampleTO("assign" + getUUIDString());
+ groupTO.getResources().clear();
+
+ GroupTO actual = createGroup(groupTO);
+ assertNotNull(actual);
+
+ try {
+ resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey());
+ fail();
+ } catch (Exception e) {
+ assertNotNull(e);
+ }
+
+ AssociationPatch associationPatch = new AssociationPatch();
+ associationPatch.setKey(actual.getKey());
+ associationPatch.setAction(ResourceAssociationAction.PROVISION);
+ associationPatch.getResources().add(RESOURCE_NAME_LDAP);
+
+ assertNotNull(groupService.associate(associationPatch).readEntity(BulkActionResult.class));
+
+ actual = groupService.read(actual.getKey());
+ assertTrue(actual.getResources().isEmpty());
+
+ assertNotNull(resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey()));
+
+ DeassociationPatch deassociationPatch = new DeassociationPatch();
+ deassociationPatch.setKey(actual.getKey());
+ deassociationPatch.setAction(ResourceDeassociationAction.DEPROVISION);
+ deassociationPatch.getResources().add(RESOURCE_NAME_LDAP);
+
+ assertNotNull(groupService.deassociate(deassociationPatch).readEntity(BulkActionResult.class));
+
+ actual = groupService.read(actual.getKey());
+ assertNotNull(actual);
+ assertTrue(actual.getResources().isEmpty());
+
+ try {
+ resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), actual.getKey());
+ fail();
+ } catch (Exception e) {
+ assertNotNull(e);
+ }
+ }
+
+ @Test
+ public void createWithMandatorySchema() {
+ // 1. create a mandatory schema
+ PlainSchemaTO badge = new PlainSchemaTO();
+ badge.setKey("badge" + getUUIDString());
+ badge.setMandatoryCondition("true");
+ schemaService.create(SchemaType.PLAIN, badge);
+
+ // 2. create a group *without* an attribute for that schema: it works
+ GroupTO groupTO = getSampleTO("lastGroup");
+ assertFalse(groupTO.getPlainAttrMap().containsKey(badge.getKey()));
+ groupTO = createGroup(groupTO);
+ assertNotNull(groupTO);
+ assertFalse(groupTO.getPlainAttrMap().containsKey(badge.getKey()));
+
+ // 3. add the new mandatory schema to the default group type
+ AnyTypeTO type = anyTypeService.read(AnyTypeKind.GROUP.name());
+ String typeClassName = type.getClasses().get(0);
+ AnyTypeClassTO typeClass = anyTypeClassService.read(typeClassName);
+ typeClass.getPlainSchemas().add(badge.getKey());
+ anyTypeClassService.update(typeClass);
+ typeClass = anyTypeClassService.read(typeClassName);
+ assertTrue(typeClass.getPlainSchemas().contains(badge.getKey()));
+
+ try {
+ // 4. update group: failure since no values are provided and it is mandatory
+ GroupPatch groupPatch = new GroupPatch();
+ groupPatch.setKey(groupTO.getKey());
+
+ try {
+ updateGroup(groupPatch);
+ fail();
+ } catch (SyncopeClientException e) {
+ assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType());
+ }
+
+ // 5. also add an actual attribute for badge - it will work
+ groupPatch.getPlainAttrs().add(attrAddReplacePatch(badge.getKey(), "xxxxxxxxxx"));
+
+ groupTO = updateGroup(groupPatch);
+ assertNotNull(groupTO);
+ assertTrue(groupTO.getPlainAttrMap().containsKey(badge.getKey()));
+ } finally {
+ // restore the original group class
+ typeClass.getPlainSchemas().remove(badge.getKey());
+ anyTypeClassService.update(typeClass);
+ typeClass = anyTypeClassService.read(typeClassName);
+ assertFalse(typeClass.getPlainSchemas().contains(badge.getKey()));
+ }
+ }
+
+ @Test
+ public void anonymous() {
+ GroupService unauthenticated = clientFactory.create().getService(GroupService.class);
+ try {
+ unauthenticated.
+ list(SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).build());
+ fail();
+ } catch (AccessControlException e) {
+ assertNotNull(e);
+ }
+
+ GroupService anonymous = clientFactory.create(ANONYMOUS_UNAME, ANONYMOUS_KEY).getService(GroupService.class);
+ assertFalse(anonymous.list(SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
+ build()).
+ getResult().isEmpty());
+ }
+
+ @Test
+ public void noContent() throws IOException {
+ SyncopeClient noContentclient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
+ GroupService noContentService = noContentclient.prefer(GroupService.class, Preference.RETURN_NO_CONTENT);
+
+ GroupTO group = getSampleTO("noContent");
+
+ Response response = noContentService.create(group);
+ assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
+ assertEquals(Preference.RETURN_NO_CONTENT.toString(), response.getHeaderString(RESTHeaders.PREFERENCE_APPLIED));
+ assertEquals(StringUtils.EMPTY, IOUtils.toString((InputStream) response.getEntity()));
+
+ group = getObject(response.getLocation(), GroupService.class, GroupTO.class);
+ assertNotNull(group);
+
+ GroupPatch groupPatch = new GroupPatch();
+ groupPatch.setKey(group.getKey());
+ groupPatch.getPlainAttrs().add(attrAddReplacePatch("badge", "xxxxxxxxxx"));
+
+ response = noContentService.update(groupPatch);
+ assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
+ assertEquals(Preference.RETURN_NO_CONTENT.toString(), response.getHeaderString(RESTHeaders.PREFERENCE_APPLIED));
+ assertEquals(StringUtils.EMPTY, IOUtils.toString((InputStream) response.getEntity()));
+
+ response = noContentService.delete(group.getKey());
+ assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
+ assertEquals(Preference.RETURN_NO_CONTENT.toString(), response.getHeaderString(RESTHeaders.PREFERENCE_APPLIED));
+ assertEquals(StringUtils.EMPTY, IOUtils.toString((InputStream) response.getEntity()));
+ }
+
+ @Test
+ public void dynMembership() {
+ assertTrue(userService.read(4L).getDynGroups().isEmpty());
+
+ GroupTO group = getBasicSampleTO("dynMembership");
+ group.setUDynMembershipCond("cool==true");
+ group = createGroup(group);
+ assertNotNull(group);
+
+ assertTrue(userService.read(4L).getDynGroups().contains(group.getKey()));
+
+ GroupPatch mod = new GroupPatch();
+ mod.setKey(group.getKey());
+ mod.setUDynMembershipCond(new StringReplacePatchItem.Builder().value("cool==false").build());
+ groupService.update(mod);
+
+ assertTrue(userService.read(4L).getDynGroups().isEmpty());
+ }
+
+ @Test
+ public void capabilitiesOverride() {
+ // resource with no capability override
+ ResourceTO ldap = resourceService.read(RESOURCE_NAME_LDAP);
+ assertNotNull(ldap);
+ assertFalse(ldap.isOverrideCapabilities());
+ assertTrue(ldap.getCapabilitiesOverride().isEmpty());
+
+ // connector with all required for create and update
+ ConnInstanceTO conn = connectorService.read(ldap.getConnector(), null);
+ assertNotNull(conn);
+ assertTrue(conn.getCapabilities().contains(ConnectorCapability.CREATE));
+ assertTrue(conn.getCapabilities().contains(ConnectorCapability.UPDATE));
+
+ try {
+ // 1. create succeeds
+ GroupTO group = getSampleTO("syncope714");
+ group.getPlainAttrs().add(attrTO("title", "first"));
+ group.getResources().add(RESOURCE_NAME_LDAP);
+
+ group = createGroup(group);
+ assertNotNull(group);
+ assertEquals(1, group.getPropagationStatusTOs().size());
+ assertEquals(RESOURCE_NAME_LDAP, group.getPropagationStatusTOs().get(0).getResource());
+ assertEquals(PropagationTaskExecStatus.SUCCESS, group.getPropagationStatusTOs().get(0).getStatus());
+
+ // 2. update succeeds
+ GroupPatch patch = new GroupPatch();
+ patch.setKey(group.getKey());
+ patch.getPlainAttrs().add(new AttrPatch.Builder().
+ operation(PatchOperation.ADD_REPLACE).attrTO(attrTO("title", "second")).build());
+
+ group = groupService.update(patch).readEntity(GroupTO.class);
+ assertNotNull(group);
+ assertEquals(1, group.getPropagationStatusTOs().size());
+ assertEquals(RESOURCE_NAME_LDAP, group.getPropagationStatusTOs().get(0).getResource());
+ assertEquals(PropagationTaskExecStatus.SUCCESS, group.getPropagationStatusTOs().get(0).getStatus());
+
+ // 3. set capability override with only search allowed, but not enable
+ ldap.getCapabilitiesOverride().add(ConnectorCapability.SEARCH);
+ resourceService.update(ldap);
+ ldap = resourceService.read(RESOURCE_NAME_LDAP);
+ assertNotNull(ldap);
+ assertFalse(ldap.isOverrideCapabilities());
+ assertEquals(1, ldap.getCapabilitiesOverride().size());
+ assertTrue(ldap.getCapabilitiesOverride().contains(ConnectorCapability.SEARCH));
+
+ // 4. update succeeds again
+ patch = new GroupPatch();
+ patch.setKey(group.getKey());
+ patch.getPlainAttrs().add(new AttrPatch.Builder().
+ operation(PatchOperation.ADD_REPLACE).attrTO(attrTO("title", "third")).build());
+
+ group = groupService.update(patch).readEntity(GroupTO.class);
+ assertNotNull(group);
+ assertEquals(1, group.getPropagationStatusTOs().size());
+ assertEquals(RESOURCE_NAME_LDAP, group.getPropagationStatusTOs().get(0).getResource());
+ assertEquals(PropagationTaskExecStatus.SUCCESS, group.getPropagationStatusTOs().get(0).getStatus());
+
+ // 5. enable capability override
+ ldap.setOverrideCapabilities(true);
+ resourceService.update(ldap);
+ ldap = resourceService.read(RESOURCE_NAME_LDAP);
+ assertNotNull(ldap);
+ assertTrue(ldap.isOverrideCapabilities());
+ assertEquals(1, ldap.getCapabilitiesOverride().size());
+ assertTrue(ldap.getCapabilitiesOverride().contains(ConnectorCapability.SEARCH));
+
+ // 6. update now fails
+ patch = new GroupPatch();
+ patch.setKey(group.getKey());
+ patch.getPlainAttrs().add(new AttrPatch.Builder().
+ operation(PatchOperation.ADD_REPLACE).attrTO(attrTO("title", "fourth")).build());
+
+ group = groupService.update(patch).readEntity(GroupTO.class);
+ assertNotNull(group);
+ assertEquals(1, group.getPropagationStatusTOs().size());
+ assertEquals(RESOURCE_NAME_LDAP, group.getPropagationStatusTOs().get(0).getResource());
+ assertEquals(PropagationTaskExecStatus.NOT_ATTEMPTED, group.getPropagationStatusTOs().get(0).getStatus());
+ } finally {
+ ldap.getCapabilitiesOverride().clear();
+ ldap.setOverrideCapabilities(false);
+ resourceService.update(ldap);
+ }
+ }
+
+ @Test
+ public void issueSYNCOPE632() {
+ GroupTO groupTO = null;
+ try {
+ // 1. create new LDAP resource having ConnObjectKey mapped to a derived attribute
+ ResourceTO newLDAP = resourceService.read(RESOURCE_NAME_LDAP);
+ newLDAP.setKey("new-ldap");
+ newLDAP.setPropagationPrimary(true);
+
+ for (ProvisionTO provision : newLDAP.getProvisions()) {
+ provision.getVirSchemas().clear();
+ }
+
+ MappingTO mapping = newLDAP.getProvision(AnyTypeKind.GROUP.name()).getMapping();
+
+ MappingItemTO connObjectKey = mapping.getConnObjectKeyItem();
+ connObjectKey.setIntMappingType(IntMappingType.GroupDerivedSchema);
+ connObjectKey.setIntAttrName("displayProperty");
+ mapping.setConnObjectKeyItem(connObjectKey);
+ mapping.setConnObjectLink("'cn=' + displayProperty + ',ou=groups,o=isp'");
+
+ MappingItemTO description = new MappingItemTO();
+ description.setIntMappingType(IntMappingType.GroupKey);
+ description.setExtAttrName("description");
+ description.setPurpose(MappingPurpose.BOTH);
+ mapping.add(description);
+
+ newLDAP = createResource(newLDAP);
+ assertNotNull(newLDAP);
+
+ // 2. create a group and give the resource created above
+ groupTO = getSampleTO("lastGroup" + getUUIDString());
+ groupTO.getPlainAttrs().add(attrTO("icon", "anIcon"));
+ groupTO.getPlainAttrs().add(attrTO("show", "true"));
+ groupTO.getDerAttrs().add(attrTO("displayProperty", null));
+ groupTO.getResources().clear();
+ groupTO.getResources().add("new-ldap");
+
+ groupTO = createGroup(groupTO);
+ assertNotNull(groupTO);
+
+ // 3. update the group
+ GroupPatch groupPatch = new GroupPatch();
+ groupPatch.setKey(groupTO.getKey());
+ groupPatch.getPlainAttrs().add(attrAddReplacePatch("icon", "anotherIcon"));
+
+ groupTO = updateGroup(groupPatch);
+ assertNotNull(groupTO);
+
+ // 4. check that a single group exists in LDAP for the group created and updated above
+ int entries = 0;
+ DirContext ctx = null;
+ try {
+ ctx = getLdapResourceDirContext(null, null);
+
+ SearchControls ctls = new SearchControls();
+ ctls.setReturningAttributes(new String[] { "*", "+" });
+ ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+ NamingEnumeration<SearchResult> result =
+ ctx.search("ou=groups,o=isp", "(description=" + groupTO.getKey() + ")", ctls);
+ while (result.hasMore()) {
+ result.next();
+ entries++;
+ }
+ } catch (Exception e) {
+ // ignore
+ } finally {
+ if (ctx != null) {
+ try {
+ ctx.close();
+ } catch (NamingException e) {
+ // ignore
+ }
+ }
+ }
+
+ assertEquals(1, entries);
+ } finally {
+ if (groupTO != null) {
+ groupService.delete(groupTO.getKey());
+ }
+ resourceService.delete("new-ldap");
+ }
+ }
+
++ @Test
++ public void issueSYNCOPE717() {
++ String doubleSchemaName = "double" + getUUIDString();
++
++ // 1. create double schema without conversion pattern
++ PlainSchemaTO schema = new PlainSchemaTO();
++ schema.setKey(doubleSchemaName);
++ schema.setType(AttrSchemaType.Double);
++
++ schema = createSchema(SchemaType.PLAIN, schema);
++ assertNotNull(schema);
++ assertNull(schema.getConversionPattern());
++
++ AnyTypeClassTO minimalGroup = anyTypeClassService.read("minimal group");
++ assertNotNull(minimalGroup);
++ minimalGroup.getPlainSchemas().add(doubleSchemaName);
++ anyTypeClassService.update(minimalGroup);
++
++ // 2. create group, provide valid input value
++ GroupTO groupTO = getBasicSampleTO("syncope717");
++ groupTO.getPlainAttrs().add(attrTO(doubleSchemaName, "11.23"));
++
++ groupTO = createGroup(groupTO);
++ assertNotNull(groupTO);
++ assertEquals("11.23", groupTO.getPlainAttrMap().get(doubleSchemaName).getValues().get(0));
++
++ // 3. update schema, set conversion pattern
++ schema.setConversionPattern("0.000");
++ schemaService.update(SchemaType.PLAIN, schema);
++
++ // 4. re-read group, verify that pattern was applied
++ groupTO = groupService.read(groupTO.getKey());
++ assertNotNull(groupTO);
++ assertEquals("11.230", groupTO.getPlainAttrMap().get(doubleSchemaName).getValues().get(0));
++
++ // 5. modify group with new double value
++ GroupPatch patch = new GroupPatch();
++ patch.setKey(groupTO.getKey());
++ patch.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO(doubleSchemaName, "11.257")).build());
++
++ groupTO = updateGroup(patch);
++ assertNotNull(groupTO);
++ assertEquals("11.257", groupTO.getPlainAttrMap().get(doubleSchemaName).getValues().get(0));
++
++ // 6. update schema, unset conversion pattern
++ schema.setConversionPattern(null);
++ schemaService.update(SchemaType.PLAIN, schema);
++
++ // 7. modify group with new double value, verify that no pattern is applied
++ patch = new GroupPatch();
++ patch.setKey(groupTO.getKey());
++ patch.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO(doubleSchemaName, "11.23")).build());
++
++ groupTO = updateGroup(patch);
++ assertNotNull(groupTO);
++ assertEquals("11.23", groupTO.getPlainAttrMap().get(doubleSchemaName).getValues().get(0));
++ }
++
+}