
Organizational Structures
If life is going to exist in a Universe of this size, then the one thing it cannot afford to have is a sense of proportion.
The Restaurant At The End Of The Universe
Organizations come in all shapes and sizes. Unless your organization is extremely unusual, there is always some form of recognizable internal structure. There may be the usual corporate divisions, departments and sections. Perhaps there are dynamic teams, projects, work groups and task forces. One way or another, some kind of organizational structure is always there, and it matters. While many organizational structures are quite far from the ideal, organizational structure is seldom completely useless. Membership in some organizational units is a reason to automatically grant privileges to users. Managers can usually access quite a wide set of data about employees in organizational units that they are managing. Team leaders and project managers often exercise elevated privileges over their teams and projects. Moreover, organizational structure is not limited to users. Roles are often organized into role catalog. Services and devices may be organized by geographical location. There are many things that need to be organized, and there are many ways to organize them.
Organizational structure affects almost every part of the identity management deployment. We have realized that in very early stages of midPoint development. Therefore, organizational structure is an integral part of midPoint functionality. It permeates almost every part of midPoint functionality. Unlike most other systems, organizational structure in midPoint is a very flexible and almost universal concept. It can be used to build functional organizational hierarchies as well as flat project-based structures. The same mechanism can be used to sort roles in a role catalog, or to manage devices by geographical location. All of those organizational structures may co-exist at the same time in the same system.
The concept of organizational structure is a very powerful one, but it is implemented by just a handful of simple components. Let us have a look at those building blocks now.
Organizational Units
Basic building blog of all organizational structures is just one simple object type. Due to the lack of poetic talent and because of critical shortage of abstract words in our dictionary, we have decided to call that object simply an org. It is a nice and short name. Org can represent any kind of organizational unit: company, division, department, section, project, team, role category, geographical location or anything else. Orgs can be used to create hierarchical structures. For example, a top-level org may represent a company. A couple of other orgs can represent divisions. Those orgs can be put "inside" the company org. Other orgs can represent departments, these can be put "inside" the division orgs. That process can be repeated until complete organizational structure is formed.

Org is quite a basic thing with a very simple anatomy:
<org oid="4d12c1ac-440c-11ea-80af-2b314d06ba95">
<name>F10000</name>
<displayName>ExAmPLE, Inc.</displayName>
</org>
Strictly speaking, the only two things that an org really needs are name and OID.
The example above adds displayName
to make the presentation of the org nicer.
As all regular midPoint objects, a name
of an org must be unique.
This often leads to a practice that org names are in fact identifiers, or that they are generated automatically.
This is also our case.
We have decided to set F1000
as the name
of this org.
The value 1000
is an identifier of the company in our HR system.
As we are building a functional organizational structure of the company, we have prefixed the identifier with F
which stands for functional.
However, names such as F1000
are not very friendly.
Therefore, there is a mechanism to set nicer display name that does not need to be unique.
The display name is used instead of the ordinary name
whenever this org is displayed to a user.

We have an organizational unit now, but how do we put users in it?
Clever reader already knows the answer: assignment.
All we need is to assign the org to a user.
This is done in almost the same way as you would assign a role, just select the Org
tab in assignment dialog.

The assignment looks like this in XML form:
<user>
<name>eevans</name>
...
<assignment>
<targetRef oid="4d12c1ac-440c-11ea-80af-2b314d06ba95" type="OrgType"/>
</assignment>
...
</user>
The user is a part of our minimalistic organizational unit now:

Organizational Structure Hierarchy
There is very little structure in our tiny organizational structure yet. Orgs would not be very useful, unless they can be placed inside each other, creating a hierarchy. It is this hierarchy that makes organizational structures attractive. Therefore, let us go corporate and create some hierarchy now. It is a well-known fact that all self-respecting corporations need sales and marketing division:
<org oid="7a1feb50-471f-11ea-8aab-1b2627541f15">
<name>F11000</name>
<description>Expensive people that make money.</description>
<displayName>Sales and Marketing Division</displayName>
<identifier>11000</identifier>
</org>
We have pimped up this organizational unit a little.
We have seen name
and displayName
before.
The description
is no stranger either.
Then there is an identifier
.
The value of the identifier
is usually an official "code" of the organizational unit assigned by HR people.
Why do we need yet another identifier?
OID is an identifier, name
is an identifier of sorts, why do we need another one?
For now, let’s just say that the identifier is going to be very useful later on, when we synchronize organizational structures.
If we import the org above into midPoint it becomes the top org. MidPoint puts it at the same level as the ExAmPLE company org. We do not want that. We want to create a hierarchy. We want to tell midPoint to put the department inside the company. How do we do that? We use an assignment, of course:
<org oid="7a1feb50-471f-11ea-8aab-1b2627541f15"
xmlns='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
xmlns:org='http://midpoint.evolveum.com/xml/ns/public/common/org-3'>
<name>F11000</name>
<description>Expensive people that make money.</description>
<displayName>Sales and Marketing Division</displayName>
<identifier>11000</identifier>
<assignment>
<targetRef oid="4d12c1ac-440c-11ea-80af-2b314d06ba95" type="OrgType"/>
</assignment>
</org>
Now we have our minimalistic hierarchy:

This makes perfect sense, doesn’t it? Users become part of organizational units when the units are assigned to them. Therefore, also organizational units become part of other organizational units when they are assigned to them. This principle applies to everything: roles, services, tasks, resources and other object types. Every object type that can be assignment holder can be placed in organizational structure, by assigning an organizational unit to it.
Assignment holders
Almost all midPoint object types are assignment holders, and therefore they can be placed into organizational structure.
Theoretically.
However, midPoint user interface has some limits.
Convenient management of the assignments is currently possible only for focal types: user, role, org and service.
Other objects can be placed in organizational structure, and they should behave up to the expectations.
However, that cannot be done by few convenient clicks in midPoint user interface
Not yet.
You have to use a different approach.
You either add the assignment manually in the XML/JSON/YAML form.
You may also try to use mappings to create the assignments automatically, or perhaps use the REST interface to do that.
Maybe it would be a good idea to send some money in the direction of midPoint development team to motivate them to add this functionality to user interface.
|
We know how to create a simple organizational hierarchy. All we need to do now is to repeat the process ad nauseam to create something that resembles real corporate organizational structure. Let us add marketing department to our division:
<org oid="a0c7d92c-4722-11ea-bc8d-d79a6cefb1bf"
xmlns='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
xmlns:org='http://midpoint.evolveum.com/xml/ns/public/common/org-3'>
<name>F11300</name>
<description>Creative bunch that spends money to get more money.</description>
<displayName>Marketing Department</displayName>
<identifier>11300</identifier>
<assignment>
<targetRef oid="7a1feb50-471f-11ea-8aab-1b2627541f15" type="OrgType"/>
</assignment>
</org>
It is the same process over and over again. However, there are so many organizational units, there are so many files to import. We like to be efficient in all the things that we do. Therefore, let’s put the entire organizational structure into a single file:
<objects>
<!-- Functional organizational structure of ExAmPLE company -->
<org oid="4d12c1ac-440c-11ea-80af-2b314d06ba95">
<name>F10000</name>
<displayName>ExAmPLE, Inc.</displayName>
</org>
<org oid="7a1feb50-471f-11ea-8aab-1b2627541f15">
<name>F11000</name>
<description>Expensive people that make money.</description>
<displayName>Sales and Marketing Division</displayName>
<identifier>11000</identifier>
<assignment>
<targetRef oid="4d12c1ac-440c-11ea-80af-2b314d06ba95" type="OrgType"/>
</assignment>
</org>
...
</objects>
It would be no big surprise to find out that laziness was a driving force behind many improvements in life, would it? Now, let us use this convenient approach to create a nice and rich corporate organizational tree:

Of course, you can create and manage organizational structure in midPoint user interface. In fact, people do that quite often. However, now we are talking about the initial organizational structure. It is the structure that gets created in midPoint at the beginning of the deployment. There is usually a lot of trial and error until you get your midPoint configuration right. It is quite likely you will have to purge all midPoint configuration and start clean. In that case, it is very convenient to have organizational structure in one file that can be easily imported after the clean-up. Also, it is a common practice to have several environments: development, testing and production. You probably want the same organizational structure in all of them. Having organizational structure in a file makes that job easy. Of course, you can also create organizational structure in the user interface and then export it into a file. However, according to our experience, many engineers prefer text editor to graphical user interfaces. |
Orgs in the Database
Organizational structures tend to form hierarchies - data structures that look like trees. However, databases are usually designed to store relational data - data structures that look like tables. If you ever tried to express hierarchical data in a spreadsheet application you know that these paradigms are not entirely easy to align. It is not entirely easy to express tree-like data structure in relational tables. Moreover, hierarchical data tend to have some specific requirements. For example, we usually want to look for people in Operations Division and all the departments and sections that belong to it. This is known as subtree searches, and it is usually not possible to execute them directly on data that are stored in relational form.
This is further complicated by the fact that midPoint assignment is a very flexible data structure. Assignments can be valid from a specific time to a specific time. Assignments can be parametric and conditional. Assignment is just too complex for the database to understand and use efficiently.
MidPoint is solving these problems with parentOrgRef
operational data item.
As the name suggests, parentOrgRef
is an object reference that points to parent org.
Any assignment holder in midPoint can have parentOrgRef, and it points to the org (or orgs) that the object belongs to.
This somehow duplicating the data in the assignment.
Yet, there are several crucial differences.
Firstly, parentOrgRef
points to the orgs that the object is currently member of.
I.e. it only reflects those assignments that are currently active and valid.
Therefore, there will be no parentOrgRef
value for assignment that is expired or not valid yet.
Secondly, parentOrgRef
represents all organizational assignments, both direct and indirect.
Orgs that are directly assigned to users are present in parentOrgRef
.
Orgs that are induced in a role that is assigned to the user are also present in parentOrgRef
.
Everything is there.
Thirdly, parentOrgRef
is a very simple data structure.
This simplicity allows efficient indexing of the parentOrgRef
values in the database (repository) layer.
The indexes are designed to allow efficient subtree searches over organizational structure hierarchies.
This is our trick to fit hierarchical data into flat data tables.
The details may be a bit complicated, but it usually works quite well.
The parentOrgRef
is automatically maintained by midPoint under the hood.
Therefore, its use is usually completely transparent.
The user does not even notice that there is a special mechanism working in the background.
However, there are also downsides to this approach.
The index that is build on parentOrgRef
is designed to work even if organizational structure is re-organized.
The index has to be continually maintained.
Maintenance overhead of the index is usually very low for small or mid-sized structures that do not change often.
However, maintenance of massive organizational structures can be painful.
Similarly, it may be problematic to maintain organizational structures that change very frequently.
Therefore, it is perhaps a good idea to prototype the design of organizational structure before putting the system into production.
Also, the parentOrgRef
is in fact a copy of the primary data (assignment).
As it is a copy, there is a risk that it may get out of synchronization.
MidPoint is designed to keep parentOrgRef
and all the indexes strictly consistent during normal operations.
However, midPoint allows systems administrators to do a lot of non-standard things.
Some of those things may lead to data inconsistencies.
Therefore, it is a good idea to check whether the values of parentOrgRef
make sense in case you notice that organizational structures are behaving strangely.
Overall, organizational structures work very well in midPoint, and you usually do not need to care about the mechanisms under the hood. However, management of organizational structures is much more complex than it seems. If you try to do strange and unusual things, you should better be sure you fully understand what you are doing.
Orgs and Roles
Organizations and roles have many things in common. Roles are granting privileges to its members. Usually, people that are members of an organization are granted privileges too. People that have the same role usually have the same set of privileges. People in an organization often have the same privileges too. In fact, organizations behave in almost the same way as roles.
MidPoint has fully embraced this similarity. Orgs are designed to behave in almost the same way as roles. Orgs are abstract roles, therefore they may have inducements, there may be constructions in them, orgs may contain authorizations and so on. Org can do everything that a role can do.
Therefore, there is no need to set up complicated configurations that assign a particular role to all members of an organization. The organization itself acts as a role. All the privileges that organization members need can be simply added as inducements in the organization itself. This is very simple, elegant and mostly fool-proof solution.
We have Sales and Marketing Division in ExAmPLE, Inc. We want to make things simple, and therefore we want to grant access to CRM system to all the members of this division. It is very easy to do:
<org oid="7a1feb50-471f-11ea-8aab-1b2627541f15">
<name>F11000</name>
<description>Expensive people that make money.</description>
<displayName>Sales and Marketing Division</displayName>
<identifier>11000</identifier>
<assignment>
<!-- Assignment of parent organizational unit -->
<targetRef oid="4d12c1ac-440c-11ea-80af-2b314d06ba95" type="OrgType"/>
</assignment>
<inducement>
<!-- Inducement that grants CRM privileges to all members of this department -->
<construction>
<!-- CRM resource -->
<resourceRef oid="04afeda6-394b-11e6-8cbe-abf7ff430056"/>
...
</construction>
</inducement>
</org>
Clever reader certainly wonders whether the CRM privileges apply also to Indirect Sales Department, which is located below Sales and Marketing Division in our organizational structure. However, clever reader is clever enough to figure out that the privileges are not "inherited" in this case. To follow the thoughts of clever reader, you have to think about orgs in the same way as you would think about roles. There is an assignment from Indirect Sales Department to Sales and Marketing Division. However, there is no inducement. Role hierarchies are built using inducements. Therefore, privileges of Sales and Marketing Division are not included in Indirect Sales Department. This may seem to be counter-intuitive, but in fact it is completely correct. Orgs and roles form separate hierarchies (see note below). However, if you want to "inherit" privileges of a parent org, there is a very simple way how to do it: add explicit inducement. For example, this is how we can "inherit" the CRM privileges in Indirect Sales Department:
<org oid="8887e0b0-4726-11ea-96b0-5f5ced221e42">
<name>F11200</name>
<description>Suits that talk to other suits that talk to customers.</description>
<displayName>Indirect Sales Department</displayName>
<identifier>11200</identifier>
<assignment>
<!-- Assignment of parent organizational unit -->
<targetRef oid="7a1feb50-471f-11ea-8aab-1b2627541f15" type="OrgType"/>
</assignment>
<inducement>
<!-- Inducement to parent organizational unit. This creates "inheritance" of privileges. -->
<targetRef oid="7a1feb50-471f-11ea-8aab-1b2627541f15" type="OrgType"/>
</assignment>
</org>
This has to be done for every org that needs to inherit privileges from parent, which may be quite daunting for large organizational structures. Fortunately, there is a clever way how to avoid placing inducements everywhere. The solution involves the concept of meta-roles, as parent org is technically a meta-role for child orgs. However, this involves an advanced thinking about application of assignment and inducements. Even a clever reader may not be ready for such abstract thoughts yet. This has to come later when the basic principles have enough time to sink in.
Org and role hierarchies
Both orgs are roles are hierarchical in a way.
However, they form a separate hierarchies.
Org hierarchy is used to model organizational trees.
Role hierarchy is used to build access control structures.
Those hierarchies have completely different purpose.
They are also built using different mechanism.
Role hierarchy is used to group privileges, and therefore it is built using inducements.
Org hierarchy is used to group subjects (users), and it is built using assignments.
There are also different internal mechanisms, indexing and data storage properties.
For example, role hierarchy does not use parentOrgRef , therefore there is much lower overhead as compared to org hierarchy.
However, this means that the capabilities to query role hierarchy is limited.
Both hierarchies have their respective place and purpose.
Even though the difference may not be entirely obvious now, it is quite substantial.
Hopefully, this will get much more clear later when there will be more examples for both org and role structures.
|
Multiple Organizational Structures
Tree is a simple and very elegant structure in many ways. However, it is a rare sight to see a lone tree growing in the field. When we think of trees, we usually think about a forrest. It takes a lot of trees to make a forrest.
This is also the case when it comes to organizational structures. It is a very rare sight when an entire organizational structure of an organization can be modeled in a single tree. There is always the usual functional organizational structure with divisions, departments, sections, companies, branches, schools and faculties. Then there is a project organizational structure that is often completely orthogonal to functional organizational structure. This is sometimes spiced up with workgroups, task forces, focus groups, research teams, interest groups, clubs and similar collective life forms. There are many trees that make a forrest of organizational structures.
Fortunately, midPoint is not very picky when it comes to organizational structures. MidPoint is not limited to a single organizational tree. You can have as many organizational trees as you like. You can have functional organizational tree, as we have seen in previous sections. Then you can have independent project organizational structure. Just create new root org for projects and place the projects under it:
<org oid="832e37e4-edfd-11ea-9f8c-ef736d6646a2">
<name>Projects</name>
</org>
<org oid="9c1b8464-edfd-11ea-87b8-db467c5ae301">
<name>PBD2020</name>
<description>Make money fast.</description>
<displayName>Big Deal</displayName>
<identifier>BD2020</identifier>
<assignment>
<targetRef oid="832e37e4-edfd-11ea-9f8c-ef736d6646a2" type="OrgType"/>
</assignment>
</org>
<org oid="22dc2bd4-edfe-11ea-a904-5be54dda2e46">
<name>PLS</name>
<description>Make sure our marketing message gets across.</description>
<displayName>Loudspeaker</displayName>
<identifier>LS</identifier>
<assignment>
<targetRef oid="832e37e4-edfd-11ea-9f8c-ef736d6646a2" type="OrgType"/>
</assignment>
</org>
<org oid="1954d496-f6ad-11ea-a96a-8bfa569f5fff">
<name>PWL2</name>
<description>Second generation wonderland. We are all mad here.</description>
<displayName>Wonderland 2.0</displayName>
<identifier>WL2</identifier>
<assignment>
<targetRef oid="832e37e4-edfd-11ea-9f8c-ef736d6646a2" type="OrgType"/>
</assignment>
</org>
We have two organizational trees now, each neatly stowed under its own tab:

This is a nice project organizational structure. However, our users are members of functional organizational structure already. How can we add our users to the projects? The answer is assignment, of course. User can belong to any number of organizational units at the same time. It makes no difference whether they are in the same organizational tree or in different trees. We can simply assign the projects to the users. In fact, midPoint does not even recognize the difference between functional and project organizational structures. They look all the same to midPoint, and midPoint treats them in the same way. If there is a need for the structures to behave differently, it has to be explicitly configured. Which is usually done by using archetypes.
There are two organizational structures now. You can have three organizational structures if you want to, or five of them. Any number you like - as long as all the tabs for organizational structures fit on the screen. The structures can be a deep trees with many branches, or they can be completely flat, with just a single level. The structure may not even be a tree. As long as it is an acyclic directed graph it will work just fine. It can have multiple roots, it may have alternate paths, it can do all the crazy stuff. Just avoid cycles. Cycles break the maths which is the foundation of organizational structure indexing and evaluation. Cycles won’t work, but pretty much all the other arrangements are perfectly fine.
Archetypes
Org is such a flexible creature. It can represent variety of concepts: divisions, sections, departments, teams, projects, companies, branches, schools, faculties, zones, locations - you name it. However, it would be very easy to get lost if all these fine shades of orgs looked and behaved the same. Fortunately, we already know what we can use to apply some character to individual subtypes of objects. We are going to apply archetypes to orgs.
In theory, application of an archetype to org is easy. First, we need a suitable archetype.
<archetype oid="5c2c123e-86ff-11ef-9f50-ab1904c498f6">
<name>Project</name>
<archetypePolicy>
<display>
<label>Project</label>
<pluralLabel>Projects</pluralLabel>
<icon>
<cssClass>fa fa-chart-gantt</cssClass>
<color>#ffc107</color>
</icon>
<tooltip>Project</tooltip>
</display>
</archetypePolicy>
<assignment>
<identifier>holderType</identifier>
<description>This archetype can be applied to orgs (OrgType).</description>
<assignmentRelation>
<holderType>OrgType</holderType>
</assignmentRelation>
</assignment>
</archetype>
Then we can apply the archetype to objects.
<org oid="9c1b8464-edfd-11ea-87b8-db467c5ae301">
<name>PBD2020</name>
<description>Make money fast.</description>
<displayName>Big Deal</displayName>
<identifier>BD2020</identifier>
<assignment>
<targetRef oid="832e37e4-edfd-11ea-9f8c-ef736d6646a2" type="OrgType"/>
</assignment>
<assignment>
<targetRef oid="5c2c123e-86ff-11ef-9f50-ab1904c498f6" type="ArchetypeType"/>
</assignment>
</org>
When the archetype is applied, the projects have nice icon and custom color.

Archetypes are easy to apply.
However, it may not be entirely easy to choose what archetypes to apply to orgs.
For example, the traditional enterprise functional organizational structure has divisions at the top, sections at the bottom and departments in between.
It may be tempting to create three archetypes: Division
, Department
and Section
.
However, this is usually not necessary.
Single Organizational unit
archetype should be enough.
Having a single archetype for all kinds of functional organizational units is usually much simpler and more flexible.
Perhaps the only reason to go for Division
, Department
and Section
would be a need to modify behavior and policies of individual types of organizational units - which is not very common.
While single Organizational unit
archetype is usually the best option, it is a good idea to create a separate archetype for top-level org.
The top-level org usually represents an organization, such as company, university or agency.
While individual organizational units are usually similar to each other, the top-level organization is likely to be quite different.
Therefore, having a separate Organization
archetype is a good idea.
<archetype oid="886bfa6e-8702-11ef-9c40-6fce51f54b0d">
<name>Organization</name>
<archetypePolicy>
<display>
<label>Organization</label>
<pluralLabel>Organizations</pluralLabel>
<icon>
<cssClass>fa fa-building-flag</cssClass>
<color>#ffc107</color>
</icon>
<tooltip>Organization</tooltip>
</display>
</archetypePolicy>
<assignment>
<identifier>holderType</identifier>
<assignmentRelation>
<holderType>OrgType</holderType>
</assignmentRelation>
</assignment>
</archetype>
Moreover, while organizations do not change often, when they change the change is usually quite substantial.
For example, companies are occasionally re-structured, re-branded or merged with other companies.
In such cases, separate top-level root object comes very handy.
E.g. in case of merger, it is quite easy to add another top-level Organization
object for the other company, and then take your time to gradually move people and organizational units around.
<org oid="4d12c1ac-440c-11ea-80af-2b314d06ba95">
<name>F10000</name>
<displayName>ExAmPLE, Inc.</displayName>
<assignment>
<targetRef oid="886bfa6e-8702-11ef-9c40-6fce51f54b0d" type="ArchetypeType"/>
</assignment>
</org>
Having a separate archetype for the top-level root orgs is generally a good idea due to the definition of assignment relations, as is explained below. However, first we need to talk a bit about the relation itself.
Managers
Placing people in organizational structures has a significant value on its own. However, all the people usually do not have the same relation to the organizational unit. Most people are ordinary members of organizational unit. Then there are people that are somehow special: departmental managers, team leaders, project managers, supervisors and similar life forms.
How do we designate a manager of an organizational unit?
You probably guessed it already.
In a typical midPoint fashion, we are re-using assignment, of course.
There is just one small detail.
We are specifying relation
in assignment target reference:
<user>
<name>aanderson</name>
...
<assignment>
<!-- Direct Sales Department -->
<targetRef oid="832f409a-4726-11ea-b0be-8b8eab99c1ed" type="OrgType" relation="manager"/>
</assignment>
...
</user>
This assignment makes Alice a manager of Sales and Marketing Division. It is as simple as that. All the power of assignment is at your disposal. Therefore, it is easy to assign a manager for a temporary time period, suspend a manager and so on.
Manager assignment is created in the user interface in almost the same way as normal assignment is created. The only difference is selection of manager relation at the bottom of the assignment target dialog:

After the assignment is in place, midPoint knows that Alice is a manager of Sales and Marketing Division. This is also displayed in the organizational tree:

MidPoint assigns managers to organizational units. That is the right way to do it. However, we have often seen a different approach. In these cases the manager is "assigned" to users. I.e. each user has a reference to his or her manager. This approach is wrong. Organizational structures change. People come and go. Everything is changing all the time. It is very easy to change one assignment in organizational structure in case that a manager is replaced. However, it is extremely difficult to replace a manager in the direct user-manager data structure. Maybe the former manager was managing several organizational units, and now we are replacing him with two managers. Maybe there is a re-organization going on at the same time. The result is going to be a mess. Avoid the direct user-manager approach whenever possible. |
We can congratulate Alice on her new position in management. However, she still has the same access rights as ordinary workers. That is not right! Managers wear suits and ties, which means that they need to have more privileges than mere mortals. As managers usually control funding of software development, it is perfectly understandable that midPoint has a way to set up privileges that apply to managers:
<org oid="7a1feb50-471f-11ea-8aab-1b2627541f15">
<name>F11000</name>
<displayName>Sales and Marketing Division</displayName>
<identifier>11000</identifier>
...
<inducement>
<construction>
... Privileges exclusive to managers are specified here ...
</construction>
<orderConstraint>
<order>1</order>
<relation>manager</relation>
</orderConstraint>
</inducement>
</org>
This inducement grants special privileges to manager of the Sales and Marketing Division.
The orderConstraint
makes sure that only the users that have manager
relation to this organization unit get the privileges.
Wait a minute! Clever reader does not like that. This approach to manager privileges is not going to be very practical. Managers usually do not have special privileges in each organizational unit. In most organizations, managers have the same privileges regardless of the unit they manage.
One way to implement this approach is to create a Manager
role, put the special privileges there, and assign the role to every manager of every organizational unit.
However, that creates redundancy.
We have to make sure this role is assigned whenever a person becomes manager, and that it is unassigned when the person is no longer manager.
This is the "standard" method used to manage privileges in other identity management platforms.
However, it is quite a fragile mechanism.
This is not a way how we do things in midPoint, we do not like fragile and tedious things here.
The orderConstraint
data structure in our example looks suspiciously complex.
That impression is correct, as it indeed is quite a complex concept.
What we see here is the first glimpse at high-order "assignment algebra" that is a work-horse of complex midPoint deployments.
This mechanism is often employed when working with meta-roles and archetypes.
As organizational units are abstract roles, and organizational structures are just a trees formed by assignments, they technically form meta-role structures.
Therefore, the right way to set up manager privileges is to move privilege definition to a central place.
It may be top-level root org, or it may be an Organizational unit
archetype.
In such case our inducement can apply to all the managers, regardless of organizational unit.
However, the exact configuration is a bit complex, and we still need to learn more about midPoint to be able to use it.
Therefore, we leave the details for later chapters.
Organizational structure may have almost any form. A user can be a member of many organizational units. Which also means that a user may manage many organizational units. That also applies the other way around: an organizational unit may have many managers. As member and manager assignments are independent, users may belong to a different organizational unit that they manage. MidPoint can support all kind of bizarre organizational arrangements. MidPoint was deliberately designed in this way, because reality has an annoying habit to bring surprises, especially when organizational structures are involved. However, you may not like all this liberalism in organizational management. Ordnung muss sein! If you want to constraint organizational management to allow only a single manager for each organizational unit, you can do it. However, you have to explicitly specify a policy by setting up assignment relation, policy rules and archetypes. Policy rules provide a very generic and very powerful mechanism to constraint and control midPoint in many ways, and archetypes provide flexible typing mechanism.
Relation
In midPoint, we like to design generic re-usable mechanisms. You did not think that we made the concept of manager in a way that would be hardcoded to organizational structure, did you? As you have got so far through this book, you would probably suspect there is more to this relation thing that we have seen so far.
The relation parameter specifies the nature of a relation between two objects. For example a user may be a member of an organizational unit, manager of a project, owner of a role or approver of role assignment requests. In such cases, member, manager, owner and approver are relations that a user can have to an object.
The most common way to use relation is to specify it in targetRef
in an assignment.
The following example illustrates the usual way to assign an owner for a role:
<user>
<name>aanderson</name>
...
<assignment>
<!-- Business Analyst role -->
<targetRef oid="aaa6cde4-0471-11e9-9b50-c743da469067" type="RoleType" relation="owner"/>
</assignment>
...
</user>
There are several built-in relations in midPoint:
Relation | Usually used for | Description |
---|---|---|
|
Everything |
This is the most ordinary, most common, non-specific relation to an object. When used with a role, it simply means that the user has the role. Usually interpreted as member when used with organizational units. It is the usual, normal relation. As the name suggests, this is the default relation. If no other relation is specified, this relation is used. |
|
Orgs |
Manager of an organizational unit, project manager, teamleader, etc.
Usually entitles a person (or a group) that have leading position in an org.
This usually specifies executive or operational privileges (cf. |
|
Roles, Orgs |
Person responsible for governance of the object.
Often used to nominate role owners that are responsible for role definition and maintenance.
May be used with organizational units to specify project sponsor or business owner.
Specifies a person responsible for governance and high-level policy decisions rather than day-to-day management (cf. |
|
Roles, Orgs |
Person responsible for deciding membership in roles and orgs, a gatekeeper or moderator. Approvers usually decide whether someone can have a role, or may be a member of organizational unit. Unlike owners, approvers do not create or modify role definition. They cannot change the role. They can only decide who can have that role and who cannot. |
|
Meta-roles |
Special-purpose relation that is sometimes used with meta-roles. Meta-role structures can be complex and confusing. However, such structures and especially policies that govern them may sometimes be simplified, if role-metarole relations are marked in a special way. This relation is designed specifically for that purpose. The |
Those are built-in relations. There are some pre-configured policies that work with them. However, you are free to specify and use your own relations. However, that is quite an advanced topic, and the majority of deployments are perfectly fine using just the built-in relations.
As you can see, the built-in relations do not have overly strict specifications. There is a lot of usually, often and almost in the description of relations. The reason is that the relations do not do anything just by themselves. They just specify how one object relates to another object. There are no strict policies or behavior associated with them.
The policies are specified elsewhere.
Assignments and inducements may behave differently for different relations, as we have seen in previous section.
Similarly, policy rules are often sensitive to relations.
For example, the policy that assignment of some roles has to be approved is implemented by a policy rule that is aware of approver
relation.
Authorizations are often sensitive to relations.
Archetypes influence how the system behaves based on relations.
User interface may behave differently for some relations.
And so on.
Relations do nothing just by themselves.
However, good part of the system is usually configured to recognize relations and behave accordingly.
It is a matter of that configuration that determines how exactly will the system behave.
This is also the reason for such vague definition of relations, even those built-in relations.
They will do what you make them do.
Assignment Relation Limitations
MidPoint is very flexible platform - which is usually a huge advantage. However, there are downsides to flexibility. It may be difficult to choose correct option from large number of possibilities. This is especially true when it comes to assignments and relations. By default, midPoint does not constrain the assignments, which means any object can be assigned to any other object using any relation. However, this makes it difficult to create a reasonable user interface, as there are just too many options to choose from. Users can be confused what relation to choose, which relations make sense. Even worse, users may to choose to do the same thing in two different ways. As midPoint deployment matures, it is more than desired to constraint the use of assignments and relations only to those combinations that make sense.
Assignment relation mechanism is used for that purpose.
We have already seen basic usage of assignment relation in archetypes.
The assignment relation was used to constraint object type that an archetype can be assigned to.
Following example of Project
archetype is using holderType
clause of the assignmentRelation
to limit application of archetype to orgs.
<archetype oid="5c2c123e-86ff-11ef-9f50-ab1904c498f6">
<name>Project</name>
...
<assignment>
<identifier>holderType</identifier>
<description>This archetype can be applied to orgs (OrgType).</description>
<assignmentRelation>
<holderType>OrgType</holderType>
</assignmentRelation>
</assignment>
</archetype>
The assignmentRelation
constraints ability to create assignment to the Project
archetype, in this case the holder of the assignment must be of OrgType
type.
However, assignment relation can be used to further constraint use of assignments.
We probably want to constraint the relations that can be applied to a project.
It is quite resonable to constraint the relations to members, managers and owners of projects.
This can simplify things, as we probably do to want approvers and "meta" as a relations to projects.
Also, we want to put only users in the project.
In theory, midPoint organizational structure can hold almost any type of object.
However, it does not make much sense for a project to contain roles or services.
We can constrain both relations and object types using assignmentRelation
in the Project
archetype.
<archetype oid="5c2c123e-86ff-11ef-9f50-ab1904c498f6">
<name>Project</name>
...
<inducement>
<identifier>membership</identifier>
<description>Projects are flat (no sub-teams), have members and manager. May have owner (sponsor).</description>
<assignmentRelation>
<description>User can be direct member of project, as well as manager and owner.</description>
<holderType>UserType</holderType>
<relation>org:default</relation>
<relation>org:manager</relation>
<relation>org:owner</relation>
</assignmentRelation>
</inducement>
</archetype>
Unlike the holderType
case above, in this case the assignmentRelation
is placed in inducement instead of assignment.
In the previous case, we were constraining assignment of projects to archetypes.
Whereas in this case we are trying to constraint assignments of users to the projects.
This is one degree of indirection farther, therefore inducement is used instead of assignment.
The arechetype acts as a meta-role, the content of the inducement is applied to the projects (archetyped objects), not to the archetype itself.
The assignment relation specification is used by the user interface. User interface is going to present only those object types and relation that make sense for the operation that user has initiated.

Support for assignment relation in midPoint 4.8 user interface is not yet completed. Some parts of user interface use assignment relation, while others are not using it yet. However, it is a good practice to specify assignment relation in archetypes quite early in midPoint deployment. The specification is going to be very useful after upgrade to a newer midPoint version. |
Beyond Users
MidPoint organizational structure can do a lot of crazy stuff. Organizational structures are usually build to contain people. However, midPoint is quite different. MidPoint organizational structure can contain a broad range of object types. Users, roles and services are the most common object types, but almost any other midPoint object can be placed in organizational structure.
Role catalog is a common use of organizational structure that does not (directly) involve people. Role catalog is used to sort the roles into categories, much like a catalog in electronic shop is used to sort the products. The catalog is used to present roles to users in organized form, so users may easily find the roles when request them in self-service interface.
MidPoint role catalog is simply an organizational structure. It does not have divisions, sections or projects, but it has categories. Categories are (almost) ordinary orgs that form the hierarchy.
<org oid="945315a6-fc23-11ea-832e-1f9945adb481">
<name>Role catalog</name>
<displayOrder>500</displayOrder>
</org>
<org oid="b7e4cd0c-fc23-11ea-a79a-079cad42b39b">
<name>RC001</name>
<displayName>Client acquisition</displayName>
<assignment>
<targetRef oid="945315a6-fc23-11ea-832e-1f9945adb481" type="OrgType"/>
</assignment>
</org>
<org oid="259625ee-fc24-11ea-8bae-1bfdce011faf">
<name>RC002</name>
<displayName>Customer support</displayName>
<assignment>
<targetRef oid="945315a6-fc23-11ea-832e-1f9945adb481" type="OrgType"/>
</assignment>
</org>
Role catalog configuration with several roles can be found in org-role-catalog.xml file in the samples.
|
Role catalog is displayed in used interface as a new organizational structure. However, as most organizational structures are built for people, midPoint user interface displays only users as members of organizational units by default. You have to explicitly change the type to role to see content of the catalog.

Primary use of the catalog is related to access request process.
The catalog makes it easier for a user to find appropriate role when requesting its assignment in self-service part of midPoint user interface.
Root org of the role catalog has to be configured in adminGuiConfig
section of system configuration object:
<systemConfiguration>
...
<adminGuiConfiguration>
...
<accessRequest>
<roleCatalog>
<roleCatalogRef oid="945315a6-fc23-11ea-832e-1f9945adb481" type="OrgType"/>
...
</roleCatalog>
</accessRequest>
</adminGuiConfiguration>
</systemConfiguration>
While the primary use of role catalog is the access request process, the catalog can also be used to apply policies to a whole group of roles. Owner of the category may be considered to be a default approver for all the roles in the category. Category owner may be authorized to modify roles in the category. And so on.
Similar approach can be applied to most objects in midPoint. Organizational structure can be used to organize roles, services, resources, function libraries and other objects. Orgs are also crucial mechanism in supporting midPoint multi-tenancy. Not everything is perfectly supported in user interface yet. Nevertheless, the organizational structure is a powerful mechanism to systematically and consistently apply policies and organize the system.
Organizational Structure Synchronization
MidPoint can manage organizational structure, but where that structure comes from? Back in 20th century there were entire teams dedicated to drawing organizational charts on paper. However, it is 21st century already. We do not use paper anymore. We are using computers to manage organizational charts now. Which means that dedicated teams are drawing organizational charts in Excel and distributing them by e-mail.
Fortunately, there are some organizations that have truly progressed into 21st century. Such organizations store their organizational structures in a machine-processable form, usually in database tables. When exported to a CSV file, the structure may look like this:
"orgnum","name","description","parentOrgNum"
"11000","Sales and Marketing Division","Expensive people that make money.","10000"
"11100","Direct Sales Department","Suits that talk to customers directly.","11000"
"11200","Indirect Sales Department","Suits that talk to other suits that talk to customers.","11000"
...
In this case, each organizational unit has a unique identifier, such as 11000
.
Each organizational unit has a reference to parent organizational unit.
When all the lines are processed, they form a complete organizational tree.
This is quite a good information source. Of course, we would like to automatically pull the data from this source instead of managing organization tree manually. How could we do it? Clever reader is smiling, remembering that we like to create generic re-usable mechanisms in midPoint. We already know how to synchronize user records from the HR system. As we are using midPoint, it is perhaps no big surprise that the same mechanisms can be easily reused to synchronize organizational unit records as well.
MidPoint synchronization mechanism can work with almost any type of object. It can synchronize HR records to users, organizational unit records to orgs, application inventory database to services, Active directory groups to roles or pretty much anything to anything. This is what we call generic synchronization.
Similarly to ordinary synchronization, we need to start with a resource. However, this resource does not contain accounts, it contains organizational units.
<resource oid="81ec779e-13b2-11eb-8e47-dfbfd542db3e">
<name>Organizational Chart</name>
<connectorRef type="ConnectorType">
<filter>
<q:text>connectorType = "com.evolveum.polygon.connector.csv.CsvConnector"</q:text>
</filter>
</connectorRef>
<connectorConfiguration>
<icfc:configurationProperties>
<icfccsvfile:filePath>/opt/midpoint/var/resources/org.csv</icfccsvfile:filePath>
<icfccsvfile:encoding>utf-8</icfccsvfile:encoding>
<icfccsvfile:fieldDelimiter>,</icfccsvfile:fieldDelimiter>
<icfccsvfile:multivalueDelimiter>;</icfccsvfile:multivalueDelimiter>
<icfccsvfile:uniqueAttribute>orgnum</icfccsvfile:uniqueAttribute>
</icfc:configurationProperties>
</connectorConfiguration>
<schemaHandling>
<objectType>
<displayName>Organizational unit</displayName>
<default>true</default>
<delineation>
<objectClass>AccountObjectClass</objectClass>
</delineation>
<kind>generic</kind>
<intent>orgunit</intent>
<focus>
<type>OrgType</type>
<archetypeRef oid="99fa4b3c-8702-11ef-896e-0b7221540b8b"/>
</focus>
<attribute>
<ref>orgnum</ref>
<inbound>
<target>
<path>$focus/identifier</path>
</target>
</inbound>
<inbound>
<expression>
<script>
<code>'F' + input</code>
</script>
</expression>
<target>
<path>$focus/name</path>
</target>
</inbound>
</attribute>
<attribute>
<ref>name</ref>
<inbound>
<target>
<path>$focus/displayName</path>
</target>
</inbound>
</attribute>
<attribute>
<ref>description</ref>
<inbound>
<target>
<path>$focus/description</path>
</target>
</inbound>
</attribute>
<attribute>
<ref>parentOrgNum</ref>
<inbound>
<expression>
<assignmentTargetSearch>
<targetType>OrgType</targetType>
<filter>
<q:text>identifier = $input</q:text>
</filter>
</assignmentTargetSearch>
</expression>
<target>
<path>$focus/assignment</path>
</target>
</inbound>
</attribute>
<correlation>
<correlators>
<items>
<item>
<ref>identifier</ref>
</item>
</items>
</correlators>
</correlation>
<synchronization>
<reaction>
<situation>linked</situation>
<actions>
<synchronize/>
</actions>
</reaction>
<reaction>
<situation>deleted</situation>
<actions>
<deleteFocus/>
</actions>
</reaction>
<reaction>
<situation>unlinked</situation>
<actions>
<link/>
</actions>
</reaction>
<reaction>
<situation>unmatched</situation>
<actions>
<addFocus/>
</actions>
</reaction>
</synchronization>
</objectType>
</schemaHandling>
<projection>
<assignmentPolicyEnforcement>none</assignmentPolicyEnforcement>
</projection>
</resource>
This should all look very familiar by now. It is almost the same resource as we have seen in the synchronization chapter. However, there are few differences, which are described in the following sections.
Kind and Intent
The definition of Organizational unit
resource object contains specification of kind and intent:
...
<objectType>
<displayName>Organizational unit</displayName>
<default>true</default>
<delineation>
<objectClass>AccountObjectClass</objectClass>
</delineation>
<kind>generic</kind>
<intent>orgunit</intent>
...
Kind and intent identify the type of resource object for use by midPoint. There are three possible values for kind:
Kind | Description |
---|---|
|
Resource object that represents identity of a person, either physical such as computer user or virtual such as |
|
Resource object that represents groupings or privileges of an account.
Entitlement resource objects represent groups, resource-specific roles, permissions or privileges.
Entitlements are meant to be associated to an account.
For example a |
|
Any other type of resource object. This is used for resource objects that cannot be classified as account or entitlement. |
You can choose any of these kinds for your resource objects. Values of kind are pre-defined in midPoint, as midPoint makes some assumptions about them. For example, midPoint expects that accounts can be associated with entitlements, for example accounts may be members of groups. Therefore, it is recommended to properly categorize your resource objects to kinds. This also helps to make the configuration understandable for mere mortals.
Then there is intent.
There are no pre-defined values for intent in midPoint, perhaps except for value default
which is used in case there is no explicit definition of intent.
You can choose any intent value that you like.
However, it is recommended to choose a value that describes the intended use of the resource object.
For example:
Kind | Example intent | Description |
---|---|---|
|
|
Default account. This usually means the usual, very ordinary user account. |
|
|
Administration account. Used in situations where administrators get dedicated accounts with administrator privileges. |
|
|
Testing account. Used when testers are given special-purpose accounts to use for testing, to avoid interference with their usual accounts. |
|
|
The usual, most ordinary, boring group of users. It can have accounts or other groups as its members. |
|
|
LDAP |
|
|
Resource object that represents system privilege. Can be "given" to an account. |
|
|
Resource object that represents physical location in our organization. Such as branch office, campus building or meeting room. It has no formal association to the account. |
|
|
Resource object that represents organizational unit. In our case, it represents one record in the organizational chart database. |
These are just examples.
You can choose any kind/intent combination that makes sense for your deployment.
For example, you may choose to use entitlement
kind for organizational units instead of generic
.
MidPoint would work fine even in that case.
However, our Organizational Chart
resource does not have any accounts, therefore the organizational units cannot be associated to anything in this resource.
Also, membership in an organizational unit does not really look like an entitlement.
Therefore, we have chosen to use generic
kind here.
You are free to make your own choices.
Why
Why is there AccountObjectClass ?AccountObjectClass in the configuration?
We are not working with accounts here, we work with organizational units.
So, why AccountObjectClass ?
The reason is the CSV connector that we are using.
The CSV connector is quite simplistic, it considers everything to be an account.
Object classes are determined by the connector, hence we need to use AccountObjectClass as the connector specified this object class.
However, the kind and intent definition is "overriding" the notion that this is an account, making it more understandable for midPoint users.
|
Kind and intent behave like coordinates when midPoint has to identify resource object that is assigned to a user.
Given normal circumstances, a user may have at most one default account on a resource (which means kind=account
, intent=default
).
That same user may also have admin account on the same resource (kind=account
, intent=admin
).
A role may be represented by at most one LDAP group on a resource (kind=entitlement
, intent=ldapGroup
).
MidPoint logic is heavily based on such assumptions.
Whenever there are two constructions that have the same combination of kind and intent, midPoint assumes that they are describing the same resource object.
MidPoint automatically merges the constructions.
If the constructions have different combination of kind and intent, midPoint assumes that they are describing different resource objects, therefore the constructions are processed separately.
Correct configuration of kind and intent is crucial for midPoint to work correctly.
Tag (a.k.a. "multiaccounts")
The requirement that there may be at most one resource object for each kind+intent combination works very well in most cases.
However, there are also cases when more than one resource object is needed.
Kind and intent has to be specified in the configuration, therefore this mechanism will not work for resource objects that appear and disappear dynamically.
Therefore, new concept of tag was introduced in midPoint 4.0.
The tag can supplement the kind+intent combination with a dynamic value, thus allowing multiple resource objects to exist for any particular kind+intent combination.
This feature is colloquially known as "multiaccounts".
|
Archetype
It would be acceptable to create our org just as plain org. Most things would work quite right. However, it is a very good practice to apply archetype to objects, especially those objects that are created automatically. Automation can create many objects very quickly. It may be tedious to modify all these objects when you figure out that you need to do something about them differently. Re-import of the objects do not always work, as not all the mappings may be strong. Of course, you can delete all the objects and re-import. However, that is going to change the OIDs, and manually created assignments are going to break - not to mention losing all manual changes to descriptions and documentation that you might have done. This is all too much inconvenience and manual work. We are using midPoint, we can do better.
When archetype is applied to the objects, common parts of object configuration and behavior can be specified in the archetype. Therefore update and maintenance of the objects is much easier. Really, there is no excuse for not applying the archetype, as it is very easy to do. All we need is to mention the archetype in the specification of object type in the schema handling.
<resource>
...
<schemaHandling>
...
<objectType>
...
<focus>
<type>OrgType</type>
<archetypeRef oid="99fa4b3c-8702-11ef-896e-0b7221540b8b"/>
</focus>
In this case we are using Organizational unit
archetype.
For now, the archetype is almost empty, it just specifies some cosmetics for nicer look and feel of organizational units.
<archetype oid="99fa4b3c-8702-11ef-896e-0b7221540b8b">
<name>Organizational unit</name>
<archetypePolicy>
<display>
<label>Organizational unit</label>
<pluralLabel>Organizational units</pluralLabel>
<icon>
<cssClass>fa fa-sitemap</cssClass>
<color>#ffc107</color>
</icon>
<tooltip>Organizational unit</tooltip>
</display>
</archetypePolicy>
</archetype>
Names and Identifiers
Synchronization of organizational structure is the same as synchronization of users.
Theoretically.
However, there are some subtle differences in practice, mostly caused by the differences of User
and Org
schemas.
The first difference originates from the fact, that name
of the org has to be unique.
This uniqueness is usually not a problem for users, as username is naturally unique among the entire user base.
However, this is slightly different for orgs, as there may be several parallel organizational structures.
There may be Security
department, Security
project and Security
workgroup at the same time.
This may be partially solved by using identifiers instead of names.
However, this still does not solve the problem of department 123
and project 123
.
The simple solution is to prefix the identifier with a code of the organizational tree that it belongs to, thus creating department F123
and project P123
.
However, users looking for project 123
may have difficulty finding it, as the P
prefix in P123
name is usually just a deliberate decision of midPoint administrator.
Therefore, we still want to store the original identifier value (123
) into the identifier
property of the org object.
There is no uniqueness constrain on the identifier
property, therefore both department 123
and project 123
can co-exist and both can be easily discovered by searching the identifier.
The result is that we need two inbound mappings for the orgnum
attribute:
<attribute>
<ref>orgnum</ref>
<inbound>
<target>
<path>$focus/identifier</path>
</target>
</inbound>
<inbound>
<expression>
<script>
<code>'F'+input</code>
</script>
</expression>
<target>
<path>$focus/name</path>
</target>
</inbound>
</attribute>
Storing original organizational unit identifier in the identifier
property makes it easier to correlate organizational units.
The idenfier
property can be used by the correlators.
If the identifier is reasonably persistent, this is a huge benefit.
Changes in organizational structure can be quite nasty. Organizational units are often renamed or moved in organizational trees. Simplistic synchronization configuration may not be able to interpret such events correctly. Rename of an organizational unit may look like new organizational unit was created, and the old unit was deleted. This is likely to wreak havoc to organizational unit assignments, especially if there were special privileges configured for renamed organizational unit. Even worse, organizational tree data are sometimes acquired from a different source than the user data, which is causing timing problems. If organizational tree is updated first, there will be new empty organizational unit, old unit will be deleted, and user assignments will become invalid. If user data are updated first, the synchronization routines may not be able to update the assignments as the new organizational unit does not exist yet. This is going to cause a whole lot of problems, most of them requiring manual intervention of midPoint administrator. Additionally, reorganizations usually happen in cycles, each cycle changing a number of units at the same time. Which means that every few months the organizational structure is going to break down, everybody is going to complain, and it is likely to take several days to fix all the problems manually.
All of that can be avoided if there are reasonably persistent organizational unit identifiers. Which means that every organizational unit has an identifier that does not change when the unit is renamed or moved. In that case midPoint can reliably detect the rename, change organizational unit name and keep the assignments intact. MidPoint can also detect that the unit was moved, change the parent unit and still keep all the assignments. Organizational unit identifiers make everything so much easier. Therefore, try really hard to use the identifier when setting up synchronization of organizational structure. If there is no such identifier, talk to the business people to add it. This is usually not an easy discussion, as the solution often involves changes in business processes. However, it is absolutely essential to get it right. All the effort will be repaid many times over during the course of identity program.
Nesting Organizational Units
We can synchronize the organizational units into midPoint. We can use mappings to set up the properties of organizational units, such as names and identifiers. However, that is still not enough, as organizational structures are usually hierarchical. How to do we nest organizational units to create organizational tree?
In midPoint, organizational tree is formed by assignments. Therefore, the answer is quite simple: create the right assignments. Clever reader is not paying attention anymore, being busy re-reading the sections on automatic role assignments. Clever reader is quite right, the same techniques that are used for automatic assignments of roles can be used to form organizational assignments. Perhaps the best way to set the assignments for organizational hierarchies is to use inbound mappings:
<attribute>
<ref>parentOrgNum</ref>
<inbound>
<expression>
<assignmentTargetSearch>
<targetType>OrgType</targetType>
<filter>
<q:text>identifier = $input</q:text>
</filter>
</assignmentTargetSearch>
</expression>
<target>
<path>$focus/assignment</path>
</target>
</inbound>
</attribute>
This mapping automatically sets up an assignment to parent organizational unit.
We are lucky as we have almost ideal source of organizational data.
Our CSV file contains an identifier of a parent organizational unit in the parentOrgNum
column.
All we need to do is to look for midPoint org that has that particular value in its identifier
property.
This is done by the assignmentTargetSearch
that we have already used for automatic assignment of roles.
The same mechanism is reused here.
All that remains is to set up a synchronization task.
Make sure that you specify kind and intent in the synchronization task.
This is important, otherwise the tasks are not going work.
Setting the right kind and intent was not emphasized before when we were synchronizing accounts.
The account
kind is the default, and midPoint is usually smart enough to use default intent.
However, the defaults do not work any longer when we go beyond the accounts.
Troubleshooting
Generic synchronization can be confusing as there may be non-obvious configuration complexities.
When mis-configured, the synchronization mechanism often does nothing.
There is no error or any other obvious indication as to what exactly went wrong.
Logging is your best friend in that case.
Try to enable logging of synchronization service (com.evolveum.midpoint.model.impl.sync ) at debug level.
MidPoint will log a reasonable amount of information about the synchronization process.
That information is very likely to lead you to the solution.
|
The configuration above works for simple cases, yet there is still a room for improvement.
The search filter in assignmentTargetSearch
expression is quite simplistic.
It matches orgs from several trees if they have the same identifier.
Similar problem is in the correlation settings.
However, clever reader would surely find a way how to improve it.
Also, this method works only if the data feed is correctly ordered. Everything works as long as parent organizational units are synchronized before child organizational units. However, that is not always the case. If ordering is wrong, child organizational units will not be able to find parent units, and the tree disintegrates. As we are living in a networked concurrent world, data ordering is usually difficult to guarantee.
MidPoint has a mechanism to handle unordered data sources. There is a way to create parent organizational units on demand. When a child organizational unit looks for a parent that is not there yet, the parent object can be created at that moment. Of course, this can only create stub parent, a very minimal object that has only the essential data. Yet, even such a stub object is sufficient to create an organizational hierarchy. The stub can be updated later, when the details about parent organizational unit are retrieved from the data feed. The details of the create on demand mechanism is beyond the scope of this chapter. We will get back to it later.
Adding Users To Organizational Units
We have a nice hierarchical organizational structure now. Yet, something is still missing. The organizational structure is all about the people, but there are no people in our organizational tree. Let’s fix this.
In our ExAmPLE case, people data are coming from HR resource.
So far we do not have any data in this data source to automatically assign people to the organizational tree.
We need to modify the HR resource to add information about organizational units into our HR feed.
It went quite well.
After several phone calls, tens of e-mails and a quick 3-hour meeting, the HR department agreed to add a new orgnum
column to the CSV file:
"empno","firstname","lastname","jobcode","orgnum"
"001","Alice","Anderson","B002","11000"
"002","Bob","Brown","O302","12000"
"003","Carol","Cooper","S101","11310"
...
The 'orgnum' column contains an identifier of the organizational unit the person belongs to. This looks quite familiar, and clever reader is working on the configuration already. Of course, we can use the same approach we have used to build up organizational hierarchy. We just need to apply it to the users instead of orgs. Therefore, we are going to add new inbound mapping to the HR resource:
<attribute>
<ref>orgnum</ref>
<inbound>
<expression>
<assignmentTargetSearch>
<targetType>OrgType</targetType>
<filter>
<q:text>identifier = $input</q:text>
</filter>
</assignmentTargetSearch>
</expression>
<target>
<path>$focus/assignment</path>
</target>
</inbound>
</attribute>
The assignmentTargetSearch
expression looks for the right organizational unit.
Then the mapping creates an assignment to that unit.
We are done, as easily as that.
Run the HR synchronization task, and all the users are going to be neatly organized in the organizational tree.
Get your data structures right at the beginning.
That 3-hour meeting with HR was in fact really useful and necessary. The result was that ExAmPLE HR department did the right thing. They put identifier of organizational unit in the HR feed, instead of organizational unit name. Having organizational unit identifier makes everything much more stable. There is a lesson to be learned. Every hour spent designing the data structures will be repaid many times over. Getting it wrong will cost you days or months spent dealing with data inconsistencies. It is also very difficult to change data formats in the future, as they effectively become data integration interfaces. Take your time and get it right at the beginning. |
Organizational Structure Provisioning
We have seen how we can synchronize organizational structure into midPoint. We are talking about midPoint here. What goes in, can also go out. It is very simple to provision organizational structure to an ordinary target system, such as database table. However, we have already learned a thing or two, and doing that would be almost boring. Therefore, let’s do something a bit more challenging. Let us synchronize the organizational structure into an LDAP directory tree.
The basic principles of organizational structure provisioning are the same as for user provisioning. We need to set up outbound mappings for organizational units. We already know how to do that. There are just few little differences:
-
We will use
organizationalUnit
object class instead ofinetOrgPerson
. -
We will use kind/intent combination that describes organizational units.
-
We have to be a bit smarter about creating LDAP distinguished names (DNs) for the entries, as we want them to create a hierarchical data structure.
Everything else is essentially the same as for users and accounts. Let us go over all the details, step by step.
First of all, we need to add new objectType
definition to the LDAP resource:
<objectType>
<kind>generic</kind>
<intent>ou</intent>
<displayName>Organizational Unit</displayName>
<delineation>
<objectClass>organizationalUnit</objectClass>
</delineation>
<attribute>
<ref>dn</ref>
<displayName>Distinguished Name</displayName>
<limitations>
<minOccurs>0</minOccurs>
<maxOccurs>1</maxOccurs>
</limitations>
<outbound>
<name>ldap-ou-dn</name>
<trace>true</trace>
<source>
<path>$focus/name</path>
</source>
<expression>
<script>
<code>
import javax.naming.ldap.Rdn
import javax.naming.ldap.LdapName
// We will collect names of the org units in the orgpath list
// We cannot add them to dn yet as we need their order to be reversed
def orgpath = []
def node = focus
while (true) {
log.debug("processing node {}", node)
orgpath.add(node.displayName.orig)
if (node.parentOrgRef == null || node.parentOrgRef.isEmpty()) {
break
} else {
node = midpoint.resolveReference(node.parentOrgRef[0])
}
}
log.debug("orgpath={}", orgpath)
def dn = new LdapName('ou=org,dc=example,dc=com')
orgpath.reverse().each { ouname -> dn.add(new Rdn('ou',ouname)) }
return dn.toString()
</code>
</script>
</expression>
</outbound>
</attribute>
<attribute>
<ref>ou</ref>
<limitations>
<maxOccurs>1</maxOccurs>
</limitations>
<outbound>
<source>
<path>$focus/displayName</path>
</source>
</outbound>
</attribute>
</objectType>
Except for that big piece of Groovy code, this configuration is relatively simple.
The delineation
definition specifies organizationalUnit
value for object class.
This is a standard LDAP object class for "ou" entries.
There is also specification of kind (generic
) and intent (ou
).
These are midPoint "coordinates" for this object type.
Then we have two outbound mappings, one for LDAP distinguished name (dn
), the other for naming attribute (ou
).
The ou
mapping is very simple, using a value of org’s displayName
.
On the other hand, the dn
mapping looks somehow scary.
There is no need to be afraid.
We are going to explain everything, and there are some really interesting parts here.
The purpose of the dn
mapping is to construct LDAP distinguished name in a hierarchical manner.
We want to put the organizational tree under the ou=org,dc=example,dc=com
entry, with the entry for ExAmPLE company at the top.
Therefore, the dn
of Operations Division need to be ou=Operations Division,ou=ExAmPLE,ou=org,dc=example,dc=com
.
IT Department goes under the Operations Division, therefore we need its dn
to be ou=IT Department,ou=Operations Division,ou=ExAmPLE,ou=org,dc=example,dc=com
.
We need to process the tree from the organizational unit all the way through all the parent units to the very top of organizational structure.
That is exactly the thing that the Groovy expression does.
Let’s skip the import
statements for now.
The first thing that the expression has to do is to figure out the "path" from the current organizational unit to the top of the tree.
The expression gets the current organizational unit in the focus
variable.
However, the org object does not contain its complete path in the tree.
All it has is a reference to its parent organizational unit (parentOrgRef
).
Therefore, the expression has to iterate over all the levels in the tree until it gets to the top.
The top organizational unit does not have any parent, that is where the iteration stops.
Display names of each organizational unit at the "path" is collected in the orgpath
list.
As the org contains only a reference to the parent, we need to explicitly read the parent object from midPoint repository.
We do that with an explicit call to midpoint.resolveReference(…)
method.
This method reads the object from midPoint repository and returns it.
When the loop stops, orgpath
contains all the display names that we want in our dn
.
Now we need to encode the names in LDAP DN format.
This can be done by simple string operations.
However, there are some intricate details about escaping the names as they are encoded.
It would be nice if someone else could do the encoding for us.
Turns out, there is someone else to do it.
Java platform comes with Java Naming and Directory Interface (JNDI), which is supposed to be a generic library to access broad range of directory services.
JNDI is not the best library that the world has ever seen, but it is part of Java platform, and it can do formatting of LDAP DN.
It is good enough for our purposes.
We take advantage of JNDI LdapName
and Rdn
classes to encode the DN.
The import
statements at the beginning made use of these classes quite convenient.
The last detail is the ordering.
We want our names in the DN to be in a different order, therefore we just reverse orgpath
before processing.
Tracing and logging
Clever reader has noticed a couple of interesting things in that mapping.
Especially the <trace> element looks very useful, which it is.
It turns on detailed tracing of the mapping.
MidPoint will record the details of mapping evaluation in the log file.
Similar <trace> element can also be applied at the expression level.
Then there are the log statements in the Groovy code, such as log.debug("processing node {}", node) .
These are explicit logging statements.
The processing node … message is recorded to the log file at debug level.
This is a very useful tool for diagnosing execution of complex expressions.
|
Our outbound mappings are ready to go. However, nothing happens yet. MidPoint does not know that it is supposed to create LDAP objects for our organizational units. MidPoint does not automatically create accounts for all the users either. We need a construction to do that. The orgs need to have an assignment with a construction - similar to these that we have used to create accounts, just with different kind and intent. We want to archive something like this:
<org oid="7a1feb50-471f-11ea-8aab-1b2627541f15">
<name>F11000</name>
<displayName>Sales and Marketing Division</displayName>
...
<assignment>
<construction>
<!-- LDAP resource -->
<resourceRef oid="8a83b1a4-be18-11e6-ae84-7301fdab1d7c"/>
<kind>generic</kind>
<intent>ou</intent>
</construction>
</assignment>
</org>
You can test your configuration by creating this assignment manually in the GUI, or by editing the XML/JSON/YAML version of the org. However, manual method is not going to work in production. We need to create these assignments automatically. There are several ways to do it.
Perhaps the most obvious way would be to add a mapping to create this assignment in the object template for Organization unit objects.
As there is an object template for users (UserType
), there may be an object template for any other midPoint object or archetype.
Therefore, you can create object template for Organizational unit
archetype and configure the mapping there.
This would be an acceptable solution.
An alternative way would be to add inbound mapping to create this assignment.
That would be in fact quite easy, as it would is very similar to the mapping that we have used to create organizational hierarchy.
However, that would not be an ideal configuration, as we would mix the concerns here.
The mapping would be an inbound mapping in the Organizational Chart
resource.
It would not be entirely appropriate for this inbound mapping to control provisioning (i.e. outbound flow) of organizational structure.
It could work, but such configuration would be difficult to understand and maintain.
We do not like that.
Clever reader is now thinking about the meta-role principle, looking at the Organizational unit
archetype.
As usual, cleaver reader is absolutely right.
All we need is to add the construction into the Organizational unit
archetype in a form of inducement.
<archetype oid="99fa4b3c-8702-11ef-896e-0b7221540b8b">
<name>Organizational unit</name>
...
<inducement>
<construction>
<!-- LDAP resource -->
<resourceRef oid="8a83b1a4-be18-11e6-ae84-7301fdab1d7c"/>
<kind>generic</kind>
<intent>ou</intent>
</construction>
</inducement>
</archetype>
Back when we were configuring inbound synchronization of organizational units, we have do the right thing and assigned an archetype to the orgs we have created. Now it pays back ist dues, archetype makes is very easy to control behavior of all the organizational units. All we need to do now is to re-run the synchronization task. The result is a nice organizational structure in LDAP directory:

This is a nice result. However, there are still several remarks to make.
If you are going to try this scenario with a real LDAP server, you would need to create a root entry for the organizational structure (ou=org,dc=example,dc=com
), as well as entry for ExAmPLE company (ou=ExAmPLE,ou=org,dc=example,dc=com
).
You would also need to update access control lists (ACLs).
However, be warned that this is not a very ideal method to maintain organizational structure in LDAP directory.
We are using display names here, which are part of LDAP identifiers (DNs).
Therefore, even a minor correction in organizational unit name will trigger LDAP rename operation.
It will change the identifier of the organizational unit, and also all the organizational units below it.
Perhaps the only thing that can make it worse is to place users in that structure as well.
Which some people actually do.
The only real reason to put organizational structure in this form is to satisfy the needs of legacy applications.
Avoid this approach whenever you can.
We are presenting it here only for demonstration purposes, to explain a method for provisioning hierarchical structures.
The clever reader have surely noticed that the big Groovy expression above is explicitly fetching objects from midPoint repository database. This may cause a performance problem in case that such expression is evaluated often or if the structure is very deep. This is usually not the case with ordinary organizational structures, therefore this approach is usually not problematic. However, it is always a good thing to keep performance in mind, especially if your user population is bigger than few thousands of users.
Finally, we still depend on ordering of the data feed. We want to create "higher" entries in LDAP first, otherwise an attempt to create "lower" entries would fail. This can be solved by using the "create on demand" approach mentioned above. However, it is going to be problematic and cumbersome when organizational unit display names are used instead of identifiers. However, in that case this little details does not matter that much anyway, as it is likely you will suffer for many different reasons if organizational display names are used instead of identifiers. Always use organizational unit identifiers if you can. We really mean it. You can thank us later.
Focus and Projection
Synchronization of an organizational structure is an application of a generic synchronization principle. Almost any resource object can be synchronized with almost any midPoint object - and vice versa. Principle of the synchronization is essentially the same as in user-account case, as we have seen in previous chapters. In that case, the accounts were linked to user, midPoint synchronized the data from account to user and from user to accounts. The synchronization follows user-account links.

Synchronization of an organizational structure is based on the same principle. However, there is an org instead of user, and there are various resource objects instead of accounts. It may look like this:

There may be user, org, service, role or similar midPoint object on the midPoint side. These may be synchronized with account, group, role, privilege, organizational unit or almost any resource object on resource side. As you can see, the terminology becomes quite cumbersome. Saying "similar midPoint object" and "almost any resource object" is not very natural or precise. Therefore, we have decided to use focus and projection terms:

The object that is "in the middle" is called focus or focal object. It is in the centre of the synchronization, it is its focal point. Every relevant piece of data is reflected onto the focal object by the synchronization mechanisms.
User is a very typical focal object. Other midPoint objects can be focal objects as well, most notably org, role and service.
The state of focal object is projected back to the resources. Therefore, the objects that reside on the resources are called projections. An account is a typical projection object, but there is wide variety of other object classes such as groups, organizational units, (resource-side) roles, privileges, access control lists, teams and so on.
Focus and projection
Focus and projection may sound like strange words to use for identity management concepts.
However, it is very difficult to find the right words.
Many identity management systems work with just user and account.
However, midPoint is more flexible, much more generic.
When we designed the generic synchronization mechanism, we needed to find good names for the generalization of user and account concepts.
We tried hard, but we could not find anything better than focus and projection.
The names may not be ideal, yet we are able to live with them.
There are only two hard problems in computer science, after all.
|
There is always one focus, one focal object in the center. There may be any number of projections linked to the focus. There may be several projections on one resource. However, each projection has to be unique, it needs to have a unique combination of kind and intent (or kind, intent and tag when "multi-accounts_ are used). This is the reason that we consider kind and intent to be coordinates, as they uniquely identify a projection on a particular resource.
This is a very flexible concept that can be used for various purposes. We have already seen how it can be used for synchronization of organizational structure. Similar principle can be used to synchronize Active Directory groups, automatically creating application role for each Active Directory group. This principle provides a mechanism to create multiple accounts for one user on one resource. For example, it can be used to create administration accounts for some users. In this case, we would use explicit kind and intent in the construction:
<role oid="0e9c448c-1f87-11eb-9703-b3d28c537192">
<name>System Administrator</name>
<inducement>
<construction>
<!-- Active Directory resource -->
<resourceRef oid="1e1e5a1c-1f87-11eb-8ace-1fbd338f61c5"/>
<kind>account</kind>
<intent>admin</intent>
</construction>
</inducement>
</user>
The System Administrator
role above specifies that a special admin
account should be created for system administrators.
When this role is combined by an ordinary Employee
role, the administrator will get two accounts: the usual employee account (intent=default
) and a special-purpose administration account (intent=admin
).
Overall, the concept of focus and projections is a generic principle that permeates entire midPoint platform. It applies to generic synchronization, access control models such as RBAC, provisioning, policy management and to almost any other aspect of midPoint functionality. It is one of the basic principles that midPoint is built on.
Conclusion
MidPoint organizational structure is a versatile and powerful mechanism. It can be used to organize users in units, teams and projects. It can be used to group variety of other midPoint objects. However, organizational structure becomes incredibly powerful when combined with other midPoint mechanisms. Authorizations can take advantage of organizational structures to implement delegated administration schemes. Organizational structures are used in certification campaigns. MidPoint multi-tenancy mechanism also relies on organizational structures. Organizational structure is a universal mechanism to organize midPoint objects.
There are many universal mechanisms in midPoint, synchronization mechanism being one of the prominent ones. Synchronization was designed to work with many types of midPoint objects, including organizational structure. Expressions and mappings bring the power to transform organizational structure data during synchronization, supporting diverse set of use cases. Similar mechanisms can be used to synchronize roles and services, granting midPoint enormous flexibility in identity management deployment.