diff options
author | Petr Vobornik <pvoborni@redhat.com> | 2014-10-02 16:57:08 +0200 |
---|---|---|
committer | Petr Vobornik <pvoborni@redhat.com> | 2014-10-17 14:11:35 +0200 |
commit | 59ee6314afc7f0f7735ab1349caa970f0f00d78a (patch) | |
tree | f1269db1d7a48c144f0cb2824b25056514439490 /ipalib/plugins | |
parent | 6f81217c18a416dcbd23360ad3d7f3fea0174fc0 (diff) | |
download | freeipa-59ee6314afc7f0f7735ab1349caa970f0f00d78a.tar.gz freeipa-59ee6314afc7f0f7735ab1349caa970f0f00d78a.tar.xz freeipa-59ee6314afc7f0f7735ab1349caa970f0f00d78a.zip |
keytab manipulation permission management
Adds new API:
ipa host-allow-retrieve-keytab HOSTNAME --users=STR --groups STR
ipa host-disallow-retrieve-keytab HOSTNAME --users=STR --groups STR
ipa host-allow-create-keytab HOSTNAME --users=STR --groups STR
ipa host-disallow-create-keytab HOSTNAME --users=STR --groups STR
ipa service-allow-retrieve-keytab PRINCIPAL --users=STR --groups STR
ipa service-disallow-retrieve-keytab PRINCIPAL --users=STR --groups STR
ipa service-allow-create-keytab PRINCIPAL --users=STR --groups STR
ipa service-disallow-create-keytab PRINCIPAL --users=STR --groups STR
these methods add or remove user or group DNs in `ipaallowedtoperform` attr with
`read_keys` and `write_keys` subtypes.
service|host-mod|show outputs these attrs only with --all option as:
Users allowed to retrieve keytab: user1
Groups allowed to retrieve keytab: group1
Users allowed to create keytab: user1
Groups allowed to create keytab: group1
Adding of object class is implemented as a reusable method since this code is
used on many places and most likely will be also used in new features. Older
code may be refactored later.
https://fedorahosted.org/freeipa/ticket/4419
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Diffstat (limited to 'ipalib/plugins')
-rw-r--r-- | ipalib/plugins/baseldap.py | 17 | ||||
-rw-r--r-- | ipalib/plugins/host.py | 116 | ||||
-rw-r--r-- | ipalib/plugins/service.py | 134 |
3 files changed, 258 insertions, 9 deletions
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py index e589a5321..375441c0f 100644 --- a/ipalib/plugins/baseldap.py +++ b/ipalib/plugins/baseldap.py @@ -494,6 +494,23 @@ def host_is_master(ldap, fqdn): return +def add_missing_object_class(ldap, objectclass, dn, entry_attrs=None, update=True): + """ + Add object class if missing into entry. Fetches entry if not passed. Updates + the entry by default. + + Returns the entry + """ + + if not entry_attrs: + entry_attrs = ldap.get_entry(dn, ['objectclass']) + if (objectclass.lower() not in (o.lower() for o in entry_attrs['objectclass'])): + entry_attrs['objectclass'].append(objectclass) + if update: + ldap.update_entry(entry_attrs) + return entry_attrs + + class LDAPObject(Object): """ Object representing a LDAP entry. diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py index 91fb75b87..c4d4bdf64 100644 --- a/ipalib/plugins/host.py +++ b/ipalib/plugins/host.py @@ -28,10 +28,11 @@ from ipalib.plugins.baseldap import (LDAPQuery, LDAPObject, LDAPCreate, LDAPDelete, LDAPUpdate, LDAPSearch, LDAPRetrieve, LDAPAddMember, LDAPRemoveMember, host_is_master, - pkey_to_value) + pkey_to_value, add_missing_object_class) from ipalib.plugins.service import (split_principal, validate_certificate, set_certificate_attrs, ticket_flags_params, update_krbticketflags, - set_kerberos_attrs) + set_kerberos_attrs, rename_ipaallowedtoperform_from_ldap, + rename_ipaallowedtoperform_to_ldap) from ipalib.plugins.dns import (dns_container_exists, _record_types, add_records_for_host_validation, add_records_for_host, get_reverse_zone) @@ -102,6 +103,9 @@ EXAMPLES: """) + _(""" Add a host that can manage this host's keytab and certificate: ipa host-add-managedby --hosts=test2 test +""") + _(""" + Allow user to create a keytab: + ipa host-allow-create-keytab test2 --users=tuser1 """) register = Registry() @@ -201,6 +205,24 @@ host_output_params = ( Str('sshpubkeyfp*', label=_('SSH public key fingerprint'), ), + Str('ipaallowedtoperform_read_keys_user', + label=_('Users allowed to retrieve keytab'), + ), + Str('ipaallowedtoperform_read_keys_group', + label=_('Groups allowed to retrieve keytab'), + ), + Str('ipaallowedtoperform_write_keys_user', + label=_('Users allowed to create keytab'), + ), + Str('ipaallowedtoperform_write_keys_group', + label=_('Groups allowed to create keytab'), + ), + Str('ipaallowedtoperform_read_keys', + label=_('Failed allowed to retrieve keytab'), + ), + Str('ipaallowedtoperform_write_keys', + label=_('Failed allowed to create keytab'), + ), ) @@ -241,17 +263,18 @@ class host(LDAPObject): object_name = _('host') object_name_plural = _('hosts') object_class = ['ipaobject', 'nshost', 'ipahost', 'pkiuser', 'ipaservice'] + possible_objectclasses = ['ipaallowedoperations'] permission_filter_objectclasses = ['ipahost'] # object_class_config = 'ipahostobjectclasses' search_attributes = [ 'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname', - 'nshardwareplatform', 'nsosversion', 'managedby' + 'nshardwareplatform', 'nsosversion', 'managedby', 'ipaallowedtoperform' ] default_attributes = [ 'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname', 'nshardwareplatform', 'nsosversion', 'usercertificate', 'memberof', 'managedby', 'memberindirect', 'memberofindirect', 'macaddress', - 'userclass' + 'userclass', 'ipaallowedtoperform' ] uuid_attribute = 'ipauniqueid' attribute_members = { @@ -261,6 +284,8 @@ class host(LDAPObject): 'managing': ['host'], 'memberofindirect': ['hostgroup', 'netgroup', 'role', 'hbacrule', 'sudorule'], + 'ipaallowedtoperform_read_keys': ['user', 'group'], + 'ipaallowedtoperform_write_keys': ['user', 'group'], } bindable = True relationships = { @@ -268,6 +293,8 @@ class host(LDAPObject): 'enrolledby': ('Enrolled by', 'enroll_by_', 'not_enroll_by_'), 'managedby': ('Managed by', 'man_by_', 'not_man_by_'), 'managing': ('Managing', 'man_', 'not_man_'), + 'ipaallowedtoperform_read_keys': ('Allow to retrieve keytab by', 'retrieve_keytab_by_', 'not_retrieve_keytab_by_'), + 'ipaallowedtoperform_write_keys': ('Allow to create keytab by', 'write_keytab_by_', 'not_write_keytab_by'), } password_attributes = [('userpassword', 'has_password'), ('krbprincipalkey', 'has_keytab')] @@ -344,6 +371,14 @@ class host(LDAPObject): ], 'default_privileges': {'Host Administrators', 'Host Enrollment'}, }, + 'System: Manage Host Keytab Permissions': { + 'ipapermright': {'read', 'search', 'compare', 'write'}, + 'ipapermdefaultattr': { + 'ipaallowedtoperform;write_keys', + 'ipaallowedtoperform;read_keys', 'objectclass' + }, + 'default_privileges': {'Host Administrators'}, + }, 'System: Modify Hosts': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { @@ -629,6 +664,7 @@ class host_add(LDAPCreate): ) set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) if options.get('all', False): entry_attrs['managing'] = self.obj.get_managed_hosts(dn) @@ -888,6 +924,7 @@ class host_mod(LDAPUpdate): entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword')) set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) self.obj.get_password_attributes(ldap, dn, entry_attrs) if entry_attrs['has_password']: # If an OTP is set there is no keytab, at least not one @@ -974,6 +1011,7 @@ class host_find(LDAPSearch): for entry_attrs in entries: set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) self.obj.get_password_attributes(ldap, entry_attrs.dn, entry_attrs) self.obj.suppress_netgroup_memberof(ldap, entry_attrs) if entry_attrs['has_password']: @@ -1012,6 +1050,7 @@ class host_show(LDAPRetrieve): set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) if options.get('all', False): entry_attrs['managing'] = self.obj.get_managed_hosts(dn) @@ -1159,3 +1198,72 @@ class host_remove_managedby(LDAPRemoveMember): self.obj.suppress_netgroup_memberof(ldap, entry_attrs) return (completed, dn) + +@register() +class host_allow_retrieve_keytab(LDAPAddMember): + __doc__ = _('Allow users or groups to retrieve a keytab of this host.') + member_attributes = ['ipaallowedtoperform_read_keys'] + has_output_params = LDAPAddMember.has_output_params + host_output_params + + def pre_callback(self, ldap, dn, found, not_found, *keys, **options): + rename_ipaallowedtoperform_to_ldap(found) + rename_ipaallowedtoperform_to_ldap(not_found) + add_missing_object_class(ldap, u'ipaallowedoperations', dn) + return dn + + def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(failed, options) + return (completed, dn) + + +@register() +class host_disallow_retrieve_keytab(LDAPRemoveMember): + __doc__ = _('Disallow users or groups to retrieve a keytab of this host.') + member_attributes = ['ipaallowedtoperform_read_keys'] + has_output_params = LDAPRemoveMember.has_output_params + host_output_params + + def pre_callback(self, ldap, dn, found, not_found, *keys, **options): + rename_ipaallowedtoperform_to_ldap(found) + rename_ipaallowedtoperform_to_ldap(not_found) + return dn + + def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(failed, options) + return (completed, dn) + + +@register() +class host_allow_create_keytab(LDAPAddMember): + __doc__ = _('Allow users or groups to create a keytab of this host.') + member_attributes = ['ipaallowedtoperform_write_keys'] + has_output_params = LDAPAddMember.has_output_params + host_output_params + + def pre_callback(self, ldap, dn, found, not_found, *keys, **options): + rename_ipaallowedtoperform_to_ldap(found) + rename_ipaallowedtoperform_to_ldap(not_found) + add_missing_object_class(ldap, u'ipaallowedoperations', dn) + return dn + + def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(failed, options) + return (completed, dn) + + +@register() +class host_disallow_create_keytab(LDAPRemoveMember): + __doc__ = _('Disallow users or groups to create a keytab of this host.') + member_attributes = ['ipaallowedtoperform_write_keys'] + has_output_params = LDAPRemoveMember.has_output_params + host_output_params + + def pre_callback(self, ldap, dn, found, not_found, *keys, **options): + rename_ipaallowedtoperform_to_ldap(found) + rename_ipaallowedtoperform_to_ldap(not_found) + return dn + + def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(failed, options) + return (completed, dn) diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py index 55f412625..2f7035444 100644 --- a/ipalib/plugins/service.py +++ b/ipalib/plugins/service.py @@ -86,7 +86,10 @@ EXAMPLES: Request a certificate for an IPA service: ipa cert-request --principal=HTTP/web.example.com example.csr - +""") + _(""" + Allow user to create a keytab: + ipa service-allow-create-keytab HTTP/web.example.com --users=tuser1 +""") + _(""" Generate and retrieve a keytab for an IPA service: ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/httpd.keytab @@ -127,7 +130,25 @@ output_params = ( ), Str('revocation_reason?', label=_('Revocation reason'), - ) + ), + Str('ipaallowedtoperform_read_keys_user', + label=_('Users allowed to retrieve keytab'), + ), + Str('ipaallowedtoperform_read_keys_group', + label=_('Groups allowed to retrieve keytab'), + ), + Str('ipaallowedtoperform_write_keys_user', + label=_('Users allowed to create keytab'), + ), + Str('ipaallowedtoperform_write_keys_group', + label=_('Groups allowed to create keytab'), + ), + Str('ipaallowedtoperform_read_keys', + label=_('Failed allowed to retrieve keytab'), + ), + Str('ipaallowedtoperform_write_keys', + label=_('Failed allowed to create keytab'), + ), ) ticket_flags_params = ( @@ -290,6 +311,23 @@ def set_kerberos_attrs(entry_attrs, options): if name in options or all_opt: entry_attrs[name] = bool(ticket_flags & value) +def rename_ipaallowedtoperform_from_ldap(entry_attrs, options): + if options.get('raw', False): + return + + for subtype in ('read_keys', 'write_keys'): + name = 'ipaallowedtoperform;%s' % subtype + if name in entry_attrs: + new_name = 'ipaallowedtoperform_%s' % subtype + entry_attrs[new_name] = entry_attrs.pop(name) + +def rename_ipaallowedtoperform_to_ldap(entry_attrs): + for subtype in ('read_keys', 'write_keys'): + name = 'ipaallowedtoperform_%s' % subtype + if name in entry_attrs: + new_name = 'ipaallowedtoperform;%s' % subtype + entry_attrs[new_name] = entry_attrs.pop(name) + @register() class service(LDAPObject): """ @@ -302,19 +340,24 @@ class service(LDAPObject): 'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject', 'ipaservice', 'pkiuser' ] - possible_objectclasses = ['ipakrbprincipal'] + possible_objectclasses = ['ipakrbprincipal', 'ipaallowedoperations'] permission_filter_objectclasses = ['ipaservice'] - search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata'] + search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata', + 'ipaallowedtoperform'] default_attributes = ['krbprincipalname', 'usercertificate', 'managedby', - 'ipakrbauthzdata', 'memberof'] + 'ipakrbauthzdata', 'memberof', 'ipaallowedtoperform'] uuid_attribute = 'ipauniqueid' attribute_members = { 'managedby': ['host'], 'memberof': ['role'], + 'ipaallowedtoperform_read_keys': ['user', 'group'], + 'ipaallowedtoperform_write_keys': ['user', 'group'], } bindable = True relationships = { 'managedby': ('Managed by', 'man_by_', 'not_man_by_'), + 'ipaallowedtoperform_read_keys': ('Allow to retrieve keytab by', 'retrieve_keytab_by_', 'not_retrieve_keytab_by_'), + 'ipaallowedtoperform_write_keys': ('Allow to create keytab by', 'write_keytab_by_', 'not_write_keytab_by'), } password_attributes = [('krbprincipalkey', 'has_keytab')] managed_permissions = { @@ -346,6 +389,14 @@ class service(LDAPObject): ], 'default_privileges': {'Service Administrators', 'Host Administrators'}, }, + 'System: Manage Service Keytab Permissions': { + 'ipapermright': {'read', 'search', 'compare', 'write'}, + 'ipapermdefaultattr': { + 'ipaallowedtoperform;write_keys', + 'ipaallowedtoperform;read_keys', 'objectclass' + }, + 'default_privileges': {'Service Administrators', 'Host Administrators'}, + }, 'System: Modify Services': { 'ipapermright': {'write'}, 'ipapermdefaultattr': {'usercertificate'}, @@ -469,6 +520,7 @@ class service_add(LDAPCreate): def post_callback(self, ldap, dn, entry_attrs, *keys, **options): set_kerberos_attrs(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) return dn @@ -561,6 +613,7 @@ class service_mod(LDAPUpdate): assert isinstance(dn, DN) set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) return dn @@ -598,6 +651,7 @@ class service_find(LDAPSearch): self.obj.get_password_attributes(ldap, entry_attrs.dn, entry_attrs) set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) return truncated @@ -620,6 +674,7 @@ class service_show(LDAPRetrieve): set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) return dn @@ -654,6 +709,75 @@ class service_remove_host(LDAPRemoveMember): has_output_params = LDAPRemoveMember.has_output_params + output_params +@register() +class service_allow_retrieve_keytab(LDAPAddMember): + __doc__ = _('Allow users or groups to retrieve a keytab of this service.') + member_attributes = ['ipaallowedtoperform_read_keys'] + has_output_params = LDAPAddMember.has_output_params + output_params + + def pre_callback(self, ldap, dn, found, not_found, *keys, **options): + rename_ipaallowedtoperform_to_ldap(found) + rename_ipaallowedtoperform_to_ldap(not_found) + add_missing_object_class(ldap, u'ipaallowedoperations', dn) + return dn + + def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(failed, options) + return (completed, dn) + + +@register() +class service_disallow_retrieve_keytab(LDAPRemoveMember): + __doc__ = _('Disallow users or groups to retrieve a keytab of this service.') + member_attributes = ['ipaallowedtoperform_read_keys'] + has_output_params = LDAPRemoveMember.has_output_params + output_params + + def pre_callback(self, ldap, dn, found, not_found, *keys, **options): + rename_ipaallowedtoperform_to_ldap(found) + rename_ipaallowedtoperform_to_ldap(not_found) + return dn + + def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(failed, options) + return (completed, dn) + + +@register() +class service_allow_create_keytab(LDAPAddMember): + __doc__ = _('Allow users or groups to create a keytab of this service.') + member_attributes = ['ipaallowedtoperform_write_keys'] + has_output_params = LDAPAddMember.has_output_params + output_params + + def pre_callback(self, ldap, dn, found, not_found, *keys, **options): + rename_ipaallowedtoperform_to_ldap(found) + rename_ipaallowedtoperform_to_ldap(not_found) + add_missing_object_class(ldap, u'ipaallowedoperations', dn) + return dn + + def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(failed, options) + return (completed, dn) + + +@register() +class service_disallow_create_keytab(LDAPRemoveMember): + __doc__ = _('Disallow users or groups to create a keytab of this service.') + member_attributes = ['ipaallowedtoperform_write_keys'] + has_output_params = LDAPRemoveMember.has_output_params + output_params + + def pre_callback(self, ldap, dn, found, not_found, *keys, **options): + rename_ipaallowedtoperform_to_ldap(found) + rename_ipaallowedtoperform_to_ldap(not_found) + return dn + + def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): + rename_ipaallowedtoperform_from_ldap(entry_attrs, options) + rename_ipaallowedtoperform_from_ldap(failed, options) + return (completed, dn) + @register() class service_disable(LDAPQuery): |