Hi guys,
I tried to write my firs plugin to add attribute host to be displayed in web UI at at user.
Plugin work ok host is displayed but I'm getting error when I try to add object class to Default user.
Error is : invalid 'ipauserobjectclasses': user default attribute host would not be allowed!
Yes I try to use host attribute and I create custom objectcalss. like this
objectClasses: ( 2.25.36.1.2.3.4.5.2 NAME 'testHost' DESC 'An object class for Aspera hosts' SUP person STRUCTURAL MAY (host) X-ORIGIN 'Extending FreeIPA' ).
It is any way that I could do that? I did create for test new Attribute with different name and it working ok. But because of migration from old LDAP is kinda forcing me to use attribute name host.
Thanks Ales
Maybe I should add plugin.
here is test.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('host*', cli_name='host', label=_('Test host'), ), )
user.default_attributes.append('host')
and test.js
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 'host' 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({ $type: 'multivalued', name: 'host', label: 'Test host' });
return true; }; phases.on('customization', emp_plugin.add_emp_number_pre_op); return emp_plugin; });
On Срд, 25 кас 2023, Ales Rozmarin via FreeIPA-users wrote:
Maybe I should add plugin.
here is test.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('host*', cli_name='host', label=_('Test host'), ), )
You named attribute 'testHost' but here you have 'host'. It is all but different attribute name for both IPA and LDAP server.
user.default_attributes.append('host')
and test.js
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 'host' 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({ $type: 'multivalued', name: 'host', label: 'Test host' });
return true; }; phases.on('customization', emp_plugin.add_emp_number_pre_op); return emp_plugin; }); _______________________________________________ FreeIPA-users mailing list -- freeipa-users@lists.fedorahosted.org To unsubscribe send an email to freeipa-users-leave@lists.fedorahosted.org Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedorahosted.org/archives/list/freeipa-users@lists.fedorahoste... Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue
Hi Alexander,
I create objectClasses named 'testHost' which have attribute 'host'.
As I mention up, I also test to create new attribute like this
attributeTypes: ( 2.25.36.1.2.3.4.5.1 NAME 'customhost' DESC 'A hostname or identifier for a Custom host' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Extending FreeIPA') # ############################################################################### # objectClasses: ( 2.25.36.1.2.3.4.5.2 NAME 'testHost' DESC 'An object class for Custom hosts' SUP person STRUCTURAL MAY (customhost) X-ORIGIN 'Extending FreeIPA' )
and not use default one:
attributeTypes: ( 0.9.2342.19200300.100.1.9 NAME 'host' EQUALITY caseIgnoreMa tch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-O RIGIN 'RFC 4524' )
I get only error when I use default attribute host it says, invalid 'ipauserobjectclasses': user default attribute host would not be allowed!
That why I'm not sure if I'm doing something wrong or is some restriction that we can't display attribute 'host' in User Web UI.
On Срд, 25 кас 2023, Ales Rozmarin via FreeIPA-users wrote:
Hi Alexander,
I create objectClasses named 'testHost' which have attribute 'host'.
As I mention up, I also test to create new attribute like this
attributeTypes: ( 2.25.36.1.2.3.4.5.1 NAME 'customhost' DESC 'A hostname or identifier for a Custom host' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Extending FreeIPA') # ############################################################################### # objectClasses: ( 2.25.36.1.2.3.4.5.2 NAME 'testHost' DESC 'An object class for Custom hosts' SUP person STRUCTURAL MAY (customhost) X-ORIGIN 'Extending FreeIPA' )
and not use default one:
attributeTypes: ( 0.9.2342.19200300.100.1.9 NAME 'host' EQUALITY caseIgnoreMa tch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-O RIGIN 'RFC 4524' )
I get only error when I use default attribute host it says, invalid 'ipauserobjectclasses': user default attribute host would not be allowed!
And that is correct because you don't have an object class that would allow having that attribute in the list of default ones.
That why I'm not sure if I'm doing something wrong or is some restriction that we can't display attribute 'host' in User Web UI.
You have two separate tasks here. First, if attribute exists in the entry, it needs to be displayed. To display it, it needs to be fetched from the LDAP entry, so the attribute needs to be specified in a list of attributes to be fetched. Second, for storing the attribute value if it doesn't exist, it needs to be added. For the latter you'd need an objectclass in the entry to allow attribute to be saved.
Attributes may be present at creation time or added afterwards, based on some conditions. Retrieval can be done differently depending on a logic. For a basic scenario where you'd always want to retrieve an attribute value if that one exists, you'd add the attribute name to the object'sa 'default_attributes' list.
'user' class is derived from the 'baseuser' -- there are two user classes in IPA, one used for normal users and one used for staged users, so we have common definitions in 'baseuser' and then inherit those by the actual objects:
class baseuser(LDAPObject): """ baseuser object. """ .... object_class_config = 'ipauserobjectclasses' possible_objectclasses = [ 'meporiginentry', 'ipauserauthtypeclass', 'ipauser', 'ipatokenradiusproxyuser', 'ipacertmapobject', 'ipantuserattrs', 'ipaidpuser', 'ipapasskeyuser', ] .... default_attributes = [ 'uid', 'givenname', 'sn', 'homedirectory', 'loginshell', 'uidnumber', 'gidnumber', 'mail', 'ou', 'telephonenumber', 'title', 'memberof', 'nsaccountlock', 'memberofindirect', 'ipauserauthtype', 'userclass', 'ipatokenradiusconfiglink', 'ipatokenradiususername', 'ipaidpconfiglink', 'ipaidpsub', 'krbprincipalexpiration', 'usercertificate;binary', 'krbprincipalname', 'krbcanonicalname', 'ipacertmapdata', 'ipantlogonscript', 'ipantprofilepath', 'ipanthomedirectory', 'ipanthomedirectorydrive', 'ipapasskey', ]
The error you've got about an attribute would not be allowed comes from 'ipa config-mod' where you tried to modify list of attributes that would be added to every single user object upon creation. That code validates presence of the attribute against user class' possible_objectclasses:
for (attr, obj) in (('ipauserobjectclasses', 'user'), ('ipagroupobjectclasses', 'group')): if attr in entry_attrs: if not entry_attrs[attr]: raise errors.ValidationError(name=attr, error=_('May not be empty')) objectclasses = list(set(entry_attrs[attr]).union( self.api.Object[obj].possible_objectclasses)) new_allowed_attrs = ldap.get_allowed_attributes(objectclasses, raise_on_unknown=True) checked_attrs = self.api.Object[obj].default_attributes
.... for obj_attr in checked_attrs: .... if obj_attr.lower() not in new_allowed_attrs: raise errors.ValidationError(name=attr, error=_('%(obj)s default attribute %(attr)s would not be allowed!') \ % dict(obj=obj, attr=obj_attr))
So in your case a plugin would need to declare both the attribute and the objectclass in those lists:
------------------------ from ipaserver.user import user
user.default_attributes += ['customhost'] user.possible_objectclasses += ['testhost'] ------------------------
Adding attributes and object classes to the lists maintained by 'ipa config-mod' will only work for cases where you always have a value assigned to those attributes. 'ipa config-mod' maintains those lists for creating user and group objects, e.g. which object classes must be present in every user and group created by IPA API.
Your client-side code would then need to always supply one or have a default value that would be used by the parameter. This is not always desirable.
For example, your parameter definition does not have a default value (I corrected the attribute name):
user.takes_params += ( Str('customhost*', cli_name='host', label=_('Test host'), ), )
It means that you would not be able to use 'customhost' as a default one through 'ipa config-mod' because nothing would put a default value to this attribute in both Web UI (unless your plugin always adds one) and in IPA API (unless you have a client-side plugin that does so).
Instead of adding the attribute to the 'ipa config-mod', you should consider whether this attribute is indeed should always be present. If it is, then you should think about a default value. If there should be no default value, then don't add it to the default list.
When an attribute is sent by the client side (be it web UI or just some IPA API caller), the server side should also add a corresponding object class in a pre-callback. This is done automatically for object.possible_objectclasses list.
You don't see that in https://github.com/abbra/freeipa-userstatus-plugin/blob/master/plugin/ipaser... from where you started with your sample plugin because those attributes are already allowed by existing IPA object classes in the user entry.
For a conditional add of the objectclasses we have baseldap.add_missing_object_class method. For example, for users we do add objectclasses depending on what additional attributes were set in the entry. This is done with a callback that is commonly called by the internal code. External plugins can define their own pre-callback and do similar actions:
class baseuser_add(LDAPCreate): """ Prototype command plugin to be implemented by real plugin """ def pre_common_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) set_krbcanonicalname(entry_attrs) self.obj.convert_usercertificate_pre(entry_attrs) if entry_attrs.get('ipatokenradiususername', None): add_missing_object_class(ldap, u'ipatokenradiusproxyuser', dn, entry_attrs, update=False) if entry_attrs.get('ipauserauthtype', None): add_missing_object_class(ldap, u'ipauserauthtypeclass', dn, entry_attrs, update=False) if ( entry_attrs.get('ipaidpconfiglink', None) or entry_attrs.get('ipaidpsub', None) ): add_missing_object_class(ldap, 'ipaidpuser', dn, entry_attrs, update=False)
I'd recommend looking at existing plugins when implementing a new one.
Thank you for explanation Alexsander
Let see what I learnt and let you know if I was able to write plugin correctly.
Ales Rozmarin via FreeIPA-users wrote:
Hi guys,
I tried to write my firs plugin to add attribute host to be displayed in web UI at at user.
Plugin work ok host is displayed but I'm getting error when I try to add object class to Default user.
I don't understand this part of your question. What does adding object class (testHost?) to "Default user" consist of?
rob
Error is : invalid 'ipauserobjectclasses': user default attribute host would not be allowed!
Yes I try to use host attribute and I create custom objectcalss. like this
objectClasses: ( 2.25.36.1.2.3.4.5.2 NAME 'testHost' DESC 'An object class for Aspera hosts' SUP person STRUCTURAL MAY (host) X-ORIGIN 'Extending FreeIPA' ).
It is any way that I could do that? I did create for test new Attribute with different name and it working ok. But because of migration from old LDAP is kinda forcing me to use attribute name host.
Thanks Ales _______________________________________________ FreeIPA-users mailing list -- freeipa-users@lists.fedorahosted.org To unsubscribe send an email to freeipa-users-leave@lists.fedorahosted.org Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedorahosted.org/archives/list/freeipa-users@lists.fedorahoste... Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue
Hi Rob,
Yes, I did write a little bit unclear, sorry of that. What I meant with that, when I go to 'IPA Server' 'Configuration' I try to add or remove 'Default user objectclasses' I get an error displayed : 'invalid 'ipauserobjectclasses': user default attribute host would not be allowed!'
freeipa-users@lists.fedorahosted.org