Different Naming Conventions For Different User Types

The user naming attribute “name” is a string attribute and can be defined manually. MidPoint will ensure that the value of this attribute is unique. Although for small setups there is no problem with entering this attribute value manually, it can be usually defined by an expression based on various UserType object properties (attributes). In this example I would like to show you how to define different user “types” and different but unique naming conventions for them.
Let’s start with a simple assumption: all users in midPoint should have “givenName” and “familyName” attributes filled with data. We will generate the “name” attribute as a simple concatenation: “givenName.familyName” and make sure that the value is unique using the iterators.
We need an objectTemplate object for this, with a iteration configuration and one mapping. First, the explanation:

  • the “name” attribute will be generated as a concatenation of “givenName”, a dot, “familyName” and iterationToken, if the name would not be unique
  • as the “givenName” and/or “familyName” can contain diacritics, we use normalized values and replace all spaces with another dot. This is because basic.norm() function returns spaces; and because the names can contain spaces.
  • the iterator is configured to generate random 3-digit number, zero-padded
  • user must have both “givenName” and “familyName” attributes filled (not empty)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<objectTemplate oid="59b65136-0f36-11e5-86f0-3c970e44b9e2"
 xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
 xmlns='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
 xmlns:c='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
 xmlns:t='http://prism.evolveum.com/xml/ns/public/types-3'
 xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3">
  <name>Default User Template</name>
  <iteration>
    <maxIterations>999</maxIterations>
    <tokenExpression>
      <script>
        <code>
    if (iteration == 0) {
    return "";
    } else {
    rnd = new Random().nextInt(999) + 1
    return "." + sprintf("{1acb01afcc33953bed28d92be9d735e579722d77ac7936fdfc467b8d28505288}03d", rnd);
    }
    break
        </code>
      </script>
    </tokenExpression>
  </iteration>
  <mapping>
    <name>Default User Template: Generate Name</name>
      <source>
        <path>givenName</path>
      </source>
      <source>
        <path>familyName</path>
      </source>
      <expression>
        <script>
            <code>
// we take the givenName/familyName, normalize (remove diacritics) and then replace spaces with a dot
tmpGivenName = basic.norm(basic.stringify(givenName))?.tr(' ', '.')
tmpFamilyName = basic.norm(basic.stringify(familyName))?.tr(' ', '.')
return tmpGivenName + '.' + tmpFamilyName + iterationToken
            </code>
        </script>
      </expression>
      <target>
        <path>name</path>
      </target>
      <condition>
        <script>
          <code>givenName != null &amp;&amp; familyName != null</code>
        </script>
      </condition>
    </mapping>
. . .

The object template must be made default for “UserType” objects – this can be done in Configuration – Basics menu in GUI.

Some examples of the behaviour:

  • givenName: John, familyName: Smith, name: john.smith
  • givenName: John, familyName: Smith, name: john.smith409
  • givenName: Leonardo, familyName: Da Vinci, name: leonardo.da.vinci

Now imagine that you have more than just ordinary users in midPoint. You can have administrators, vendors, technical users, testing users, external users etc. Their naming conventions would be probably different and you will need to define different naming conventions for different user types. This was my case. All I needed to do was to extend the configuration in the object template and make the generator use an additional attribute: “employeeType”. I’ve defined a set of usable values, such as:

  • EMP
  • ADM
  • TST
  • SYS
  • EXT

The modified fragment of the object template is below. I’ve updated the iteration configuration to generate the previously used 3-digit random number for “EMP” and “EXT” values of “employeeType” attribute, and a simple number starting from “2″ for all other types.

More mappings for generating “name” were added, see the conditions using “employeeType”. “givenName” is no more used in some of the mappings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<objectTemplate oid="59b65136-0f36-11e5-86f0-3c970e44b9e2"
 xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
 xmlns='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
 xmlns:c='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
 xmlns:t='http://prism.evolveum.com/xml/ns/public/types-3'
 xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3">
  <name>Default User Template</name>
  <iteration>
    <maxIterations>999</maxIterations>
    <tokenExpression>
      <variable>
        <name>employeeType</name>
        <path>$focus/employeeType</path>
      </variable>
      <script>
        <code>
switch (basic.stringify(employeeType)) {
    case 'EMP':
    if (iteration == 0) {
    return "";
    } else {
    rnd = new Random().nextInt(999) + 1
    return "." + sprintf("{1acb01afcc33953bed28d92be9d735e579722d77ac7936fdfc467b8d28505288}03d", rnd);
    }
    break
    case 'EXT':
    if (iteration == 0) {
    return "";
    } else {
    rnd = new Random().nextInt(999) + 1
    return "." + sprintf("{1acb01afcc33953bed28d92be9d735e579722d77ac7936fdfc467b8d28505288}03d", rnd);
    }
    break
    default:
        if (iteration == 0) {
          return "";
        } else {
          return "" + (iteration+1) // will return 2 as the first iterationToken
        }
        break
}
        </code>
      </script>
    </tokenExpression>
  </iteration>
  <mapping>
    <name>Default User Template: Generate Name for EMP / EXT</name>
      <source>
        <path>givenName</path>
      </source>
      <source>
        <path>familyName</path>
      </source>
      <source>
        <path>employeeType</path>
      </source>
      <expression>
        <script>
            <code>
// we take the givenName/familyName, normalize (remove diacritics) and then replace spaces with a dot
tmpGivenName = basic.norm(basic.stringify(givenName))?.tr(' ', '.')
tmpFamilyName = basic.norm(basic.stringify(familyName))?.tr(' ', '.')
return tmpGivenName + '.' + tmpFamilyName + iterationToken
            </code>
        </script>
      </expression>
      <target>
        <path>name</path>
      </target>
      <condition>
        <script>
          <code>givenName != null &amp;&amp; familyName != null &amp;&amp; (employeeType == 'EMP' || employeeType == 'EXT')</code>
        </script>
      </condition>
    </mapping>
  <mapping>
    <name>Default User Template: Generate Name for SYS</name>
      <source>
        <path>familyName</path>
      </source>
      <source>
        <path>employeeType</path>
      </source>
      <expression>
        <script>
            <code>
// we take the familyName (not givenName), normalize (remove diacritics) and then replace spaces with a dot
// then we add a "sys_" prefix
tmpFamilyName = basic.norm(basic.stringify(familyName))?.tr(' ', '.')
return 'sys_' + tmpFamilyName + iterationToken
            </code>
        </script>
      </expression>
      <target>
        <path>name</path>
      </target>
      <condition>
        <script>
          <code>familyName != null &amp;&amp; employeeType == 'SYS'</code>
        </script>
      </condition>
    </mapping>
  <mapping>
    <name>Default User Template: Generate Name for TST</name>
      <source>
        <path>givenName</path>
      </source>
      <source>
        <path>familyName</path>
      </source>
      <source>
        <path>employeeType</path>
      </source>
      <expression>
        <script>
            <code>
// we take the givenName/familyName, normalize (remove diacritics) and then replace spaces with a dot
// then we add a "t_" prefix
tmpGivenName = basic.norm(basic.stringify(givenName))?.tr(' ', '.')
tmpFamilyName = basic.norm(basic.stringify(familyName))?.tr(' ', '.')
return "t_" + tmpGivenName + '.' + tmpFamilyName + iterationToken
            </code>
        </script>
      </expression>
      <target>
        <path>name</path>
      </target>
      <condition>
        <script>
          <code>givenName != null &amp;&amp; familyName != null &amp;&amp; employeeType == 'TST'</code>
        </script>
      </condition>
    </mapping>
. . .

Some examples of the behaviour:

  • employeeType: EMP, givenName: John, familyName: Smith, name: john.smith
  • employeeType: EXT, givenName: John, familyName: Smith, name: john.smith409
  • employeeType: SYS, givenName: whatever, familyName: XYReporter, name: sys_xyreporter
  • employeeType: SYS, givenName: whatever or nothing, familyName: XYReporter, name: sys_xyreporter2
  • employeeType: TST, givenName: Jack, familyName: Sparrow, name: t_jack.sparrow

Similarly you can add a mapping for “ADM” users or any other that you need. Of course, there are still things you need to decide and configure later:

  • if you wish to use the “name” attribute as a target system login, you may need to make sure that it’s not too long; or you can shorten the name while generating it in midPoint (in the object template mappings above)
  • you may need more attributes to decide how the generated “name” attribute should look like, not only “employeeType”
  • different types of users may need different types of accounts in the target systems. E.g. in directory system, there may be different containers for different account types and you may need either to generate the “DN” attribute with the “employeeType” attribute value in mind, or to make different account intents in the resource schema handling

Leave a Reply

Your email address will not be published. Required fields are marked *