Intro
If you’ve worked in IT for any length of time, you’ve run into the mess that is manual account management: a new hire needs accounts on five different systems, someone leaves the company and their AD account stays active for months, and nobody can answer “Who has access to what?”.
This is the problem space that Identity and Access Management (IAM) tooling exists to solve. In this post we’ll look at MidPoint, an open source Identity Governance and Administration (IGA) platform built by Evolveum.
Evolveum is an EU-based company established in 2011. Everything they build is open source: the source code and documentation are freely available.
We’ll use a basic MidPoint scenario with an HR database as the source of identity data and LDAP as the target system. The full configuration is shown in the demo video, while the article focuses on how the pieces fit together.
What is IAM and how does it differ from IGA?
“IAM” is often used as a catch-all term, but it covers a few distinct disciplines:
- Access Management (AM) – proving who you are and letting you in: login, single sign-on (SSO) and multi-factor authentication. This is where tools such as Okta and Keycloak specialize.
- Identity Governance and Administration (IGA) – managing the full lifecycle of an identity: provisioning accounts when someone joins, adjusting access when their role changes, deprovisioning when they leave, and maintaining an audit trail for compliance. This is where MidPoint and IBM Security Verify Governance fit.
- Privileged Access Management (PAM) – securing administrator and root-level credentials. CyberArk is a common example.
An SSO tool answers “Can this person log in?”, while an IGA tool answers a broader question: “Should this person still have access, and can I prove why they have it?”
Components
The demo environment contains four containers: MidPoint, its PostgreSQL repository, an HR PostgreSQL database and OpenLDAP.
The HR database provides employee information through the v_hr_employees view. It starts with 26 sample employees and contains data such as username, name, email, job title, department, activation status, cost center and location.
OpenLDAP plays the role of the target system, representing the kind of directory applications could authenticate against. It starts with the suffix dc=croz,dc=net and an empty ou=employees branch.
Key MidPoint terms
Resource: An external system MidPoint communicates with through a connector. In this demo, the resources are the HR database and LDAP.
Shadow: MidPoint’s local record of an account on a resource. It contains identifiers and cached attributes, not the account itself.
Focus: The central identity object that mappings point to. In this example, the focus is a User.
Projection: An account seen from the user’s side. A user in this demo can have both an HR and an LDAP projection.
Object type: A definition of what a class of resource objects represents, defined by its kind and intent.
Inbound and outbound mapping: Inbound mappings copy resource attributes into a user, while outbound mappings push user properties to a resource.
Situation: MidPoint’s assessment of an account relationship, such as linked, unlinked, unmatched or deleted.
Lifecycle state: Proposed means changes are simulated but not written. Active means MidPoint can perform real changes.
Assignment and inducement: An assignment gives something directly to an object. An inducement gives it to whoever holds that object.
Import, reconciliation and live synchronization: Import reads all accounts from a resource, reconciliation compares both sides and repairs differences, while live synchronization picks up changes since the previous run.
Installation
MidPoint supports several installation options, including Docker, Kubernetes, distribution packages and building from source.
For this demo we use Docker Compose with four containers: MidPoint, its PostgreSQL repository, the HR PostgreSQL database and OpenLDAP.
Connecting the HR database
The first resource we configure is the HR database.
MidPoint uses the DatabaseTableConnector to connect to the PostgreSQL database and read the v_hr_employees view. The emp_id column is used as the key column.
The resource is initially kept in the Proposed lifecycle state. This acts as a simulation mode: MidPoint can evaluate the configuration without making real changes.
Once the connection is configured, the resource preview shows the rows directly from the HR view. At this stage, nothing has been imported into MidPoint yet.
HR object type and mappings
An object type tells MidPoint what a row from the HR resource represents. For this scenario, the HR resource uses an Account object type that creates MidPoint Users with the existing Person archetype.
Because HR is the source of truth, its mappings are inbound only.
The main mappings are:
uid→ employeeNumberusername→ namefirst_name→ givenNamelast_name→ familyNameemail→ emailAddressfull_name→ fullNamejob_title→ titledepartment→ organizationalUnitcost_center→ costCenterlocation→ localityactivation_status→ lifecycleStateactivation_status→ activation/administrativeStatus
The uid attribute is the connector’s identifier, which is bound to the emp_id key column in the resource configuration. This is why it maps to employeeNumber.
Most of the mappings are direct copies. activation_status uses scripts to translate the HR status into MidPoint’s lifecycle and administrative states.
For lifecycle state:
active→ activeterminated→ suspendeddisabled→ archived
For administrative status:
active→ ENABLEDterminated→ DISABLEDdisabled→ ARCHIVED
administrativeStatus determines whether the user and its accounts are actually enabled or disabled, while lifecycleState represents the governance state of the identity.
MidPoint 4.10 marks employeeNumber as deprecated in favour of personalNumber. It still works in this example, but for a new deployment it is worth considering personalNumber instead.
HR synchronization
Synchronization rules define what MidPoint should do when it encounters different account situations.
For the HR resource:
- Linked → Synchronize: reapply the inbound mappings to an already linked user.
- Unlinked → Link: connect an HR record to an existing matching MidPoint user.
- Unmatched → Add focus: create a new MidPoint user when no matching user exists.
- Deleted → Inactivate focus: disable the MidPoint user if the HR record disappears instead of deleting the identity completely.
Importing users from HR
Once the HR configuration is ready, an Import task reads the HR rows and creates the corresponding MidPoint users.
While the resource is still Proposed, MidPoint evaluates the import but does not write anything.
After the resource is changed to Active, the import task is run again. In the demo, all 26 HR objects are processed successfully and appear in MidPoint as Persons.
Connecting LDAP
The second resource is OpenLDAP.
MidPoint connects using LdapConnector, with dc=croz,dc=net as the base context and uid as the VLV sort attribute.
The resource uses inetOrgPerson as the object class for employee accounts. groupOfNames is also available, but it is not used in this example.
LDAP is initially kept in the Proposed state as well, so the configuration can be tested before any accounts are actually created.
LDAP account mappings
The LDAP resource uses an LDAP Account object type.
Unlike the HR resource, it does not use the Person archetype. HR is responsible for creating users; LDAP should only create or attach accounts for identities that already exist in MidPoint.
LDAP has both inbound and outbound mappings.
The inbound mappings allow changes made directly in LDAP to flow back into MidPoint. The corresponding properties include:
sn→ familyNamegivenName→ givenNamel→ localityemployeeNumber→ employeeNumbertitle→ titlemail→ emailAddresstelephoneNumber→ telephoneNumberou→ organizationalUnito→ organizationcn→ fullName
The outbound mappings push the same user information from MidPoint to LDAP:
- familyName →
sn - givenName →
givenName - locality →
l - employeeNumber →
employeeNumber - title →
title - emailAddress →
mail - telephoneNumber →
telephoneNumber - organizationalUnit →
ou - organization →
o - fullName →
cn - name →
dn
The DN mapping uses:
basic.composeDnWithSuffix('uid', name, 'ou=employees,dc=croz,dc=net')
For a user named abakker, this produces:
uid=abakker,ou=employees,dc=croz,dc=net
There is no separate mapping to uid: the connector derives it from the naming attribute in the DN.
LDAP synchronization
The LDAP synchronization configuration handles three situations:
- Linked → Synchronize: keep an existing account synchronized with its user.
- Unlinked → Link: connect an existing LDAP account to a matching MidPoint user.
- Unmatched → Add focus: create a user if an LDAP account exists without a matching identity.
There is no Deleted reaction in this example. If an account disappears from LDAP, it will be recreated during the next reconciliation.
LDAP Employee role
Before MidPoint can provision users to LDAP, the LDAP resource needs to be assigned to them.
For this, we create an application role called LDAP Employee. The role grants an LDAP Account on the LDAP resource.
The 26 existing employees can initially be assigned to the role in bulk. This creates the relationship needed for their LDAP accounts.
Attaching the role to the Person archetype
Bulk assignment works for the existing users, but it would require a manual step for every future employee.
Instead, the LDAP Employee role is added to the Person archetype as an inducement.
An inducement means that whoever has the Person archetype also receives the LDAP Employee role.
From this point on, every user imported from the HR database automatically receives the role and therefore an LDAP account. The original manual assignments are no longer needed.
LDAP reconciliation
Before accounts can actually be created, the LDAP resource is changed from Proposed to Active.
The LDAP Employee role was assigned while the resource was still Proposed, so account creation was only simulated. A reconciliation task now compares what MidPoint expects each user to have with what actually exists in LDAP and fixes the difference.
This is why reconciliation is used instead of another import task: HR is a source system that feeds identities into MidPoint, while LDAP is a target system that needs to be brought in line with MidPoint’s desired state.
Once reconciliation finishes, the ou=employees branch contains the 26 employee accounts. The mapped attributes, including the generated DN, are populated from MidPoint.
Demo: adding a new employee
Now we can see the complete flow in action.
A new employee, Laura Garcia, is added to the HR database with employee ID EMP027, username lgarcia and an active status.
The HR import task is run again. The number of processed records increases from 26 to 27, with EMP027 as the latest object.
MidPoint creates Laura as a new Person and populates her properties through the inbound HR mappings.
Her user also receives two projections:
- the HR Account
EMP027 - an LDAP Account with the DN
uid=lgarcia,ou=employees,dc=croz,dc=net
The LDAP Employee role and LDAP Account construction arrive indirectly through the Person archetype, rather than through a manual assignment.
Finally, the LDAP reconciliation task is run again. It processes 27 objects and provisions Laura’s LDAP account with the attributes supplied by MidPoint.
At that point, the complete joiner flow is working: add the employee to HR, and MidPoint takes care of creating and provisioning the identity downstream.
Conclusion
We went from an empty MidPoint instance to a working identity flow.
HR acts as the single source of truth: every row in the v_hr_employees view becomes a Person in MidPoint through inbound mappings, while the activation status determines whether that identity is enabled or disabled.
The Person archetype carries an inducement to the LDAP Employee role, and the role carries the LDAP account. Because of that chain, a new hire only needs to be added to the HR database and MidPoint takes care of the rest.
Everything shown here runs on the MidPoint community edition. The Evolveum documentation and the free MidPoint book cover these topics in more depth.
In the next post, we’ll build on this setup with LDAP group membership and a scheduled deprovisioning flow.