| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.syncope.core.provisioning.java; |
| |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertNotEquals; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| |
| import java.util.List; |
| import java.util.Set; |
| import org.apache.commons.lang3.tuple.Pair; |
| import org.apache.syncope.common.lib.types.AnyTypeKind; |
| import org.apache.syncope.common.lib.types.CipherAlgorithm; |
| import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO; |
| import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; |
| import org.apache.syncope.core.persistence.api.dao.GroupDAO; |
| import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO; |
| import org.apache.syncope.core.persistence.api.dao.RealmDAO; |
| import org.apache.syncope.core.persistence.api.dao.UserDAO; |
| import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; |
| import org.apache.syncope.core.persistence.api.entity.EntityFactory; |
| import org.apache.syncope.core.persistence.api.entity.group.Group; |
| import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; |
| import org.apache.syncope.core.persistence.api.entity.resource.Provision; |
| import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount; |
| import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership; |
| import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr; |
| import org.apache.syncope.core.persistence.api.entity.user.User; |
| import org.apache.syncope.core.provisioning.api.MappingManager; |
| import org.identityconnectors.common.security.SecurityUtil; |
| import org.identityconnectors.framework.common.objects.Attribute; |
| import org.identityconnectors.framework.common.objects.AttributeUtil; |
| import org.junit.jupiter.api.Test; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.transaction.annotation.Transactional; |
| import org.identityconnectors.framework.common.objects.OperationalAttributes; |
| |
| @Transactional("Master") |
| public class DefaultMappingManagerTest extends AbstractTest { |
| |
| @Autowired |
| private MappingManager mappingManager; |
| |
| @Autowired |
| private UserDAO userDAO; |
| |
| @Autowired |
| private ExternalResourceDAO resourceDAO; |
| |
| @Autowired |
| private RealmDAO realmDAO; |
| |
| @Autowired |
| private GroupDAO groupDAO; |
| |
| @Autowired |
| private AnyTypeClassDAO anyTypeClassDAO; |
| |
| @Autowired |
| private PlainSchemaDAO plainSchemaDAO; |
| |
| @Autowired |
| private AnyUtilsFactory anyUtilsFactory; |
| |
| @Autowired |
| private EntityFactory entityFactory; |
| |
| @Test |
| public void prepareAttrsForUser() { |
| User bellini = userDAO.findByUsername("bellini"); |
| ExternalResource ldap = resourceDAO.find("resource-ldap"); |
| Provision provision = ldap.getProvision(AnyTypeKind.USER.name()).get(); |
| |
| assertNotEquals(CipherAlgorithm.AES, bellini.getCipherAlgorithm()); |
| |
| // 1. with clear-text password |
| Pair<String, Set<Attribute>> attrs = mappingManager.prepareAttrsFromAny( |
| bellini, |
| "Password123", |
| true, |
| Boolean.TRUE, |
| provision); |
| assertEquals("bellini", attrs.getLeft()); |
| assertEquals( |
| "uid=bellini,ou=people,o=isp", |
| AttributeUtil.getNameFromAttributes(attrs.getRight()).getNameValue()); |
| assertEquals("Password123", SecurityUtil.decrypt(AttributeUtil.getPasswordValue(attrs.getRight()))); |
| |
| // 2. with changePwd == false |
| attrs = mappingManager.prepareAttrsFromAny( |
| bellini, |
| "Password123", |
| false, |
| Boolean.TRUE, |
| provision); |
| assertNull(AttributeUtil.getPasswordValue(attrs.getRight())); |
| |
| // 3. with no clear-text password but random password generation enabled |
| ldap.setRandomPwdIfNotProvided(true); |
| ldap = resourceDAO.save(ldap); |
| entityManager().flush(); |
| |
| String encPassword = bellini.getPassword(); |
| attrs = mappingManager.prepareAttrsFromAny( |
| bellini, |
| null, |
| true, |
| Boolean.TRUE, |
| provision); |
| assertNotEquals(encPassword, SecurityUtil.decrypt(AttributeUtil.getPasswordValue(attrs.getRight()))); |
| |
| // 4. with no clear-text password and random password generation disabled |
| ldap.setRandomPwdIfNotProvided(false); |
| resourceDAO.save(ldap); |
| entityManager().flush(); |
| |
| attrs = mappingManager.prepareAttrsFromAny( |
| bellini, |
| null, |
| true, |
| Boolean.TRUE, |
| provision); |
| assertNull(AttributeUtil.getPasswordValue(attrs.getRight())); |
| |
| // 5. with no clear-text password, random password generation disabled but AES |
| bellini.setPassword("newPassword123", CipherAlgorithm.AES); |
| userDAO.save(bellini); |
| entityManager().flush(); |
| |
| assertEquals(CipherAlgorithm.AES, bellini.getCipherAlgorithm()); |
| |
| attrs = mappingManager.prepareAttrsFromAny( |
| bellini, |
| null, |
| true, |
| Boolean.TRUE, |
| provision); |
| assertEquals("newPassword123", SecurityUtil.decrypt(AttributeUtil.getPasswordValue(attrs.getRight()))); |
| } |
| |
| @Test |
| public void prepareAttrsForLinkedAccount() { |
| User vivaldi = userDAO.findByUsername("vivaldi"); |
| ExternalResource ldap = resourceDAO.find("resource-ldap"); |
| Provision provision = ldap.getProvision(AnyTypeKind.USER.name()).get(); |
| |
| LinkedAccount account = entityFactory.newEntity(LinkedAccount.class); |
| account.setConnObjectKeyValue("admin"); |
| account.setResource(ldap); |
| account.setOwner(vivaldi); |
| account.setSuspended(Boolean.FALSE); |
| account.setPassword("Password321", CipherAlgorithm.AES); |
| vivaldi.add(account); |
| |
| vivaldi = userDAO.save(vivaldi); |
| entityManager().flush(); |
| |
| // 1. with account password and clear-text default password |
| Set<Attribute> attrs = mappingManager.prepareAttrsFromLinkedAccount( |
| vivaldi, |
| account, |
| "Password123", |
| true, |
| provision); |
| assertEquals("admin", AttributeUtil.getStringValue(AttributeUtil.find("cn", attrs))); |
| assertEquals("Password321", SecurityUtil.decrypt(AttributeUtil.getPasswordValue(attrs))); |
| assertTrue(AttributeUtil.getBooleanValue(AttributeUtil.find(OperationalAttributes.ENABLE_NAME, attrs))); |
| |
| // 2. without account password and clear-text default password |
| account.setEncodedPassword(null, null); |
| |
| attrs = mappingManager.prepareAttrsFromLinkedAccount( |
| vivaldi, |
| account, |
| "Password123", |
| true, |
| provision); |
| assertEquals("Password123", SecurityUtil.decrypt(AttributeUtil.getPasswordValue(attrs))); |
| |
| // 3. with changePwd == false |
| attrs = mappingManager.prepareAttrsFromLinkedAccount( |
| vivaldi, |
| account, |
| "Password123", |
| false, |
| provision); |
| assertNull(AttributeUtil.getPasswordValue(attrs)); |
| |
| // 4. without account password, no clear-text password but random password generation enabled |
| ldap.setRandomPwdIfNotProvided(true); |
| ldap = resourceDAO.save(ldap); |
| entityManager().flush(); |
| |
| String encPassword = vivaldi.getPassword(); |
| attrs = mappingManager.prepareAttrsFromLinkedAccount( |
| vivaldi, |
| account, |
| null, |
| true, |
| provision); |
| assertNotEquals(encPassword, SecurityUtil.decrypt(AttributeUtil.getPasswordValue(attrs))); |
| |
| // 5. without account password, no clear-text password and random password generation disabled |
| ldap.setRandomPwdIfNotProvided(false); |
| resourceDAO.save(ldap); |
| entityManager().flush(); |
| |
| attrs = mappingManager.prepareAttrsFromLinkedAccount( |
| vivaldi, |
| account, |
| null, |
| true, |
| provision); |
| assertNull(AttributeUtil.getPasswordValue(attrs)); |
| } |
| |
| @Test |
| public void issueSYNCOPE1583() { |
| // 0. create user matching the condition below |
| User user = entityFactory.newEntity(User.class); |
| user.setUsername("username"); |
| user.setRealm(realmDAO.findByFullPath("/even/two")); |
| user.add(anyTypeClassDAO.find("other")); |
| |
| UPlainAttr cool = entityFactory.newEntity(UPlainAttr.class); |
| cool.setOwner(user); |
| cool.setSchema(plainSchemaDAO.find("cool")); |
| cool.add("true", anyUtilsFactory.getInstance(AnyTypeKind.USER)); |
| user.add(cool); |
| |
| user = userDAO.save(user); |
| String newUserKey = user.getKey(); |
| assertNotNull(newUserKey); |
| |
| // 1. update group with dynamic membership |
| Group group = groupDAO.findByName("root"); |
| assertNotNull(group); |
| |
| UDynGroupMembership dynMembership = entityFactory.newEntity(UDynGroupMembership.class); |
| dynMembership.setFIQLCond("cool==true"); |
| dynMembership.setGroup(group); |
| group.setUDynMembership(dynMembership); |
| |
| group = groupDAO.saveAndRefreshDynMemberships(group); |
| assertNotNull(group); |
| |
| entityManager().flush(); |
| |
| // 2. verify that dynamic membership is in place |
| assertTrue(userDAO.findAllGroupKeys(user).contains(group.getKey())); |
| |
| // 3. check propagation attrs |
| ExternalResource csv = resourceDAO.find("resource-csv"); |
| Provision provision = csv.getProvision(AnyTypeKind.USER.name()).get(); |
| assertNotNull(provision); |
| |
| Pair<String, Set<Attribute>> attrs = mappingManager.prepareAttrsFromAny( |
| user, |
| null, |
| false, |
| Boolean.TRUE, |
| provision); |
| assertTrue(attrs.getRight().stream().anyMatch( |
| attr -> "theirgroup".equals(attr.getName()) && List.of("sx-dx").equals(attr.getValue()))); |
| } |
| } |