Разработки
April 17

Добавляем параметры OwnCloud/NextCloud к freeipa АЛД ПРО

Задача: расширить схему и добавить дополнительные параметры пользователям так, чтобы параметры можно было определять простыми LDAP-запросами, а управлять из интерфейса IPA

Покажу на примере атрибутов для работы с OwnCloud/NextCloud.

1. Создаем файл определения атрибутов схемы ```file.ldif```

dn: cn=schema
changetype: modify
add: attributeTypes
attributeTypes: ( 1.3.6.1.4.1.49213.1.1.1 NAME 'owncloudEnabled'
        DESC 'whether user or group should be available in owncloud'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)
attributeTypes: ( 1.3.6.1.4.1.49213.1.1.2 NAME 'owncloudQuota'
        DESC 'defines how much disk space is available for the user'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)
-
add: objectclasses
objectClasses: ( 1.3.6.1.4.1.49213.1.2.1 NAME 'owncloudUser'
        DESC 'A owncloud user'
        SUP top AUXILIARY
        MAY ( owncloudEnabled $ owncloudQuota )
        )

Создаем скрипт модуля ```userncenabled.py```

from ipaserver.plugins import user
from ipalib.parameters import Bool
from ipalib import _

user.user.takes_params = user.user.takes_params + (
    Bool(
        "owncloudenabled?",
        cli_name="owncloudenabled",
        label=_("Owncloud Share enabled?"),
        doc=_(
            "Whether or not a owncloud share is created for this user (default is false)."
        ),
        default=False,
        autofill=True,
    ),
)

user.user.default_attributes.append("owncloudenabled")


# pylint: disable-msg=unused-argument,invalid-name,line-too-long
def useradd_precallback(self, ldap, dn, entry, attrs_list, *keys, **options):
    """Callback for `register_pre_callback`.

    See <https://github.com/freeipa/freeipa/blob/master/doc/guide/guide.org#extending-existing-object> for details.
    """
    entry["objectclass"].append("ownclouduser")
    return dn


user.user_add.register_pre_callback(useradd_precallback)


# pylint: disable-msg=unused-argument,invalid-name,line-too-long
def usermod_precallback(self, ldap, dn, entry, attrs_list, *keys, **options):
    """Callback for `register_pre_callback`.

    See <https://github.com/freeipa/freeipa/blob/master/doc/guide/guide.org#extending-existing-object> for details.
    """
    if "objectclass" not in entry.keys():
        old_entry = ldap.get_entry(dn, ["objectclass"])
        entry["objectclass"] = old_entry["objectclass"]
    entry["objectclass"].append("ownclouduser")
    return dn


user.user_mod.register_pre_callback(usermod_precallback)

Создаем скрипт модуля ```userncquota.py```

from ipaserver.plugins import user
from ipalib.parameters import Str
from ipalib.text import _

user.user.takes_params = user.user.takes_params + (
    Str(
        "owncloudquota?",
        cli_name="owncloudquota",
        label=_("Owncloud Share Quota"),
        doc=_(
            "Defines Owncloud share quota in Bytes. "
            'Allowed values are "none",'
            '"default", e.g. "1024 MB" (default is "default").'
        ),
        default="default",
        autofill=True,
        pattern="^(default|none|[0-9]+ [MGT]B)quot;,
        pattern_errmsg="".join(
            'may only be "none", '
            '"default" or a number of mega-, giga- or terabytes (e.g. 1024 MB)'
        ),
    ),
)

user.user.default_attributes.append("owncloudquota")

def useradd_precallback(self, ldap, dn, entry, attrs_list, *keys, **options):
    """Callback for `register_pre_callback`.

    See <https://github.com/freeipa/freeipa/blob/master/doc/guide/guide.org#extending-existing-object> for details.
    """
    entry["objectclass"].append("ownclouduser")
    return dn

user.user_add.register_pre_callback(useradd_precallback)

def usermod_precallback(self, ldap, dn, entry, attrs_list, *keys, **options):
    if "objectclass" not in entry.keys():
        old_entry = ldap.get_entry(dn, ["objectclass"])
        entry["objectclass"] = old_entry["objectclass"]
    entry["objectclass"].append("ownclouduser")
    return dn


user.user_mod.register_pre_callback(usermod_precallback)

Создаем скрипт модуля webUI ```userncenabled.js```

define([
		'freeipa/phases',
		'freeipa/user'],
		function(phases, user_mod) {
			
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 nc_enabled_plugin = {};

nc_enabled_plugin.add_nc_enabled_pre_op = function() {	
	var facet = get_item(user_mod.entity_spec.facets, '$type', 'details');
	var section = get_item(facet.sections, 'name', 'account');
	section.fields.push({
				$type: 'checkbox', 
				name: 'owncloudenabled', 
				label: 'Owncloud Share enabled',
				flags: ['w_if_no_aci']
	});
	return true;	
};

phases.on('customization', nc_enabled_plugin.add_nc_enabled_pre_op);

return nc_enabled_plugin;
});

Создаем скрипт модуля webUI ```userncquota.js```

define([
		'freeipa/phases',
		'freeipa/user'],
		function(phases, user_mod) {
			
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 nc_quota_plugin = {};

nc_quota_plugin.add_nc_quota_pre_op = function() {
        var facet = get_item(user_mod.entity_spec.facets, '$type', 'details');
        var section = get_item(facet.sections, 'name', 'account');
        section.fields.push({
                                name: 'owncloudquota',
                                label: 'Owncloud Share Quota',
                                flags: ['w_if_no_aci']
        });
        return true;
};

phases.on('customization', nc_quota_plugin.add_nc_quota_pre_op);
return nc_quota_plugin;
});

Добавляем в схему нужный класс и нужные атрибуты

ldapadd -H ldap://$HOSTNAME -D 'cn=Directory Manager' -W -f file.ldif

Проверяем, что класс добавился

 ldapsearch -H ldap://$HOSTNAME -D 'cn=Directory Manager' -W -x -s base -b 'cn=schema' objectclasses | grep -i owncloud

Проверяем, что атрибут добавился

ldapsearch -H ldap://$HOSTNAME -D 'cn=Directory Manager' -W -x -s base -b 'cn=schema' attributetypes | grep -i owncloud

Добавляем атрибут

ipa config-mod --addattr=ipaUserObjectClasses=owncloudUser

Копируем скрипты и перезапускаем

cp usernc*.py /usr/lib/python3/dist-packages/ipaserver/plugins/
cd /usr/lib/python3/dist-packages/ipaserver/plugins/
python -m compileall usernc* && python -O -m compileall usernc*
apachectl graceful

Копируем модули к WebUI и перезапускаем

mkdir /usr/share/ipa/ui/js/plugins/{userncenabled,userncquota}
cp userncenabled.js /usr/share/ipa/ui/js/plugins/userncenabled/
cp userncquota.js /usr/share/ipa/ui/js/plugins/userncquota/
apachectl graceful

После этого в UI FreeIpa можно добавлять\изменять параметры

на англиском языке я прописал по умолчанию, чтобы не возиться с кодировкой

А так можно определить через LDAP-запрос

ldapsearch -H ldap://$HOSTNAME -Y GSSAPI "uid=slakwik" -o ldif-wrap=no | grep own

Модификация несложная, но напомню, что самодельные модули между КД АЛД ПРО не копируются и нужно разложить эти python и js скрипты на все КД домена.