31 05 2019
Adding a user attribute in FreeIPA 4.x
The main guide is here: https://www.freeipa.org/images/5/5b/FreeIPA33-extending-freeipa.pdf but it’s for an older version so some of the examples don’t work and doesn’t cover all the steps for updating existing users.
We will be adding the attribute ‘car’ as an example.
Add the attribute with ldapmodify:
ldapmodify -D "cn=Directory Manager" -x -W dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( 2.25.28639311321113238241701611583088740684.14.2.1 NAME 'car' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Extending FreeIPA' )
press ctrl + d after entering the above to save/exit.
Next add an object class that includes the attribute the same way as above.
dn: cn=schema changetype: modify add: objectclasses objectclasses: ( 2.25.28639311321113238241701611583088740684.14.2.2 NAME 'customPerson' SUP person STRUCTURAL MAY (car) X-ORIGIN 'Extending FreeIPA' )
Then we need to restart the IPA service
systemctl restart ipa
Get a kerberos ticket for ipa commands
kinit admin
Add the customPerson objectclass to the list of user object classes
ipa config-mod --userobjectclasses={ipasshgroupofpubkeys,ipaobject,organizationalperson,top,ipasshuser,inetorgperson,person,krbticketpolicyaux,krbprincipalaux,inetuser,posixaccount,ipantuserattrs,ipauser,customPerson}
You can now add a new user and set the attribute for them
# ipa user-add besttest --first Best --last Test --setattr car=landrover # ipa user-show besttest --all | grep car car: landrover
However, if you try to add the attribute to existing users it will error:
# ipa user-mod notsobest --setattr car=landrover ipa: ERROR: attribute "car" not allowed
We need to modify the user to add the objectclass
ldapmodify -D "cn=Directory Manager" -x -W dn: uid=notsobest,cn=users,cn=accounts,dc=serverhostna,dc=me changetype: modify add: objectclass objectclass: customPerson
Then the attribute can be set
# ipa user-mod notsobest --setattr=car=landrover -------------------------- Modified user "notsobest" # ipa user-show notsobest --all | grep car car: landrover
Though this has to be done for every user, and when you have hundreds of existing users doing it one by one is a no go.
I made a little php script to generate a list, which can be outputted to a LDIF file for importing.
<?php //generate ldif file for adding object class to existing users exec("ipa user-find --all | grep 'dn:'",$output); $output = array_filter($output); foreach ($output as $uid) { $uid = trim($uid); $ldif .= $uid . PHP_EOL . 'changetype: modify' . PHP_EOL . 'add: objectclass' . PHP_EOL . 'objectclass: customPerson' . PHP_EOL . PHP_EOL; } echo $ldif;
Then ran it with:
php ldif.php > customPerson.ldif
This can then be imported with
ldapmodify -D "cn=Directory Manager" -x -W -f customPerson.ldif
Next up, getting a box to show up in the web interface for useradmins.
We need a server plugin script, and a web plugin script.
The plugin needs to go in
/usr/lib/python2.7/site-packages/ipaserver/plugins/
with the name of the plugin you are creating and the py extension. eg
/usr/lib/python2.7/site-packages/ipaserver/plugins/car.py
The contents will be
from ipaserver.plugins.user import user from ipalib.parameters import Str from ipalib.text import _ from ipaserver.plugins.internal import i18n_messages user.takes_params += ( Str('car?', cli_name='car', label=_('Users Car'), ), ) user.default_attributes.append('car')
And for the web script, simular but you make a directory with the name of the plugin, in the plugins dir and put your file(s) in there.
/usr/share/ipa/ui/js/plugins/car/car.js
With the contents of
define([ 'freeipa/phases', 'freeipa/user'], function(phases, user_mod) { // helper function function get_item(array, attr, value) { for (var i=0,l=array.length; i<l; i++) { if (array[i][attr] === value) return array[i]; } return null; } var emp_plugin = {}; // adds 'car' field into user details facet emp_plugin.add_emp_number_pre_op = function() { var facet = get_item(user_mod.entity_spec.facets, '$type', 'details'); var section = get_item(facet.sections, 'name', 'identity'); section.fields.push({ name: 'car', label: 'Users Car' }); return true; }; phases.on('customization', emp_plugin.add_emp_number_pre_op); return emp_plugin; });
You will then need to restart the ipa service
systemctl restart ipa
Then when you go to a users page, the box will show up under ‘Identity Settings’ you will also be able to modify it and save.
If you have more than one server these files will need to be on all of them. I enforced them with puppet
file { '/usr/lib/python2.7/site-packages/ipaserver/plugins/car.py': ensure => present, source => 'puppet:///modules/freeipa/server/car.py', notify => Service['ipa'], } file { '/usr/share/ipa/ui/js/plugins/car': ensure => directory, } file { '/usr/share/ipa/ui/js/plugins/car/car.js': ensure => present, source => 'puppet:///modules/freeipa/server/car.js', require => File['/usr/share/ipa/ui/js/plugins/car'], notify => Service['ipa'], } service { 'ipa': ensure => running, enable => true, }
freeipa: ipaNTSecurityIdentifier and ipaNTHash missing. puppet: Error 400 on SERVER: Attempt to assign to a reserved variable name: ‘trusted’
Thank you for this post! It’s been very userful
I followed all the steps, however, when I run ipa user-show uid –all on one of our ipa clients, the new attribute doesn’t show up.
Do you know what changes need to be made on the ipa client for the attribute to be exposed properly?
Apologies for the delayed reply, your comment got buried by all the spam comments in the moderation list. As to your query, on my installation the attribute shows up under the label title you set in the plugin code, when running user-show. In the example above it would be under ‘Users Car’ instead of just ‘car’. If it’s not showing up on one of the servers but works on another you could possibly have a replication issue or the plugin isn’t correctly installed on the server.
Thank you this was very helpful. How do we add attributes for group? When writing the plugin for the group do we just simply replace all the places it says “user” with group
Sorry I can’t help here as I’ve not had to do this yet.
Hey,
Do you know how to add custom attributes to hostgroups?
Not working for me.
Trying to add a field for description attribute from the inetOrgPerson objectClass.
vi /usr/lib/python2.7/site-packages/ipaserver/plugins/descr.py
from ipaserver.plugins.user import user
from ipalib.parameters import Str
from ipalib.text import _
from ipaserver.plugins.internal import i18n_messages
user.takes_params += (
Str(‘description?’,
cli_name=’description’,
label=_(‘User Description’),
),
)
user.default_attributes.append(‘description’)
systemctl restart ipa
ipa user-add test.user –first Test –last User –description test1
Usage: ipa [global-options] user-add LOGIN [options]
ipa: error: no such option: –description
Since description is already defined in inetOrgPerson, I’m not defining it. I can set it through
ipa user-add test.user –first Test –last User –addattr description=”test1″
# ipa –version
VERSION: 4.6.8, API_VERSION: 2.237
Try clearing IPA cli cache with:
rm -Rf ~/.cache/ipa/
thanks for that tutorial, I have example where I would like to add multiple values to same attribute. For example: host and I would have
host: example1
host: example2
or more if needed. I know how to add them with ldif, but how could I do this in WEB UI? I was looking to do similar as is for email, but no luck.