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

Leave a Reply

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