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 && 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 && familyName != null && (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 && 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 && familyName != null && 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