Nerdier

Adjective: Comparative form of nerdy: more nerdy.

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,
}

8 thoughts on “Adding a user attribute in FreeIPA 4.x

  • Karnik Ram says:

    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?

    • absw says:

      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.

  • Shibly says:

    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

  • Shibly says:

    Hey,
    Do you know how to add custom attributes to hostgroups?

  • Saumya says:

    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

  • Ales says:

    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.

Leave a Reply

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