From 4239b77a6db24a3492f2e8ee4d2aea9a7e676272 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Fri, 24 Mar 2023 08:07:04 +0200 Subject: [PATCH] IPA API changes to support RBCD IPA API commands to manage RBCD access controls. Fixes: https://pagure.io/freeipa/issue/9354 Signed-off-by: Alexander Bokovoy Reviewed-By: Rob Crittenden --- ACI.txt | 10 +- API.txt | 108 ++++++++++++++++++++ VERSION.m4 | 4 +- doc/api/commands.rst | 8 ++ doc/api/host_add_delegation.md | 32 ++++++ doc/api/host_allow_add_delegation.md | 35 +++++++ doc/api/host_disallow_add_delegation.md | 35 +++++++ doc/api/host_remove_delegation.md | 32 ++++++ doc/api/service_add_delegation.md | 32 ++++++ doc/api/service_allow_add_delegation.md | 35 +++++++ doc/api/service_disallow_add_delegation.md | 35 +++++++ doc/api/service_remove_delegation.md | 32 ++++++ install/share/61kerberos-ipav3.ldif | 2 + ipalib/util.py | 68 +++++++++++-- ipaserver/plugins/host.py | 91 ++++++++++++++++- ipaserver/plugins/service.py | 109 ++++++++++++++++++++- 16 files changed, 649 insertions(+), 19 deletions(-) create mode 100644 doc/api/host_add_delegation.md create mode 100644 doc/api/host_allow_add_delegation.md create mode 100644 doc/api/host_disallow_add_delegation.md create mode 100644 doc/api/host_remove_delegation.md create mode 100644 doc/api/service_add_delegation.md create mode 100644 doc/api/service_allow_add_delegation.md create mode 100644 doc/api/service_disallow_add_delegation.md create mode 100644 doc/api/service_remove_delegation.md diff --git a/ACI.txt b/ACI.txt index 49d82ebe1..f00901375 100644 --- a/ACI.txt +++ b/ACI.txt @@ -153,6 +153,8 @@ aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;read_keys dn: cn=computers,cn=accounts,dc=ipa,dc=example aci: (targetattr = "krbcanonicalname || krbprincipalname")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Principals";allow (write) groupdn = "ldap:///cn=System: Manage Host Principals,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=computers,cn=accounts,dc=ipa,dc=example +aci: (targetattr = "memberprincipal || objectclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Resource Delegation";allow (delete,write) groupdn = "ldap:///cn=System: Manage Host Resource Delegation,cn=permissions,cn=pbac,dc=ipa,dc=example";) +dn: cn=computers,cn=accounts,dc=ipa,dc=example aci: (targetattr = "ipasshpubkey")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host SSH Public Keys";allow (write) groupdn = "ldap:///cn=System: Manage Host SSH Public Keys,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=computers,cn=accounts,dc=ipa,dc=example aci: (targetattr = "description || ipaassignedidview || krbprincipalauthind || l || macaddress || nshardwareplatform || nshostlocation || nsosversion || userclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Modify Hosts";allow (write) groupdn = "ldap:///cn=System: Modify Hosts,cn=permissions,cn=pbac,dc=ipa,dc=example";) @@ -161,7 +163,7 @@ aci: (targetattr = "cn || createtimestamp || entryusn || macaddress || modifytim dn: cn=computers,cn=accounts,dc=ipa,dc=example aci: (targetattr = "memberof")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Read Host Membership";allow (compare,read,search) userdn = "ldap:///all";) dn: cn=computers,cn=accounts,dc=ipa,dc=example -aci: (targetattr = "cn || createtimestamp || description || enrolledby || entryusn || fqdn || ipaassignedidview || ipaclientversion || ipakrbauthzdata || ipasshpubkey || ipauniqueid || krbcanonicalname || krblastpwdchange || krbpasswordexpiration || krbprincipalaliases || krbprincipalauthind || krbprincipalexpiration || krbprincipalname || l || macaddress || managedby || modifytimestamp || nshardwareplatform || nshostlocation || nsosversion || objectclass || serverhostname || usercertificate || userclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Read Hosts";allow (compare,read,search) userdn = "ldap:///all";) +aci: (targetattr = "cn || createtimestamp || description || enrolledby || entryusn || fqdn || ipaassignedidview || ipaclientversion || ipakrbauthzdata || ipasshpubkey || ipauniqueid || krbcanonicalname || krblastpwdchange || krbpasswordexpiration || krbprincipalaliases || krbprincipalauthind || krbprincipalexpiration || krbprincipalname || l || macaddress || managedby || memberprincipal || modifytimestamp || nshardwareplatform || nshostlocation || nsosversion || objectclass || serverhostname || usercertificate || userclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Read Hosts";allow (compare,read,search) userdn = "ldap:///all";) dn: cn=computers,cn=accounts,dc=ipa,dc=example aci: (targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Remove Hosts";allow (delete) groupdn = "ldap:///cn=System: Remove Hosts,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=hostgroups,cn=accounts,dc=ipa,dc=example @@ -281,11 +283,15 @@ aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;read_keys dn: cn=services,cn=accounts,dc=ipa,dc=example aci: (targetattr = "krbcanonicalname || krbprincipalname")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Manage Service Principals";allow (write) groupdn = "ldap:///cn=System: Manage Service Principals,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=services,cn=accounts,dc=ipa,dc=example +aci: (targetattr = "memberprincipal || objectclass")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Manage Service Resource Delegation";allow (delete,write) groupdn = "ldap:///cn=System: Manage Service Resource Delegation,cn=permissions,cn=pbac,dc=ipa,dc=example";) +dn: cn=services,cn=accounts,dc=ipa,dc=example +aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;write_delegation || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Manage Service Resource Delegation Permissions";allow (compare,read,search,write) groupdn = "ldap:///cn=System: Manage Service Resource Delegation Permissions,cn=permissions,cn=pbac,dc=ipa,dc=example";) +dn: cn=services,cn=accounts,dc=ipa,dc=example aci: (targetattr = "krbprincipalauthind || usercertificate")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Modify Services";allow (write) groupdn = "ldap:///cn=System: Modify Services,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=services,cn=accounts,dc=ipa,dc=example aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || ipantsecurityidentifier || loginshell || modifytimestamp || objectclass || uid || uidnumber")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Read POSIX details of SMB services";allow (compare,read,search) userdn = "ldap:///all";) dn: cn=services,cn=accounts,dc=ipa,dc=example -aci: (targetattr = "createtimestamp || entryusn || ipakrbauthzdata || ipakrbprincipalalias || ipauniqueid || krbcanonicalname || krblastpwdchange || krbobjectreferences || krbpasswordexpiration || krbprincipalaliases || krbprincipalauthind || krbprincipalexpiration || krbprincipalname || managedby || memberof || modifytimestamp || objectclass || usercertificate")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Read Services";allow (compare,read,search) userdn = "ldap:///all";) +aci: (targetattr = "createtimestamp || entryusn || ipakrbauthzdata || ipakrbprincipalalias || ipauniqueid || krbcanonicalname || krblastpwdchange || krbobjectreferences || krbpasswordexpiration || krbprincipalaliases || krbprincipalauthind || krbprincipalexpiration || krbprincipalname || managedby || memberof || memberprincipal || modifytimestamp || objectclass || usercertificate")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Read Services";allow (compare,read,search) userdn = "ldap:///all";) dn: cn=services,cn=accounts,dc=ipa,dc=example aci: (targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Remove Services";allow (delete) groupdn = "ldap:///cn=System: Remove Services,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=s4u2proxy,cn=etc,dc=ipa,dc=example diff --git a/API.txt b/API.txt index 062a6c756..0fc975947 100644 --- a/API.txt +++ b/API.txt @@ -2507,6 +2507,17 @@ option: Str('version?') output: Entry('result') output: Output('summary', type=[, ]) output: PrimaryKey('value') +command: host_add_delegation/1 +args: 2,4,3 +arg: Str('fqdn', cli_name='hostname') +arg: Str('memberprincipal+', alwaysask=True, cli_name='principal') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Flag('no_members', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('version?') +output: Entry('result') +output: Output('summary', type=[, ]) +output: PrimaryKey('value') command: host_add_managedby/1 args: 1,5,3 arg: Str('fqdn', cli_name='hostname') @@ -2529,6 +2540,20 @@ option: Str('version?') output: Entry('result') output: Output('summary', type=[, ]) output: PrimaryKey('value') +command: host_allow_add_delegation/1 +args: 1,8,3 +arg: Str('fqdn', cli_name='hostname') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Str('group*', alwaysask=True, cli_name='groups') +option: Str('host*', alwaysask=True, cli_name='hosts') +option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups') +option: Flag('no_members', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('user*', alwaysask=True, cli_name='users') +option: Str('version?') +output: Output('completed', type=[]) +output: Output('failed', type=[]) +output: Entry('result') command: host_allow_create_keytab/1 args: 1,8,3 arg: Str('fqdn', cli_name='hostname') @@ -2573,6 +2598,20 @@ option: Str('version?') output: Output('result', type=[]) output: Output('summary', type=[, ]) output: PrimaryKey('value') +command: host_disallow_add_delegation/1 +args: 1,8,3 +arg: Str('fqdn', cli_name='hostname') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Str('group*', alwaysask=True, cli_name='groups') +option: Str('host*', alwaysask=True, cli_name='hosts') +option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups') +option: Flag('no_members', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('user*', alwaysask=True, cli_name='users') +option: Str('version?') +output: Output('completed', type=[]) +output: Output('failed', type=[]) +output: Entry('result') command: host_disallow_create_keytab/1 args: 1,8,3 arg: Str('fqdn', cli_name='hostname') @@ -2685,6 +2724,17 @@ option: Str('version?') output: Entry('result') output: Output('summary', type=[, ]) output: PrimaryKey('value') +command: host_remove_delegation/1 +args: 2,4,3 +arg: Str('fqdn', cli_name='hostname') +arg: Str('memberprincipal+', alwaysask=True, cli_name='principal') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Flag('no_members', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('version?') +output: Entry('result') +output: Output('summary', type=[, ]) +output: PrimaryKey('value') command: host_remove_managedby/1 args: 1,5,3 arg: Str('fqdn', cli_name='hostname') @@ -4705,6 +4755,17 @@ option: Str('version?') output: Entry('result') output: Output('summary', type=[, ]) output: PrimaryKey('value') +command: service_add_delegation/1 +args: 2,4,3 +arg: Principal('krbcanonicalname', cli_name='canonical_principal') +arg: Str('memberprincipal+', alwaysask=True, cli_name='principal') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Flag('no_members', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('version?') +output: Entry('result') +output: Output('summary', type=[, ]) +output: PrimaryKey('value') command: service_add_host/1 args: 1,5,3 arg: Principal('krbcanonicalname', cli_name='canonical_principal') @@ -4743,6 +4804,20 @@ option: Str('version?') output: Entry('result') output: Output('summary', type=[, ]) output: PrimaryKey('value') +command: service_allow_add_delegation/1 +args: 1,8,3 +arg: Principal('krbcanonicalname', cli_name='canonical_principal') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Str('group*', alwaysask=True, cli_name='groups') +option: Str('host*', alwaysask=True, cli_name='hosts') +option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups') +option: Flag('no_members', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('user*', alwaysask=True, cli_name='users') +option: Str('version?') +output: Output('completed', type=[]) +output: Output('failed', type=[]) +output: Entry('result') command: service_allow_create_keytab/1 args: 1,8,3 arg: Principal('krbcanonicalname', cli_name='canonical_principal') @@ -4786,6 +4861,20 @@ option: Str('version?') output: Output('result', type=[]) output: Output('summary', type=[, ]) output: PrimaryKey('value') +command: service_disallow_add_delegation/1 +args: 1,8,3 +arg: Principal('krbcanonicalname', cli_name='canonical_principal') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Str('group*', alwaysask=True, cli_name='groups') +option: Str('host*', alwaysask=True, cli_name='hosts') +option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups') +option: Flag('no_members', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('user*', alwaysask=True, cli_name='users') +option: Str('version?') +output: Output('completed', type=[]) +output: Output('failed', type=[]) +output: Entry('result') command: service_disallow_create_keytab/1 args: 1,8,3 arg: Principal('krbcanonicalname', cli_name='canonical_principal') @@ -4866,6 +4955,17 @@ option: Str('version?') output: Entry('result') output: Output('summary', type=[, ]) output: PrimaryKey('value') +command: service_remove_delegation/1 +args: 2,4,3 +arg: Principal('krbcanonicalname', cli_name='canonical_principal') +arg: Str('memberprincipal+', alwaysask=True, cli_name='principal') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Flag('no_members', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('version?') +output: Entry('result') +output: Output('summary', type=[, ]) +output: PrimaryKey('value') command: service_remove_host/1 args: 1,5,3 arg: Principal('krbcanonicalname', cli_name='canonical_principal') @@ -7092,17 +7192,21 @@ default: hbactest/1 default: host/1 default: host_add/1 default: host_add_cert/1 +default: host_add_delegation/1 default: host_add_managedby/1 default: host_add_principal/1 +default: host_allow_add_delegation/1 default: host_allow_create_keytab/1 default: host_allow_retrieve_keytab/1 default: host_del/1 default: host_disable/1 +default: host_disallow_add_delegation/1 default: host_disallow_create_keytab/1 default: host_disallow_retrieve_keytab/1 default: host_find/1 default: host_mod/1 default: host_remove_cert/1 +default: host_remove_delegation/1 default: host_remove_managedby/1 default: host_remove_principal/1 default: host_show/1 @@ -7272,18 +7376,22 @@ default: server_state/1 default: service/1 default: service_add/1 default: service_add_cert/1 +default: service_add_delegation/1 default: service_add_host/1 default: service_add_principal/1 default: service_add_smb/1 +default: service_allow_add_delegation/1 default: service_allow_create_keytab/1 default: service_allow_retrieve_keytab/1 default: service_del/1 default: service_disable/1 +default: service_disallow_add_delegation/1 default: service_disallow_create_keytab/1 default: service_disallow_retrieve_keytab/1 default: service_find/1 default: service_mod/1 default: service_remove_cert/1 +default: service_remove_delegation/1 default: service_remove_host/1 default: service_remove_principal/1 default: service_show/1 diff --git a/VERSION.m4 b/VERSION.m4 index 95ab71b1f..d7aa5000b 100644 --- a/VERSION.m4 +++ b/VERSION.m4 @@ -86,8 +86,8 @@ define(IPA_DATA_VERSION, 20100614120000) # # ######################################################## define(IPA_API_VERSION_MAJOR, 2) -# Last change: fix vault interoperability issues. -define(IPA_API_VERSION_MINOR, 251) +# Last change: RBCD implementation +define(IPA_API_VERSION_MINOR, 252) ######################################################## # Following values are auto-generated from values above diff --git a/doc/api/commands.rst b/doc/api/commands.rst index b9d16071d..85259bd5f 100644 --- a/doc/api/commands.rst +++ b/doc/api/commands.rst @@ -182,17 +182,21 @@ IPA API Commands hbactest.md host_add.md host_add_cert.md + host_add_delegation.md host_add_managedby.md host_add_principal.md + host_allow_add_delegation.md host_allow_create_keytab.md host_allow_retrieve_keytab.md host_del.md host_disable.md + host_disallow_add_delegation.md host_disallow_create_keytab.md host_disallow_retrieve_keytab.md host_find.md host_mod.md host_remove_cert.md + host_remove_delegation.md host_remove_managedby.md host_remove_principal.md host_show.md @@ -336,18 +340,22 @@ IPA API Commands server_state.md service_add.md service_add_cert.md + service_add_delegation.md service_add_host.md service_add_principal.md service_add_smb.md + service_allow_add_delegation.md service_allow_create_keytab.md service_allow_retrieve_keytab.md service_del.md service_disable.md + service_disallow_add_delegation.md service_disallow_create_keytab.md service_disallow_retrieve_keytab.md service_find.md service_mod.md service_remove_cert.md + service_remove_delegation.md service_remove_host.md service_remove_principal.md service_show.md diff --git a/doc/api/host_add_delegation.md b/doc/api/host_add_delegation.md new file mode 100644 index 000000000..613b8660c --- /dev/null +++ b/doc/api/host_add_delegation.md @@ -0,0 +1,32 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) +# host_add_delegation +Add new resource delegation to a host + +### Arguments +|Name|Type|Required +|-|-|- +|fqdn|:ref:`Str`|True +|memberprincipal|:ref:`Str`|True + +### Options +* all : :ref:`Flag` **(Required)** + * Default: False +* raw : :ref:`Flag` **(Required)** + * Default: False +* no_members : :ref:`Flag` **(Required)** + * Default: False +* version : :ref:`Str` + +### Output +|Name|Type +|-|- +|result|Entry +|summary|Output +|value|PrimaryKey + +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) +### Semantics + +### Notes + +### Version differences \ No newline at end of file diff --git a/doc/api/host_allow_add_delegation.md b/doc/api/host_allow_add_delegation.md new file mode 100644 index 000000000..b6743cdff --- /dev/null +++ b/doc/api/host_allow_add_delegation.md @@ -0,0 +1,35 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) +# host_allow_add_delegation +Allow users, groups, hosts or host groups to handle a resource delegation of this host. + +### Arguments +|Name|Type|Required +|-|-|- +|fqdn|:ref:`Str`|True + +### Options +* all : :ref:`Flag` **(Required)** + * Default: False +* raw : :ref:`Flag` **(Required)** + * Default: False +* no_members : :ref:`Flag` **(Required)** + * Default: False +* version : :ref:`Str` +* user : :ref:`Str` +* group : :ref:`Str` +* host : :ref:`Str` +* hostgroup : :ref:`Str` + +### Output +|Name|Type +|-|- +|completed|Output +|failed|Output +|result|Entry + +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) +### Semantics + +### Notes + +### Version differences \ No newline at end of file diff --git a/doc/api/host_disallow_add_delegation.md b/doc/api/host_disallow_add_delegation.md new file mode 100644 index 000000000..b7a58291b --- /dev/null +++ b/doc/api/host_disallow_add_delegation.md @@ -0,0 +1,35 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) +# host_disallow_add_delegation +Disallow users, groups, hosts or host groups to handle a resource delegation of this host. + +### Arguments +|Name|Type|Required +|-|-|- +|fqdn|:ref:`Str`|True + +### Options +* all : :ref:`Flag` **(Required)** + * Default: False +* raw : :ref:`Flag` **(Required)** + * Default: False +* no_members : :ref:`Flag` **(Required)** + * Default: False +* version : :ref:`Str` +* user : :ref:`Str` +* group : :ref:`Str` +* host : :ref:`Str` +* hostgroup : :ref:`Str` + +### Output +|Name|Type +|-|- +|completed|Output +|failed|Output +|result|Entry + +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) +### Semantics + +### Notes + +### Version differences \ No newline at end of file diff --git a/doc/api/host_remove_delegation.md b/doc/api/host_remove_delegation.md new file mode 100644 index 000000000..eec2a8503 --- /dev/null +++ b/doc/api/host_remove_delegation.md @@ -0,0 +1,32 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) +# host_remove_delegation +Remove resource delegation from a host + +### Arguments +|Name|Type|Required +|-|-|- +|fqdn|:ref:`Str`|True +|memberprincipal|:ref:`Str`|True + +### Options +* all : :ref:`Flag` **(Required)** + * Default: False +* raw : :ref:`Flag` **(Required)** + * Default: False +* no_members : :ref:`Flag` **(Required)** + * Default: False +* version : :ref:`Str` + +### Output +|Name|Type +|-|- +|result|Entry +|summary|Output +|value|PrimaryKey + +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) +### Semantics + +### Notes + +### Version differences \ No newline at end of file diff --git a/doc/api/service_add_delegation.md b/doc/api/service_add_delegation.md new file mode 100644 index 000000000..9c830db61 --- /dev/null +++ b/doc/api/service_add_delegation.md @@ -0,0 +1,32 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) +# service_add_delegation +Add new resource delegation to a service + +### Arguments +|Name|Type|Required +|-|-|- +|krbcanonicalname|:ref:`Principal`|True +|memberprincipal|:ref:`Str`|True + +### Options +* all : :ref:`Flag` **(Required)** + * Default: False +* raw : :ref:`Flag` **(Required)** + * Default: False +* no_members : :ref:`Flag` **(Required)** + * Default: False +* version : :ref:`Str` + +### Output +|Name|Type +|-|- +|result|Entry +|summary|Output +|value|PrimaryKey + +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) +### Semantics + +### Notes + +### Version differences \ No newline at end of file diff --git a/doc/api/service_allow_add_delegation.md b/doc/api/service_allow_add_delegation.md new file mode 100644 index 000000000..c534834ec --- /dev/null +++ b/doc/api/service_allow_add_delegation.md @@ -0,0 +1,35 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) +# service_allow_add_delegation +Allow users, groups, hosts or host groups to handle a resource delegation of this service. + +### Arguments +|Name|Type|Required +|-|-|- +|krbcanonicalname|:ref:`Principal`|True + +### Options +* all : :ref:`Flag` **(Required)** + * Default: False +* raw : :ref:`Flag` **(Required)** + * Default: False +* no_members : :ref:`Flag` **(Required)** + * Default: False +* version : :ref:`Str` +* user : :ref:`Str` +* group : :ref:`Str` +* host : :ref:`Str` +* hostgroup : :ref:`Str` + +### Output +|Name|Type +|-|- +|completed|Output +|failed|Output +|result|Entry + +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) +### Semantics + +### Notes + +### Version differences \ No newline at end of file diff --git a/doc/api/service_disallow_add_delegation.md b/doc/api/service_disallow_add_delegation.md new file mode 100644 index 000000000..2d6d55c91 --- /dev/null +++ b/doc/api/service_disallow_add_delegation.md @@ -0,0 +1,35 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) +# service_disallow_add_delegation +Disallow users, groups, hosts or host groups to handle a resource delegation of this service. + +### Arguments +|Name|Type|Required +|-|-|- +|krbcanonicalname|:ref:`Principal`|True + +### Options +* all : :ref:`Flag` **(Required)** + * Default: False +* raw : :ref:`Flag` **(Required)** + * Default: False +* no_members : :ref:`Flag` **(Required)** + * Default: False +* version : :ref:`Str` +* user : :ref:`Str` +* group : :ref:`Str` +* host : :ref:`Str` +* hostgroup : :ref:`Str` + +### Output +|Name|Type +|-|- +|completed|Output +|failed|Output +|result|Entry + +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) +### Semantics + +### Notes + +### Version differences \ No newline at end of file diff --git a/doc/api/service_remove_delegation.md b/doc/api/service_remove_delegation.md new file mode 100644 index 000000000..2bc7bb0ec --- /dev/null +++ b/doc/api/service_remove_delegation.md @@ -0,0 +1,32 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) +# service_remove_delegation +Remove resource delegation from a service + +### Arguments +|Name|Type|Required +|-|-|- +|krbcanonicalname|:ref:`Principal`|True +|memberprincipal|:ref:`Str`|True + +### Options +* all : :ref:`Flag` **(Required)** + * Default: False +* raw : :ref:`Flag` **(Required)** + * Default: False +* no_members : :ref:`Flag` **(Required)** + * Default: False +* version : :ref:`Str` + +### Output +|Name|Type +|-|- +|result|Entry +|summary|Output +|value|PrimaryKey + +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) +### Semantics + +### Notes + +### Version differences \ No newline at end of file diff --git a/install/share/61kerberos-ipav3.ldif b/install/share/61kerberos-ipav3.ldif index c81ce51df..91a4ba609 100644 --- a/install/share/61kerberos-ipav3.ldif +++ b/install/share/61kerberos-ipav3.ldif @@ -1,3 +1,5 @@ dn: cn=schema attributeTypes: (2.16.840.1.113730.3.8.11.32 NAME 'ipaKrbPrincipalAlias' DESC 'DEPRECATED - DO NOT USE' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3') objectClasses: (2.16.840.1.113730.3.8.12.8 NAME 'ipaKrbPrincipal' SUP krbPrincipalAux AUXILIARY MUST ( krbPrincipalName $ ipaKrbPrincipalAlias ) X-ORIGIN 'IPA v3' ) +# Resource delegation object class uses memberPrincipal to specify targets and requires a Kerberos principal +objectClasses: (2.16.840.1.113730.3.8.24.10 NAME 'resourceDelegation' SUP krbPrincipal AUXILIARY MAY ( memberPrincipal ) X-ORIGIN 'IPA v4.10' ) diff --git a/ipalib/util.py b/ipalib/util.py index ef8e3ad67..128420181 100644 --- a/ipalib/util.py +++ b/ipalib/util.py @@ -74,6 +74,7 @@ from ipapython.dnsutil import ( resolve_ip_addresses, ) from ipapython.admintool import ScriptError +from ipapython.kerberos import Principal if sys.version_info >= (3, 2): import reprlib @@ -1232,16 +1233,15 @@ def check_client_configuration(env=None): ) -def check_principal_realm_in_trust_namespace(api_instance, *keys): +def _collect_trust_namespaces(api_instance, add_local=False): """ - Check that principal name's suffix does not overlap with UPNs and realm - names of trusted forests. + Return UPNs and realm names of trusted forests. :param api_instance: API instance - :param suffixes: principal suffixes + :param add_local: bool flag - :raises: ValidationError if the suffix coincides with realm name, UPN - suffix or netbios name of trusted domains + :return: set of namespace names as strings. + If add_local is True, add own realm namesapce """ trust_objects = api_instance.Command.trust_find(u'', sizelimit=0)['result'] @@ -1258,17 +1258,69 @@ def check_principal_realm_in_trust_namespace(api_instance, *keys): trust_suffix_namespace.add(obj['cn'][0].lower()) - for principal in keys[-1]: + if add_local: + trust_suffix_namespace.add(api_instance.env.realm.lower()) + + return trust_suffix_namespace + + +def check_principal_realm_in_trust_namespace(api_instance, *suffixes, + attr_name='krbprincipalname'): + """ + Check that principal name's suffix does not overlap with UPNs and realm + names of trusted forests. + + :param api_instance: API instance + :param suffixes: principal suffixes + + :raises: ValidationError if the suffix coincides with realm name, UPN + suffix or netbios name of trusted domains + """ + trust_suffix_namespace = _collect_trust_namespaces(api_instance, + add_local=False) + + for p in suffixes[-1]: + principal = Principal(p, realm=api_instance.env.realm) realm = principal.realm upn = principal.upn_suffix if principal.is_enterprise else None if realm in trust_suffix_namespace or upn in trust_suffix_namespace: raise errors.ValidationError( - name='krbprincipalname', + name=attr_name, error=_('realm or UPN suffix overlaps with trusted domain ' 'namespace')) +def check_principal_realm_supported(api_instance, *suffixes, + attr_name='krbprincipalname'): + """ + Check that principal name's suffix does not overlap with UPNs and realm + names of trusted forests. + + :param api_instance: API instance + :param suffixes: principal suffixes + + :raises: ValidationError if the suffix does not match with realm name, UPN + suffix or netbios name of trusted domains or IPA domain + """ + trust_suffix_namespace = _collect_trust_namespaces(api_instance, + add_local=True) + + for p in suffixes[-1]: + principal = Principal(p, realm=api_instance.env.realm) + realm = principal.realm + upn = principal.upn_suffix if principal.is_enterprise else None + + conditions = [(realm.lower() not in trust_suffix_namespace), + (upn is not None and ( + upn.lower() not in trust_suffix_namespace))] + if any(conditions): + raise errors.ValidationError( + name=attr_name, + error=_('realm or UPN suffix outside of supported realm ' + 'domains or trusted domains namespace')) + + def no_matching_interface_for_ip_address_warning(addr_list): for ip in addr_list: if not ip.get_matching_interface(): diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py index 83d670ec6..e3eb7aebc 100644 --- a/ipaserver/plugins/host.py +++ b/ipaserver/plugins/host.py @@ -238,6 +238,14 @@ host_output_params = ( Str('ipaallowedtoperform_write_keys', label=_('Failed allowed to create keytab'), ), + Str('ipaallowedtoperform_write_delegation_user', + label=_('Users allowed to add resource delegation')), + Str('ipaallowedtoperform_write_delegation_group', + label=_('Groups allowed to add resource delegation')), + Str('ipaallowedtoperform_write_delegation_host', + label=_('Hosts allowed to add resource delegation')), + Str('ipaallowedtoperform_write_delegation_hostgroup', + label=_('Host Groups allowed to add resource delegation')), ) @@ -296,7 +304,8 @@ class host(LDAPObject): 'krbprincipalname', 'nshardwareplatform', 'nsosversion', 'usercertificate', 'memberof', 'managedby', 'memberofindirect', 'macaddress', - 'userclass', 'ipaallowedtoperform', 'ipaassignedidview', 'krbprincipalauthind' + 'userclass', 'ipaallowedtoperform', 'ipaassignedidview', + 'krbprincipalauthind', 'memberprincipal', ] uuid_attribute = 'ipauniqueid' attribute_members = { @@ -308,6 +317,8 @@ class host(LDAPObject): 'sudorule'], 'ipaallowedtoperform_read_keys': ['user', 'group', 'host', 'hostgroup'], 'ipaallowedtoperform_write_keys': ['user', 'group', 'host', 'hostgroup'], + 'ipaallowedtoperform_write_delegation': + ['user', 'group', 'host', 'hostgroup'], } bindable = True relationships = { @@ -317,6 +328,9 @@ class host(LDAPObject): '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'), + 'ipaallowedtoperform_write_delegation': + ('Allow to modify resource delegation ACL', + 'write_delegation_by_', 'not_write_delegation_by'), } password_attributes = [('userpassword', 'has_password'), ('krbprincipalkey', 'has_keytab')] @@ -334,7 +348,7 @@ class host(LDAPObject): 'enrolledby', 'managedby', 'ipaassignedidview', 'krbcanonicalname', 'krbprincipalaliases', 'krbprincipalexpiration', 'krbpasswordexpiration', - 'krblastpwdchange', 'krbprincipalauthind', + 'krblastpwdchange', 'krbprincipalauthind', 'memberprincipal', }, }, 'System: Read Host Membership': { @@ -456,6 +470,11 @@ class host(LDAPObject): 'objectclass', 'cn', 'macaddress', }, }, + 'System: Manage Host Resource Delegation': { + 'ipapermright': {'write', 'delete'}, + 'ipapermdefaultattr': {'memberprincipal', 'objectclass'}, + 'default_privileges': {'Host Administrators'}, + } } label = _('Hosts') @@ -563,6 +582,14 @@ class host(LDAPObject): normalizer=normalize_principal, flags=['no_create', 'no_search'], ), + Str( + 'memberprincipal*', + cli_name='principal', + label=_('Delegation principal'), + doc=_('Delegation principal'), + normalizer=normalize_principal, + flags={'no_create', 'no_update', 'no_search'} + ), Str('macaddress*', normalizer=lambda value: value.upper(), pattern=r'^([a-fA-F0-9]{2}[:|\-]?){5}[a-fA-F0-9]{2}$', @@ -1400,3 +1427,63 @@ class host_remove_principal(LDAPRemoveAttribute): def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): util.ensure_last_krbprincipalname(ldap, entry_attrs, *keys) return dn + + +@register() +class host_add_delegation(LDAPAddAttribute): + __doc__ = _('Add new resource delegation to a host') + msg_summary = _('Added new resource delegation to the host "%(value)s"') + attribute = 'memberprincipal' + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + util.check_principal_realm_supported( + self.api, *keys, attr_name=self.attribute) + if self.attribute in entry_attrs: + add_missing_object_class(ldap, 'resourcedelegation', dn) + return dn + + +@register() +class host_remove_delegation(LDAPRemoveAttribute): + __doc__ = _('Remove resource delegation from a host') + msg_summary = _('Removed resource delegation from the host "%(value)s"') + attribute = 'memberprincipal' + + +@register() +class host_allow_add_delegation(LDAPAddMember): + __doc__ = _('Allow users, groups, hosts or host groups to handle a ' + 'resource delegation of this host.') + member_attributes = ['ipaallowedtoperform_write_delegation'] + 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_add_delegation(LDAPRemoveMember): + __doc__ = _('Disallow users, groups, hosts or host groups to handle a ' + 'resource delegation of this host.') + member_attributes = ['ipaallowedtoperform_write_delegation'] + 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/ipaserver/plugins/service.py b/ipaserver/plugins/service.py index 26a79509b..d3b6cd259 100644 --- a/ipaserver/plugins/service.py +++ b/ipaserver/plugins/service.py @@ -160,6 +160,14 @@ output_params = ( Str('ipaallowedtoperform_write_keys', label=_('Failed allowed to create keytab'), ), + Str('ipaallowedtoperform_write_delegation_user', + label=_('Users allowed to add resource delegation')), + Str('ipaallowedtoperform_write_delegation_group', + label=_('Groups allowed to add resource delegation')), + Str('ipaallowedtoperform_write_delegation_host', + label=_('Hosts allowed to add resource delegation')), + Str('ipaallowedtoperform_write_delegation_hostgroup', + label=_('Host Groups allowed to add resource delegation')), ) ticket_flags_params = ( @@ -373,14 +381,14 @@ def rename_ipaallowedtoperform_from_ldap(entry_attrs, options): if options.get('raw', False): return - for subtype in ('read_keys', 'write_keys'): + for subtype in ('read_keys', 'write_keys', 'write_delegation'): 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'): + for subtype in ('read_keys', 'write_keys', 'write_delegation'): name = 'ipaallowedtoperform_%s' % subtype if name in entry_attrs: new_name = 'ipaallowedtoperform;%s' % subtype @@ -398,25 +406,31 @@ class service(LDAPObject): 'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject', 'ipaservice', 'pkiuser' ] - possible_objectclasses = ['ipakrbprincipal', 'ipaallowedoperations'] + possible_objectclasses = ['ipakrbprincipal', 'ipaallowedoperations', + 'resourcedelegation'] permission_filter_objectclasses = ['ipaservice'] search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata'] default_attributes = [ 'krbprincipalname', 'krbcanonicalname', 'usercertificate', 'managedby', 'ipakrbauthzdata', 'memberof', 'ipaallowedtoperform', - 'krbprincipalauthind'] + 'krbprincipalauthind', 'memberprincipal'] uuid_attribute = 'ipauniqueid' attribute_members = { 'managedby': ['host'], 'memberof': ['role'], 'ipaallowedtoperform_read_keys': ['user', 'group', 'host', 'hostgroup'], 'ipaallowedtoperform_write_keys': ['user', 'group', 'host', 'hostgroup'], + 'ipaallowedtoperform_write_delegation': + ['user', 'group', 'host', 'hostgroup'], } 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'), + 'ipaallowedtoperform_write_delegation': + ('Allow to modify resource delegation ACL', + 'write_delegation_by_', 'not_write_delegation_by'), } password_attributes = [('krbprincipalkey', 'has_keytab')] managed_permissions = { @@ -430,7 +444,7 @@ class service(LDAPObject): 'krbprincipalname', 'krbcanonicalname', 'krbprincipalaliases', 'krbprincipalexpiration', 'krbpasswordexpiration', 'krblastpwdchange', 'ipakrbauthzdata', 'ipakrbprincipalalias', - 'krbobjectreferences', 'krbprincipalauthind', + 'krbobjectreferences', 'krbprincipalauthind', 'memberprincipal', }, }, 'System: Add Services': { @@ -487,6 +501,21 @@ class service(LDAPObject): 'homedirectory', 'loginshell', 'uidnumber', 'ipantsecurityidentifier', }, + }, + 'System: Manage Service Resource Delegation Permissions': { + 'ipapermright': {'read', 'search', 'compare', 'write'}, + 'ipapermdefaultattr': { + 'ipaallowedtoperform;write_delegation', + 'objectclass' + }, + 'default_privileges': {'Service Administrators', + 'Host Administrators'}, + }, + 'System: Manage Service Resource Delegation': { + 'ipapermright': {'write', 'delete'}, + 'ipapermdefaultattr': {'memberPrincipal', 'objectclass'}, + 'default_privileges': {'Service Administrators', + 'Host Administrators'}, } } @@ -514,6 +543,14 @@ class service(LDAPObject): require_service=True, flags={'no_create'} ), + Str( + 'memberprincipal*', + cli_name='principal', + label=_('Delegation principal'), + doc=_('Delegation principal'), + normalizer=normalize_principal, + flags={'no_create', 'no_update', 'no_search'} + ), Certificate('usercertificate*', cli_name='certificate', label=_('Certificate'), @@ -1200,3 +1237,65 @@ class service_remove_principal(LDAPRemoveAttribute): def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): util.ensure_last_krbprincipalname(ldap, entry_attrs, *keys) return dn + + +@register() +class service_add_delegation(LDAPAddAttribute): + __doc__ = _('Add new resource delegation to a service') + msg_summary = _('Added new resource delegation to ' + 'the service principal "%(value)s"') + attribute = 'memberprincipal' + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + util.check_principal_realm_supported( + self.api, *keys, attr_name=self.attribute) + if self.attribute in entry_attrs: + add_missing_object_class(ldap, 'resourcedelegation', dn) + return dn + + +@register() +class service_remove_delegation(LDAPRemoveAttribute): + __doc__ = _('Remove resource delegation from a service') + msg_summary = _('Removed resource delegation from ' + 'the service principal "%(value)s"') + attribute = 'memberprincipal' + + +@register() +class service_allow_add_delegation(LDAPAddMember): + __doc__ = _('Allow users, groups, hosts or host groups to handle a ' + 'resource delegation of this service.') + member_attributes = ['ipaallowedtoperform_write_delegation'] + 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_add_delegation(LDAPRemoveMember): + __doc__ = _('Disallow users, groups, hosts or host groups to handle a ' + 'resource delegation of this service.') + member_attributes = ['ipaallowedtoperform_write_delegation'] + 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)