<resource>
...
<schemaHandling>
<objectType>
<displayName>Default Account</displayName>
<default>true</default>
<objectClass>ri:inetOrgPerson</objectClass>
</objectType>
</schemaHandling>
</resource>
User Interface Form Fields
MidPoint is Schema-Driven
MidPoint has a flexible user interface that automatically adapts to changed schema. This is one of the crucial midPoint features that supports efficient midPoint deployments. Change of schema is usually the only thing that is needed to customize the way how midPoint displays data. E.g. if a new account attribute appears on the resource all that is needed is to refresh the cached resource schema. MidPoint will automatically use the schema to display account forms in the user interface, it will automatically use input field that is appropriate for the attribute type, it will automatically indicate whether the attribute is optional, mandatory, single-value or multi-value, it will display a proper label and so on.
Similar behavior can be seen for all the other parts of midPoint. E.g. the fields of user form are determined from the schema of UserType, the resource configuration in the resource wizard is driven by the connector schema and so on.
Customizing the Schema
Default midPoint schema-driven behavior is ideal for a significant number of properties and resource attributes and it is extremely useful mechanism that saves significant amount of deployment effort. But there are (as always) exceptions. And especially for resource attributes these exceptions are quite common. Let’s explain that using an example of a LDAP resource.
We have a simple LDAP resource with root suffix dc=example,dc=com
. We want to manage LDAP accounts in ou=people,dc=example,dc=com.
The accounts will have inetOrgPerson
object class.
This all easy.
MidPoint will discover LDAP schema and we will configure basic account object type in resource schema handling section:
The default LDAP resource identifiers are entryUUID
and dn
. The entryUUID
is primary identifier.
It is persistent (immutable) and it is generated by the LDAP server when a new entry is added.
The dn
(distinguished name) is a secondary identifier.
It is a structured string that determines location of the object in the LDAP tree.
The dn
is a requited (pseudo)attribute when the new entry is added.
Therefore the dn
is a required attribute.
And this is also reflected by midPoint when displaying account forms.
The "Distinguished Name" field will be marked as required.
But LDAP distinguished names are quite ugly (e.g. uid=foo,ou=people,dc=example,dc=com). We definitely do not want users to enter that information manually every time the account is created. So we define a mapping to determine distinguished name automatically from the username:
<resource>
...
<schemaHandling>
<objectType>
<displayName>Default Account</displayName>
<default>true</default>
<objectClass>ri:inetOrgPerson</objectClass>
<attribute>
<ref>ri:dn</ref>
<outbound>
<strength>weak</strength>
<source>
<path>$user/name</path>
</source>
<expression>
<script>
<code>
'uid=' + name + ',ou=people,dc=example,dc=com'
</code>
</script>
</expression>
</outbound>
</attribute>
</objectType>
</schemaHandling>
</resource>
Now the dn
attribute will be automatically computed every time that the account is added.
So there is no need for user to enter that value manually.
However, the "Distinguished Name" field in the account form will still be marked as required because that is what the resource schema is saying.
MidPoint cannot automatically relax that constraint just because there is a mapping.
The mapping is too flexible.
The mapping might be conditional or it may provide value only for some inputs.
MidPoint does not know that.
Only the author of the mapping knows it.
However, our mapping is quite simple and it will provide a valid output for all the practical input values.
Therefore now we want to mark the "Distinguished Name" field as optional.
We can do it by changing the resource schema but that is not correct as the dn attribute is still required by the resource.
We want to make it optional only in the user interface.
And there is a simple way to do it.
Limitations and Layers
The resource schema handling sections allows to specify limitations for each attribute. The limitations override the definitions in resource schema. The limitations can change whether the attribute will be understood as required, optional, single-value or multi-value, whether it can be read, modified and so on.
However, it is usual that different limitations apply to different system layers.
E.g. we want the dn
attribute to be presented as optional in the user interface because there is an outbound mapping for it.
But we want to consider it as mandatory on the low system levels so if the mapping fails to produce a value we will get a reasonable error message.
Therefore we want to change only the limitations that apply to the presentation layer and make the dn
attribute optional (i.e. specify that minOccurs
is zero):
<resource>
...
<schemaHandling>
<objectType>
<displayName>Default Account</displayName>
<default>true</default>
<objectClass>ri:inetOrgPerson</objectClass>
<attribute>
<ref>ri:dn</ref>
<limitations>
<layer>presentation</layer>
<minOccurs>0</minOccurs>
</limitations>
<outbound>
<strength>weak</strength>
<source>
<path>$user/name</path>
</source>
<expression>
<script>
<code>
'uid=' + name + ',ou=people,dc=example,dc=com'
</code>
</script>
</expression>
</outbound>
</attribute>
</objectType>
</schemaHandling>
</resource>
There are three system layers defined:
Layer | Description |
---|---|
presentation |
The presentation layer that is used to display information to the user. This limitation applies to the midPoint user interface. It will affect the presentation logic, but not the deeper system logic.E.g. if a required attribute is marked as optional in the presentation layer the midPoint user interface will not require user to fill it in. But the processing may still fail after the form is submitted unless a mapping provides a valid value for the attribute.This also means presentation of the data outside midpoint. Therefore it applies both to GUI and also the web service interface and also to similar interfaces. |
model |
Model layer means application of schema constraints inside the IDM Model Subsystem. This is the value that the midPoint identity management logic will be using.
It will be used by mappings and similar mechanisms.E.g. LDAP attributes |
schema |
The Resource Schema layer. This is the lowest layer. Limitations on this layer can be used to override the values given by the resource schema. Some resources notoriously present wrong schema and it must be corrected to use usable. However the resource schema is usually automatically generated and therefore it is not practical to modify it directly. This layer can be used as an elegant mechanism to correct such errors. |
Object Template
Similarly as resource schema handling is used to modify the resource schema, object template can be used to modify the schema of focal objects (UserType, RoleType, OrgType). The following example shows user template that is used to hide the additionalName
property from the schema.
<objectTemplate>
<item>
<ref>additionalName</ref>
<limitations>
<ignore>true</ignore>
</limitations>
</item>
</objectTemplate>
Form Validation
Since 3.8.1
This functionality is available since version 3.8.1.
|
In addition to hide or change multiplicity of the item, it is also possible to defined custom validation for their values. The example of such custom validation is show below:
<item>
<ref>telephoneNumber</ref>
<validation>
<server>
<expression>
<trace>true</trace>
<script>
<code>
import java.util.regex.Matcher
import java.util.regex.Pattern
import com.evolveum.midpoint.schema.result.OperationResult
import com.evolveum.midpoint.schema.result.OperationResultStatus
if (input == null) {
return null
}
match = (input ==~ "^[0-9]*\$")
if (match) {
return null
}
result = new OperationResult("Validate telephone number");
result.setMessage("Telephone number must contains only digits");
result.setStatus(OperationResultStatus.FATAL_ERROR)
return result.createOperationResultType();
</code>
</script>
</expression>
</server>
</validation>
</item>
In the example above, the value of the telephoneNumber is validated. The validation pass if the value contains only digits, otherwise it fails. The expected return type (in 3.8.1) is always OperationResultType. The message and status are required. If the status is not set, midPoint cannot know that the validation failed. The message is shown to the user after validation failed.
There are two variables available to the expression:
Variable name | Content |
---|---|
|
The attribute value to check |
|
The currently processed object (e.g. user) |
Refined Schema
The native schema (Resource Schema or a static Data Model) is merged together with limitations in resource schema handling and object template to create a refined schema. The refined schema defines the effective schema that applies to current midPoint configuration. The concept of refined schema is not directly visible to the midPoint user. But it is refined schema that is used to display user interface forms, evaluate mappings and so on. The concept of refined schema is used all over the midPoint internal implementation, therefore it might be mentioned in the documentation, issues or samples.
Authorizations and Schema
One set of constraints is given by the (refined) schema. But there is also a flexible authorization mechanism that determines who has access to what. Given the midPoint philosophy of efficiency, if an authorization allows user to see only part of the attributes then the user interface adapts automatically and it only shows the attributes that the user is allowed to see. Similarly, if user is allowed to edit only some attributes the user interface adapts and correctly displays field as read-only or read-write. Therefore the (refined) schema and authorizations are combined to provide final user experience.
However there are differences. The (refined) schema is inherently global. The limitations given by the schema apply to all users in the same way. The authorizations are much more flexible. The each user can be authorized to see a different set of data. However there is also associated cost. The (refined) schema is very efficient and it scales well. The authorization mechanism is less efficient. Large number of authorizations might cause a scalability problem.