User Interface Form Fields

Last modified 12 Nov 2021 16:57 +01:00

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:

Basic account type configuration
<resource>
     ...
     <schemaHandling>
        <objectType>
            <displayName>Default Account</displayName>
            <default>true</default>
            <objectClass>ri:inetOrgPerson</objectClass>
        </objectType>
     </schemaHandling>
</resource>

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:

Account type with a mapping
<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):

Account type with a mapping
<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 uid, cn, sn are formally multi-valued in the LDAP schema. But vast majority of systems are using them as single-valued attributes. Setting multiple values for these attributes can easily ruin interoperability. Therefore these attributes can be defined as single valued (maxOccurs=1) in the model layer. Then any mapping that produces multiple values for these attributes will fail which makes the diagnostics and troubleshooting much easier.

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.

Modifying schema in object template
<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

input

The attribute value to check

object

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.

Was this page helpful?
YES NO
Thanks for your feedback