blob: 9b652739dbe3929c23082998cfc7a79c6007310e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.syncope.fit.core;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.security.AccessControlException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
import org.apache.syncope.client.lib.BasicAuthenticationHandler;
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.request.AnyObjectCR;
import org.apache.syncope.common.lib.request.GroupCR;
import org.apache.syncope.common.lib.request.MembershipUR;
import org.apache.syncope.common.lib.request.ResourceDR;
import org.apache.syncope.common.lib.request.PasswordPatch;
import org.apache.syncope.common.lib.request.StatusR;
import org.apache.syncope.common.lib.request.StringPatchItem;
import org.apache.syncope.common.lib.request.StringReplacePatchItem;
import org.apache.syncope.common.lib.request.UserCR;
import org.apache.syncope.common.lib.request.UserUR;
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.to.AnyTypeClassTO;
import org.apache.syncope.common.lib.to.AnyTypeTO;
import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.MembershipTO;
import org.apache.syncope.common.lib.to.PagedResult;
import org.apache.syncope.common.lib.to.PlainSchemaTO;
import org.apache.syncope.common.lib.to.ProvisioningResult;
import org.apache.syncope.common.lib.to.RoleTO;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.to.UserRequestForm;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.common.lib.types.ResourceDeassociationAction;
import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.syncope.common.lib.types.StatusRType;
import org.apache.syncope.common.rest.api.RESTHeaders;
import org.apache.syncope.common.rest.api.beans.AnyQuery;
import org.apache.syncope.common.rest.api.beans.UserRequestQuery;
import org.apache.syncope.common.rest.api.service.AnyObjectService;
import org.apache.syncope.common.rest.api.service.SchemaService;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.core.spring.security.Encryptor;
import org.apache.syncope.fit.AbstractITCase;
import org.apache.syncope.fit.ElasticsearchDetector;
import org.apache.syncope.fit.FlowableDetector;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
public class AuthenticationITCase extends AbstractITCase {
private static int getFailedLogins(final UserService userService, final String userKey) {
UserTO readUserTO = userService.read(userKey);
assertNotNull(readUserTO);
assertNotNull(readUserTO.getFailedLogins());
return readUserTO.getFailedLogins();
}
@Test
public void readEntitlements() {
// 1. as not authenticated (not allowed)
try {
clientFactory.create().self();
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e);
}
// 2. as anonymous
Triple<Map<String, Set<String>>, List<String>, UserTO> self = clientFactory.create(
new AnonymousAuthenticationHandler(ANONYMOUS_UNAME, ANONYMOUS_KEY)).self();
assertEquals(1, self.getLeft().size());
assertTrue(self.getLeft().keySet().contains(IdRepoEntitlement.ANONYMOUS));
assertEquals(List.of(), self.getMiddle());
assertEquals(ANONYMOUS_UNAME, self.getRight().getUsername());
// 3. as admin
self = adminClient.self();
assertEquals(syncopeService.platform().getEntitlements().size(), self.getLeft().size());
assertFalse(self.getLeft().keySet().contains(IdRepoEntitlement.ANONYMOUS));
assertEquals(List.of(), self.getMiddle());
assertEquals(ADMIN_UNAME, self.getRight().getUsername());
// 4. as user
self = clientFactory.create("bellini", ADMIN_PWD).self();
assertFalse(self.getLeft().isEmpty());
assertFalse(self.getLeft().keySet().contains(IdRepoEntitlement.ANONYMOUS));
assertEquals(List.of(), self.getMiddle());
assertEquals("bellini", self.getRight().getUsername());
}
@Test
public void userSchemaAuthorization() {
String schemaName = "authTestSchema" + getUUIDString();
// 1. create a schema (as admin)
PlainSchemaTO schemaTO = new PlainSchemaTO();
schemaTO.setKey(schemaName);
schemaTO.setMandatoryCondition("false");
schemaTO.setType(AttrSchemaType.String);
PlainSchemaTO newPlainSchemaTO = createSchema(SchemaType.PLAIN, schemaTO);
assertEquals(schemaTO, newPlainSchemaTO);
// 2. create an user with the role created above (as admin)
UserCR userCR = UserITCase.getUniqueSample("auth@test.org");
UserTO userTO = createUser(userCR).getEntity();
assertNotNull(userTO);
// 3. read the schema created above (as admin) - success
schemaTO = schemaService.read(SchemaType.PLAIN, schemaName);
assertNotNull(schemaTO);
// 4. read the schema created above (as user) - success
SchemaService schemaService2 = clientFactory.create(userTO.getUsername(), "password123").
getService(SchemaService.class);
schemaTO = schemaService2.read(SchemaType.PLAIN, schemaName);
assertNotNull(schemaTO);
// 5. update the schema create above (as user) - failure
try {
schemaService2.update(SchemaType.PLAIN, schemaTO);
fail("Schema update as user should not work");
} catch (ForbiddenException e) {
assertNotNull(e);
}
assertEquals(0, getFailedLogins(userService, userTO.getKey()));
}
@Test
public void userRead() {
UserCR userCR = UserITCase.getUniqueSample("testuserread@test.org");
userCR.getRoles().add("User manager");
UserTO userTO = createUser(userCR).getEntity();
assertNotNull(userTO);
UserService userService2 = clientFactory.create(userTO.getUsername(), "password123").
getService(UserService.class);
UserTO readUserTO = userService2.read("1417acbe-cbf6-4277-9372-e75e04f97000");
assertNotNull(readUserTO);
UserService userService3 = clientFactory.create("puccini", ADMIN_PWD).getService(UserService.class);
try {
userService3.read("b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee");
fail("This should not happen");
} catch (SyncopeClientException e) {
assertNotNull(e);
assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
}
}
@Test
public void userSearch() {
UserCR userCR = UserITCase.getUniqueSample("testusersearch@test.org");
userCR.getRoles().add("User reviewer");
UserTO userTO = createUser(userCR).getEntity();
assertNotNull(userTO);
// 1. user assigned to role 1, with search entitlement on realms /odd and /even: won't find anything with
// root realm
UserService userService2 = clientFactory.create(userTO.getUsername(), "password123").
getService(UserService.class);
PagedResult<UserTO> matchingUsers = userService2.search(new AnyQuery.Builder().
realm(SyncopeConstants.ROOT_REALM).
fiql(SyncopeClient.getUserSearchConditionBuilder().isNotNull("key").query()).build());
assertNotNull(matchingUsers);
assertFalse(matchingUsers.getResult().isEmpty());
Set<String> matchingUserKeys = matchingUsers.getResult().stream().
map(AnyTO::getKey).collect(Collectors.toSet());
assertTrue(matchingUserKeys.contains("1417acbe-cbf6-4277-9372-e75e04f97000"));
assertFalse(matchingUserKeys.contains("74cd8ece-715a-44a4-a736-e17b46c4e7e6"));
assertFalse(matchingUserKeys.contains("823074dc-d280-436d-a7dd-07399fae48ec"));
// 2. user assigned to role 4, with search entitlement on realm /even/two
UserService userService3 = clientFactory.create("puccini", ADMIN_PWD).getService(UserService.class);
matchingUsers = userService3.search(new AnyQuery.Builder().realm("/even/two").
fiql(SyncopeClient.getUserSearchConditionBuilder().isNotNull("loginDate").query()).build());
assertNotNull(matchingUsers);
assertTrue(matchingUsers.getResult().stream().allMatch(matching -> "/even/two".equals(matching.getRealm())));
}
@Test
public void delegatedUserCRUD() {
String roleKey = null;
String delegatedAdminKey = null;
try {
// 1. create role for full user administration, under realm /even/two
RoleTO role = new RoleTO();
role.setKey("Delegated user admin");
role.getEntitlements().add(IdRepoEntitlement.USER_CREATE);
role.getEntitlements().add(IdRepoEntitlement.USER_UPDATE);
role.getEntitlements().add(IdRepoEntitlement.USER_DELETE);
role.getEntitlements().add(IdRepoEntitlement.USER_SEARCH);
role.getEntitlements().add(IdRepoEntitlement.USER_READ);
role.getRealms().add("/even/two");
roleKey = roleService.create(role).getHeaderString(RESTHeaders.RESOURCE_KEY);
assertNotNull(roleKey);
// 2. as admin, create delegated admin user, and assign the role just created
UserCR delegatedAdminCR = UserITCase.getUniqueSample("admin@syncope.apache.org");
delegatedAdminCR.getRoles().add(roleKey);
UserTO delegatedAdmin = createUser(delegatedAdminCR).getEntity();
delegatedAdminKey = delegatedAdmin.getKey();
// 3. instantiate a delegate user service client, for further operations
UserService delegatedUserService =
clientFactory.create(delegatedAdmin.getUsername(), "password123").getService(UserService.class);
// 4. as delegated, create user under realm / -> fail
UserCR userCR = UserITCase.getUniqueSample("delegated@syncope.apache.org");
try {
delegatedUserService.create(userCR);
fail("This should not happen");
} catch (SyncopeClientException e) {
assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
}
// 5. set realm to /even/two -> succeed
userCR.setRealm("/even/two");
Response response = delegatedUserService.create(userCR);
assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
UserTO user = response.readEntity(new GenericType<ProvisioningResult<UserTO>>() {
}).getEntity();
assertEquals("surname", user.getPlainAttr("surname").get().getValues().get(0));
// 5. as delegated, update user attempting to move under realm / -> fail
UserUR userUR = new UserUR();
userUR.setKey(user.getKey());
userUR.setRealm(new StringReplacePatchItem.Builder().value("/odd").build());
userUR.getPlainAttrs().add(attrAddReplacePatch("surname", "surname2"));
try {
delegatedUserService.update(userUR);
fail("This should not happen");
} catch (SyncopeClientException e) {
assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
}
// 6. revert realm change -> succeed
userUR.setRealm(null);
response = delegatedUserService.update(userUR);
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
user = response.readEntity(new GenericType<ProvisioningResult<UserTO>>() {
}).getEntity();
assertEquals("surname2", user.getPlainAttr("surname").get().getValues().get(0));
// 7. as delegated, delete user
delegatedUserService.delete(user.getKey());
try {
userService.read(user.getKey());
fail("This should not happen");
} catch (SyncopeClientException e) {
assertEquals(ClientExceptionType.NotFound, e.getType());
}
} finally {
if (roleKey != null) {
roleService.delete(roleKey);
}
if (delegatedAdminKey != null) {
userService.delete(delegatedAdminKey);
}
}
}
@Test
public void checkFailedLogins() {
UserCR userCR = UserITCase.getUniqueSample("checkFailedLogin@syncope.apache.org");
userCR.getRoles().add("User manager");
UserTO userTO = createUser(userCR).getEntity();
assertNotNull(userTO);
String userKey = userTO.getKey();
UserService userService2 = clientFactory.create(userTO.getUsername(), "password123").
getService(UserService.class);
assertEquals(0, getFailedLogins(userService2, userKey));
// authentications failed ...
try {
clientFactory.create(userTO.getUsername(), "wrongpwd1");
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e);
}
try {
clientFactory.create(userTO.getUsername(), "wrongpwd1");
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e);
}
assertEquals(2, getFailedLogins(userService, userKey));
UserService userService4 = clientFactory.create(userTO.getUsername(), "password123").
getService(UserService.class);
assertEquals(0, getFailedLogins(userService4, userKey));
}
@Test
public void checkUserSuspension() {
UserCR userCR = UserITCase.getUniqueSample("checkSuspension@syncope.apache.org");
userCR.setRealm("/odd");
userCR.getRoles().add("User manager");
UserTO userTO = createUser(userCR).getEntity();
String userKey = userTO.getKey();
assertNotNull(userTO);
assertEquals(0, getFailedLogins(userService, userKey));
// authentications failed ...
try {
clientFactory.create(userTO.getUsername(), "wrongpwd1");
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e);
}
try {
clientFactory.create(userTO.getUsername(), "wrongpwd1");
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e);
}
try {
clientFactory.create(userTO.getUsername(), "wrongpwd1");
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e);
}
assertEquals(3, getFailedLogins(userService, userKey));
// last authentication before suspension
try {
clientFactory.create(userTO.getUsername(), "wrongpwd1");
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e);
}
userTO = userService.read(userTO.getKey());
assertNotNull(userTO);
assertNotNull(userTO.getFailedLogins());
assertEquals(3, userTO.getFailedLogins().intValue());
assertEquals("suspended", userTO.getStatus());
// Access with correct credentials should fail as user is suspended
try {
clientFactory.create(userTO.getUsername(), "password123");
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e);
}
StatusR reactivate = new StatusR.Builder().key(userTO.getKey()).
type(StatusRType.REACTIVATE).build();
userTO = userService.status(reactivate).readEntity(new GenericType<ProvisioningResult<UserTO>>() {
}).getEntity();
assertNotNull(userTO);
assertEquals("active", userTO.getStatus());
SyncopeClient goodPwdClient = clientFactory.create(userTO.getUsername(), "password123");
assertEquals(0, goodPwdClient.self().getRight().getFailedLogins().intValue());
}
@Test
public void anyTypeEntitlement() {
String anyTypeKey = "FOLDER " + getUUIDString();
// 1. no entitlement exists (yet) for the any type to be created
assertFalse(syncopeService.platform().getEntitlements().stream().
anyMatch(entitlement -> entitlement.contains(anyTypeKey)));
// 2. create plain schema, any type class and any type
PlainSchemaTO path = new PlainSchemaTO();
path.setKey("path" + getUUIDString());
path.setType(AttrSchemaType.String);
path = createSchema(SchemaType.PLAIN, path);
AnyTypeClassTO anyTypeClass = new AnyTypeClassTO();
anyTypeClass.setKey("folder" + getUUIDString());
anyTypeClass.getPlainSchemas().add(path.getKey());
anyTypeClassService.create(anyTypeClass);
AnyTypeTO anyTypeTO = new AnyTypeTO();
anyTypeTO.setKey(anyTypeKey);
anyTypeTO.setKind(AnyTypeKind.ANY_OBJECT);
anyTypeTO.getClasses().add(anyTypeClass.getKey());
anyTypeService.create(anyTypeTO);
// 2. now entitlement exists for the any type just created
assertTrue(syncopeService.platform().getEntitlements().stream().
anyMatch(entitlement -> entitlement.contains(anyTypeKey)));
// 3. attempt to create an instance of the type above: fail because no entitlement was assigned
AnyObjectCR folder = new AnyObjectCR();
folder.setName("home");
folder.setRealm(SyncopeConstants.ROOT_REALM);
folder.setType(anyTypeKey);
folder.getPlainAttrs().add(attr(path.getKey(), "/home"));
SyncopeClient belliniClient = clientFactory.create("bellini", ADMIN_PWD);
try {
belliniClient.getService(AnyObjectService.class).create(folder);
fail("This should not happen");
} catch (SyncopeClientException e) {
assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
}
// 4. give create entitlement for the any type just created
RoleTO role = new RoleTO();
role.setKey("role" + getUUIDString());
role.getRealms().add(SyncopeConstants.ROOT_REALM);
role.getEntitlements().add(anyTypeKey + "_READ");
role.getEntitlements().add(anyTypeKey + "_CREATE");
role = createRole(role);
UserTO bellini = userService.read("bellini");
UserUR req = new UserUR();
req.setKey(bellini.getKey());
req.getRoles().add(new StringPatchItem.Builder().
operation(PatchOperation.ADD_REPLACE).value(role.getKey()).build());
bellini = updateUser(req).getEntity();
assertTrue(bellini.getRoles().contains(role.getKey()));
// 5. now the instance of the type above can be created successfully
belliniClient.logout();
belliniClient.login(new BasicAuthenticationHandler("bellini", ADMIN_PWD));
belliniClient.getService(AnyObjectService.class).create(folder);
}
@Test
public void asGroupOwner() {
// 0. prepare
UserTO owner = createUser(UserITCase.getUniqueSample("owner@syncope.org")).getEntity();
assertNotNull(owner);
GroupCR groupCR = GroupITCase.getSample("forgroupownership");
groupCR.setUserOwner(owner.getKey());
GroupTO group = createGroup(groupCR).getEntity();
assertNotNull(group);
assertEquals(owner.getKey(), group.getUserOwner());
UserCR memberCR = UserITCase.getUniqueSample("forgroupownership@syncope.org");
memberCR.getMemberships().add(new MembershipTO.Builder(group.getKey()).build());
memberCR.getMemberships().add(new MembershipTO.Builder("37d15e4c-cdc1-460b-a591-8505c8133806").build());
UserTO member = createUser(memberCR).getEntity();
assertEquals(2, member.getMemberships().size());
String memberKey = member.getKey();
if (ElasticsearchDetector.isElasticSearchEnabled(syncopeService)) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
// ignore
}
}
PagedResult<UserTO> matching = userService.search(
new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
fiql(SyncopeClient.getUserSearchConditionBuilder().inGroups(group.getKey()).query()).
page(1).size(1000).build());
int fullMatchSize = matching.getResult().size();
assertTrue(matching.getResult().stream().anyMatch(user -> memberKey.equals(user.getKey())));
UserService groupOwnerService = clientFactory.create(owner.getUsername(), "password123").
getService(UserService.class);
// 1. search
matching = groupOwnerService.search(
new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
fiql(SyncopeClient.getUserSearchConditionBuilder().isNotNull("key").query()).
page(1).size(1000).build());
assertEquals(fullMatchSize, matching.getResult().size());
assertTrue(matching.getResult().stream().anyMatch(user -> memberKey.equals(user.getKey())));
// 2. update and read
UserUR memberUR = new UserUR();
memberUR.setKey(memberKey);
memberUR.setUsername(new StringReplacePatchItem.Builder().value("new" + getUUIDString()).build());
Response response = groupOwnerService.update(memberUR);
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
member = groupOwnerService.read(memberKey);
assertEquals(memberUR.getUsername().getValue(), member.getUsername());
assertEquals(2, member.getMemberships().size());
// 3. update with membership removal -> fail
memberUR.setUsername(null);
memberUR.getMemberships().add(new MembershipUR.Builder(group.getKey()).
operation(PatchOperation.DELETE).build());
try {
groupOwnerService.update(memberUR);
fail();
} catch (SyncopeClientException e) {
assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
}
// 4. update non-member -> fail
UserTO nonmember = createUser(UserITCase.getUniqueSample("nonmember@syncope.org")).getEntity();
UserUR nonmemberUR = new UserUR();
nonmemberUR.setKey(nonmember.getKey());
nonmemberUR.setUsername(new StringReplacePatchItem.Builder().value("new" + getUUIDString()).build());
try {
groupOwnerService.update(nonmemberUR);
fail();
} catch (SyncopeClientException e) {
assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
}
// 5. update user under /even
memberCR = UserITCase.getUniqueSample("forgroupownership2@syncope.org");
memberCR.setRealm("/even");
memberCR.getMemberships().add(new MembershipTO.Builder(group.getKey()).build());
member = createUser(memberCR).getEntity();
memberUR = new UserUR();
memberUR.setKey(member.getKey());
memberUR.setUsername(new StringReplacePatchItem.Builder().value("new" + getUUIDString()).build());
response = groupOwnerService.update(memberUR);
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
// 6 delete
groupOwnerService.delete(memberKey);
try {
userService.read(memberKey);
fail();
} catch (SyncopeClientException e) {
assertEquals(ClientExceptionType.NotFound, e.getType());
}
}
@Test
public void issueSYNCOPE434() {
assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(syncopeService));
// 1. create user with group 'groupForWorkflowApproval'
// (users with group groupForWorkflowApproval are defined in workflow as subject to approval)
UserCR userCR = UserITCase.getUniqueSample("createWithReject@syncope.apache.org");
userCR.getMemberships().add(new MembershipTO.Builder("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
UserTO userTO = createUser(userCR).getEntity();
assertNotNull(userTO);
assertEquals("createApproval", userTO.getStatus());
// 2. try to authenticate: fail
try {
clientFactory.create(userTO.getUsername(), "password123").self();
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e);
}
// 3. approve user
UserRequestForm form = userRequestService.listForms(
new UserRequestQuery.Builder().user(userTO.getKey()).build()).getResult().get(0);
form = userRequestService.claimForm(form.getTaskId());
form.getProperty("approveCreate").get().setValue(Boolean.TRUE.toString());
userTO = userRequestService.submitForm(form).readEntity(new GenericType<ProvisioningResult<UserTO>>() {
}).getEntity();
assertNotNull(userTO);
assertEquals("active", userTO.getStatus());
// 4. try to authenticate again: success
Triple<Map<String, Set<String>>, List<String>, UserTO> self =
clientFactory.create(userTO.getUsername(), "password123").self();
assertNotNull(self);
assertNotNull(self.getLeft());
assertEquals(List.of(), self.getMiddle());
assertNotNull(self.getRight());
}
@Test
public void issueSYNCOPE164() throws Exception {
// 1. create user with db resource
UserCR userCR = UserITCase.getUniqueSample("syncope164@syncope.apache.org");
userCR.setRealm("/even/two");
userCR.setPassword("password123");
userCR.getResources().add(RESOURCE_NAME_TESTDB);
UserTO user = createUser(userCR).getEntity();
assertNotNull(user);
// 2. unlink the resource from the created user
ResourceDR resourceDR = new ResourceDR.Builder().key(user.getKey()).
action(ResourceDeassociationAction.UNLINK).resource(RESOURCE_NAME_TESTDB).build();
assertNotNull(parseBatchResponse(userService.deassociate(resourceDR)));
// 3. change password on Syncope
UserUR userUR = new UserUR();
userUR.setKey(user.getKey());
userUR.setPassword(new PasswordPatch.Builder().value("password234").build());
user = updateUser(userUR).getEntity();
assertNotNull(user);
// 4. check that the db resource has still the initial password value
JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
String value = queryForObject(jdbcTemplate, MAX_WAIT_SECONDS,
"SELECT PASSWORD FROM test WHERE ID=?", String.class, user.getUsername());
assertEquals(Encryptor.getInstance().encode("password123", CipherAlgorithm.SHA1), value.toUpperCase());
// 5. successfully authenticate with old (on db resource) and new (on internal storage) password values
Triple<Map<String, Set<String>>, List<String>, UserTO> self =
clientFactory.create(user.getUsername(), "password123").self();
assertNotNull(self);
self = clientFactory.create(user.getUsername(), "password234").self();
assertNotNull(self);
}
@Test
public void issueSYNCOPE706() {
String username = getUUIDString();
try {
userService.read(username);
fail("This should not happen");
} catch (SyncopeClientException e) {
assertEquals(ClientExceptionType.NotFound, e.getType());
}
try {
clientFactory.create(username, "anypassword").self();
fail("This should not happen");
} catch (AccessControlException e) {
assertNotNull(e.getMessage());
}
}
}