http://git-wip-us.apache.org/repos/asf/syncope/blob/054ea9ca/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java ---------------------------------------------------------------------- diff --cc fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java index 5fe876f,0000000..375f0d7 mode 100644,000000..100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java @@@ -1,2527 -1,0 +1,2576 @@@ +/* + * 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.assertNotEquals; +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.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.naming.NamingException; +import javax.ws.rs.core.EntityTag; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.cxf.common.util.Base64Utility; +import org.apache.cxf.helpers.IOUtils; +import org.apache.syncope.client.lib.SyncopeClient; +import org.apache.syncope.common.lib.AnyOperations; +import org.apache.syncope.common.lib.SyncopeClientException; +import org.apache.syncope.common.lib.SyncopeConstants; +import org.apache.syncope.common.lib.mod.ResourceAssociationMod; +import org.apache.syncope.common.lib.mod.StatusMod; +import org.apache.syncope.common.lib.mod.UserMod; +import org.apache.syncope.common.lib.policy.AccountPolicyTO; +import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf; +import org.apache.syncope.common.lib.policy.PasswordPolicyTO; +import org.apache.syncope.common.lib.to.AttrTO; +import org.apache.syncope.common.lib.to.BulkAction; +import org.apache.syncope.common.lib.to.BulkActionResult; +import org.apache.syncope.common.lib.to.BulkActionResult.Status; +import org.apache.syncope.common.lib.to.ConnObjectTO; +import org.apache.syncope.common.lib.to.MappingItemTO; +import org.apache.syncope.common.lib.to.MappingTO; +import org.apache.syncope.common.lib.to.MembershipTO; +import org.apache.syncope.common.lib.to.PagedResult; +import org.apache.syncope.common.lib.to.PropagationStatus; +import org.apache.syncope.common.lib.to.PropagationTaskTO; +import org.apache.syncope.common.lib.to.ResourceTO; +import org.apache.syncope.common.lib.to.GroupTO; +import org.apache.syncope.common.lib.to.RealmTO; +import org.apache.syncope.common.lib.to.UserTO; +import org.apache.syncope.common.lib.types.AnyTypeKind; +import org.apache.syncope.common.lib.types.CipherAlgorithm; +import org.apache.syncope.common.lib.types.ClientExceptionType; +import org.apache.syncope.common.lib.types.MappingPurpose; +import org.apache.syncope.common.lib.types.PropagationTaskExecStatus; +import org.apache.syncope.common.lib.types.ResourceAssociationAction; +import org.apache.syncope.common.lib.types.ResourceDeassociationActionType; +import org.apache.syncope.common.lib.types.TaskType; +import org.apache.syncope.common.lib.wrap.ResourceKey; +import org.apache.syncope.common.rest.api.CollectionWrapper; +import org.apache.syncope.common.rest.api.Preference; +import org.apache.syncope.common.rest.api.RESTHeaders; +import org.apache.syncope.common.rest.api.service.ResourceService; +import org.apache.syncope.common.rest.api.service.UserSelfService; +import org.apache.syncope.common.rest.api.service.UserService; +import org.apache.syncope.core.misc.security.Encryptor; +import org.apache.syncope.core.provisioning.java.propagation.DBPasswordPropagationActions; +import org.apache.syncope.core.provisioning.java.propagation.LDAPPasswordPropagationActions; +import org.identityconnectors.framework.common.objects.Name; +import org.identityconnectors.framework.common.objects.OperationalAttributes; +import org.junit.Assume; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; + +@FixMethodOrder(MethodSorters.JVM) +public class UserITCase extends AbstractITCase { + + private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() { + + @Override + protected SimpleDateFormat initialValue() { + SimpleDateFormat sdf = new SimpleDateFormat(); + sdf.applyPattern("yyyy-MM-dd"); + return sdf; + } + }; + + private boolean getBooleanAttribute(final ConnObjectTO connObjectTO, final String attrName) { + return Boolean.parseBoolean(connObjectTO.getPlainAttrMap().get(attrName).getValues().get(0)); + } + + public static UserTO getUniqueSampleTO(final String email) { + return getSampleTO(getUUIDString() + email); + } + + public static UserTO getSampleTO(final String email) { + UserTO userTO = new UserTO(); + userTO.setRealm(SyncopeConstants.ROOT_REALM); + userTO.setPassword("password123"); + userTO.setUsername(email); + + userTO.getPlainAttrs().add(attrTO("fullname", email)); + userTO.getPlainAttrs().add(attrTO("firstname", email)); + userTO.getPlainAttrs().add(attrTO("surname", "surname")); + userTO.getPlainAttrs().add(attrTO("type", "a type")); + userTO.getPlainAttrs().add(attrTO("userId", email)); + userTO.getPlainAttrs().add(attrTO("email", email)); + userTO.getPlainAttrs().add(attrTO("loginDate", DATE_FORMAT.get().format(new Date()))); + userTO.getDerAttrs().add(attrTO("cn", null)); + userTO.getVirAttrs().add(attrTO("virtualdata", "virtualvalue")); + return userTO; + } + + @Test + public void createUserWithNoPropagation() { + // get task list + PagedResult<PropagationTaskTO> tasks = taskService.list( + TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()); + assertNotNull(tasks); + assertFalse(tasks.getResult().isEmpty()); + + long maxKey = tasks.getResult().iterator().next().getKey(); + + // create a new user + UserTO userTO = getUniqueSampleTO("x...@xxx.xxx"); + + userTO.setPassword("password123"); + userTO.getResources().add(RESOURCE_NAME_NOPROPAGATION); + + createUser(userTO); + + // get the new task list + tasks = taskService.list( + TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()); + assertNotNull(tasks); + assertFalse(tasks.getResult().isEmpty()); + + long newMaxId = tasks.getResult().iterator().next().getKey(); + + assertTrue(newMaxId > maxKey); + + // get last task + PropagationTaskTO taskTO = taskService.read(newMaxId); + + assertNotNull(taskTO); + assertTrue(taskTO.getExecutions().isEmpty()); + } + + @Test + public void issue186() { + // 1. create an user with strict mandatory attributes only + UserTO userTO = new UserTO(); + userTO.setRealm(SyncopeConstants.ROOT_REALM); + String userId = getUUIDString() + "issue...@syncope.apache.org"; + userTO.setUsername(userId); + userTO.setPassword("password123"); + + userTO.getPlainAttrs().add(attrTO("userId", userId)); + userTO.getPlainAttrs().add(attrTO("fullname", userId)); + userTO.getPlainAttrs().add(attrTO("surname", userId)); + + userTO = createUser(userTO); + assertNotNull(userTO); + assertTrue(userTO.getResources().isEmpty()); + + // 2. update assigning a resource forcing mandatory constraints: must fail with RequiredValuesMissing + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("newPassword123"); + userMod.getResourcesToAdd().add(RESOURCE_NAME_WS2); + + try { + userTO = updateUser(userMod); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType()); + } + + // 3. update assigning a resource NOT forcing mandatory constraints + // AND primary: must fail with PropagationException + userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("newPassword123"); + userMod.getResourcesToAdd().add(RESOURCE_NAME_WS1); + + userTO = updateUser(userMod); + assertNotNull(userTO.getPropagationStatusTOs().get(0).getFailureReason()); + + // 4. update assigning a resource NOT forcing mandatory constraints + // BUT not primary: must succeed + userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("newPassword123456"); + userMod.getResourcesToAdd().add(RESOURCE_NAME_CSV); + updateUser(userMod); + } + + @Test + public void enforceMandatoryCondition() { + UserTO userTO = getUniqueSampleTO("enfo...@apache.org"); + userTO.getResources().add(RESOURCE_NAME_WS2); + userTO.setPassword("newPassword12"); + + AttrTO type = null; + for (AttrTO attr : userTO.getPlainAttrs()) { + if ("type".equals(attr.getSchema())) { + type = attr; + } + } + assertNotNull(type); + userTO.getPlainAttrs().remove(type); + + try { + userTO = createUser(userTO); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType()); + } + + userTO.getPlainAttrs().add(type); + userTO = createUser(userTO); + assertNotNull(userTO); + } + + @Test + public void enforceMandatoryConditionOnDerived() { + ResourceTO resourceTO = resourceService.read(RESOURCE_NAME_CSV); + assertNotNull(resourceTO); + resourceTO.setKey("resource-csv-enforcing"); + resourceTO.setEnforceMandatoryCondition(true); + + Response response = resourceService.create(resourceTO); + resourceTO = getObject(response.getLocation(), ResourceService.class, ResourceTO.class); + assertNotNull(resourceTO); + + UserTO userTO = getUniqueSampleTO("syncope...@apache.org"); + userTO.getResources().add(resourceTO.getKey()); + userTO.setPassword("newPassword12"); + + try { + userTO = createUser(userTO); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType()); + } + + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + + userTO = createUser(userTO); + assertNotNull(userTO); + assertEquals(Collections.singleton("resource-csv-enforcing"), userTO.getResources()); + } + + @Test + public void createUserWithDbPropagation() { + UserTO userTO = getUniqueSampleTO("y...@yyy.yyy"); + userTO.getResources().add(RESOURCE_NAME_TESTDB); + userTO = createUser(userTO); + assertNotNull(userTO); + assertEquals(1, userTO.getPropagationStatusTOs().size()); + assertTrue(userTO.getPropagationStatusTOs().get(0).getStatus().isSuccessful()); + } + + @Test(expected = SyncopeClientException.class) + public void createWithInvalidPassword() { + UserTO userTO = getSampleTO("invalidpas...@syncope.apache.org"); + userTO.setPassword("pass"); + createUser(userTO); + } + + @Test(expected = SyncopeClientException.class) + public void createWithInvalidUsername() { + UserTO userTO = getSampleTO("invalidusern...@syncope.apache.org"); + userTO.setUsername("us"); + userTO.setRealm("/odd"); + + createUser(userTO); + } + + @Test(expected = SyncopeClientException.class) + public void createWithInvalidPasswordByRes() { + UserTO userTO = getSampleTO("invalidpwdby...@passwd.com"); + + // configured to be minLength=16 + userTO.setPassword("password1"); + userTO.getResources().add(RESOURCE_NAME_NOPROPAGATION); + createUser(userTO); + } + + @Test(expected = SyncopeClientException.class) + public void createWithInvalidPasswordByGroup() { + UserTO userTO = getSampleTO("invalidpwdbygr...@passwd.com"); + + // configured to be minLength=16 + userTO.setPassword("password1"); + + MembershipTO membership = new MembershipTO(); + membership.setRightKey(8L); + + userTO.getMemberships().add(membership); + + createUser(userTO); + } + + @Test(expected = SyncopeClientException.class) + public void createWithException() { + UserTO newUserTO = new UserTO(); + newUserTO.getPlainAttrs().add(attrTO("userId", "use...@nowhere.org")); + createUser(newUserTO); + } + + @Test + public void create() { + // get task list + PagedResult<PropagationTaskTO> tasks = taskService.list( + TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()); + assertNotNull(tasks); + assertFalse(tasks.getResult().isEmpty()); + + long maxKey = tasks.getResult().iterator().next().getKey(); + PropagationTaskTO taskTO = taskService.read(maxKey); + + assertNotNull(taskTO); + int maxTaskExecutions = taskTO.getExecutions().size(); + + UserTO userTO = getUniqueSampleTO("a...@c.com"); + + // add a membership + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(8L); + userTO.getMemberships().add(membershipTO); + + // add an attribute with a non-existing schema: must be ignored + AttrTO attrWithInvalidSchemaTO = attrTO("invalid schema", "a value"); + userTO.getPlainAttrs().add(attrWithInvalidSchemaTO); + + // add an attribute with null value: must be ignored + userTO.getPlainAttrs().add(attrTO("activationDate", null)); + + // 1. create user + UserTO newUserTO = createUser(userTO); + + assertNotNull(newUserTO); + + // issue SYNCOPE-15 + assertNotNull(newUserTO.getCreationDate()); + assertNotNull(newUserTO.getCreator()); + assertNotNull(newUserTO.getLastChangeDate()); + assertNotNull(newUserTO.getLastModifier()); + assertEquals(newUserTO.getCreationDate(), newUserTO.getLastChangeDate()); + + assertFalse(newUserTO.getPlainAttrs().contains(attrWithInvalidSchemaTO)); + + // check for changePwdDate + assertNotNull(newUserTO.getCreationDate()); + + // 2. check for virtual attribute value + newUserTO = userService.read(newUserTO.getKey()); + assertNotNull(newUserTO); + + assertNotNull(newUserTO.getVirAttrMap()); + assertNotNull(newUserTO.getVirAttrMap().get("virtualdata").getValues()); + assertFalse(newUserTO.getVirAttrMap().get("virtualdata").getValues().isEmpty()); + assertEquals("virtualvalue", newUserTO.getVirAttrMap().get("virtualdata").getValues().get(0)); + + // get the new task list + tasks = taskService.list( + TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()); + assertNotNull(tasks); + assertFalse(tasks.getResult().isEmpty()); + + long newMaxKey = tasks.getResult().iterator().next().getKey(); + + // default configuration for ws-target-resource2: + // only failed executions have to be registered + // --> no more tasks/executions should be added + assertEquals(newMaxKey, maxKey); + + // get last task + taskTO = taskService.read(newMaxKey); + + assertNotNull(taskTO); + assertEquals(maxTaskExecutions, taskTO.getExecutions().size()); + + // 3. verify password + try { + Pair<Map<String, Set<String>>, UserTO> self = + clientFactory.create(newUserTO.getUsername(), "password123").self(); + assertNotNull(self); + } catch (AccessControlException e) { + fail("Credentials should be valid and not cause AccessControlException"); + } + + UserSelfService userSelfService2 = clientFactory.create( + newUserTO.getUsername(), "passwordXX").getService(UserSelfService.class); + try { + userSelfService2.read(); + fail("Credentials are invalid, thus request should raise AccessControlException"); + } catch (AccessControlException e) { + assertNotNull(e); + } + + // 4. try (and fail) to create another user with same (unique) values + userTO = getSampleTO(userTO.getUsername()); + AttrTO userIdAttr = userTO.getPlainAttrMap().get("userId"); + userIdAttr.getValues().clear(); + userIdAttr.getValues().add("a...@c.com"); + + try { + createUser(userTO); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.GenericPersistence, e.getType()); + } + } + + @Test + public void createWithRequiredValueMissing() { + UserTO userTO = getSampleTO("a...@c.it"); + + AttrTO type = userTO.getPlainAttrMap().get("type"); + userTO.getPlainAttrs().remove(type); + + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(8L); + userTO.getMemberships().add(membershipTO); + + // 1. create user without type (mandatory by UserSchema) + try { + createUser(userTO); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType()); + } + + userTO.getPlainAttrs().add(attrTO("type", "F")); + + AttrTO surname = userTO.getPlainAttrMap().get("surname"); + userTO.getPlainAttrs().remove(surname); + + // 2. create user without surname (mandatory when type == 'F') + try { + createUser(userTO); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType()); + } + } + + @Test + public void delete() { + try { + userService.delete(0L); + } catch (SyncopeClientException e) { + assertEquals(Response.Status.NOT_FOUND, e.getType().getResponseStatus()); + } + + UserTO userTO = getSampleTO("qqg...@nn.com"); + + // specify a propagation + userTO.getResources().add(RESOURCE_NAME_TESTDB); + + userTO = createUser(userTO); + + long id = userTO.getKey(); + + userTO = deleteUser(id); + + assertNotNull(userTO); + assertEquals(id, userTO.getKey()); + assertTrue(userTO.getPlainAttrs().isEmpty()); + + // check for propagation result + assertFalse(userTO.getPropagationStatusTOs().isEmpty()); + assertTrue(userTO.getPropagationStatusTOs().get(0).getStatus().isSuccessful()); + + try { + userService.delete(userTO.getKey()); + } catch (SyncopeClientException e) { + assertEquals(Response.Status.NOT_FOUND, e.getType().getResponseStatus()); + } + } + + @Test + public void deleteByUsername() { + UserTO userTO = getSampleTO("delete.by.usern...@apache.org"); + + // specify a propagation + userTO.getResources().add(RESOURCE_NAME_TESTDB); + + userTO = createUser(userTO); + + long id = userTO.getKey(); + userTO = userService.read(id); + userTO = deleteUser(userTO.getKey()); + + assertNotNull(userTO); + assertEquals(id, userTO.getKey()); + assertTrue(userTO.getPlainAttrs().isEmpty()); + + // check for propagation result + assertFalse(userTO.getPropagationStatusTOs().isEmpty()); + assertTrue(userTO.getPropagationStatusTOs().get(0).getStatus().isSuccessful()); + + try { + userService.read(userTO.getKey()); + } catch (SyncopeClientException e) { + assertEquals(Response.Status.NOT_FOUND, e.getType().getResponseStatus()); + } + } + + @Test + public void list() { + PagedResult<UserTO> users = userService.list( + SyncopeClient.getAnyListQueryBuilder().realm(SyncopeConstants.ROOT_REALM).build()); + assertNotNull(users); + assertFalse(users.getResult().isEmpty()); + + for (UserTO user : users.getResult()) { + assertNotNull(user); + } + } + + @Test + public void paginatedList() { + PagedResult<UserTO> users = userService.list( + SyncopeClient.getAnyListQueryBuilder().realm(SyncopeConstants.ROOT_REALM).page(1).size(2).build()); + assertNotNull(users); + assertFalse(users.getResult().isEmpty()); + assertEquals(2, users.getResult().size()); + + for (UserTO user : users.getResult()) { + assertNotNull(user); + } + + users = userService.list(SyncopeClient.getAnyListQueryBuilder().realm(SyncopeConstants.ROOT_REALM). + page(2).size(2).build()); + assertNotNull(users); + assertEquals(2, users.getPage()); + assertEquals(2, users.getResult().size()); + + users = userService.list(SyncopeClient.getAnyListQueryBuilder().realm(SyncopeConstants.ROOT_REALM). + page(100).size(2).build()); + assertNotNull(users); + assertTrue(users.getResult().isEmpty()); + } + + @Test + public void read() { + UserTO userTO = userService.read(1L); + + assertNotNull(userTO); + assertNotNull(userTO.getPlainAttrs()); + assertFalse(userTO.getPlainAttrs().isEmpty()); + } + + @Test + public void readWithMailAddressAsUserName() { + UserTO userTO = createUser(getUniqueSampleTO("m...@domain.org")); + userTO = userService.read(userTO.getKey()); + assertNotNull(userTO); + } + + @Test + public void updateWithouPassword() { + UserTO userTO = getUniqueSampleTO("updatewith...@password.com"); + + userTO = createUser(userTO); + + assertNotNull(userTO); + + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.getDerAttrsToRemove().add("cn"); + + userTO = updateUser(userMod); + + assertNotNull(userTO); + assertNotNull(userTO.getDerAttrMap()); + assertFalse(userTO.getDerAttrMap().containsKey("cn")); + } + + @Test(expected = SyncopeClientException.class) + public void updateInvalidPassword() { + UserTO userTO = getSampleTO("updateinva...@password.com"); + + userTO = createUser(userTO); + assertNotNull(userTO); + + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("pass"); + + userService.update(userMod); + } + + @Test(expected = SyncopeClientException.class) + public void updateSamePassword() { + UserTO userTO = getUniqueSampleTO("updates...@password.com"); + userTO.setRealm("/even/two"); + + userTO = createUser(userTO); + assertNotNull(userTO); + + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("password123"); + + userService.update(userMod); + } + + @Test + public void update() { + UserTO userTO = getUniqueSampleTO("g...@t.com"); + + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(8L); + userTO.getMemberships().add(membershipTO); + + userTO = createUser(userTO); + + assertFalse(userTO.getDerAttrs().isEmpty()); + assertEquals(1, userTO.getMemberships().size()); + + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("new2Password"); + + userMod.getPlainAttrsToRemove().add("userId"); + String newUserId = getUUIDString() + "t...@spre.net"; + userMod.getPlainAttrsToUpdate().add(attrMod("userId", newUserId)); + + userMod.getPlainAttrsToRemove().add("fullname"); + String newFullName = getUUIDString() + "g...@t.com"; + userMod.getPlainAttrsToUpdate().add(attrMod("fullname", newFullName)); + + userMod.getDerAttrsToAdd().add("cn"); + userMod.getMembershipsToAdd().add(8L); + userMod.getMembershipsToRemove().add(userTO.getMemberships().get(0).getRightKey()); + + userTO = updateUser(userMod); + assertNotNull(userTO); + + // issue SYNCOPE-15 + assertNotNull(userTO.getCreationDate()); + assertNotNull(userTO.getCreator()); + assertNotNull(userTO.getLastChangeDate()); + assertNotNull(userTO.getLastModifier()); + assertTrue(userTO.getCreationDate().before(userTO.getLastChangeDate())); + + assertEquals(1, userTO.getMemberships().size()); + assertFalse(userTO.getDerAttrs().isEmpty()); + + AttrTO userIdAttr = userTO.getPlainAttrMap().get("userId"); + assertEquals(Collections.singletonList(newUserId), userIdAttr.getValues()); + + AttrTO fullNameAttr = userTO.getPlainAttrMap().get("fullname"); + assertEquals(Collections.singletonList(newFullName), fullNameAttr.getValues()); + } + + @Test + public void updatePasswordOnly() { + int beforeTasks = taskService.list(TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()).getTotalCount(); + assertFalse(beforeTasks <= 0); + + UserTO userTO = getUniqueSampleTO("pwdo...@t.com"); + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(8L); + userTO.getMemberships().add(membershipTO); + + userTO = createUser(userTO); + + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("newPassword123"); + + userTO = updateUser(userMod); + + // check for changePwdDate + assertNotNull(userTO.getChangePwdDate()); + + int afterTasks = taskService.list(TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()).getTotalCount(); + assertFalse(beforeTasks <= 0); + + assertTrue(beforeTasks < afterTasks); + } + + @SuppressWarnings("unchecked") + @Test + public void verifyTaskRegistration() { + // get task list + PagedResult<PropagationTaskTO> tasks = taskService.list( + TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()); + assertNotNull(tasks); + assertFalse(tasks.getResult().isEmpty()); + + long maxKey = tasks.getResult().iterator().next().getKey(); + + // -------------------------------------- + // Create operation + // -------------------------------------- + UserTO userTO = getUniqueSampleTO("t...@p.mode"); + + // add a membership + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(8L); + userTO.getMemberships().add(membershipTO); + + // 1. create user + userTO = createUser(userTO); + assertNotNull(userTO); + + // get the new task list + tasks = taskService.list( + TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()); + assertNotNull(tasks); + assertFalse(tasks.getResult().isEmpty()); + + long newMaxKey = tasks.getResult().iterator().next().getKey(); + + // default configuration for ws-target-resource2: + // only failed executions have to be registered + // --> no more tasks/executions should be added + assertEquals(newMaxKey, maxKey); + + // -------------------------------------- + // Update operation + // -------------------------------------- + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + + userMod.getPlainAttrsToUpdate().add(attrMod("surname", "surname")); + + userTO = updateUser(userMod); + + assertNotNull(userTO); + + // get the new task list + tasks = taskService.list( + TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()); + + maxKey = newMaxKey; + newMaxKey = tasks.getResult().iterator().next().getKey(); + + // default configuration for ws-target-resource2: + // all update executions have to be registered + assertTrue(newMaxKey > maxKey); + + final PropagationTaskTO taskTO = taskService.read(newMaxKey); + + assertNotNull(taskTO); + assertEquals(1, taskTO.getExecutions().size()); + + // -------------------------------------- + // Delete operation + // -------------------------------------- + userService.delete(userTO.getKey()); + + // get the new task list + tasks = taskService.list( + TaskType.PROPAGATION, + SyncopeClient.getListQueryBuilder().page(1).size(1).build()); + + maxKey = newMaxKey; + newMaxKey = tasks.getResult().iterator().next().getKey(); + + // default configuration for ws-target-resource2: no delete executions have to be registered + // --> no more tasks/executions should be added + assertEquals(newMaxKey, maxKey); + } + + @Test + public void createActivate() { + Assume.assumeTrue(ActivitiDetector.isActivitiEnabledForUsers(syncopeService)); + + UserTO userTO = getUniqueSampleTO("createactiv...@syncope.apache.org"); + + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(11L); + userTO.getMemberships().add(membershipTO); + + userTO = createUser(userTO); + + assertNotNull(userTO); + assertNotNull(userTO.getToken()); + assertNotNull(userTO.getTokenExpireTime()); + + assertEquals("created", userTO.getStatus()); + + StatusMod statusMod = new StatusMod(); + statusMod.setKey(userTO.getKey()); + statusMod.setType(StatusMod.ModType.ACTIVATE); + statusMod.setToken(userTO.getToken()); + userTO = userService.status(statusMod).readEntity(UserTO.class); + + assertNotNull(userTO); + assertNull(userTO.getToken()); + assertNull(userTO.getTokenExpireTime()); + assertEquals("active", userTO.getStatus()); + } + + @Test + public void suspendReactivate() { + UserTO userTO = getUniqueSampleTO("suspendreactiv...@syncope.apache.org"); + + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(7L); + userTO.getMemberships().add(membershipTO); + + userTO = createUser(userTO); + + assertNotNull(userTO); + assertEquals(ActivitiDetector.isActivitiEnabledForUsers(syncopeService) + ? "active" + : "created", userTO.getStatus()); + + StatusMod statusMod = new StatusMod(); + statusMod.setKey(userTO.getKey()); + statusMod.setType(StatusMod.ModType.SUSPEND); + userTO = userService.status(statusMod).readEntity(UserTO.class); + assertNotNull(userTO); + assertEquals("suspended", userTO.getStatus()); + + statusMod = new StatusMod(); + statusMod.setKey(userTO.getKey()); + statusMod.setType(StatusMod.ModType.REACTIVATE); + userTO = userService.status(statusMod).readEntity(UserTO.class); + assertNotNull(userTO); + assertEquals("active", userTO.getStatus()); + } + + @Test + public void suspendReactivateOnResource() { + // Assert resources are present + ResourceTO dbTable = resourceService.read(RESOURCE_NAME_TESTDB); + assertNotNull(dbTable); + ResourceTO ldap = resourceService.read(RESOURCE_NAME_LDAP); + assertNotNull(ldap); + + // Create user with reference to resources + UserTO userTO = getUniqueSampleTO("suspreactonresou...@syncope.apache.org"); + userTO.getMemberships().clear(); + userTO.getResources().clear(); + userTO.getResources().add(RESOURCE_NAME_TESTDB); + userTO.getResources().add(RESOURCE_NAME_LDAP); + userTO = createUser(userTO); + assertNotNull(userTO); + assertEquals(ActivitiDetector.isActivitiEnabledForUsers(syncopeService) + ? "active" + : "created", userTO.getStatus()); + long userKey = userTO.getKey(); + + // Suspend with effect on syncope, ldap and db => user should be suspended in syncope and all resources + StatusMod statusMod = new StatusMod(); + statusMod.setKey(userKey); + statusMod.setType(StatusMod.ModType.SUSPEND); + statusMod.setOnSyncope(true); - statusMod.getResourceNames().add(RESOURCE_NAME_TESTDB); - statusMod.getResourceNames().add(RESOURCE_NAME_LDAP); ++ statusMod.getResources().add(RESOURCE_NAME_TESTDB); ++ statusMod.getResources().add(RESOURCE_NAME_LDAP); + userTO = userService.status(statusMod).readEntity(UserTO.class); + assertNotNull(userTO); + assertEquals("suspended", userTO.getStatus()); + + ConnObjectTO connObjectTO = + resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userKey); + assertFalse(getBooleanAttribute(connObjectTO, OperationalAttributes.ENABLE_NAME)); + + connObjectTO = resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userKey); + assertNotNull(connObjectTO); + + // Suspend and reactivate only on ldap => db and syncope should still show suspended + statusMod = new StatusMod(); + statusMod.setKey(userKey); + statusMod.setType(StatusMod.ModType.SUSPEND); + statusMod.setOnSyncope(false); - statusMod.getResourceNames().add(RESOURCE_NAME_LDAP); ++ statusMod.getResources().add(RESOURCE_NAME_LDAP); + userService.status(statusMod); + statusMod.setType(StatusMod.ModType.REACTIVATE); + userTO = userService.status(statusMod).readEntity(UserTO.class); + assertNotNull(userTO); + assertEquals("suspended", userTO.getStatus()); + + connObjectTO = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userKey); + assertFalse(getBooleanAttribute(connObjectTO, OperationalAttributes.ENABLE_NAME)); + + // Reactivate on syncope and db => syncope and db should show the user as active + statusMod = new StatusMod(); + statusMod.setKey(userKey); + statusMod.setType(StatusMod.ModType.REACTIVATE); + statusMod.setOnSyncope(true); - statusMod.getResourceNames().add(RESOURCE_NAME_TESTDB); ++ statusMod.getResources().add(RESOURCE_NAME_TESTDB); + + userTO = userService.status(statusMod).readEntity(UserTO.class); + assertNotNull(userTO); + assertEquals("active", userTO.getStatus()); + + connObjectTO = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userKey); + assertTrue(getBooleanAttribute(connObjectTO, OperationalAttributes.ENABLE_NAME)); + } + + @Test + public void updateMultivalueAttribute() { + UserTO userTO = getUniqueSampleTO("multiva...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + + userTO = createUser(userTO); + assertNotNull(userTO); + + AttrTO loginDate = userTO.getPlainAttrMap().get("loginDate"); + assertNotNull(loginDate); + assertEquals(1, loginDate.getValues().size()); + + UserMod userMod = new UserMod(); + + userMod.setKey(userTO.getKey()); + userMod.getPlainAttrsToUpdate().add(attrMod("loginDate", "2000-01-01")); + + userTO = updateUser(userMod); + assertNotNull(userTO); + + loginDate = userTO.getPlainAttrMap().get("loginDate"); + assertNotNull(loginDate); + assertEquals(2, loginDate.getValues().size()); + } + + @Test(expected = EmptyResultDataAccessException.class) + public void issue213() { + UserTO userTO = getUniqueSampleTO("issue...@syncope.apache.org"); + userTO.getResources().add(RESOURCE_NAME_TESTDB); + + userTO = createUser(userTO); + assertNotNull(userTO); + assertEquals(1, userTO.getResources().size()); + + JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource); + + String username = jdbcTemplate.queryForObject("SELECT id FROM test WHERE id=?", String.class, + userTO.getUsername()); + + assertEquals(userTO.getUsername(), username); + + UserMod userMod = new UserMod(); + + userMod.setKey(userTO.getKey()); + userMod.getResourcesToRemove().add(RESOURCE_NAME_TESTDB); + + userTO = updateUser(userMod); + assertTrue(userTO.getResources().isEmpty()); + + jdbcTemplate.queryForObject("SELECT id FROM test WHERE id=?", String.class, userTO.getUsername()); + } + + @Test + public void issue234() { + UserTO inUserTO = getUniqueSampleTO("issue...@syncope.apache.org"); + inUserTO.getResources().add(RESOURCE_NAME_LDAP); + + UserTO userTO = createUser(inUserTO); + assertNotNull(userTO); + + UserMod userMod = new UserMod(); + + userMod.setKey(userTO.getKey()); + userMod.setUsername("1" + userTO.getUsername()); + + userTO = updateUser(userMod); + assertNotNull(userTO); + assertEquals("1" + inUserTO.getUsername(), userTO.getUsername()); + } + + @Test + public void issue270() { + // 1. create a new user without virtual attributes + UserTO original = getUniqueSampleTO("issue...@syncope.apache.org"); + // be sure to remove all virtual attributes + original.getVirAttrs().clear(); + + original = createUser(original); + + assertNotNull(original); + + assertTrue(original.getVirAttrs().isEmpty()); + + UserTO toBeUpdated = userService.read(original.getKey()); + + AttrTO virtual = attrTO("virtualdata", "virtualvalue"); + toBeUpdated.getVirAttrs().add(virtual); + + // 2. try to update by adding a resource, but no password: must fail + UserMod userMod = AnyOperations.diff(toBeUpdated, original); + assertNotNull(userMod); + + toBeUpdated = updateUser(userMod); + assertNotNull(toBeUpdated); + + assertFalse(toBeUpdated.getVirAttrs().isEmpty()); + assertNotNull(toBeUpdated.getVirAttrs().iterator().next()); + + assertEquals(virtual.getSchema(), toBeUpdated.getVirAttrs().iterator().next().getSchema()); + } + + @Test + public final void issue280() { + UserTO userTO = getUniqueSampleTO("issue...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + + userTO = createUser(userTO); + assertNotNull(userTO); + + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("123password"); + userMod.getResourcesToAdd().add(RESOURCE_NAME_TESTDB); + + final StatusMod st = new StatusMod(); + st.setOnSyncope(false); - st.getResourceNames().add(RESOURCE_NAME_TESTDB); ++ st.getResources().add(RESOURCE_NAME_TESTDB); + userMod.setPwdPropRequest(st); + + userTO = updateUser(userMod); + assertNotNull(userTO); + + final List<PropagationStatus> propagations = userTO.getPropagationStatusTOs(); + + assertNotNull(propagations); + assertEquals(1, propagations.size()); + + final PropagationTaskExecStatus status = propagations.get(0).getStatus(); + final String resource = propagations.get(0).getResource(); + + assertNotNull(status); + assertEquals(RESOURCE_NAME_TESTDB, resource); + assertTrue(status.isSuccessful()); + } + + @Test + public void issue281() { + UserTO userTO = getUniqueSampleTO("issue...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getResources().add(RESOURCE_NAME_CSV); + + userTO = createUser(userTO); + assertNotNull(userTO); + + final List<PropagationStatus> propagations = userTO.getPropagationStatusTOs(); + + assertNotNull(propagations); + assertEquals(1, propagations.size()); + + final PropagationTaskExecStatus status = propagations.get(0).getStatus(); + final String resource = propagations.get(0).getResource(); + + assertNotNull(status); + assertEquals(RESOURCE_NAME_CSV, resource); + assertFalse(status.isSuccessful()); + } + + @Test + public void issue288() { + UserTO userTO = getSampleTO("issue...@syncope.apache.org"); + userTO.getPlainAttrs().add(attrTO("aLong", "STRING")); + + try { + createUser(userTO); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.InvalidValues, e.getType()); + } + } + + @Test + public void groupAttrPropagation() { + UserTO userTO = getUniqueSampleTO("checkgroupattrpropagat...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(1L); + + userTO.getMemberships().add(membershipTO); + + userTO.getResources().add(RESOURCE_NAME_CSV); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + assertNotNull(actual.getDerAttrMap().get("csvuserid")); + + ConnObjectTO connObjectTO = + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + assertNotNull(connObjectTO); + assertEquals("sx-dx", connObjectTO.getPlainAttrMap().get("THEIRGROUP").getValues().get(0)); + } + + @Test + public void noContent() throws IOException { + SyncopeClient noContentclient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD); + UserService noContentService = noContentclient.prefer(UserService.class, Preference.RETURN_NO_CONTENT); + + UserTO user = getUniqueSampleTO("nocont...@syncope.apache.org"); + + Response response = noContentService.create(user, true); + 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())); + + user = getObject(response.getLocation(), UserService.class, UserTO.class); + assertNotNull(user); + + UserMod userMod = new UserMod(); + userMod.setKey(user.getKey()); + userMod.setPassword("password321"); + + response = noContentService.update(userMod); + 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(user.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 customPolicyRules() { + // Using custom policy rules with application/xml requires to overwrite + // org.apache.syncope.common.lib.policy.AbstractAccountRuleConf's and / or + // org.apache.syncope.common.lib.policy.AbstractPasswordRuleConf's + // @XmlSeeAlso - the power of JAXB :-/ + Assume.assumeTrue(MediaType.APPLICATION_JSON_TYPE.equals(clientFactory.getContentType().getMediaType())); + + AccountPolicyTO accountPolicy = new AccountPolicyTO(); + accountPolicy.setDescription("Account Policy with custom rules"); + accountPolicy.getRuleConfs().add(new TestAccountRuleConf()); + accountPolicy = createPolicy(accountPolicy); + assertNotNull(accountPolicy); + + PasswordPolicyTO passwordPolicy = new PasswordPolicyTO(); + passwordPolicy.setDescription("Password Policy with custom rules"); + passwordPolicy.getRuleConfs().add(new TestPasswordRuleConf()); + passwordPolicy = createPolicy(passwordPolicy); + assertNotNull(passwordPolicy); + + RealmTO realm = realmService.list("/even/two").get(0); + Long oldAccountPolicy = realm.getAccountPolicy(); + realm.setAccountPolicy(accountPolicy.getKey()); + Long oldPasswordPolicy = realm.getPasswordPolicy(); + realm.setPasswordPolicy(passwordPolicy.getKey()); + realmService.update(realm); + + try { + UserTO user = getUniqueSampleTO("custompolicyru...@syncope.apache.org"); + user.setRealm(realm.getFullPath()); + try { + createUser(user); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.InvalidUser, e.getType()); + assertTrue(e.getElements().iterator().next().startsWith("InvalidPassword")); + } + + user.setPassword(user.getPassword() + "XXX"); + try { + createUser(user); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.InvalidUser, e.getType()); + assertTrue(e.getElements().iterator().next().startsWith("InvalidUsername")); + } + + user.setUsername("YYY" + user.getUsername()); + user = createUser(user); + assertNotNull(user); + } finally { + realm.setAccountPolicy(oldAccountPolicy); + realm.setPasswordPolicy(oldPasswordPolicy); + realmService.update(realm); + + policyService.delete(passwordPolicy.getKey()); + policyService.delete(accountPolicy.getKey()); + } + } + + @Test + public void issueSYNCOPE108() { + UserTO userTO = getUniqueSampleTO("syncope...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + + MembershipTO memb12 = new MembershipTO(); + memb12.setRightKey(12L); + + userTO.getMemberships().add(memb12); + + MembershipTO memb13 = new MembershipTO(); + memb13.setRightKey(13L); + + userTO.getMemberships().add(memb13); + + userTO.getResources().add(RESOURCE_NAME_CSV); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + assertEquals(2, actual.getMemberships().size()); + assertEquals(1, actual.getResources().size()); + + ConnObjectTO connObjectTO = + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + assertNotNull(connObjectTO); + + // ----------------------------------- + // Remove the first membership: de-provisioning shouldn't happen + // ----------------------------------- + UserMod userMod = new UserMod(); + userMod.setKey(actual.getKey()); + + userMod.getMembershipsToRemove().add(actual.getMemberships().get(0).getRightKey()); + + actual = updateUser(userMod); + assertNotNull(actual); + assertEquals(1, actual.getMemberships().size()); + + connObjectTO = resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + assertNotNull(connObjectTO); + // ----------------------------------- + + // ----------------------------------- + // Remove the resource assigned directly: de-provisioning shouldn't happen + // ----------------------------------- + userMod = new UserMod(); + userMod.setKey(actual.getKey()); + + userMod.getResourcesToRemove().add(actual.getResources().iterator().next()); + + actual = updateUser(userMod); + assertNotNull(actual); + assertEquals(1, actual.getMemberships().size()); + assertFalse(actual.getResources().isEmpty()); + + connObjectTO = resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + assertNotNull(connObjectTO); + // ----------------------------------- + + // ----------------------------------- + // Remove the first membership: de-provisioning should happen + // ----------------------------------- + userMod = new UserMod(); + userMod.setKey(actual.getKey()); + + userMod.getMembershipsToRemove().add(actual.getMemberships().get(0).getRightKey()); + + actual = updateUser(userMod); + assertNotNull(actual); + assertTrue(actual.getMemberships().isEmpty()); + assertTrue(actual.getResources().isEmpty()); + + try { + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + fail("Read should not succeeed"); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.NotFound, e.getType()); + } + } + + @Test + public void issueSYNCOPE185() { + // 1. create user with LDAP resource, succesfully propagated + UserTO userTO = getSampleTO("syncope...@syncope.apache.org"); + userTO.getVirAttrs().clear(); + userTO.getResources().add(RESOURCE_NAME_LDAP); + + userTO = createUser(userTO); + assertNotNull(userTO); + assertFalse(userTO.getPropagationStatusTOs().isEmpty()); + assertEquals(RESOURCE_NAME_LDAP, userTO.getPropagationStatusTOs().get(0).getResource()); + assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus()); + + // 2. delete this user + userService.delete(userTO.getKey()); + + // 3. try (and fail) to find this user on the external LDAP resource + try { + resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userTO.getKey()); + fail("This entry should not be present on this resource"); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.NotFound, e.getType()); + } + } + + @Test() + public void issueSYNCOPE51() { + AttrTO defaultCA = configurationService.get("password.cipher.algorithm"); + final String originalCAValue = defaultCA.getValues().get(0); + defaultCA.getValues().set(0, "MD5"); + configurationService.set(defaultCA); + + AttrTO newCA = configurationService.get(defaultCA.getSchema()); + assertEquals(defaultCA, newCA); + + UserTO userTO = getSampleTO("syncop...@syncope.apache.org"); + userTO.setPassword("password"); + + try { + createUser(userTO); + fail("Create user should not succeed"); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.NotFound, e.getType()); + assertTrue(e.getElements().iterator().next().contains("MD5")); + } + + defaultCA.getValues().set(0, originalCAValue); + configurationService.set(defaultCA); + + AttrTO oldCA = configurationService.get(defaultCA.getSchema()); + assertEquals(defaultCA, oldCA); + } + + @Test + public void issueSYNCOPE267() { + // ---------------------------------- + // create user and check virtual attribute value propagation + // ---------------------------------- + UserTO userTO = getUniqueSampleTO("syncope...@apache.org"); + userTO.getResources().clear(); + userTO.getResources().add(RESOURCE_NAME_DBVIRATTR); + + userTO = createUser(userTO); + assertNotNull(userTO); + assertFalse(userTO.getPropagationStatusTOs().isEmpty()); + assertEquals(RESOURCE_NAME_DBVIRATTR, userTO.getPropagationStatusTOs().get(0).getResource()); + assertEquals(PropagationTaskExecStatus.SUBMITTED, userTO.getPropagationStatusTOs().get(0).getStatus()); + + ConnObjectTO connObjectTO = + resourceService.readConnObject(RESOURCE_NAME_DBVIRATTR, AnyTypeKind.USER.name(), userTO.getKey()); + assertNotNull(connObjectTO); + assertEquals("virtualvalue", connObjectTO.getPlainAttrMap().get("USERNAME").getValues().get(0)); + // ---------------------------------- + + userTO = userService.read(userTO.getKey()); + + assertNotNull(userTO); + assertEquals(1, userTO.getVirAttrs().size()); + assertEquals("virtualvalue", userTO.getVirAttrs().iterator().next().getValues().get(0)); + } + + @Test + public void issueSYNCOPE266() { + UserTO userTO = getUniqueSampleTO("syncope...@apache.org"); + userTO.getResources().clear(); + + userTO = createUser(userTO); + assertNotNull(userTO); + + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + + // this resource has not a mapping for Password + userMod.getResourcesToAdd().add(RESOURCE_NAME_UPDATE); + + userTO = updateUser(userMod); + assertNotNull(userTO); + } + + @Test + public void issueSYNCOPE279() { + UserTO userTO = getUniqueSampleTO("syncope...@apache.org"); + userTO.getResources().clear(); + userTO.getResources().add(RESOURCE_NAME_TIMEOUT); + userTO = createUser(userTO); + assertEquals(RESOURCE_NAME_TIMEOUT, userTO.getPropagationStatusTOs().get(0).getResource()); + assertNotNull(userTO.getPropagationStatusTOs().get(0).getFailureReason()); + assertEquals(PropagationTaskExecStatus.UNSUBMITTED, userTO.getPropagationStatusTOs().get(0).getStatus()); + } + + @Test + public void issueSYNCOPE122() { + // 1. create user on testdb and testdb2 + UserTO userTO = getUniqueSampleTO("syncope...@apache.org"); + userTO.getResources().clear(); + + userTO.getResources().add(RESOURCE_NAME_TESTDB); + userTO.getResources().add(RESOURCE_NAME_TESTDB2); + + userTO = createUser(userTO); + assertNotNull(userTO); + assertTrue(userTO.getResources().contains(RESOURCE_NAME_TESTDB)); + assertTrue(userTO.getResources().contains(RESOURCE_NAME_TESTDB2)); + + final String pwdOnSyncope = userTO.getPassword(); + + ConnObjectTO userOnDb = resourceService.readConnObject( + RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userTO.getKey()); + final AttrTO pwdOnTestDbAttr = userOnDb.getPlainAttrMap().get(OperationalAttributes.PASSWORD_NAME); + assertNotNull(pwdOnTestDbAttr); + assertNotNull(pwdOnTestDbAttr.getValues()); + assertFalse(pwdOnTestDbAttr.getValues().isEmpty()); + final String pwdOnTestDb = pwdOnTestDbAttr.getValues().iterator().next(); + + ConnObjectTO userOnDb2 = resourceService.readConnObject( + RESOURCE_NAME_TESTDB2, AnyTypeKind.USER.name(), userTO.getKey()); + final AttrTO pwdOnTestDb2Attr = userOnDb2.getPlainAttrMap().get(OperationalAttributes.PASSWORD_NAME); + assertNotNull(pwdOnTestDb2Attr); + assertNotNull(pwdOnTestDb2Attr.getValues()); + assertFalse(pwdOnTestDb2Attr.getValues().isEmpty()); + final String pwdOnTestDb2 = pwdOnTestDb2Attr.getValues().iterator().next(); + + // 2. request to change password only on testdb (no Syncope, no testdb2) + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword(getUUIDString()); + StatusMod pwdPropRequest = new StatusMod(); + pwdPropRequest.setOnSyncope(false); - pwdPropRequest.getResourceNames().add(RESOURCE_NAME_TESTDB); ++ pwdPropRequest.getResources().add(RESOURCE_NAME_TESTDB); + userMod.setPwdPropRequest(pwdPropRequest); + + userTO = updateUser(userMod); + + // 3a. Chech that only a single propagation took place + assertNotNull(userTO.getPropagationStatusTOs()); + assertEquals(1, userTO.getPropagationStatusTOs().size()); + assertEquals(RESOURCE_NAME_TESTDB, userTO.getPropagationStatusTOs().iterator().next().getResource()); + + // 3b. verify that password hasn't changed on Syncope + assertEquals(pwdOnSyncope, userTO.getPassword()); + + // 3c. verify that password *has* changed on testdb + userOnDb = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userTO.getKey()); + final AttrTO pwdOnTestDbAttrAfter = userOnDb.getPlainAttrMap().get(OperationalAttributes.PASSWORD_NAME); + assertNotNull(pwdOnTestDbAttrAfter); + assertNotNull(pwdOnTestDbAttrAfter.getValues()); + assertFalse(pwdOnTestDbAttrAfter.getValues().isEmpty()); + assertNotEquals(pwdOnTestDb, pwdOnTestDbAttrAfter.getValues().iterator().next()); + + // 3d. verify that password hasn't changed on testdb2 + userOnDb2 = resourceService.readConnObject(RESOURCE_NAME_TESTDB2, AnyTypeKind.USER.name(), userTO.getKey()); + final AttrTO pwdOnTestDb2AttrAfter = userOnDb2.getPlainAttrMap().get(OperationalAttributes.PASSWORD_NAME); + assertNotNull(pwdOnTestDb2AttrAfter); + assertNotNull(pwdOnTestDb2AttrAfter.getValues()); + assertFalse(pwdOnTestDb2AttrAfter.getValues().isEmpty()); + assertEquals(pwdOnTestDb2, pwdOnTestDb2AttrAfter.getValues().iterator().next()); + } + + @Test + public void isseSYNCOPE136AES() { + // 1. read configured cipher algorithm in order to be able to restore it at the end of test + AttrTO pwdCipherAlgo = configurationService.get("password.cipher.algorithm"); + final String origpwdCipherAlgo = pwdCipherAlgo.getValues().get(0); + + // 2. set AES password cipher algorithm + pwdCipherAlgo.getValues().set(0, "AES"); + configurationService.set(pwdCipherAlgo); + - // 3. create user with no resources - UserTO userTO = getUniqueSampleTO("syncope136_...@apache.org"); - userTO.getResources().clear(); - - userTO = createUser(userTO); - assertNotNull(userTO); - - // 4. update user, assign a propagation primary resource but don't provide any password - UserMod userMod = new UserMod(); - userMod.setKey(userTO.getKey()); - userMod.getResourcesToAdd().add(RESOURCE_NAME_WS1); ++ try { ++ // 3. create user with no resources ++ UserTO userTO = getUniqueSampleTO("syncope136_...@apache.org"); ++ userTO.getResources().clear(); + - final StatusMod st = new StatusMod(); - st.setOnSyncope(false); - st.getResourceNames().add(RESOURCE_NAME_WS1); - userMod.setPwdPropRequest(st); ++ userTO = createUser(userTO); ++ assertNotNull(userTO); + - userTO = updateUser(userMod); - assertNotNull(userTO); ++ // 4. update user, assign a propagation primary resource but don't provide any password ++ UserMod userMod = new UserMod(); ++ userMod.setKey(userTO.getKey()); ++ userMod.getResourcesToAdd().add(RESOURCE_NAME_WS1); + - // 5. verify that propagation was successful - List<PropagationStatus> props = userTO.getPropagationStatusTOs(); - assertNotNull(props); - assertEquals(1, props.size()); - PropagationStatus prop = props.iterator().next(); - assertNotNull(prop); - assertEquals(RESOURCE_NAME_WS1, prop.getResource()); - assertEquals(PropagationTaskExecStatus.SUBMITTED, prop.getStatus()); ++ StatusMod st = new StatusMod(); ++ st.setOnSyncope(false); ++ st.getResources().add(RESOURCE_NAME_WS1); ++ userMod.setPwdPropRequest(st); + - // 6. restore initial cipher algorithm - pwdCipherAlgo.getValues().set(0, origpwdCipherAlgo); - configurationService.set(pwdCipherAlgo); ++ userTO = updateUser(userMod); ++ assertNotNull(userTO); ++ ++ // 5. verify that propagation was successful ++ List<PropagationStatus> props = userTO.getPropagationStatusTOs(); ++ assertNotNull(props); ++ assertEquals(1, props.size()); ++ PropagationStatus prop = props.iterator().next(); ++ assertNotNull(prop); ++ assertEquals(RESOURCE_NAME_WS1, prop.getResource()); ++ assertEquals(PropagationTaskExecStatus.SUBMITTED, prop.getStatus()); ++ } finally { ++ // restore initial cipher algorithm ++ pwdCipherAlgo.getValues().set(0, origpwdCipherAlgo); ++ configurationService.set(pwdCipherAlgo); ++ } + } + + @Test + public void isseSYNCOPE136Random() { + // 1. create user with no resources + UserTO userTO = getUniqueSampleTO("syncope136_ran...@apache.org"); + userTO.getResources().clear(); + userTO = createUser(userTO); + assertNotNull(userTO); + + // 2. update user, assign a propagation primary resource but don't provide any password + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.getResourcesToAdd().add(RESOURCE_NAME_LDAP); + - final StatusMod st = new StatusMod(); ++ StatusMod st = new StatusMod(); + st.setOnSyncope(false); - st.getResourceNames().add(RESOURCE_NAME_LDAP); ++ st.getResources().add(RESOURCE_NAME_LDAP); + userMod.setPwdPropRequest(st); + + userTO = updateUser(userMod); + assertNotNull(userTO); + + // 3. verify that propagation was successful + List<PropagationStatus> props = userTO.getPropagationStatusTOs(); + assertNotNull(props); + assertEquals(1, props.size()); + PropagationStatus prop = props.iterator().next(); + assertNotNull(prop); + assertEquals(RESOURCE_NAME_LDAP, prop.getResource()); + assertEquals(PropagationTaskExecStatus.SUCCESS, prop.getStatus()); + } + + @Test + public void mappingPurpose() { + UserTO userTO = getUniqueSampleTO("mpurp...@apache.org"); + userTO.getAuxClasses().add("csv"); + + AttrTO csvuserid = new AttrTO(); + csvuserid.setSchema("csvuserid"); + userTO.getDerAttrs().add(csvuserid); + + userTO.getResources().clear(); + userTO.getResources().add(RESOURCE_NAME_CSV); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + + ConnObjectTO connObjectTO = + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + assertNull(connObjectTO.getPlainAttrMap().get("email")); + } + + @Test + public void issueSYNCOPE265() { + for (long key = 1; key <= 5; key++) { + UserMod userMod = new UserMod(); + userMod.setKey(key); + + userMod.getPlainAttrsToRemove().add("type"); + userMod.getPlainAttrsToUpdate().add(attrMod("type", "a type")); + + UserTO userTO = updateUser(userMod); + + assertEquals("a type", userTO.getPlainAttrMap().get("type").getValues().get(0)); + } + } + + @Test + public void bulkActions() { + BulkAction bulkAction = new BulkAction(); + + for (int i = 0; i < 10; i++) { + UserTO userTO = getUniqueSampleTO("bulk_" + i + "@apache.org"); + bulkAction.getTargets().add(String.valueOf(createUser(userTO).getKey())); + } + + // check for a fail + bulkAction.getTargets().add(String.valueOf(Long.MAX_VALUE)); + + assertEquals(11, bulkAction.getTargets().size()); + + bulkAction.setType(BulkAction.Type.SUSPEND); + BulkActionResult res = userService.bulk(bulkAction); + assertEquals(10, res.getResultByStatus(Status.SUCCESS).size()); + assertEquals(1, res.getResultByStatus(Status.FAILURE).size()); + assertEquals("suspended", userService.read( + Long.parseLong(res.getResultByStatus(Status.SUCCESS).get(3))).getStatus()); + + bulkAction.setType(BulkAction.Type.REACTIVATE); + res = userService.bulk(bulkAction); + assertEquals(10, res.getResultByStatus(Status.SUCCESS).size()); + assertEquals(1, res.getResultByStatus(Status.FAILURE).size()); + assertEquals("active", userService.read( + Long.parseLong(res.getResultByStatus(Status.SUCCESS).get(3))).getStatus()); + + bulkAction.setType(BulkAction.Type.DELETE); + res = userService.bulk(bulkAction); + assertEquals(10, res.getResultByStatus(Status.SUCCESS).size()); + assertEquals(1, res.getResultByStatus(Status.FAILURE).size()); + } + + @Test + public void issueSYNCOPE354() { + // change resource-ldap group mapping for including uniqueMember (need for assertions below) + ResourceTO ldap = resourceService.read(RESOURCE_NAME_LDAP); + for (MappingItemTO item : ldap.getProvision(AnyTypeKind.GROUP.name()).getMapping().getItems()) { + if ("description".equals(item.getExtAttrName())) { + item.setExtAttrName("uniqueMember"); + } + } + resourceService.update(ldap); + + // 1. create group with LDAP resource + GroupTO groupTO = new GroupTO(); + groupTO.setName("SYNCOPE354-" + getUUIDString()); + groupTO.setRealm("/"); + groupTO.getResources().add(RESOURCE_NAME_LDAP); + + groupTO = createGroup(groupTO); + assertNotNull(groupTO); + + // 2. create user with LDAP resource and membership of the above group + UserTO userTO = getUniqueSampleTO("syncope...@syncope.apache.org"); + userTO.getResources().add(RESOURCE_NAME_LDAP); + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(groupTO.getKey()); + userTO.getMemberships().add(membershipTO); + + userTO = createUser(userTO); + assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP)); + + // 3. read group on resource, check that user DN is included in uniqueMember + ConnObjectTO connObj = resourceService.readConnObject( + RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), groupTO.getKey()); + assertNotNull(connObj); + assertTrue(connObj.getPlainAttrMap().get("uniqueMember").getValues(). + contains("uid=" + userTO.getUsername() + ",ou=people,o=isp")); + + // 4. remove membership + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.getMembershipsToRemove().add(userTO.getMemberships().get(0).getRightKey()); + + userTO = updateUser(userMod); + assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP)); + + // 5. read group on resource, check that user DN was removed from uniqueMember + connObj = resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), groupTO.getKey()); + assertNotNull(connObj); + assertFalse(connObj.getPlainAttrMap().get("uniqueMember").getValues(). + contains("uid=" + userTO.getUsername() + ",ou=people,o=isp")); + + // 6. restore original resource-ldap group mapping + for (MappingItemTO item : ldap.getProvision(AnyTypeKind.GROUP.name()).getMapping().getItems()) { + if ("uniqueMember".equals(item.getExtAttrName())) { + item.setExtAttrName("description"); + } + } + resourceService.update(ldap); + } + + @Test + public void issueSYNCOPE357() throws IOException { + // 1. create group with LDAP resource + GroupTO groupTO = new GroupTO(); + groupTO.setName("SYNCOPE357-" + getUUIDString()); + groupTO.setRealm("/"); + groupTO.getResources().add(RESOURCE_NAME_LDAP); + + groupTO = createGroup(groupTO); + assertNotNull(groupTO); + + // 2. create user with membership of the above group + UserTO userTO = getUniqueSampleTO("syncope...@syncope.apache.org"); + userTO.getPlainAttrs().add(attrTO("obscure", "valueToBeObscured")); + userTO.getPlainAttrs().add(attrTO("photo", + Base64Utility.encode(IOUtils.readBytesFromStream(getClass().getResourceAsStream("/favicon.jpg"))))); + MembershipTO membershipTO = new MembershipTO(); + membershipTO.setRightKey(groupTO.getKey()); + userTO.getMemberships().add(membershipTO); + + userTO = createUser(userTO); + assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP)); + assertNotNull(userTO.getPlainAttrMap().get("obscure")); + assertNotNull(userTO.getPlainAttrMap().get("photo")); + + // 3. read user on resource + ConnObjectTO connObj = resourceService.readConnObject( + RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userTO.getKey()); + assertNotNull(connObj); + AttrTO registeredAddress = connObj.getPlainAttrMap().get("registeredAddress"); + assertNotNull(registeredAddress); + assertEquals(userTO.getPlainAttrMap().get("obscure").getValues(), registeredAddress.getValues()); + AttrTO jpegPhoto = connObj.getPlainAttrMap().get("jpegPhoto"); + assertNotNull(jpegPhoto); + assertEquals(userTO.getPlainAttrMap().get("photo").getValues(), jpegPhoto.getValues()); + + // 4. remove group + groupService.delete(groupTO.getKey()); + + // 5. try to read user on resource: fail + try { + resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userTO.getKey()); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.NotFound, e.getType()); + } + } + + @Test + public void issueSYNCOPE383() { + // 1. create user without resources + UserTO userTO = getUniqueSampleTO("syncope...@apache.org"); + userTO.getResources().clear(); + userTO = createUser(userTO); + assertNotNull(userTO); + + // 2. assign resource without specifying a new pwd and check propagation failure + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.getResourcesToAdd().add(RESOURCE_NAME_TESTDB); + userTO = updateUser(userMod); + assertEquals(RESOURCE_NAME_TESTDB, userTO.getResources().iterator().next()); + assertFalse(userTO.getPropagationStatusTOs().get(0).getStatus().isSuccessful()); + assertNotNull(userTO.getPropagationStatusTOs().get(0).getFailureReason()); + + // 3. request to change password only on testdb + userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword(getUUIDString() + "abbcbcbddd123"); + StatusMod pwdPropRequest = new StatusMod(); - pwdPropRequest.getResourceNames().add(RESOURCE_NAME_TESTDB); ++ pwdPropRequest.getResources().add(RESOURCE_NAME_TESTDB); + userMod.setPwdPropRequest(pwdPropRequest); + + userTO = updateUser(userMod); + assertEquals(RESOURCE_NAME_TESTDB, userTO.getResources().iterator().next()); + assertTrue(userTO.getPropagationStatusTOs().get(0).getStatus().isSuccessful()); + } + + @Test + public void issueSYNCOPE402() { + // 1. create an user with strict mandatory attributes only + UserTO userTO = new UserTO(); + userTO.setRealm(SyncopeConstants.ROOT_REALM); + String userId = getUUIDString() + "syncope...@syncope.apache.org"; + userTO.setUsername(userId); + userTO.setPassword("password123"); + + userTO.getPlainAttrs().add(attrTO("userId", userId)); + userTO.getPlainAttrs().add(attrTO("fullname", userId)); + userTO.getPlainAttrs().add(attrTO("surname", userId)); + + userTO = createUser(userTO); + assertNotNull(userTO); + assertTrue(userTO.getResources().isEmpty()); + + // 2. update assigning a resource NOT forcing mandatory constraints + // AND primary: must fail with PropagationException + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("newPassword123"); + + userMod.getResourcesToAdd().add(RESOURCE_NAME_WS1); + userMod.getResourcesToAdd().add(RESOURCE_NAME_TESTDB); + userTO = updateUser(userMod); + + List<PropagationStatus> propagationStatuses = userTO.getPropagationStatusTOs(); + PropagationStatus ws1PropagationStatus = null; + if (propagationStatuses != null) { + for (PropagationStatus propStatus : propagationStatuses) { + if (RESOURCE_NAME_WS1.equals(propStatus.getResource())) { + ws1PropagationStatus = propStatus; + break; + } + } + } + assertNotNull(ws1PropagationStatus); + assertEquals(RESOURCE_NAME_WS1, ws1PropagationStatus.getResource()); + assertNotNull(ws1PropagationStatus.getFailureReason()); + assertEquals(PropagationTaskExecStatus.UNSUBMITTED, ws1PropagationStatus.getStatus()); + } + + @Test + public void unlink() { + UserTO userTO = getUniqueSampleTO("unl...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + userTO.getResources().add(RESOURCE_NAME_CSV); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey())); + + assertNotNull(userService.deassociate(actual.getKey(), + ResourceDeassociationActionType.UNLINK, + CollectionWrapper.wrap(RESOURCE_NAME_CSV, ResourceKey.class)). + readEntity(BulkActionResult.class)); + + actual = userService.read(actual.getKey()); + assertNotNull(actual); + assertTrue(actual.getResources().isEmpty()); + + assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey())); + } + + @Test + public void link() { + UserTO userTO = getUniqueSampleTO("l...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + assertTrue(actual.getResources().isEmpty()); + + try { + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + fail(); + } catch (Exception e) { + assertNotNull(e); + } + + final ResourceAssociationMod associationMod = new ResourceAssociationMod(); + associationMod.getTargetResources().addAll(CollectionWrapper.wrap(RESOURCE_NAME_CSV, ResourceKey.class)); + + assertNotNull(userService.associate(actual.getKey(), ResourceAssociationAction.LINK, associationMod).readEntity( + BulkActionResult.class)); + + actual = userService.read(actual.getKey()); + assertNotNull(actual); + assertFalse(actual.getResources().isEmpty()); + + try { + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + fail(); + } catch (Exception e) { + assertNotNull(e); + } + } + + @Test + public void unassign() { + UserTO userTO = getUniqueSampleTO("unass...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + userTO.getResources().add(RESOURCE_NAME_CSV); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey())); + + assertNotNull(userService.deassociate(actual.getKey(), + ResourceDeassociationActionType.UNASSIGN, + CollectionWrapper.wrap(RESOURCE_NAME_CSV, ResourceKey.class)). + readEntity(BulkActionResult.class)); + + actual = userService.read(actual.getKey()); + assertNotNull(actual); + assertTrue(actual.getResources().isEmpty()); + + try { + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + fail(); + } catch (Exception e) { + assertNotNull(e); + } + } + + @Test + public void assign() { + UserTO userTO = getUniqueSampleTO("ass...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + assertTrue(actual.getResources().isEmpty()); + + try { + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + fail(); + } catch (Exception e) { + assertNotNull(e); + } + + ResourceAssociationMod associationMod = new ResourceAssociationMod(); + associationMod.getTargetResources().addAll(CollectionWrapper.wrap(RESOURCE_NAME_CSV, ResourceKey.class)); + associationMod.setChangePwd(true); + associationMod.setPassword("password"); + + assertNotNull(userService.associate(actual.getKey(), ResourceAssociationAction.ASSIGN, associationMod) + .readEntity(BulkActionResult.class)); + + actual = userService.read(actual.getKey()); + assertNotNull(actual); + assertFalse(actual.getResources().isEmpty()); + assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey())); + } + + @Test + public void deprovision() { + UserTO userTO = getUniqueSampleTO("deprovis...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + userTO.getResources().add(RESOURCE_NAME_CSV); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey())); + + assertNotNull(userService.deassociate(actual.getKey(), + ResourceDeassociationActionType.DEPROVISION, + CollectionWrapper.wrap(RESOURCE_NAME_CSV, ResourceKey.class)). + readEntity(BulkActionResult.class)); + + actual = userService.read(actual.getKey()); + assertNotNull(actual); + assertFalse(actual.getResources().isEmpty()); + + try { + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + fail(); + } catch (SyncopeClientException e) { + assertEquals(ClientExceptionType.NotFound, e.getType()); + } + } + + @Test + public void provision() { + UserTO userTO = getUniqueSampleTO("provis...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + assertTrue(actual.getResources().isEmpty()); + + try { + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + fail(); + } catch (Exception e) { + assertNotNull(e); + } + + ResourceAssociationMod associationMod = new ResourceAssociationMod(); + associationMod.getTargetResources().addAll(CollectionWrapper.wrap(RESOURCE_NAME_CSV, ResourceKey.class)); + associationMod.setChangePwd(true); + associationMod.setPassword("password"); + + assertNotNull(userService.associate(actual.getKey(), ResourceAssociationAction.PROVISION, associationMod). + readEntity(BulkActionResult.class)); + + actual = userService.read(actual.getKey()); + assertNotNull(actual); + assertTrue(actual.getResources().isEmpty()); + assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey())); + } + + @Test + public void deprovisionUnlinked() { + UserTO userTO = getUniqueSampleTO("provis...@syncope.apache.org"); + userTO.getResources().clear(); + userTO.getMemberships().clear(); + userTO.getDerAttrs().clear(); + userTO.getVirAttrs().clear(); + userTO.getAuxClasses().add("csv"); + userTO.getDerAttrs().add(attrTO("csvuserid", null)); + + UserTO actual = createUser(userTO); + assertNotNull(actual); + assertTrue(actual.getResources().isEmpty()); + + try { + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + fail(); + } catch (Exception e) { + assertNotNull(e); + } + + final ResourceAssociationMod associationMod = new ResourceAssociationMod(); + associationMod.getTargetResources().addAll(CollectionWrapper.wrap(RESOURCE_NAME_CSV, ResourceKey.class)); + associationMod.setChangePwd(true); + associationMod.setPassword("password"); + + assertNotNull(userService.associate(actual.getKey(), ResourceAssociationAction.PROVISION, + associationMod) + .readEntity(BulkActionResult.class)); + + actual = userService.read(actual.getKey()); + assertNotNull(actual); + assertTrue(actual.getResources().isEmpty()); + assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey())); + + assertNotNull(userService.deassociate(actual.getKey(), + ResourceDeassociationActionType.DEPROVISION, + CollectionWrapper.wrap(RESOURCE_NAME_CSV, ResourceKey.class)). + readEntity(BulkActionResult.class)); + + actual = userService.read(actual.getKey()); + assertNotNull(actual); + assertTrue(actual.getResources().isEmpty()); + + try { + resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()); + fail(); + } catch (Exception e) { + assertNotNull(e); + } + } + + @Test + public void issueSYNCOPE420() { + UserTO userTO = getUniqueSampleTO("syncope...@syncope.apache.org"); + userTO.getPlainAttrs().add(attrTO("makeItDouble", "3")); + + userTO = createUser(userTO); + assertEquals("6", userTO.getPlainAttrMap().get("makeItDouble").getValues().get(0)); + + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.getPlainAttrsToRemove().add("makeItDouble"); + userMod.getPlainAttrsToUpdate().add(attrMod("makeItDouble", "7")); + + userTO = updateUser(userMod); + assertEquals("14", userTO.getPlainAttrMap().get("makeItDouble").getValues().get(0)); + } + + @Test + public void issueSYNCOPE426() { + UserTO userTO = getUniqueSampleTO("syncope...@syncope.apache.org"); + userTO = createUser(userTO); + assertNotNull(userTO); + + UserMod userMod = new UserMod(); + userMod.setKey(userTO.getKey()); + userMod.setPassword("anotherPassword123"); + userTO = userService.update(userMod).readEntity(UserTO.class); + assertNotNull(userTO); + } + + @Test + public void issueSYNCOPE435() { + // 1. create user without password + UserTO userTO = getUniqueSampleTO("syncope...@syncope.apache.org"); + userTO.setPassword(null); + userTO = createUser(userTO, false); + assertNotNull(userTO); + + // 2. try to update user by subscribing a resource - works
<TRUNCATED>