Introduction:
In this blog post, I will be sharing a scenario which I have implemented to update an employee to AD using the LDAP Search and Modify Operations.
Scenario:
I will be getting data from an API. From that data,
- All the Active employees should be updated to AD.
- All the Terminated employees should be disabled in AD and their respective manager name should be removed.
- If an employee state is missing, I must raise a mail to the HR.
Prerequisites:
Cloud Connector: As AD which used here is an On-Premise system, we must establish a connectivity to CPI Tenant using SAP Cloud Connector.
Once the Cloud Connector part is done, we can start the development in CPI.
Design:
I have used Process Calls in the Integration for better readability and error handling.
Main Integration:
- Used Content Modifier as a Source for this Integration Process for testing.
- Used Parallel Multicast to share the same incoming data to all the Process Calls
1. Process Call: Active
- As a first step, Filtered the incoming records to check the employee_status = ‘Active’.
- Content Modifier to Add the root node after filter step as it removes the root.
- General Splitter to separate the records as AD accepts only one record at a time for Updating.
- Content Modifier to store the incoming attributes in Header as the structure is getting changed after the Request-Reply step. [These Header names will be used in the subsequent steps for performing the Search operation and in Updating the AD]
- Router is used because, Manager attribute for few employees is empty in the payload and AD will not accept a Manager if empty.
So, used router to separate the incoming payload
- Default route will used for records with Manager name.
- Route 1 will be for the records with no Manager name.
I. Default Route:
- Once the record is having Manager name, we need to get the Manager distinguishedName from AD as the manager name will be his DN in AD.
- To achieve this, I have performed Search Operation to get the Manager distinguishedName from AD using his name coming in the payload.
- For this we are using Request-Reply [1] with LDAP Adaptor.
Address: Provide the Virtual address what you have provided in the Cloud Connector.
Proxy Type: On-Premise
Authentication: Simple
Credential Name: Name what you gave to store the credentials in Security Material.
Operation: Search
Base DN: Entity from where you will begin the search.
Search Filter: Criteria which should qualify to fulfil the search.
Attribute: Here we are getting distinguishedName.
- XSLT to remove extra header information.
- Content Modifier to catch the Manager distinguishedName into header using XPATH.
- Request-Reply [2] to get the Employee Distinguished Name from AD as we need to pass the DN as reference for the employee to AD to make sure the right record gets updated.
- For this step, I have performed the same search operation what we did in the above step to get the Manager distinguishedName but changed the (cn=${header.display_name}).
- Content Modifier to catch the Employee distinguishedName into header using XPATH.
- Java Script to map the attributes as per the AD Structure.
importClass(com.sap.gateway.ip.core.customdev.util.Message);
importClass(java.util.HashMap);
importClass(javax.naming.directory.Attribute);
importClass(javax.naming.directory.BasicAttribute);
importClass(javax.naming.directory.BasicAttributes);
importClass(javax.naming.directory.Attributes);
function processData(message) {
var body = message.getBody();
var pMap=message.getHeaders();
var employeeNumber = pMap.get("employee_number");
var displayName = pMap.get("display_name");
var department = pMap.get("department");
var TelephoneNumber = pMap.get("business_phone");
var Company = pMap.get("company_name");
var UserPrincipalName = pMap.get("employee_SSO");
var employeeType = pMap.get("employee_category");
var ExtensionAttribute1 = pMap.get("employee_group");
var Title = pMap.get("job_title");
var mobile = pMap.get("mobile_phone");
var City = pMap.get("work_city");
var Country = pMap.get("work_country");
var PhysicalDeliveryOfficeName = pMap.get("work_location");
var Extensionattribute3 = pMap.get("work_region");
var State = pMap.get("work_state");
var manager_dn = pMap.get("distinguishedName");
var UserAccountControl = pMap.get("userAccControl");
var Employee_dn = pMap.get("employee_dn");
var dn= Employee_dn;
var EmployeeNumber = new BasicAttribute("EmployeeNumber", employeeNumber);
var DisplayName = new BasicAttribute("DisplayName", displayName);
var Department = new BasicAttribute("Department", department);
var telephonenumber = new BasicAttribute("telephonenumber", TelephoneNumber);
var company = new BasicAttribute("company", Company);
var userprincipalname = new BasicAttribute("userprincipalname", UserPrincipalName);
var employeetype = new BasicAttribute("employeetype", employeeType);
var extensionAttribute1 = new BasicAttribute("extensionAttribute1", ExtensionAttribute1);
var title = new BasicAttribute("title", Title);
var Mobile = new BasicAttribute("Mobile", mobile);
var l = new BasicAttribute("l", City);
var co = new BasicAttribute("co", Country);
var physicalDeliveryOfficeName = new BasicAttribute("physicalDeliveryOfficeName", PhysicalDeliveryOfficeName);
var extensionattribute3= new BasicAttribute("extensionattribute3", Extensionattribute3);
var st= new BasicAttribute("st", State);
var Manager= new BasicAttribute("Manager", manager_dn);
var description= new BasicAttribute("description", Title);
var userAccountControl= new BasicAttribute("userAccountControl", UserAccountControl);
var attributes = new BasicAttributes();
attributes.put(EmployeeNumber);
attributes.put(DisplayName);
attributes.put(Department);
attributes.put(telephonenumber);
attributes.put(company);
attributes.put(userprincipalname);
attributes.put(employeetype);
attributes.put(extensionAttribute1);
attributes.put(title);
attributes.put(Mobile);
attributes.put(l);
attributes.put(co);
attributes.put(physicalDeliveryOfficeName);
attributes.put(extensionattribute3);
attributes.put(st);
attributes.put(Manager);
attributes.put(description);
attributes.put(userAccountControl);
var resultingMap = new HashMap();
resultingMap.put("dn", dn);
resultingMap.put("attributes", attributes);
message.setBody(resultingMap);
return message;
return message;
}
- Used Groovy to log the Payload for testing purpose.
- Request-Reply [3] to Update the data into AD.
II. Route 1:
- As we know that the records which comes in this way will not have Manager, we need to make it NULL.
- Request-Reply [3] to get the Employee distinguishedName as we did the same to update the records with manager name.
- Java Script to set the data. Used the same Script which I have used above except for the manager attribute.
- For this I am changing var Manager= new BasicAttribute(“Manager”, null); from the above given code. [Here null is the keyword not the string]. If you pass a string, you will get Error.
2. Process Call 2: Terminated Employees
- Filter to the incoming records to check the employee_status = ‘Terminated’.
- Content Modifier to ADD the root node.
- General Splitter to separate the records.
- Content Modifier to save the incoming fields data into Header using the XPATH.
- Request-Reply [1] to get the employee distinguishedName from AD as we for the Active Employees by performing Search
- XSLT to remove extra header information.
- Content Modifier to catch the Manager distinguishedName into header using XPATH.
- Java Script to set the AD data. For this am using the same code which I have already provided in the previous step by changing userAccountControl attribute and the Manager Attribute.
- To Disable an employee, set userAccountControl to 514.
- Also change var Manager= new BasicAttribute(“Manager”, null); as Terminated employee will not have a manager
- Request-Reply [2] to Update the Terminated employees into AD.
- Followed the same procedure what I have done to update the Active Employees.
3. Process Call 3: Missing Data
- Filter to the incoming records to check the work_state = ‘ ’.
- Content Modifier to ADD the root node.
- Used Router to stop unnecessary mails which will be triggered with only as we used content modifier to ADD root node.
- Message Mapping to Map and get the work_location from the source as I was asked to send a mail with work_location of that state for which the data is missing.
- General Splitter to separate the records.
- Content Modifier to catch the work_location using XPATH.
- Gather to combine the locations.
- Used few more steps to build the final structure for Mail body and finally used send to send a mail sing the Mail Adaptor.