# Importing users and their entitlement memberships

OpenIAM **does not allow**, by default, importing both users and the list of entitlements in one process. You must first:

* Import your entitlements.
* Import users + their entitlements.

The [importing entitlements](/application-onboarding/importing-entitlements.md) section showed how to configure synchronization and import entitlements to OpenIAM, covering step one of the whole process. In this document, the issue of importing users + their entitlement memberships is covered.

{% stepper %}
{% step %}

### **Go to Webconsole > Provisioning > Synchronization.**

The synchronization page contains ready-made examples of synchronization for various objects. **If you are new to OpenIAM, then please leverage these examples instead of creating a new configuration.** The example template for users + entitlement memberships is called *CSV USER Entitlements Sync Example*. You can find it by entering its name in a search line in the synchronization page.

In case you want to configure synchronization from scratch, use the steps described [here](/application-onboarding/importing-entitlements.md).
{% endstep %}

{% step %}

### Fill in the fields

Fill in the fields as described in the referenced document except:

* *Synchronization source* must be CSV file.
* *Synchronization object* field must be *User*.

Select the **Validation rule** and **Transformation rule** fields to use Groovy scripts. Sample validation and transformation scripts for importing users and entitlements are given below.
{% endstep %}
{% endstepper %}

Upon completing the fields, synchronization is **ready to run**.

## Transformation scripts

Transformation scripts are aimed at helping map the data you're loading into OpenIAM, such as deleting an unneeded attribute, overwriting an existing attribute, modifying attributes, or creating new attributes. In other words, they take attributes from the source and map them to objects in OpenIAM to create a user profile.

As mentioned earlier, these scripts are vital for a successful mapping. Below, you can find some transformation scripts used in OpenIAM. You can take the ready-made script and, after amending it, apply it to meet your mapping needs.

### Sample transformation script for a CSV file

#### CSV file structure example

For the script to work correctly, make sure the fields in the CSV file are the same as written in the transformation script. An example of the CSV file structure for importing users and entitlements is given below.

```csv
USER_NAME,APPLICATION,TYPE,ENTITLEMENT_NAME
test.user,ManagedSystemName,GROUP,GroupName
test.user,ManagedSystemName,ROLE,RoleName
```

#### Transformation script example

The text for transformation script (with comments) to get users and entitlements via CSV file for manual applications is provided below.

{% code lineNumbers="true" expandable="true" %}

```groovy
import org.apache.commons.collections.CollectionUtils
import org.openiam.base.request.BaseSearchServiceRequest
import org.openiam.base.response.list.ManagedSysListResponse
import org.openiam.base.ws.MatchType
import org.openiam.base.ws.SearchParam
import org.openiam.common.beans.mq.GroupRabbitMQService
import org.openiam.common.beans.mq.RabbitMQSender
import org.openiam.common.beans.mq.RoleRabbitMQService
import org.openiam.idm.searchbeans.GroupSearchBean
import org.openiam.idm.searchbeans.ManagedSysSearchBean
import org.openiam.idm.searchbeans.RoleSearchBean
import org.openiam.idm.srvc.mngsys.dto.ManagedSysDto
import org.openiam.idm.srvc.role.dto.Role
import org.openiam.idm.srvc.synch.dto.LineObject
import org.openiam.mq.constants.api.idm.ManagedSystemAPI
import org.openiam.mq.constants.queue.idm.ManagedSysQueue
import org.openiam.provision.dto.ProvisionUser
import org.openiam.sync.service.TransformScript
import org.openiam.sync.service.impl.service.AbstractUserTransformScript
import org.springframework.context.ApplicationContext

class CsvUserEntitlementsTransformationScript extends AbstractUserTransformScript {

    private ApplicationContext context

    /**
     * The main execution method that performs the transformation.
     * @param rowObj The line object representing a row in the CSV file.
     * @param pUser The ProvisionUser object to be transformed.
     * @return The status code indicating the outcome of the transformation.
     */
    @Override
    int execute(LineObject rowObj, ProvisionUser pUser) {
        println "** - Transformation script called."
        
        // If it's not a new user, populate the ProvisionUser object with data from the CSV row.
        if (!isNewUser) {
            try {
                populateObject(rowObj, pUser)
            } catch (Exception ex) {
                ex.printStackTrace();
                println "** - Transformation script error."
                return -1
            }
        } else {
            println("User not found in the system!")
            return TransformScript.SKIP
        }

        println "** - Transformation script completed."

        pUser.setSkipPreprocessor(false)
        pUser.setSkipPostProcessor(false)

        return TransformScript.NO_DELETE
    }

    /**
     * Populates the ProvisionUser object with entitlement data from the CSV row.
     * @param rowObj The line object representing a row in the CSV file.
     * @param pUser The ProvisionUser object to be populated.
     */
    private void populateObject(LineObject rowObj, ProvisionUser pUser) {
        def columnMap = rowObj.columnMap
        def manSys = columnMap.get("APPLICATION")?.value
        def type = columnMap.get("TYPE")?.value
        def name = columnMap.get("ENTITLEMENT_NAME")?.value
        
        // Get the ManagedSysDto object based on the application name.
        ManagedSysDto dto = getManagedSystemByName(manSys)
        
        if (dto) {
            // If the entitlement type is "GROUP", add the group to the ProvisionUser object.
            if ("GROUP".equals(type)) {
                addGroup(pUser, name, dto.getId())
            }
            // If the entitlement type is "ROLE", add the role to the ProvisionUser object.
            else if ("ROLE".equals(type)) {
                addRole(pUser, name, dto.getId())
            }
        }
    }

    /**
     * Adds a group to the ProvisionUser object.
     * @param pUser The ProvisionUser object.
     * @param groupName The name of the group to be added.
     * @param managedSysId The ID of the ManagedSysDto object.
     */
    def addGroup(ProvisionUser pUser, String groupName, String managedSysId) {
        println "Start addGroup function"
        
        // Get the GroupRabbitMQService bean from the application context.
        GroupRabbitMQService groupWS = (GroupRabbitMQService) context.getBean(GroupRabbitMQService.class)
        
        GroupSearchBean groupSearchBean = new GroupSearchBean()
        groupSearchBean.setNameToken(new SearchParam(groupName, MatchType.EXACT))
        groupSearchBean.addManagedSystemId(managedSysId)
        
        // Find the group bean based on the search criteria.
        def groups = groupWS.findBeans(groupSearchBean, 0, 1)
        
        if (groups) {
            // Add the group to the ProvisionUser object.
            pUser.addGroup(groups.first(), new HashSet<String>(), null, null)
        }
    }

    /**
     * Adds a role to the ProvisionUser object.
     * @param pUser The ProvisionUser object.
     * @param roleName The name of the role to be added.
     * @param managedSysId The ID of the ManagedSysDto object.
     */
    def addRole(ProvisionUser pUser, String roleName, String managedSysId) {
        println "Start addRole function"
        
        // Get the RoleRabbitMQService bean from the application context.
        def roleDataService = context?.getBean(RoleRabbitMQService.class) as RoleRabbitMQService
        
        RoleSearchBean roleSearchBean = new RoleSearchBean()
        roleSearchBean.setDeepCopy(false)
        roleSearchBean.setNameToken(new SearchParam(roleName, MatchType.EXACT))
        roleSearchBean.addManagedSystemId(managedSysId)
        
        // Find the role bean based on the search criteria.
        def roles = roleDataService.findBeans(roleSearchBean, 0, 1)
        
        Role role = null
        if (roles != null && roles.size() > 0) {
            role = roles.get(0)
        }
        
        if (role) {
            // Add the role to the ProvisionUser object.
            pUser.addRole(role, null, null, null)
        } else {
            println "Role with name " + roleName + " was not found"
        }
    }

    @Override
    void init() {}
```

{% endcode %}

### Sample transformation script for AD users and group memberships

The text for transformation script (with comments) to get users and their group memberships for Active Directory instances with a connector is given below.

{% code lineNumbers="true" expandable="true" %}

```groovy
import org.openiam.base.AttributeOperationEnum
import org.openiam.idm.searchbeans.GroupSearchBean
import org.openiam.idm.srvc.auth.dto.Login
import org.openiam.idm.srvc.continfo.dto.EmailAddress
import org.openiam.idm.srvc.synch.dto.LineObject
import org.openiam.idm.srvc.user.dto.UserStatusEnum
import org.openiam.provision.dto.ProvisionUser
import org.openiam.provision.type.Attribute
import org.openiam.idm.srvc.grp.dto.Group
import org.apache.commons.collections.CollectionUtils
import org.openiam.sync.service.impl.service.AbstractUserTransformScript

public class ADPowerShellTransformation extends AbstractUserTransformScript {

    @Override
    int execute(LineObject rowObj, ProvisionUser pUser) {
        populateObject(rowObj, pUser)
        pUser.status = UserStatusEnum.ACTIVE
        pUser.mdTypeId = "DEFAULT_USER"
        // Add default role
        addUserRoleByName(pUser, "End User", null, null, null, null, null)
        pUser.setSkipPreprocessor(false)
        pUser.setSkipPostProcessor(false)
        return NO_DELETE
    }

    @Override
    void init() {}

    private void populateObject(LineObject rowObj, ProvisionUser pUser) {

        def attrVal
        Map<String, Attribute> columnMap = rowObj.columnMap
        /*  for (Map.Entry<String, Attribute> entry : columnMap.entrySet()) {
              addAttribute(pUser, entry.value)
          }*/

        attrVal = columnMap.get("Name")
        if (attrVal) {
            addUserAttribute(pUser, attrVal.getName(), attrVal.getValue())
        }

        attrVal = columnMap.get("GivenName")
        if (attrVal) {
            pUser.firstName = attrVal.value
        }

        attrVal = columnMap.get("Surname")
        if (attrVal) {
            pUser.middleInit = attrVal.value
        }

        attrVal = columnMap.get("DisplayName")
        if (attrVal) {
            pUser.setNickname(attrVal?.value);
        }

        attrVal = columnMap.get("Surname")
        if (attrVal) {
            pUser.lastName = attrVal.value
        }

        //uncomment this line to send email notification to the user
        /* if(isNewUser){
            pUser.emailCredentialsToNewUsers = true;
        }*/

        def memberOf = columnMap.get("memberOf");
        if (memberOf) {
            final Set<String> groupSet = new HashSet<>();

            if (memberOf.isMultiValued()) {
                groupSet.addAll(memberOf.getValueList());
            } else {
                groupSet.add(memberOf.getValue());
            }

            for (String dn : groupSet) {
                addUserGroupByAttribute(pUser, "DistinguishedName", dn, CERTIFIED_RIGHT_SET, null, null, null);
            }
        }

        List<Group> currentGroups = new ArrayList<>();

        if (pUser.getId()) {
            final Set<String> usrIds = new HashSet<>();
            usrIds.add(pUser.getId());
            final GroupSearchBean gsb = new GroupSearchBean();
            gsb.setUserIdSet(usrIds);
            gsb.setMetadataTypes(Set.of("AD_GROUP"));
            currentGroups = groupRabbitMQService.findBeans(gsb, null, 0, Integer.MAX_VALUE);
        }

        if (CollectionUtils.isNotEmpty(currentGroups)) {  
            currentGroups.forEach{ Group current ->
                if (pUser.getGroup(current.getId()) && (pUser.getGroup(current.getId()).getOperation() == AttributeOperationEnum.NO_CHANGE ||
                        //if rights are not empty - it means user either admin or owner selected for the access certification
                        CollectionUtils.isEmpty(pUser.getGroup(current.getId()).getRights())) && pUser.getGroup(current.getId()).getEndDate() == null) {
                    println("Removing group: " + current.getName());
                    pUser.removeGroup(current);
                }
            }
        }
    

        attrVal = columnMap.get("EmailAddress")
        if (!attrVal) {
            attrVal = columnMap.get("UserPrincipalName")
        }

        if (attrVal) {
            // Processing email address
            addUserAttribute(pUser, attrVal.getName(), attrVal.getValue())
            def emailAddress = new EmailAddress()
            emailAddress.name = "PRIMARY_EMAIL"
            emailAddress.default = true
            emailAddress.active = true
            emailAddress.emailAddress = attrVal.value
            emailAddress.mdTypeId = "PRIMARY_EMAIL"
            addUserEmailAddress(pUser, emailAddress)
        }

        attrVal = columnMap.get(config.getMatchSrcFieldName())

        if (isNewUser) {

            //attrVal = columnMap.get("sAMAccountName")
            if (attrVal) {


                // PRE-POPULATE THE USER LOGIN. IN SOME CASES THE COMPANY WANTS
                // TO KEEP THE LOGIN THAT THEY HAVE
                // THIS SHOWS HOW WE CAN DO THAT

                def lg = new Login()
                lg.operation = AttributeOperationEnum.ADD
                lg.login = attrVal.value
                lg.managedSysId = "0"
                lg.setActive(true)
                pUser.principalList.add(lg)

                /*Login lg2 = new Login()
                lg2.operation = AttributeOperationEnum.ADD
                lg2.login = attrVal.value
                lg2.managedSysId = config.getManagedSysId()
                lg2.setActive(true)
                pUser.principalList.add(lg2)*/

            }
        }
    }


}
```

{% endcode %}

}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs-beta.openiam.com/application-onboarding/importing-users-and-their-entitlement-memberships.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
