diff --git a/.wheelconstraints.in b/.wheelconstraints.in index 4c99d335f..2c8e11b8e 100644 --- a/.wheelconstraints.in +++ b/.wheelconstraints.in @@ -10,6 +10,5 @@ ipaserver == @VERSION@ ipatests == @VERSION@ # keep pylint version in sync with current Fedora release -# F36 has 2.12.2 -# https://pagure.io/freeipa/issue/8818 added pylint 2.8 support -pylint ~= 2.12.2 +# F37 has 2.15.5 +pylint ~= 2.15.5 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/Contributors.txt b/Contributors.txt index a60ec868e..4633d04b8 100644 --- a/Contributors.txt +++ b/Contributors.txt @@ -18,6 +18,7 @@ Developers: Alexander Scheel Alexandre Mulatinho Alexey Slaykovsky + Alexey Tikhonov Amit Kumar Ana Krivokapić Andika Triwidada @@ -33,6 +34,7 @@ Developers: Brian J. Murrell Brian Turek Carl George + Carla Martinez Cédric Jeanneret Changmin Teng Chris Kelley @@ -42,6 +44,7 @@ Developers: David Kreitschmann David Kupka David O'Brien + David Pascual David Spångberg Diane Trout Dinesh Prasanth M K @@ -51,8 +54,11 @@ Developers: Drew Erny Emilio Herrera Endi Sukma Dewata + Erik + Erik Belko Fabiano Fidêncio Felipe Volpone + Filip Dvorak Filip Skola Florence Blanc-Renaud Francesco Marella @@ -77,12 +83,15 @@ Developers: Jan Kuparinen Jan Pazdziora Jan Zelený + Jarl Gullberg Jason Gerard DeRose Jason Woods Jayesh Jayesh Garg Jeremy Frasier Jérôme Fenal + Jerry James + Jesse Sandberg jh23453 Jim Meyering Jochen Kellner @@ -117,6 +126,7 @@ Developers: Martin Nagy Matt Rogers Matthew Davis + mbhalodi Michael Simacek Michal Polovka Michal Reznik @@ -132,6 +142,7 @@ Developers: ndehadra Nick Hatch Nikhil Dehadrai + Nikola Knazekova Nikolai Kondrashov Niranjan Mallapadi Niranjan MR @@ -159,13 +170,16 @@ Developers: realsobek René Genz Rich Megginson + Ricky Tigg Rishabh Dave Rob Crittenden Robbie Harwood Robert Collins Robert Kuska + s1341 Sam Bristow Sam Morris + Scott Poore Sergey Orlov Sergio Oliveira Campos Serhii Tsymbaliuk @@ -184,17 +198,20 @@ Developers: Sumit Bose Sylvain Baubeau Takeshi MIZUTA + Temuri Doghonadze Theodor van Nahl Thierry Bordaz Thomas Woerner Thorsten Scherf Tibor Dudlák Timo Aaltonen + Todd Zullinger Tomáš Babej Tomas Halman Tomáš Křížek Troy Dawson Varun Mylaraiah + Viacheslav Sychov Viktor Ashirov Vit Mojzis W. Michael Petullo @@ -205,6 +222,7 @@ Developers: Yuri Chornoivan Zdenek Pytela zdover + 김인수 Documentation: Gabe Alford diff --git a/Makefile.am b/Makefile.am index 20b338c6a..e0cd8f105 100644 --- a/Makefile.am +++ b/Makefile.am @@ -244,7 +244,7 @@ fastcodestyle: $(GENERATED_PYTHON_FILES) ipasetup.py | xargs -n1 file 2>/dev/null | grep Python \ | cut -d':' -f1; ); \ if [ -n "$${PYFILES}" ] && [ -n "$${INFILES}" ]; then \ - FILES="$$( printf $${PYFILES}\\n$${INFILES} )" ; \ + FILES="$$( printf '%s\n' "$${PYFILES}" "$${INFILES}" )" ; \ elif [ -n "$${PYFILES}" ]; then \ FILES="$${PYFILES}" ; \ else \ @@ -274,7 +274,7 @@ endif | xargs -n1 file 2>/dev/null | grep Python \ | cut -d':' -f1; ); \ if [ -n "$${PYFILES}" ] && [ -n "$${INFILES}" ]; then \ - FILES="$$( printf $${PYFILES}\\n$${INFILES} )" ; \ + FILES="$$( printf '%s\n' "$${PYFILES}" "$${INFILES}" )" ; \ elif [ -n "$${PYFILES}" ]; then \ FILES="$${PYFILES}" ; \ else \ diff --git a/VERSION.m4 b/VERSION.m4 index e5d60c4c3..9d7870060 100644 --- a/VERSION.m4 +++ b/VERSION.m4 @@ -21,7 +21,7 @@ ######################################################## define(IPA_VERSION_MAJOR, 4) define(IPA_VERSION_MINOR, 10) -define(IPA_VERSION_RELEASE, 1) +define(IPA_VERSION_RELEASE, 2) ######################################################## # For 'pre' releases the version will be # @@ -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 @@ -137,6 +137,11 @@ ifelse(IPA_VERSION_IS_GIT_SNAPSHOT, yes, IPA_GIT_VERSION), NEWLINE)) dnl IPA_VERSION end +######################################################## +# Version of MIT krb5 used to build IPA +######################################################## +define(IPA_KRB5_BUILD_VERSION, translit(esyscmd(krb5-config --version | awk '{ print $NF }'), NEWLINE)) + dnl DEBUG: uncomment following lines and run command m4 VERSION.m4 dnl `IPA_VERSION: ''IPA_VERSION' dnl `IPA_GIT_VERSION: ''IPA_GIT_VERSION' @@ -144,3 +149,4 @@ dnl `IPA_GIT_BRANCH: ''IPA_GIT_BRANCH' dnl `IPA_API_VERSION: ''IPA_API_VERSION' dnl `IPA_DATA_VERSION: ''IPA_DATA_VERSION' dnl `IPA_NUM_VERSION: ''IPA_NUM_VERSION' +dnl `IPA_KRB5_BUILD_VERSION: ''IPA_KRB5_BUILD_VERSION' diff --git a/client/man/ipa-client-install.1 b/client/man/ipa-client-install.1 index bd8818807..4a755ac33 100644 --- a/client/man/ipa-client-install.1 +++ b/client/man/ipa-client-install.1 @@ -253,6 +253,12 @@ Remove the IPA client software and restore the configuration to the pre\-IPA sta \fB\-U\fR, \fB\-\-unattended\fR Unattended uninstallation. The user will not be prompted. +.SH "DISABLED SERVICES" +.TP +ipa-client-install will automatically disable the Name Service Caching Daemon (nscd) when configuring the SSSD client. These are competing services and cannot co-exist. +.TP +If there are other similar services providing nss capabilities they will need to be manually disabled by the user. An example is unscd, a complete replacement for nscd. + .SH "FILES" .TP Files that will be replaced if SSSD is configured (default): diff --git a/configure.ac b/configure.ac index 140045821..973cba33c 100644 --- a/configure.ac +++ b/configure.ac @@ -460,6 +460,7 @@ AC_SUBST(VENDOR_SUFFIX) AC_SUBST([VERSION], [IPA_VERSION]) AC_SUBST([GIT_VERSION], [IPA_GIT_VERSION]) AC_SUBST([GIT_BRANCH], [IPA_GIT_BRANCH]) +AC_SUBST([KRB5_BUILD_VERSION], [IPA_KRB5_BUILD_VERSION]) # used by Makefile.am for files depending on templates AC_SUBST([CONFIG_STATUS]) diff --git a/contrib/lite-server.py b/contrib/lite-server.py index 51f7c0888..6d42f6aab 100755 --- a/contrib/lite-server.py +++ b/contrib/lite-server.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 # # Copyright (C) 2017 FreeIPA Contributors see COPYING for license # diff --git a/contrib/lite-setup.py b/contrib/lite-setup.py index d8ca1b229..6453cb88a 100755 --- a/contrib/lite-setup.py +++ b/contrib/lite-setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 # # Copyright (C) 2020 FreeIPA Contributors see COPYING for license # diff --git a/daemons/dnssec/ipa-dnskeysyncd.in b/daemons/dnssec/ipa-dnskeysyncd.in index 91e0e43ce..3b3aa9134 100644 --- a/daemons/dnssec/ipa-dnskeysyncd.in +++ b/daemons/dnssec/ipa-dnskeysyncd.in @@ -57,7 +57,7 @@ KEYTAB_FB = paths.IPA_DNSKEYSYNCD_KEYTAB def commenceShutdown(signum, stack): # Declare the needed global variables global watcher_running - global ldap_connection # pylint: disable=global-variable-not-assigned + global ldap_connection logger.info('Signal %s received: Shutting down!', signum) diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c index 93563536c..17ce10bef 100644 --- a/daemons/ipa-kdb/ipa_kdb.c +++ b/daemons/ipa-kdb/ipa_kdb.c @@ -49,6 +49,11 @@ static void ipadb_context_free(krb5_context kcontext, size_t c; if (*ctx != NULL) { + if ((*ctx)->magic != IPA_CONTEXT_MAGIC) { + krb5_klog_syslog(LOG_ERR, "IPA context is corrupted"); + *ctx = NULL; + return; + } free((*ctx)->uri); free((*ctx)->base); free((*ctx)->realm_base); @@ -615,6 +620,8 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext, goto fail; } + ipactx->optional_pac_tkt_chksum = IPADB_TRISTATE_UNDEFINED; + ret = ipadb_get_connection(ipactx); if (ret != 0) { /* Not a fatal failure, as the LDAP server may be temporarily down. */ @@ -628,6 +635,7 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext, goto fail; } + return 0; fail: @@ -839,7 +847,7 @@ kdb_vftabl kdb_function_table = { .check_allowed_to_delegate = ipadb_check_allowed_to_delegate, .free_principal_e_data = ipadb_free_principal_e_data, .get_s4u_x509_principal = NULL, - .allowed_to_delegate_from = NULL, + .allowed_to_delegate_from = ipadb_allowed_to_delegate_from, .issue_pac = ipadb_v9_issue_pac, }; #endif diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h index 7aa5be494..7b7c03b35 100644 --- a/daemons/ipa-kdb/ipa_kdb.h +++ b/daemons/ipa-kdb/ipa_kdb.h @@ -126,6 +126,12 @@ struct ipadb_global_config { bool disable_preauth_for_spns; }; +enum ipadb_tristate_option { + IPADB_TRISTATE_FALSE = FALSE, + IPADB_TRISTATE_TRUE = TRUE, + IPADB_TRISTATE_UNDEFINED, +}; + #define IPA_CONTEXT_MAGIC 0x0c027ea7 struct ipadb_context { int magic; @@ -143,6 +149,7 @@ struct ipadb_context { krb5_key_salt_tuple *def_encs; int n_def_encs; struct ipadb_mspac *mspac; + enum ipadb_tristate_option optional_pac_tkt_chksum; #ifdef HAVE_KRB5_CERTAUTH_PLUGIN krb5_certauth_moddata certauth_moddata; #endif @@ -222,6 +229,16 @@ int ipadb_ldap_attr_has_value(LDAP *lcontext, LDAPMessage *le, int ipadb_ldap_deref_results(LDAP *lcontext, LDAPMessage *le, LDAPDerefRes **results); +krb5_error_code ipadb_get_tl_data(krb5_db_entry *entry, + krb5_int16 type, + krb5_ui_2 length, + krb5_octet *data); + +krb5_error_code ipadb_set_tl_data(krb5_db_entry *entry, + krb5_int16 type, + krb5_ui_2 length, + const krb5_octet *data); + struct ipadb_multires; krb5_error_code ipadb_multires_init(LDAP *lcontext, struct ipadb_multires **r); void ipadb_multires_free(struct ipadb_multires *r); @@ -374,6 +391,12 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext, const krb5_db_entry *server, krb5_const_principal proxy); +krb5_error_code ipadb_allowed_to_delegate_from(krb5_context context, + krb5_const_principal client, + krb5_const_principal server, + krb5_pac server_pac, + const krb5_db_entry *proxy); + /* AS AUDIT */ void ipadb_audit_as_req(krb5_context kcontext, diff --git a/daemons/ipa-kdb/ipa_kdb_common.c b/daemons/ipa-kdb/ipa_kdb_common.c index 42e0856d0..ae7742a32 100644 --- a/daemons/ipa-kdb/ipa_kdb_common.c +++ b/daemons/ipa-kdb/ipa_kdb_common.c @@ -158,12 +158,75 @@ static bool ipadb_need_retry(struct ipadb_context *ipactx, int error) return false; } +static char *no_attrs[] = { + LDAP_NO_ATTRS, + + NULL +}; + +static int +should_support_pac_tkt_sign(struct ipadb_context *ipactx, bool *result) +{ + int ret; + LDAPMessage *res = NULL; + char *masters_dn = NULL; + int count; + + char *kdc_filter = "(&(cn=KDC)(objectClass=ipaConfigObject)" + "(!(ipaConfigString=pacTktSignSupported)))"; + + if (!ipactx) { + ret = KRB5_KDB_DBNOTINITED; + goto done; + } + + count = asprintf(&masters_dn, "cn=masters,cn=ipa,cn=etc,%s", ipactx->base); + if (count < 0) { + ret = ENOMEM; + goto done; + } + + ret = ipadb_simple_search(ipactx, masters_dn, LDAP_SCOPE_SUBTREE, + kdc_filter, no_attrs, &res); + if (ret) + goto done; + + count = ldap_count_entries(ipactx->lcontext, res); + + if (result) + *result = (count == 0); + +done: + free(masters_dn); + ldap_msgfree(res); + return ret; +} + static int ipadb_check_connection(struct ipadb_context *ipactx) { + int ret = 0; + if (ipactx->lcontext == NULL) { - return ipadb_get_connection(ipactx); + ret = ipadb_get_connection(ipactx); } - return 0; + if ((ret == 0) && (ipactx->optional_pac_tkt_chksum == IPADB_TRISTATE_UNDEFINED)) { + bool pac_tkt_sign_supported; + + /* Enforce PAC ticket signature verification if supported by all KDCs + * To avoid loops as all search functions call into + * ipadb_check_connection(), mark that the init is complete at this + * point. Default to not issuing PAC to be safe. + */ + ipactx->optional_pac_tkt_chksum = IPADB_TRISTATE_FALSE; + ret = should_support_pac_tkt_sign(ipactx, + &pac_tkt_sign_supported); + if (ret == 0) { + ipactx->optional_pac_tkt_chksum = !pac_tkt_sign_supported; + } else { + ipactx->optional_pac_tkt_chksum = IPADB_TRISTATE_UNDEFINED; + } + } + return ret; } krb5_error_code ipadb_simple_search(struct ipadb_context *ipactx, diff --git a/daemons/ipa-kdb/ipa_kdb_delegation.c b/daemons/ipa-kdb/ipa_kdb_delegation.c index de82174ad..ce5409d2b 100644 --- a/daemons/ipa-kdb/ipa_kdb_delegation.c +++ b/daemons/ipa-kdb/ipa_kdb_delegation.c @@ -42,7 +42,7 @@ static krb5_error_code ipadb_get_delegation_acl(krb5_context kcontext, { struct ipadb_context *ipactx; krb5_error_code kerr; - char *filter = NULL; + char *filter = NULL, *basedn = NULL; int ret; ipactx = ipadb_get_context(kcontext); @@ -58,12 +58,20 @@ static krb5_error_code ipadb_get_delegation_acl(krb5_context kcontext, goto done; } + ret = asprintf(&basedn, + "cn=s4u2proxy,cn=etc,%s", ipactx->base); + if (ret == -1) { + kerr = ENOMEM; + goto done; + } + /* == Search ACL info == */ - kerr = ipadb_deref_search(ipactx, ipactx->base, + kerr = ipadb_deref_search(ipactx, basedn, LDAP_SCOPE_SUBTREE, filter, acl_attrs, search_attrs, acl_attrs, results); done: + free(basedn); free(filter); return kerr; } @@ -284,3 +292,44 @@ done: ldap_msgfree(res); return kerr; } + + +krb5_error_code ipadb_allowed_to_delegate_from(krb5_context context, + krb5_const_principal client, + krb5_const_principal server, + krb5_pac server_pac, + const krb5_db_entry *proxy) +{ + char **acl_list = NULL; + krb5_error_code kerr; + size_t i; + + kerr = ipadb_get_tl_data((krb5_db_entry *) proxy, KRB5_TL_CONSTRAINED_DELEGATION_ACL, + sizeof(acl_list), (krb5_octet *)&acl_list); + + if (kerr != 0 && kerr != ENOENT) { + return KRB5KDC_ERR_BADOPTION; + } + + if (kerr == ENOENT) { + return KRB5_PLUGIN_OP_NOTSUPP; + } + + kerr = KRB5KDC_ERR_BADOPTION; + if (acl_list != NULL) { + krb5_principal acl; + for (i = 0; acl_list[i] != NULL; i++) { + if (krb5_parse_name(context, acl_list[i], &acl) != 0) + continue; + if ((server == NULL) || + (krb5_principal_compare(context, server, acl) == TRUE)) { + kerr = 0; + krb5_free_principal(context, acl); + break; + } + krb5_free_principal(context, acl); + } + } + + return kerr; +} diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c index a15050e21..83b507cb4 100644 --- a/daemons/ipa-kdb/ipa_kdb_mspac.c +++ b/daemons/ipa-kdb/ipa_kdb_mspac.c @@ -1086,7 +1086,7 @@ krb5_error_code ipadb_get_pac(krb5_context kcontext, } sentry = ldap_first_entry(ipactx->lcontext, sresults); - if (!lentry) { + if (!sentry) { kerr = ENOENT; goto done; } @@ -1827,11 +1827,43 @@ krb5_error_code filter_logon_info(krb5_context context, bool result; char *domstr = NULL; + ipactx = ipadb_get_context(context); + if (!ipactx || !ipactx->mspac) { + return KRB5_KDB_DBNOTINITED; + } + domain = get_domain_from_realm_update(context, realm); if (!domain) { return EINVAL; } + /* check exact sid */ + result = dom_sid_check(&domain->domsid, info->info->info3.base.domain_sid, true); + if (!result) { + struct ipadb_mspac *mspac_ctx = ipactx->mspac; + result = FALSE; + /* Didn't match but perhaps the original PAC was issued by a child domain's DC? */ + for (k = 0; k < mspac_ctx->num_trusts; k++) { + result = dom_sid_check(&mspac_ctx->trusts[k].domsid, + info->info->info3.base.domain_sid, true); + if (result) { + domain = &mspac_ctx->trusts[k]; + break; + } + } + if (!result) { + domstr = dom_sid_string(NULL, info->info->info3.base.domain_sid); + krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, " + "expected domain SID = %s, " + "found domain SID = %s", + domain->domain_name, domain->domain_sid, + domstr ? domstr : ""); + talloc_free(domstr); + return EINVAL; + } + } + + /* At this point we may have changed the domain we look at, */ /* check netbios/flat name */ if (strcasecmp(info->info->info3.base.logon_domain.string, domain->flat_name) != 0) { @@ -1843,21 +1875,6 @@ krb5_error_code filter_logon_info(krb5_context context, return EINVAL; } - /* check exact sid */ - result = dom_sid_check(&domain->domsid, info->info->info3.base.domain_sid, true); - if (!result) { - domstr = dom_sid_string(NULL, info->info->info3.base.domain_sid); - if (!domstr) { - return EINVAL; - } - krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, " - "expected domain SID = %s, " - "found domain SID = %s", - domain->domain_name, domain->domain_sid, domstr); - talloc_free(domstr); - return EINVAL; - } - /* Check if this domain has been filtered out by the trust itself*/ if (domain->parent != NULL) { for(k = 0; k < domain->parent->len_sid_blocklist_incoming; k++) { @@ -1944,10 +1961,6 @@ krb5_error_code filter_logon_info(krb5_context context, * should include different possibilities into account * */ if (info->info->info3.sidcount != 0) { - ipactx = ipadb_get_context(context); - if (!ipactx || !ipactx->mspac) { - return KRB5_KDB_DBNOTINITED; - } count = info->info->info3.sidcount; i = 0; j = 0; @@ -2354,7 +2367,10 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context, for (i = 0; i < num_buffers; i++) { if (types[i] == KRB5_PAC_SERVER_CHECKSUM || types[i] == KRB5_PAC_PRIVSVR_CHECKSUM || - types[i] == KRB5_PAC_CLIENT_INFO) { +#ifdef KRB5_PAC_FULL_CHECKSUM + types[i] == KRB5_PAC_FULL_CHECKSUM || +#endif + types[i] == KRB5_PAC_CLIENT_INFO) { continue; } diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_v6.c b/daemons/ipa-kdb/ipa_kdb_mspac_v6.c index e506a0fd2..faf47ad1b 100644 --- a/daemons/ipa-kdb/ipa_kdb_mspac_v6.c +++ b/daemons/ipa-kdb/ipa_kdb_mspac_v6.c @@ -176,11 +176,21 @@ static krb5_error_code ipadb_sign_pac(krb5_context context, /* only pass with_realm TRUE when it is cross-realm ticket and S4U2Self * was requested */ +#ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT + kerr = krb5_pac_full_sign_compat( + context, pac, authtime, client_princ, server->princ, server_key, + right_krbtgt_signing_key, + (is_issuing_referral && (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)), + pac_data + ); +#else + /* Use standard function, PAC extended KDC signature not supported */ kerr = krb5_pac_sign_ext(context, pac, authtime, client_princ, server_key, right_krbtgt_signing_key, (is_issuing_referral && (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)), pac_data); +#endif done: free(princ); diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c index e95cb453c..3d7225988 100644 --- a/daemons/ipa-kdb/ipa_kdb_principals.c +++ b/daemons/ipa-kdb/ipa_kdb_principals.c @@ -82,6 +82,7 @@ static char *std_principal_attrs[] = { "krbAuthIndMaxRenewableAge", "ipaNTSecurityIdentifier", "ipaUniqueID", + "memberPrincipal", "objectClass", NULL @@ -113,6 +114,14 @@ static char *std_principal_obj_classes[] = { #define DEFAULT_TL_DATA_CONTENT "\x00\x00\x00\x00principal@UNINITIALIZED" +#ifndef KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM +#define KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM "optional_pac_tkt_chksum" +#endif + +#ifndef KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE +#define KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE "pac_privsvr_enctype" +#endif + static int ipadb_ldap_attr_to_tl_data(LDAP *lcontext, LDAPMessage *le, char *attrname, krb5_tl_data **result, int *num) @@ -178,10 +187,56 @@ done: return ret; } -static krb5_error_code ipadb_set_tl_data(krb5_db_entry *entry, - krb5_int16 type, - krb5_ui_2 length, - const krb5_octet *data) +static bool +is_tgs_princ(krb5_context kcontext, krb5_const_principal princ) +{ + krb5_data *primary; + size_t l_tgs_name; + + if (2 != krb5_princ_size(kcontext, princ)) + return false; + + primary = krb5_princ_component(kcontext, princ, 0); + + l_tgs_name = strlen(KRB5_TGS_NAME); + + if (l_tgs_name != primary->length) + return false; + + return 0 == memcmp(primary->data, KRB5_TGS_NAME, l_tgs_name); +} + +static krb5_error_code +cmp_local_tgs_princ(krb5_context kcontext, const char *local_realm, + krb5_const_principal princ, bool *result) +{ + krb5_principal local_tgs_princ; + size_t l_local_realm; + krb5_error_code kerr; + bool res; + + l_local_realm = strlen(local_realm); + + kerr = krb5_build_principal(kcontext, &local_tgs_princ, + l_local_realm, local_realm, + KRB5_TGS_NAME, local_realm, NULL); + if (kerr) + goto end; + + res = (bool) krb5_principal_compare(kcontext, local_tgs_princ, princ); + + if (result) + *result = res; + +end: + krb5_free_principal(kcontext, local_tgs_princ); + return kerr; +} + +krb5_error_code ipadb_set_tl_data(krb5_db_entry *entry, + krb5_int16 type, + krb5_ui_2 length, + const krb5_octet *data) { krb5_error_code kerr; krb5_tl_data *new_td = NULL; @@ -633,6 +688,7 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext, char *uidstring; char **authz_data_list; char *princ_sid; + char **acl_list; krb5_timestamp restime; bool resbool; int result; @@ -1029,6 +1085,30 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext, ied->has_sid = true; } + /* check if it has the serviceDelegation objectclass */ + ret = ipadb_ldap_attr_has_value(lcontext, lentry, + "objectClass", "resourceDelegation"); + if (ret != 0 && ret != ENOENT) { + kerr = ret; + goto done; + } + if (ret == 0) { + ret = ipadb_ldap_attr_to_strlist(lcontext, lentry, + "memberPrincipal", &acl_list); + if (ret != 0 && ret != ENOENT) { + kerr = KRB5_KDB_INTERNAL_ERROR; + goto done; + } + if (ret == 0) { + kerr = ipadb_set_tl_data(entry, KRB5_TL_CONSTRAINED_DELEGATION_ACL, + sizeof(acl_list), + (const krb5_octet *) &acl_list); + if (kerr) { + goto done; + } + } + } + kerr = 0; done: @@ -1459,6 +1539,14 @@ done: return kerr; } +/* For krb5 1.19, there is no KRB5_KDB_FLAG_REFERRAL_OK, emulate it + * See krb5 commit a441fbe329ebbd7775eb5d4ccc4a05eef370f08b */ +#ifndef KRB5_KDB_FLAG_REFERRAL_OK +#ifdef KRB5_KDB_FLAG_CANONICALIZE +#define KRB5_KDB_FLAG_REFERRAL_OK KRB5_KDB_FLAG_CANONICALIZE +#endif +#endif + static krb5_error_code dbget_alias(krb5_context kcontext, struct ipadb_context *ipactx, krb5_const_principal search_for, @@ -1472,18 +1560,39 @@ static krb5_error_code dbget_alias(krb5_context kcontext, krb5_db_entry *kentry = NULL; krb5_data *realm; krb5_boolean check = FALSE; + /* KRB5_NT_PRINCIPAL must be the last element */ + krb5_int32 supported_types[] = { + [0] = KRB5_NT_ENTERPRISE_PRINCIPAL, + [1] = KRB5_NT_PRINCIPAL, + -1, + }; + size_t i = 0; - /* TODO: also support hostbased aliases */ + /* For TGS-REQ server principal lookup, KDC asks with KRB5_KDB_FLAG_REFERRAL_OK + * and client usually asks for an KRB5_NT_PRINCIPAL type principal. */ + if ((flags & KRB5_KDB_FLAG_REFERRAL_OK) == 0) { + /* this is *not* TGS-REQ server principal search, remove + * KRB5_NT_PRINCIPAL from the supported principal types for this lookup */ + supported_types[(sizeof(supported_types) / sizeof(supported_types[0])) - 2] = -1; + } /* Enterprise principal name type is for potential aliases or principals - * from trusted realms. The logic below only applies to this type */ - if (krb5_princ_type(kcontext, search_for) != KRB5_NT_ENTERPRISE_PRINCIPAL) { + * from trusted realms. Except for the TGS-REQ server lookup, we only + * expect enterprise principals here */ + for (i = 0; supported_types[i] != -1; i++) { + if (krb5_princ_type(kcontext, search_for) == supported_types[i]) { + break; + } + } + + if (supported_types[i] == -1) { return KRB5_KDB_NOENTRY; } /* enterprise principal can only have single component in the name * according to RFC6806 section 5. */ - if (krb5_princ_size(kcontext, search_for) != 1) { + if ((krb5_princ_type(kcontext, search_for) == KRB5_NT_ENTERPRISE_PRINCIPAL) && + (krb5_princ_size(kcontext, search_for) != 1)) { return KRB5_KDB_NOENTRY; } @@ -1507,6 +1616,12 @@ static krb5_error_code dbget_alias(krb5_context kcontext, if (krb5_realm_compare(kcontext, ipactx->local_tgs, norm_princ)) { /* In realm alias, try to retrieve it and let the caller handle it. */ kerr = dbget_princ(kcontext, ipactx, norm_princ, flags, entry); + } + + /* if we haven't found the principal in our realm, it might still + * be a referral to a known realm. Otherwise, bail out with the result */ + if ((kerr != KRB5_KDB_NOENTRY) && + (flags & KRB5_KDB_FLAG_REFERRAL_OK) == 0) { goto done; } @@ -1550,7 +1665,30 @@ static krb5_error_code dbget_alias(krb5_context kcontext, &trusted_realm); } + if (kerr == KRB5_KDB_NOENTRY) { + krb5_data *hstname = NULL; + int ncomponents = krb5_princ_size(kcontext, norm_princ); + + /* We did not find any alias so far for non-server principal lookups */ + if ((ncomponents < 2) && ((flags & KRB5_KDB_FLAG_REFERRAL_OK) == 0)) { + goto done; + } + + /* At this point it is a server principal lookup that might be + * referencing a host name in a trusted domain. It might also + * have multiple service components so take the last one for the + * hostname or the domain name. See MS-ADTS 2.2.21 and MS-DRSR 2.2.4.2. + */ + hstname = krb5_princ_component(kcontext, norm_princ, ncomponents - 1); + + kerr = ipadb_is_princ_from_trusted_realm(kcontext, + hstname->data, + hstname->length, + &trusted_realm); + } + if (kerr != 0) { + kerr = KRB5_KDB_NOENTRY; goto done; } @@ -1632,6 +1770,8 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext, krb5_db_entry **entry) { struct ipadb_context *ipactx; + bool is_local_tgs_princ; + const char *opt_pac_tkt_chksum_val; krb5_error_code kerr; *entry = NULL; @@ -1647,11 +1787,47 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext, /* Lookup local names and aliases first. */ kerr = dbget_princ(kcontext, ipactx, search_for, flags, entry); - if (kerr != KRB5_KDB_NOENTRY) { + if (kerr == KRB5_KDB_NOENTRY) { + kerr = dbget_alias(kcontext, ipactx, search_for, flags, entry); + } + if (kerr) return kerr; + + /* If TGS principal, some virtual attributes may be added */ + if (is_tgs_princ(kcontext, (*entry)->princ)) { + kerr = cmp_local_tgs_princ(kcontext, ipactx->realm, (*entry)->princ, + &is_local_tgs_princ); + if (kerr) + return kerr; + + /* for trusted AD forests we currently must use SHA-1-based + * encryption types. For details, see + * https://github.com/krb5/krb5/commit/5af907156f8f502bbe268f0c62274f88a61261e4 + */ + if (!is_local_tgs_princ) { + kerr = krb5_dbe_set_string(kcontext, *entry, + KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE, + "aes256-sha1"); + } + + /* We should have been initialized at this point already */ + if (ipactx->optional_pac_tkt_chksum == IPADB_TRISTATE_UNDEFINED) { + return KRB5_KDB_SERVER_INTERNAL_ERR; + } + /* PAC ticket signature should be optional for foreign realms, and local + * realm if not supported by all servers + */ + if (!is_local_tgs_princ || ipactx->optional_pac_tkt_chksum) + opt_pac_tkt_chksum_val = "true"; + else + opt_pac_tkt_chksum_val = "false"; + + kerr = krb5_dbe_set_string(kcontext, *entry, + KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM, + opt_pac_tkt_chksum_val); } - return dbget_alias(kcontext, ipactx, search_for, flags, entry); + return kerr; } void ipadb_free_principal_e_data(krb5_context kcontext, krb5_octet *e_data) @@ -1682,12 +1858,20 @@ void ipadb_free_principal_e_data(krb5_context kcontext, krb5_octet *e_data) void ipadb_free_principal(krb5_context kcontext, krb5_db_entry *entry) { krb5_tl_data *prev, *next; + size_t i; if (entry) { krb5_free_principal(kcontext, entry->princ); prev = entry->tl_data; while(prev) { next = prev->tl_data_next; + /* Handle RBCD ACL type */ + if (prev->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL) { + char **acl_list = (char **) prev->tl_data_contents; + for (i = 0; (acl_list != NULL) && (acl_list[i] != NULL); i++) { + free(acl_list[i]); + } + } free(prev->tl_data_contents); free(prev); prev = next; @@ -1702,10 +1886,10 @@ void ipadb_free_principal(krb5_context kcontext, krb5_db_entry *entry) } } -static krb5_error_code ipadb_get_tl_data(krb5_db_entry *entry, - krb5_int16 type, - krb5_ui_2 length, - krb5_octet *data) +krb5_error_code ipadb_get_tl_data(krb5_db_entry *entry, + krb5_int16 type, + krb5_ui_2 length, + krb5_octet *data) { krb5_tl_data *td; @@ -1954,6 +2138,21 @@ done: return kerr; } +static bool should_filter_out_attr(krb5_tl_data *data) +{ + switch (data->tl_data_type) { + case KRB5_TL_CONSTRAINED_DELEGATION_ACL: + case KRB5_TL_DB_ARGS: + case KRB5_TL_KADM_DATA: + case KRB5_TL_LAST_ADMIN_UNLOCK: + case KRB5_TL_LAST_PWD_CHANGE: + case KRB5_TL_MKVNO: + return true; + default: + return false; + } +} + static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods, krb5_tl_data *tl_data, int mod_op) @@ -1965,13 +2164,8 @@ static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods, int n, i; for (n = 0, data = tl_data; data; data = data->tl_data_next) { - if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE || - data->tl_data_type == KRB5_TL_KADM_DATA || - data->tl_data_type == KRB5_TL_DB_ARGS || - data->tl_data_type == KRB5_TL_MKVNO || - data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK) { + if (should_filter_out_attr(data)) continue; - } n++; } @@ -1987,13 +2181,8 @@ static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods, for (i = 0, data = tl_data; data; data = data->tl_data_next) { - if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE || - data->tl_data_type == KRB5_TL_KADM_DATA || - data->tl_data_type == KRB5_TL_DB_ARGS || - data->tl_data_type == KRB5_TL_MKVNO || - data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK) { + if (should_filter_out_attr(data)) continue; - } be_type = htons(data->tl_data_type); @@ -2745,10 +2934,43 @@ done: return kerr; } +static krb5_error_code +remove_virtual_str_attrs(krb5_context kcontext, krb5_db_entry *entry) +{ + char *str_attr_val; + krb5_error_code kerr; + const char *str_attrs[] = { + KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM, + KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE, + NULL}; + + for(int i = 0; str_attrs[i] != NULL; i++) { + kerr = krb5_dbe_get_string(kcontext, entry, + str_attrs[i], + &str_attr_val); + if (kerr) + return kerr; + + if (str_attr_val) + kerr = krb5_dbe_set_string(kcontext, entry, + str_attrs[i], + NULL); + + krb5_dbe_free_string(kcontext, str_attr_val); + } + return kerr; +} + krb5_error_code ipadb_put_principal(krb5_context kcontext, krb5_db_entry *entry, char **db_args) { + krb5_error_code kerr; + + kerr = remove_virtual_str_attrs(kcontext, entry); + if (kerr) + return kerr; + if (entry->mask & KMASK_PRINCIPAL) { return ipadb_add_principal(kcontext, entry); } else { diff --git a/daemons/ipa-otpd/ipa-otpd@.service.in b/daemons/ipa-otpd/ipa-otpd@.service.in index 65bf754f6..4a366b810 100644 --- a/daemons/ipa-otpd/ipa-otpd@.service.in +++ b/daemons/ipa-otpd/ipa-otpd@.service.in @@ -7,4 +7,4 @@ EnvironmentFile=@sysconfdir@/ipa/default.conf ExecStart=@libexecdir@/ipa/ipa-otpd $ldap_uri StandardInput=socket StandardOutput=socket -StandardError=syslog +StandardError=journal diff --git a/doc/api/A6Record.md b/doc/api/A6Record.md index e95c9fbcb..79a1b475f 100644 --- a/doc/api/A6Record.md +++ b/doc/api/A6Record.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _A6Record: -# A6Record \ No newline at end of file +# A6Record +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A6 DNS record. diff --git a/doc/api/AAAARecord.md b/doc/api/AAAARecord.md index 09a9ed546..d1aef90e6 100644 --- a/doc/api/AAAARecord.md +++ b/doc/api/AAAARecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _AAAARecord: -# AAAARecord \ No newline at end of file +# AAAARecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +AAAA DNS record. diff --git a/doc/api/AFSDBRecord.md b/doc/api/AFSDBRecord.md index fde8ec158..df65d1707 100644 --- a/doc/api/AFSDBRecord.md +++ b/doc/api/AFSDBRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _AFSDBRecord: -# AFSDBRecord \ No newline at end of file +# AFSDBRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +AFSDB DNS record. diff --git a/doc/api/APLRecord.md b/doc/api/APLRecord.md index 5e545e7b1..62dbbc141 100644 --- a/doc/api/APLRecord.md +++ b/doc/api/APLRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _APLRecord: -# APLRecord \ No newline at end of file +# APLRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +APL DNS record. diff --git a/doc/api/ARecord.md b/doc/api/ARecord.md index de130ac41..731248190 100644 --- a/doc/api/ARecord.md +++ b/doc/api/ARecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _ARecord: -# ARecord \ No newline at end of file +# ARecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A DNS record. diff --git a/doc/api/AccessTime.md b/doc/api/AccessTime.md index 57c4739ad..417fc0dd5 100644 --- a/doc/api/AccessTime.md +++ b/doc/api/AccessTime.md @@ -1,3 +1,9 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _AccessTime: -# AccessTime \ No newline at end of file +# AccessTime +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Access time parameter type. + +Accepts values conforming to generalizedTime as defined in RFC 4517 section 3.3.13 without time zone information. diff --git a/doc/api/Any.md b/doc/api/Any.md index c93d392ad..efe968905 100644 --- a/doc/api/Any.md +++ b/doc/api/Any.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Any: -# Any \ No newline at end of file +# Any +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A parameter capable of holding values of any type. For internal use only. diff --git a/doc/api/BinaryFile.md b/doc/api/BinaryFile.md index 8df897010..3e6c11baa 100644 --- a/doc/api/BinaryFile.md +++ b/doc/api/BinaryFile.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _BinaryFile: -# BinaryFile \ No newline at end of file +# BinaryFile +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Binary file parameter type. diff --git a/doc/api/Bool.md b/doc/api/Bool.md index 2fcdb1c58..6809b9e04 100644 --- a/doc/api/Bool.md +++ b/doc/api/Bool.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Bool: -# Bool \ No newline at end of file +# Bool +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A parameter for boolean values (stored in the ``bool`` type). diff --git a/doc/api/Bytes.md b/doc/api/Bytes.md index 7bd08a55c..7de5f8ace 100644 --- a/doc/api/Bytes.md +++ b/doc/api/Bytes.md @@ -1,3 +1,11 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Bytes: -# Bytes \ No newline at end of file +# Bytes +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A parameter for binary data (stored in the ``str`` type). +This class is named *Bytes* instead of *Str* so it's aligned with the +Python v3 ``(str, unicode) => (bytes, str)`` clean-up. +See: http://docs.python.org/3.0/whatsnew/3.0.html +Also see the `Str` parameter. diff --git a/doc/api/BytesEnum.md b/doc/api/BytesEnum.md index fed9cb39c..2fa7070bc 100644 --- a/doc/api/BytesEnum.md +++ b/doc/api/BytesEnum.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _BytesEnum: -# BytesEnum \ No newline at end of file +# BytesEnum +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Enumerable for binary data (stored in the ``str`` type). diff --git a/doc/api/CERTRecord.md b/doc/api/CERTRecord.md index 73dbbcd4b..d05b6df92 100644 --- a/doc/api/CERTRecord.md +++ b/doc/api/CERTRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _CERTRecord: -# CERTRecord \ No newline at end of file +# CERTRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +CERT DNS record. diff --git a/doc/api/CNAMERecord.md b/doc/api/CNAMERecord.md index a4300de08..5c26aaf70 100644 --- a/doc/api/CNAMERecord.md +++ b/doc/api/CNAMERecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _CNAMERecord: -# CNAMERecord \ No newline at end of file +# CNAMERecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +CNAME DNS record. diff --git a/doc/api/Certificate.md b/doc/api/Certificate.md index 825fbec33..7266b432f 100644 --- a/doc/api/Certificate.md +++ b/doc/api/Certificate.md @@ -1,3 +1,5 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Certificate: -# Certificate \ No newline at end of file +# Certificate +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) diff --git a/doc/api/CertificateSigningRequest.md b/doc/api/CertificateSigningRequest.md index 193c09f5f..4b33d2cab 100644 --- a/doc/api/CertificateSigningRequest.md +++ b/doc/api/CertificateSigningRequest.md @@ -1,3 +1,5 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _CertificateSigningRequest: -# CertificateSigningRequest \ No newline at end of file +# CertificateSigningRequest +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) diff --git a/doc/api/DHCIDRecord.md b/doc/api/DHCIDRecord.md index 0bda2460f..468f36d0e 100644 --- a/doc/api/DHCIDRecord.md +++ b/doc/api/DHCIDRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _DHCIDRecord: -# DHCIDRecord \ No newline at end of file +# DHCIDRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +DHCID DNS record. diff --git a/doc/api/DLVRecord.md b/doc/api/DLVRecord.md index 7620c2aca..0ceb1e41f 100644 --- a/doc/api/DLVRecord.md +++ b/doc/api/DLVRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _DLVRecord: -# DLVRecord \ No newline at end of file +# DLVRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +DLV DNS record. diff --git a/doc/api/DNAMERecord.md b/doc/api/DNAMERecord.md index 9f40b11ae..012980e8d 100644 --- a/doc/api/DNAMERecord.md +++ b/doc/api/DNAMERecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _DNAMERecord: -# DNAMERecord \ No newline at end of file +# DNAMERecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +DNAME DNS record. diff --git a/doc/api/DNOrURL.md b/doc/api/DNOrURL.md index 9e65d06f5..cd990211d 100644 --- a/doc/api/DNOrURL.md +++ b/doc/api/DNOrURL.md @@ -1,3 +1,9 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _DNOrURL: -# DNOrURL \ No newline at end of file +# DNOrURL +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +DN parameter that allows, and strips, a "ldap:///" prefix on input. + +Used for ``subtree`` to maintain backward compatibility. diff --git a/doc/api/DNParam.md b/doc/api/DNParam.md index 6da9c9aec..cad9b65bc 100644 --- a/doc/api/DNParam.md +++ b/doc/api/DNParam.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _DNParam: -# DNParam \ No newline at end of file +# DNParam +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +LDAP DN. diff --git a/doc/api/DNSNameParam.md b/doc/api/DNSNameParam.md index 0ec7988c7..ec1bb8227 100644 --- a/doc/api/DNSNameParam.md +++ b/doc/api/DNSNameParam.md @@ -1,3 +1,10 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _DNSNameParam: -# DNSNameParam \ No newline at end of file +# DNSNameParam +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Domain name parameter type. + +* `only_absolute`: a domain name has to be absolute (makes it absolute from unicode input) +* `only_relative`: a domain name has to be relative diff --git a/doc/api/DNSRecord.md b/doc/api/DNSRecord.md index 13cf1a912..355fd1ae0 100644 --- a/doc/api/DNSRecord.md +++ b/doc/api/DNSRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _DNSRecord: -# DNSRecord \ No newline at end of file +# DNSRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Base class for DNS records, subclass of `Str`. diff --git a/doc/api/DSRecord.md b/doc/api/DSRecord.md index 060aa7881..4126e21e6 100644 --- a/doc/api/DSRecord.md +++ b/doc/api/DSRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _DSRecord: -# DSRecord \ No newline at end of file +# DSRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +DS DNS record. diff --git a/doc/api/Data.md b/doc/api/Data.md index 68cbd7f69..0f0751d74 100644 --- a/doc/api/Data.md +++ b/doc/api/Data.md @@ -1,3 +1,11 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Data: -# Data \ No newline at end of file +# Data +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Base class for the `Bytes` and `Str` parameters. + +Previously `Str` was as subclass of `Bytes`. Now the common functionality +has been split into this base class so that ``isinstance(foo, Bytes)`` wont +be ``True`` when ``foo`` is actually an `Str` instance (which is confusing). diff --git a/doc/api/DateTime.md b/doc/api/DateTime.md index 97f315281..c477b0307 100644 --- a/doc/api/DateTime.md +++ b/doc/api/DateTime.md @@ -1,3 +1,19 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _DateTime: -# DateTime \ No newline at end of file +# DateTime +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +DateTime parameter type. + +Accepts LDAP Generalized time without in the following format: + '%Y%m%d%H%M%SZ' + +Accepts subset of values defined by ISO 8601: + '%Y-%m-%dT%H:%M:%SZ' + '%Y-%m-%dT%H:%MZ' + '%Y-%m-%dZ' + +Also accepts above formats using ' ' (space) as a separator instead of 'T'. + +Refer to the `man strftime` for the explanations for the %Y,%m,%d,%H.%M,%S. diff --git a/doc/api/Decimal.md b/doc/api/Decimal.md index cd0f035f5..df7740cdb 100644 --- a/doc/api/Decimal.md +++ b/doc/api/Decimal.md @@ -1,3 +1,12 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Decimal: -# Decimal \ No newline at end of file +# Decimal +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A parameter for floating-point values (stored in the ``Decimal`` type). + +Python Decimal type helps overcome problems tied to plain "float" type, +e.g. problem with representation or value comparison. In order to safely +transfer the value over RPC libraries, it is being converted to string +which is then converted back to Decimal number. diff --git a/doc/api/Dict.md b/doc/api/Dict.md index 7187604be..41aedb410 100644 --- a/doc/api/Dict.md +++ b/doc/api/Dict.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Dict: -# Dict \ No newline at end of file +# Dict +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A parameter for dictionary. diff --git a/doc/api/Enum.md b/doc/api/Enum.md index 6d6ffb089..081b1b89a 100644 --- a/doc/api/Enum.md +++ b/doc/api/Enum.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Enum: -# Enum \ No newline at end of file +# Enum +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Base class for parameters with enumerable values. diff --git a/doc/api/File.md b/doc/api/File.md index c00f3f673..0233bd525 100644 --- a/doc/api/File.md +++ b/doc/api/File.md @@ -1,3 +1,9 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _File: -# File \ No newline at end of file +# File +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Text file parameter type. + +Accepts file names and loads their content into the parameter value. diff --git a/doc/api/Flag.md b/doc/api/Flag.md index e64836809..b917c5a06 100644 --- a/doc/api/Flag.md +++ b/doc/api/Flag.md @@ -1,3 +1,37 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Flag: -# Flag \ No newline at end of file +# Flag +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A boolean parameter that always gets filled in with a default value. + +This `Bool` subclass forces ``autofill=True`` in `Flag.__init__()`. If no +default is provided, it also fills in a default value of ``False``. +Lastly, unlike the `Bool` class, the default must be either ``True`` or +``False`` and cannot be ``None``. + +For example: +``` +>>> flag = Flag('my_flag') +>>> (flag.autofill, flag.default) +(True, False) +``` + +To have a default value of ``True``, create your `Flag` intance with +``default=True``. For example: + +``` +>>> flag = Flag('my_flag', default=True) +>>> (flag.autofill, flag.default) +(True, True) +``` + +Also note that creating a `Flag` instance with ``autofill=False`` will have +no effect. For example: + +``` +>>> flag = Flag('my_flag', autofill=False) +>>> flag.autofill +True +``` diff --git a/doc/api/ForwardRecord.md b/doc/api/ForwardRecord.md index dd718b037..6fff207f4 100644 --- a/doc/api/ForwardRecord.md +++ b/doc/api/ForwardRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _ForwardRecord: -# ForwardRecord \ No newline at end of file +# ForwardRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Forward DNS record. diff --git a/doc/api/HINFORecord.md b/doc/api/HINFORecord.md index d3d518efe..b1292424a 100644 --- a/doc/api/HINFORecord.md +++ b/doc/api/HINFORecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _HINFORecord: -# HINFORecord \ No newline at end of file +# HINFORecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +HINFO DNS record. diff --git a/doc/api/HIPRecord.md b/doc/api/HIPRecord.md index 5eae940fe..42a82e0cc 100644 --- a/doc/api/HIPRecord.md +++ b/doc/api/HIPRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _HIPRecord: -# HIPRecord \ No newline at end of file +# HIPRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +HIP DNS record. diff --git a/doc/api/HostPassword.md b/doc/api/HostPassword.md index 3427cfe9d..4cb229909 100644 --- a/doc/api/HostPassword.md +++ b/doc/api/HostPassword.md @@ -1,3 +1,11 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _HostPassword: -# HostPassword \ No newline at end of file +# HostPassword +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A data type for host passwords to not log password values. + +The `Password` type cannot be used because it disallows +setting a password on the command-line which would break +backwards compatibility. diff --git a/doc/api/IA5Str.md b/doc/api/IA5Str.md index a0b02e7ca..c8c15f4a2 100644 --- a/doc/api/IA5Str.md +++ b/doc/api/IA5Str.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _IA5Str: -# IA5Str \ No newline at end of file +# IA5Str +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +An IA5String per RFC 4517. diff --git a/doc/api/IPSECKEYRecord.md b/doc/api/IPSECKEYRecord.md index 90361b6a8..b8e4bb4b5 100644 --- a/doc/api/IPSECKEYRecord.md +++ b/doc/api/IPSECKEYRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _IPSECKEYRecord: -# IPSECKEYRecord \ No newline at end of file +# IPSECKEYRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +IPSECKEY DNS record. diff --git a/doc/api/Int.md b/doc/api/Int.md index def4c7317..cbe4733aa 100644 --- a/doc/api/Int.md +++ b/doc/api/Int.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Int: -# Int \ No newline at end of file +# Int +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A parameter for integer values (stored in the ``int`` type). diff --git a/doc/api/IntEnum.md b/doc/api/IntEnum.md index f4a41588d..4294b75bd 100644 --- a/doc/api/IntEnum.md +++ b/doc/api/IntEnum.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _IntEnum: -# IntEnum \ No newline at end of file +# IntEnum +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Enumerable for integer data (stored in the ``int`` type). diff --git a/doc/api/KEYRecord.md b/doc/api/KEYRecord.md index 45a11c5a6..c96804271 100644 --- a/doc/api/KEYRecord.md +++ b/doc/api/KEYRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _KEYRecord: -# KEYRecord \ No newline at end of file +# KEYRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +KEY DNS record. diff --git a/doc/api/KXRecord.md b/doc/api/KXRecord.md index 637b9236b..cedb3f905 100644 --- a/doc/api/KXRecord.md +++ b/doc/api/KXRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _KXRecord: -# KXRecord \ No newline at end of file +# KXRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +KX DNS record. diff --git a/doc/api/LOCRecord.md b/doc/api/LOCRecord.md index aa4622788..d4ffa0f92 100644 --- a/doc/api/LOCRecord.md +++ b/doc/api/LOCRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _LOCRecord: -# LOCRecord \ No newline at end of file +# LOCRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +LOC DNS record. diff --git a/doc/api/MDRecord.md b/doc/api/MDRecord.md index 62e3b64db..f529e27d8 100644 --- a/doc/api/MDRecord.md +++ b/doc/api/MDRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _MDRecord: -# MDRecord \ No newline at end of file +# MDRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +MD DNS record. diff --git a/doc/api/MINFORecord.md b/doc/api/MINFORecord.md index f36b1f28b..ff4164c66 100644 --- a/doc/api/MINFORecord.md +++ b/doc/api/MINFORecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _MINFORecord: -# MINFORecord \ No newline at end of file +# MINFORecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +MINFO DNS record. diff --git a/doc/api/MXRecord.md b/doc/api/MXRecord.md index b582103f5..240d90ed8 100644 --- a/doc/api/MXRecord.md +++ b/doc/api/MXRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _MXRecord: -# MXRecord \ No newline at end of file +# MXRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +MX DNS record. diff --git a/doc/api/NAPTRRecord.md b/doc/api/NAPTRRecord.md index f2e1bf488..c549c5cdc 100644 --- a/doc/api/NAPTRRecord.md +++ b/doc/api/NAPTRRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _NAPTRRecord: -# NAPTRRecord \ No newline at end of file +# NAPTRRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +NAPTR DNS record. diff --git a/doc/api/NSECRecord.md b/doc/api/NSECRecord.md index 654875eba..ddfc061d9 100644 --- a/doc/api/NSECRecord.md +++ b/doc/api/NSECRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _NSECRecord: -# NSECRecord \ No newline at end of file +# NSECRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +NSEC DNS record. diff --git a/doc/api/NSRecord.md b/doc/api/NSRecord.md index f9b485005..586dba38f 100644 --- a/doc/api/NSRecord.md +++ b/doc/api/NSRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _NSRecord: -# NSRecord \ No newline at end of file +# NSRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +NS DNS record. diff --git a/doc/api/NXTRecord.md b/doc/api/NXTRecord.md index fd6605d0f..4ff5c3a44 100644 --- a/doc/api/NXTRecord.md +++ b/doc/api/NXTRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _NXTRecord: -# NXTRecord \ No newline at end of file +# NXTRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +NXT DNS record. diff --git a/doc/api/Number.md b/doc/api/Number.md index 3b5ba999b..1e63de5a9 100644 --- a/doc/api/Number.md +++ b/doc/api/Number.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Number: -# Number \ No newline at end of file +# Number +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Base class for the `Int` and `Decimal` parameters. diff --git a/doc/api/OTPTokenKey.md b/doc/api/OTPTokenKey.md index b1758f26d..93e452a33 100644 --- a/doc/api/OTPTokenKey.md +++ b/doc/api/OTPTokenKey.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _OTPTokenKey: -# OTPTokenKey \ No newline at end of file +# OTPTokenKey +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A binary password type specified in base32. diff --git a/doc/api/PTRRecord.md b/doc/api/PTRRecord.md index e45231502..5831422e3 100644 --- a/doc/api/PTRRecord.md +++ b/doc/api/PTRRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _PTRRecord: -# PTRRecord \ No newline at end of file +# PTRRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +PTR DNS record. diff --git a/doc/api/Password.md b/doc/api/Password.md index 662adc474..0cafd452f 100644 --- a/doc/api/Password.md +++ b/doc/api/Password.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Password: -# Password \ No newline at end of file +# Password +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A parameter for passwords (stored in the ``unicode`` type). diff --git a/doc/api/Principal.md b/doc/api/Principal.md index 429b6f200..d7b52a1cf 100644 --- a/doc/api/Principal.md +++ b/doc/api/Principal.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Principal: -# Principal \ No newline at end of file +# Principal +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Kerberos principal name. diff --git a/doc/api/RPRecord.md b/doc/api/RPRecord.md index d3a512520..27715b8d6 100644 --- a/doc/api/RPRecord.md +++ b/doc/api/RPRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _RPRecord: -# RPRecord \ No newline at end of file +# RPRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +RP DNS record. diff --git a/doc/api/RRSIGRecord.md b/doc/api/RRSIGRecord.md index 961ed6912..224e05f92 100644 --- a/doc/api/RRSIGRecord.md +++ b/doc/api/RRSIGRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _RRSIGRecord: -# RRSIGRecord \ No newline at end of file +# RRSIGRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +RRSIG DNS record. diff --git a/doc/api/SIGRecord.md b/doc/api/SIGRecord.md index b554c34be..b44ef9648 100644 --- a/doc/api/SIGRecord.md +++ b/doc/api/SIGRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _SIGRecord: -# SIGRecord \ No newline at end of file +# SIGRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +SIG DNS record. diff --git a/doc/api/SPFRecord.md b/doc/api/SPFRecord.md index 5dc66501d..9136431ed 100644 --- a/doc/api/SPFRecord.md +++ b/doc/api/SPFRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _SPFRecord: -# SPFRecord \ No newline at end of file +# SPFRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +SPF DNS record. diff --git a/doc/api/SRVRecord.md b/doc/api/SRVRecord.md index 9c969d50f..c52738426 100644 --- a/doc/api/SRVRecord.md +++ b/doc/api/SRVRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _SRVRecord: -# SRVRecord \ No newline at end of file +# SRVRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +SRV DNS record. diff --git a/doc/api/SSHFPRecord.md b/doc/api/SSHFPRecord.md index 3705f063c..aff3128bf 100644 --- a/doc/api/SSHFPRecord.md +++ b/doc/api/SSHFPRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _SSHFPRecord: -# SSHFPRecord \ No newline at end of file +# SSHFPRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +SSHFP DNS record. diff --git a/doc/api/SerialNumber.md b/doc/api/SerialNumber.md index e7ee4a0bb..b6040d6c1 100644 --- a/doc/api/SerialNumber.md +++ b/doc/api/SerialNumber.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _SerialNumber: -# SerialNumber \ No newline at end of file +# SerialNumber +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Certificate serial number parameter type. diff --git a/doc/api/Str.md b/doc/api/Str.md index 917f96d9f..439fe3d32 100644 --- a/doc/api/Str.md +++ b/doc/api/Str.md @@ -1,3 +1,14 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _Str: -# Str \ No newline at end of file +# Str +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +A parameter for Unicode text (stored in the ``unicode`` type). + +This class is named `Str` instead of `Unicode` so it's aligned with the +Python v3 ``(str, unicode) => (bytes, str)`` clean-up. + +See: http://docs.python.org/3.0/whatsnew/3.0.html + +Also see the `Bytes` parameter. diff --git a/doc/api/StrEnum.md b/doc/api/StrEnum.md index 7a2651485..1f7d2fa81 100644 --- a/doc/api/StrEnum.md +++ b/doc/api/StrEnum.md @@ -1,3 +1,19 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _StrEnum: -# StrEnum \ No newline at end of file +# StrEnum +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Enumerable for Unicode text (stored in the ``unicode`` type). + +For example: + +``` +>>> enum = StrEnum('my_enum', values=(u'One', u'Two', u'Three')) +>>> enum.validate(u'Two', 'cli') is None +True +>>> enum.validate(u'Four', 'cli') +Traceback (most recent call last): + ... +ValidationError: invalid 'my_enum': must be one of 'One', 'Two', 'Three' +``` diff --git a/doc/api/TLSARecord.md b/doc/api/TLSARecord.md index 6ac192875..41e835e79 100644 --- a/doc/api/TLSARecord.md +++ b/doc/api/TLSARecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _TLSARecord: -# TLSARecord \ No newline at end of file +# TLSARecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +TLSA DNS record. diff --git a/doc/api/TXTRecord.md b/doc/api/TXTRecord.md index bc577d862..35ea51029 100644 --- a/doc/api/TXTRecord.md +++ b/doc/api/TXTRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _TXTRecord: -# TXTRecord \ No newline at end of file +# TXTRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +TXT DNS record. diff --git a/doc/api/URIRecord.md b/doc/api/URIRecord.md index c8a9372b8..03245d31d 100644 --- a/doc/api/URIRecord.md +++ b/doc/api/URIRecord.md @@ -1,3 +1,7 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _URIRecord: -# URIRecord \ No newline at end of file +# URIRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +URI DNS record. diff --git a/doc/api/UnsupportedDNSRecord.md b/doc/api/UnsupportedDNSRecord.md index 6b45cec62..bac3a06b0 100644 --- a/doc/api/UnsupportedDNSRecord.md +++ b/doc/api/UnsupportedDNSRecord.md @@ -1,3 +1,8 @@ +[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) .. _UnsupportedDNSRecord: -# UnsupportedDNSRecord \ No newline at end of file +# UnsupportedDNSRecord +[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end) + +Records which are not supported by IPA, but we allow to show them if LDAP +contains these records. diff --git a/doc/api/access_control_guide.md b/doc/api/access_control_guide.md new file mode 100644 index 000000000..2fda3bb2b --- /dev/null +++ b/doc/api/access_control_guide.md @@ -0,0 +1,66 @@ +# Access control examples + +IPA provides a way to manage delegation of rights. Permissions allows to define +certain management actions, which can then be grouped in privileges. These +privileges can then be added to roles, which can be assigned to users and +groups. + +- [Access control examples](#access-control-examples) + - [Managing permissions](#managing-permissions) + - [Managing privileges](#managing-privileges) + - [Managing roles](#managing-roles) + - [Assigning roles to users and groups](#assigning-roles-to-users-and-groups) + +## Managing permissions + +Add a permission for creating users. + +```python +api.Command.permission_add("Create users", ipapermright='add', type='user') +``` + +Add a permission for managing group membership. + +```python +api.Command.permission_add("Manage group membership", ipapermright='write', type='group', attrs="member") +``` + +## Managing privileges + +Add a privilege for user creation process (creating user, adding it to groups, +manage user certificates). + +```python +api.Command.permission_add("Create users", ipapermright='add', type='user') +api.Command.permission_add("Manage group membership", ipapermright='write', type='group', attrs="member") +api.Command.permission_add("Manage User certificates", ipapermright='write', type='user', attrs='usercertificate') + +api.Command.privilege_add("User creation") +api.Command.privilege_add_permission("User creation", permission="Create users") +api.Command.privilege_add_permission("User creation", permission="Manage group membership") +api.Command.privilege_add_permission("User creation", permission="Manage User certificates") +``` + +## Managing roles + +Add a role with the privilege created earlier. + +```python +api.Command.role_add("usermanager", description="Users manager") +api.Command.role_add_privilege("usermanager", privilege="User creation") +``` + +## Assigning roles to users and groups + +Assign the role `usermanager` to user `bob`. + +```python +api.Command.role_add_member("usermanager", user="bob") +``` + +Users, groups, hosts and hostgroups may be members of a role. Assign the +`usermanager` role to `managers` group. + +```python +api.Command.role_add_member("usermanager", group="managers") +``` diff --git a/doc/api/api_cli_differences.md b/doc/api/api_cli_differences.md new file mode 100644 index 000000000..cd1b511dc --- /dev/null +++ b/doc/api/api_cli_differences.md @@ -0,0 +1,47 @@ +# Differences between API and CLI usage + +While the functionality between API and CLI is mostly the same, there are some +difference in their usage that should be taken into account. + +- [Differences between API and CLI usage](#differences-between-api-and-cli-usage) + - [Command naming](#command-naming) + - [Parameter naming](#parameter-naming) + - [Date format](#date-format) + - [CLI-specific tools](#cli-specific-tools) + +## Command naming + +Commands in the CLI are constructed by specifying a topic and an action, with a +hyphen between them: `user-add`, `group-mod`, `host-del`. When accessing through +the API, the topic and the action are divided by an underscore instead: +`user_add`, `group_mod`, `host_del`. All available commands can be found below +`api.Command` after the API is initialized. + +## Parameter naming + +When managing plugins through the CLI, their parameters have different names +than the API, where names are the same as the LDAP attributes. For example, +`user-add` takes the `first` parameter in the CLI. However, this is named +`givenname` when calling `user_add` through the Python API. + +## Date format + +When passing dates through the CLI, multiple date string formats are available: + +* %Y%m%d%H%M%SZ +* %Y-%m-%dT%H:%M:%SZ +* %Y-%m-%dT%H:%MZ +* %Y-%m-%dZ +* %Y-%m-%d %H:%M:%SZ +* %Y-%m-%d %H:%MZ + +When using the API, apart from these formats, the Python built-in `datetime` class +can be used as well. + +## CLI-specific tools + +FreeIPA provides multiple tools that are mainly useful for CLI usage: + +* `console`: starts an interactive Python console with an IPA API object already initialized. +* `help`: shows help about topics and commands, including examples for the CLI. +* `show-mappings`: shows the mapping between CLI parameter names and LDAP attributes. diff --git a/doc/api/basic_usage.md b/doc/api/basic_usage.md index 33442fc2e..ace8c850b 100644 --- a/doc/api/basic_usage.md +++ b/doc/api/basic_usage.md @@ -6,6 +6,8 @@ - [Running commands](#running-commands) - [Passing arguments and options](#passing-arguments-and-options) - [Retrieving output](#retrieving-output) + - [Displaying information about commands and parameters](#displaying-information-about-commands-and-parameters) + - [API Contexts](#api-contexts) - [Batch operations](#batch-operations) ## Introduction @@ -18,7 +20,12 @@ that can be accessed through Python, allowing users to interact with FreeIPA programatically and develop custom tools to respond to specific needs not covered by the main interfaces. For users looking to perform stateless operations or manage deployments with statically defined properties, -[ansible-freeipa](https://github.com/freeipa/ansible-freeipa) is recommended instead. +[ansible-freeipa](https://github.com/freeipa/ansible-freeipa) is recommended +instead. + +While FreeIPA API provides a JSON-RPC interface, it is recommended to access the +API through Python instead, since it automates important parts such as the +metadata retrieval from the server, which allows to list all available commands. ## Initializing API access @@ -92,6 +99,10 @@ kw = { api.Command.user_show(*args, **kw) ``` +The full list of available arguments and options for each command can be found +in the API Reference. Alternatively, it is possible to see the mapping of CLI +option to API attribute through `ipa show-mappings`. + ## Retrieving output Command output is returned as a Python dictionary. Example shown is the output @@ -165,6 +176,86 @@ The output contains four sections: * `messages`: Different diagnostic information provided by FreeIPA after the operation. * `summary`: A summary of the operation. +## Displaying information about commands and parameters + +All available information about commands and their parameters is provided in the +API Reference. Additionally, the API provides tools to display this information. +It can be retrieved using the `command_show` and `param_show` commands. + +```python +api.Command.command_show("user_add") +``` + +```python +{ + "result": { + "name": "user_add", + "version": "1", + "full_name": "user_add/1", + "doc": "Add a new user.", + "topic_topic": "user/1", + "obj_class": "user/1", + "attr_name": "add", + }, + "value": "user_add", + "messages": [ + { + "type": "warning", + "name": "VersionMissing", + "message": "API Version number was not sent, forward compatibility not guaranteed. Assuming server's API version, 2.251", + "code": 13001, + "data": {"server_version": "2.251"}, + } + ], + "summary": None, +} +``` + +For listing all available parameters for a certain command, the `param_find` +command can be used. We can additionally show information of a certain +parameter from a command using `param_show`. + + +```python +api.Command.param_show("user_add", name="givenname") +``` + +```python +{ + "result": { + "name": "givenname", + "type": "str", + "positional": False, + "cli_name": "first", + "label": "First name", + }, + "value": "givenname", + "messages": [ + { + "type": "warning", + "name": "VersionMissing", + "message": "API Version number was not sent, forward compatibility not guaranteed. Assuming server's API version, 2.251", + "code": 13001, + "data": {"server_version": "2.251"}, + } + ], + "summary": None, +} +``` + +## API Contexts + +As explained earlier, a context can be specified before initializing the API. +The purpose of the context is to define the set of methods that can be +performed. FreeIPA defines by default four major contexts: + +* `server`: plugins validate any arguments and options passed and then execute + the requested action. +* `client`: plugins validate any arguments and options passed and then forward + the request to the FreeIPA server to execute. +* `installer`: plugins specific to the installation process are loaded. +* `updates`: plugins specific the update process are loaded. + ## Batch operations Batch operations are useful for executing multiple commands at once, as it 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/dnszone_add.md b/doc/api/dnszone_add.md index 2b23dc9ec..925ecc543 100644 --- a/doc/api/dnszone_add.md +++ b/doc/api/dnszone_add.md @@ -10,7 +10,6 @@ Create new DNS zone (SOA record). ### Options * idnssoarname : :ref:`DNSNameParam` **(Required)** * Default: hostmaster -* idnssoaserial : :ref:`Int` **(Required)** * idnssoarefresh : :ref:`Int` **(Required)** * Default: 3600 * idnssoaretry : :ref:`Int` **(Required)** @@ -34,6 +33,7 @@ Create new DNS zone (SOA record). * idnsforwardpolicy : :ref:`StrEnum` * Values: ('only', 'first', 'none') * idnssoamname : :ref:`DNSNameParam` +* idnssoaserial : :ref:`Int` * dnsttl : :ref:`Int` * dnsdefaultttl : :ref:`Int` * dnsclass : :ref:`StrEnum` diff --git a/doc/api/group_management.md b/doc/api/group_management.md new file mode 100644 index 000000000..38fe54ff0 --- /dev/null +++ b/doc/api/group_management.md @@ -0,0 +1,98 @@ +# Group management examples + +This guide provides various examples on how to perform common tasks related to +group management in a IPA environment making use of the provided API. + +- [Group management examples](#group-management-examples) + - [Creating a group](#creating-a-group) + - [Adding members to a group](#adding-members-to-a-group) + - [Adding group managers](#adding-group-managers) + - [Finding a group](#finding-a-group) + - [Showing group information](#showing-group-information) + - [Modifying a group](#modifying-a-group) + - [Removing members from a group](#removing-members-from-a-group) + - [Removing group managers](#removing-group-managers) + - [Removing a group](#removing-a-group) + + +## Creating a group + +Create a group for developers, with an specific Group ID number. + +```python +api.Command.group_add("developers", gidnumber=500, description="Developers") +``` + +## Adding members to a group + +Add the admin user to the `developers` group. + +```python +api.Command.group_add_member("developers", user="admin") +``` + +Apart from users, groups can also have services and groups as members: + +```python +api.Command.group_add_member("developers", service="HTTP/server.ipa.test") +``` + +```python +api.Command.group_add_member("developers", group="admins") +``` + +## Adding group managers + +Add `bob` as the group manager for `developers` group. + +```python +api.Command.group_add_member_manager("developers", user="bob") +``` + +## Finding a group + +Find all groups managed by `bob`. + +```python +api.Command.group_find(membermanager_user="bob") +``` + +## Showing group information + +Show information about the `developers` group, excluding the members list. + +```python +api.Command.group_show("developers", no_members=True) +``` + +## Modifying a group + +Convert a non-POSIX group to POSIX: + +```python +api.Command.group_mod("testgroup", posix=True) +``` + +## Removing members from a group + +Remove the admin user to the `developers` group. + +```python +api.Command.group_remove_member("developers", user="admin") +``` + +## Removing group managers + +Remove `bob` as the group manager from `developers` group. + +```python +api.Command.group_remove_member_manager("developers", user="bob") +``` + +## Removing a group + +Remove the `developers` group. + +```python +api.Command.group_del("developers") +``` \ No newline at end of file diff --git a/doc/api/guides.rst b/doc/api/guides.rst index 0902a228b..75f99a49e 100644 --- a/doc/api/guides.rst +++ b/doc/api/guides.rst @@ -4,3 +4,10 @@ IPA API Guides :maxdepth: 1 basic_usage.md + jsonrpc_usage.md + api_cli_differences.md + user_management.md + group_management.md + access_control_guide.md + hbac_guide.md + sudorule_management.md \ No newline at end of file diff --git a/doc/api/hbac_guide.md b/doc/api/hbac_guide.md new file mode 100644 index 000000000..6d25ec536 --- /dev/null +++ b/doc/api/hbac_guide.md @@ -0,0 +1,89 @@ +# Host-based Access Control (HBAC) Examples + +HBAC rules allow to define policies to control how hosts and services are +accessed based on the user, user's group or host that is attempting to access. + +- [Host-based Access Control (HBAC) Examples](#host-based-access-control-hbac-examples) + - [Creating an HBAC rule](#creating-an-hbac-rule) + - [Managing members of a HBAC rule](#managing-members-of-a-hbac-rule) + - [Managing targets of a HBAC rule](#managing-targets-of-a-hbac-rule) + - [Testing a HBAC rule](#testing-a-hbac-rule) + - [Enabling and disabling HBAC rules](#enabling-and-disabling-hbac-rules) + + +## Creating an HBAC rule + +Create a base rule that will handle SSH service access. + +```python +api.Command.hbacrule_add("sshd_rule") +``` + +## Managing members of a HBAC rule + +Add user `john` to the previously created HBAC rule. + +```python +api.Command.hbacrule_add_user("sshd_rule", user="john") +``` + +Additionally, you can set access based on groups: + +```python +api.Command.hbacrule_add_user("sshd_rule", group="developers") +``` + +Remove user `john` from the HBAC rule. + +```python +api.Command.hbacrule_remove_user("sshd_rule", user="john") +``` + +## Managing targets of a HBAC rule + +After we have created the rule and set the members, targets must be registered +before being added to the rule. + +Adding a new HBAC service. + +```python +api.Command.hbacsvc_add("chronyd") +``` + +Services must be attached to rules. Attach the sshd service to the previously +created rule. This service is registered in IPA by default, so there's no need +to add it with `hbacsvc_add` before. + +```python +api.Command.hbacrule_add_service("sshd_rule", hbacsvc="sshd") +``` + +Hosts can be added as targets as well. Allow the SSH service to be accessed only in +the hosts part of the `workstations` hostgroup. + +```python +api.Command.hbacrule_add_host("sshd_rule", hostgroup="workstations") +``` + +## Testing a HBAC rule + +Simulate the use of the rule we previously created, against the host +`workstation.ipa.test`, the service `sshd` coming from the user `john`. + +```python +api.Command.hbactest(user="john", targethost="workstation.ipa.test", service="sshd", rules="sshd_rule") +``` + +## Enabling and disabling HBAC rules + +Enable a HBAC rule. + +```python +api.Command.hbacrule_enable("sshd_rule") +``` + +Disable a HBAC rule. + +```python +api.Command.hbacrule_disable("sshd_rule") +``` \ No newline at end of file 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/idp_add.md b/doc/api/idp_add.md index feb8d0737..f398b7d00 100644 --- a/doc/api/idp_add.md +++ b/doc/api/idp_add.md @@ -1,6 +1,6 @@ [//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) # idp_add -Add a new Identity Provider server. +Add a new Identity Provider reference. ### Arguments |Name|Type|Required diff --git a/doc/api/idp_del.md b/doc/api/idp_del.md index 881782bbf..c1ddc38d8 100644 --- a/doc/api/idp_del.md +++ b/doc/api/idp_del.md @@ -1,6 +1,6 @@ [//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) # idp_del -Delete an Identity Provider server. +Delete an Identity Provider reference. ### Arguments |Name|Type|Required diff --git a/doc/api/idp_find.md b/doc/api/idp_find.md index 606f2c0a4..7c5fb20dc 100644 --- a/doc/api/idp_find.md +++ b/doc/api/idp_find.md @@ -1,6 +1,6 @@ [//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) # idp_find -Search for Identity Provider servers. +Search for Identity Provider references. ### Arguments |Name|Type|Required diff --git a/doc/api/idp_mod.md b/doc/api/idp_mod.md index 778147081..18ab42d83 100644 --- a/doc/api/idp_mod.md +++ b/doc/api/idp_mod.md @@ -1,6 +1,6 @@ [//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) # idp_mod -Modify an Identity Provider server. +Modify an Identity Provider reference. ### Arguments |Name|Type|Required diff --git a/doc/api/idp_show.md b/doc/api/idp_show.md index ad95c7935..1687d4f87 100644 --- a/doc/api/idp_show.md +++ b/doc/api/idp_show.md @@ -1,6 +1,6 @@ [//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.) # idp_show -Display information about an Identity Provider server. +Display information about an Identity Provider reference. ### Arguments |Name|Type|Required diff --git a/doc/api/jsonrpc_usage.md b/doc/api/jsonrpc_usage.md new file mode 100644 index 000000000..51856864b --- /dev/null +++ b/doc/api/jsonrpc_usage.md @@ -0,0 +1,135 @@ +# JSON-RPC API usage + +Apart from Python, the FreeIPA API is also available through HTTPS exchanging +requests in JSON-RPC format. + +## Basic usage + +Before sending requests to the FreeIPA server, we need to properly authenticate. + +It is possible to authenticate both through Kerberos and password. + +### Kerberos authentication + +To authenticate via Kerberos, it is needed to have actual credentials in the +credentials cache first. After this, we need to send a login request to the +FreeIPA endpoint, `https://$IPAHOSTNAME/ipa/session/login_kerberos`. + +```bash +$ export KRB5CCNAME=FILE:/path/to/ccache +$ export COOKIEJAR=/path/to/my.cookie +$ export IPAHOSTNAME=ipa-master.example.com +$ kinit -k -t /path/to/service.keytab service/ipa-client.example.com +$ curl -v \ + -H referer:https://$IPAHOSTNAME/ipa \ + -c $COOKIEJAR -b $COOKIEJAR \ + --cacert /etc/ipa/ca.crt \ + --negotiate -u : \ + -X POST \ + https://$IPAHOSTNAME/ipa/session/login_kerberos +``` + +If authentication was successful, `$COOKIEJAR` will contain all session cookies +returned from the server. We will need to pass this with every request we send +to the server. + +### Password authentication + +For password authentication, we just need to post it over HTTPS. + +```bash +$ export COOKIEJAR=/path/to/my.cookie +$ export IPAHOSTNAME=ipa-master.example.com +$ s_username=admin s_password=mYSecReT1P2 curl -v \ + -H referer:https://$IPAHOSTNAME/ipa \ + -H "Content-Type:application/x-www-form-urlencoded" \ + -H "Accept:text/plain"\ + -c $COOKIEJAR -b $COOKIEJAR \ + --cacert /etc/ipa/ca.crt \ + --data "user=$s_username&password=$s_password" \ + -X POST \ + https://$IPAHOSTNAME/ipa/session/login_password +``` + +Same as kerberos authentication, we will need to pass the sessions cookies with +every request. + +### Request and Response format + +A JSON-RPC request consists of three properties: + +* `method`: A string containing the name of the name that will be called. +* `params`: the array of parameters for the command. +* `id`: the request id, it can be of any type, the response will match it. + +The response received from the server consists of four properties: + +* `result`: The returned Object from the command. If the command failed, this + will be null. +* `principal`: The Kerberos principal under which identity the command was performed. +* `error`: An Error object containing information about the command if it + failed. If it succeeded, this will be null. +* `ìd`: An ID matching the request this response is replying to. + +### Sending a request + +Requests should be sent to the API endpoint +`https://$IPAHOSTNAME/ipa/session/json` over HTTPS. The content type must be set +to `application/json` and session cookies obtained when authentication must be +passed with the request. + +An example request for the `user_find` command would be: + +```bash +curl -v \ + -H referer:https://$IPAHOSTNAME/ipa \ + -H "Content-Type:application/json" \ + -H "Accept:applicaton/json"\ + -c $COOKIEJAR -b $COOKIEJAR \ + --cacert /etc/ipa/ca.crt \ + -d '{"method":"user_find","params":[[""],{}],"id":0}' \ + -X POST \ + https://$IPAHOSTNAME/ipa/session/json +``` + +An easy way to understand how IPA requests are built is via the CLI, by passing +the `-vv` option to an IPA command. + +```bash +$ ipa -vv user-find +ipa: INFO: Request: { + "id": 0, + "method": "user_find/1", + "params": [ + [], + { + "version": "2.251" + } + ] +} + +[...] +``` + +## Converting JSON-RPC requests to Python + +FreeIPA provides methods to convert JSON-RPC requests to Python format. This is +included in the `freeipa-python-ipaserver` package in Fedora. + +```python +from ipaserver.rpcserver import jsonserver + +json_request = '{"method":"user_find","params":[[""],{}],"id":0}' +j = jsonserver(api) # `api` is the initialized IPA API object + +(name, args, opts, response_id) = j.unmarshal(json_request) + +result = api.Command[name](*args, **opts) +``` + +## Reporting issues + +To report issues related to API usage, they should be reproducible using the API +through Python, in order to discard errors related to misconstruction of +JSON-RPC requests. These requests can be converted to Python using the steps +mentioned earlier. 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/doc/api/sudorule_management.md b/doc/api/sudorule_management.md new file mode 100644 index 000000000..2d7312c6d --- /dev/null +++ b/doc/api/sudorule_management.md @@ -0,0 +1,105 @@ +# Sudo rules management examples + +Sudo rules provide the system administrator a way to delegate privileges to +certain users in order to perform commands either as root or as another user. + +- [Sudo rules management examples](#sudo-rules-management-examples) + - [Creating a sudo rule](#creating-a-sudo-rule) + - [Managing sudo commands](#managing-sudo-commands) + - [Adding users and hosts to sudo rules](#adding-users-and-hosts-to-sudo-rules) + - [Setting "run as" for sudo rules](#setting-run-as-for-sudo-rules) + - [Managing sudo options](#managing-sudo-options) + - [Enabling and disabling sudo rule](#enabling-and-disabling-sudo-rule) + + +## Creating a sudo rule + +Create a sudo rule that will hold time change commands. + +```python +api.Command.sudorule_add("timechange") +``` + +## Managing sudo commands + +Sudo rules must be filled with sudo commands. Create one for `date`. + +```python +api.Command.sudocmd_add("/usr/bin/date") +``` + +Then, attach the sudo command to the sudo rule. + +```python +api.Command.sudorule_add_allow_command("timechange", sudocmd="/usr/bin/date") +``` + +Alternatively, groups of sudo commands can be created and attached to the rule +in the same manner. + +```python +api.Command.sudocmd_add("/usr/bin/date") +api.Command.sudocmd_add("/usr/bin/timedatectl") +api.Command.sudocmd_add("/usr/sbin/hwclock") +api.Command.sudocmdgroup_add("timecmds") +api.Command.sudocmdgroup_add_member("timecmds", sudocmd="/usr/bin/date") +api.Command.sudocmdgroup_add_member("timecmds", sudocmd="/usr/bin/timedatectl") +api.Command.sudocmdgroup_add_member("timecmds", sudocmd="/usr/sbin/hwclock") +api.Command.sudorule_add_allow_command("timechange", sudocmdgroup="timecmds") +``` + +Commands can be denied as well. Deny the `rm` command to be run as sudo. + +```python +api.Command.sudocmd_add("/usr/bin/rm") +api.Command.sudorule_add_deny_command("timechange", sudocmd="/usr/bin/rm") +``` + +## Adding users and hosts to sudo rules + +Add the user `bob` to the previously created rule. + +```python +api.Command.sudorule_add_user("timechange", user="bob") +``` + +Restrict the rule to only be available for the `client.ipa.test` host. + +```python +api.Command.sudorule_add_host("timechange", host="client.ipa.test") +``` + +## Setting "run as" for sudo rules + +While sudo rules are run as root by default, a different "run as" can be +configured, both for user and group rights. + +```python +api.Command.sudorule_add_runasuser("timechange", user="alice") +``` + +```python +api.Command.sudorule_add_runasgroup("timechange", group="sysadmins") +``` + +## Managing sudo options + +Set a sudo option for the `timechange` sudo rule. + +```python +api.Command.sudorule_add_option("timechange", ipasudoopt="logfile='/var/log/timechange_log'") +``` + +## Enabling and disabling sudo rule + +Enable a sudo sule. + +```python +api.Command.sudorule_enable("timechange") +``` + +Disable a sudo sule. + +```python +api.Command.sudorule_disable("timechange") +``` \ No newline at end of file diff --git a/doc/api/user_management.md b/doc/api/user_management.md new file mode 100644 index 000000000..bb9071cb4 --- /dev/null +++ b/doc/api/user_management.md @@ -0,0 +1,127 @@ +# User Management Examples + +This guide provides various examples for performing common tasks related to +user management using IPA's API. + +- [User Management Examples](#user-management-examples) + - [Adding a user](#adding-a-user) + - [Finding a user](#finding-a-user) + - [Showing user information](#showing-user-information) + - [Modifying a user](#modifying-a-user) + - [Deleting a user](#deleting-a-user) + - [Adding a certificate for a user](#adding-a-certificate-for-a-user) + - [Removing a certificate from a user](#removing-a-certificate-from-a-user) + - [Disabling a user](#disabling-a-user) + - [Enabling a user](#enabling-a-user) + +## Adding a user + +Create a user for John Smith, with `jsmith` as username and OTP as the supported +user authentication. + +```python +api.Command.user_add("jsmith", givenname="John", sn="Smith", ipauserauthtype="otp") +``` + +## Finding a user + +Find all users in the `admins` group that match `bob` as search criteria. + +```python +api.Command.user_find(criteria="bob", in_group="admins") +``` + +## Showing user information + +Show all available information about the admin user. + +```python +api.Command.user_show("admin", all=True) +``` + +## Modifying a user + +Modify a user's email address. + +```python +api.Command.user_mod("bob", mail="bob@example.org") +``` + +## Deleting a user + +Delete a user. + +```python +api.Command.user_del("bob") +``` + +The `preserve` option can be used to save this user's entry on deletion. +This way, the user can undeleted by running the `user_undel` command. + + +## Adding a certificate for a user + +Add a certificate for a user. This certificate must be Base-64 encoded. + +```python +args = ["bob"] +kw = { + "usercertificate": """ + MIICYzCCAcygAwIBAgIBADANBgkqhkiG9w0BAQUFADAuMQswCQYDVQQGEwJVUzEMMAoGA1UEC + hMDSUJNMREwDwYDVQQLEwhMb2NhbCBDQTAeFw05OTEyMjIwNTAwMDBaFw0wMDEyMjMwNDU5NT + laMC4xCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNJQk0xETAPBgNVBAsTCExvY2FsIENBMIGfMA0 + GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD2bZEo7xGaX2/0GHkrNFZvlxBou9v1Jmt/PDiTMPve + 8r9FeJAQ0QdvFST/0JPQYD20rH0bimdDLgNdNynmyRoS2S/IInfpmf69iyc2G0TPyRvmHIiOZ + bdCd+YBHQi1adkj17NDcWj6S14tVurFX73zx0sNoMS79q3tuXKrDsxeuwIDAQABo4GQMIGNME + sGCVUdDwGG+EIBDQQ+EzxHZW5lcmF0ZWQgYnkgdGhlIFNlY3VyZVdheSBTZWN1cml0eSBTZXJ + 2ZXIgZm9yIE9TLzM5MCAoUkFDRikwDgYDVR0PAQH/BAQDAgAGMA8GA1UdEwEB/wQFMAMBAf8w + HQYDVR0OBBYEFJ3+ocRyCTJw067dLSwr/nalx6YMMA0GCSqGSIb3DQEBBQUAA4GBAMaQzt+za + j1GU77yzlr8iiMBXgdQrwsZZWJo5exnAucJAEYQZmOfyLiMD6oYq+ZnfvM0n8G/Y79q8nhwvu + xpYOnRSAXFp6xSkrIOeZtJMY1h00LKp/JX3Ng1svZ2agE126JHsQ0bhzN5TKsYfbwfTwfjdWA + Gy6Vf1nYi/rO+ryMO + """ +} + +api.Command.user_add_cert(*args, **kw) +``` + +## Removing a certificate from a user +Remove a certificate from a user. This certificate must be Base-64 encoded. + +```python +args = ["bob"] +kw = { + "usercertificate": """ + MIICYzCCAcygAwIBAgIBADANBgkqhkiG9w0BAQUFADAuMQswCQYDVQQGEwJVUzEMMAoGA1UEC + hMDSUJNMREwDwYDVQQLEwhMb2NhbCBDQTAeFw05OTEyMjIwNTAwMDBaFw0wMDEyMjMwNDU5NT + laMC4xCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNJQk0xETAPBgNVBAsTCExvY2FsIENBMIGfMA0 + GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD2bZEo7xGaX2/0GHkrNFZvlxBou9v1Jmt/PDiTMPve + 8r9FeJAQ0QdvFST/0JPQYD20rH0bimdDLgNdNynmyRoS2S/IInfpmf69iyc2G0TPyRvmHIiOZ + bdCd+YBHQi1adkj17NDcWj6S14tVurFX73zx0sNoMS79q3tuXKrDsxeuwIDAQABo4GQMIGNME + sGCVUdDwGG+EIBDQQ+EzxHZW5lcmF0ZWQgYnkgdGhlIFNlY3VyZVdheSBTZWN1cml0eSBTZXJ + 2ZXIgZm9yIE9TLzM5MCAoUkFDRikwDgYDVR0PAQH/BAQDAgAGMA8GA1UdEwEB/wQFMAMBAf8w + HQYDVR0OBBYEFJ3+ocRyCTJw067dLSwr/nalx6YMMA0GCSqGSIb3DQEBBQUAA4GBAMaQzt+za + j1GU77yzlr8iiMBXgdQrwsZZWJo5exnAucJAEYQZmOfyLiMD6oYq+ZnfvM0n8G/Y79q8nhwvu + xpYOnRSAXFp6xSkrIOeZtJMY1h00LKp/JX3Ng1svZ2agE126JHsQ0bhzN5TKsYfbwfTwfjdWA + Gy6Vf1nYi/rO+ryMO + """ +} + +api.Command.user_remove_cert(*args, **kw) +``` + + +## Disabling a user + +Disable a user account. + +```python +api.Command.user_disable("bob") +``` + +## Enabling a user +Enable a previously disabled user. + +```python +api.Command.user_enable("bob") +``` diff --git a/doc/api/vault_archive_internal.md b/doc/api/vault_archive_internal.md index 169f5477a..d09eccf4b 100644 --- a/doc/api/vault_archive_internal.md +++ b/doc/api/vault_archive_internal.md @@ -20,7 +20,7 @@ Archive data into a vault. * Default: False * username : :ref:`Str` * wrapping_algo : :ref:`StrEnum` - * Default: aes-128-cbc + * Default: des-ede3-cbc * Values: ('aes-128-cbc', 'des-ede3-cbc') * version : :ref:`Str` diff --git a/doc/api/vault_retrieve_internal.md b/doc/api/vault_retrieve_internal.md index edc35ca37..f8982b29b 100644 --- a/doc/api/vault_retrieve_internal.md +++ b/doc/api/vault_retrieve_internal.md @@ -18,7 +18,7 @@ Retrieve data from a vault. * Default: False * username : :ref:`Str` * wrapping_algo : :ref:`StrEnum` - * Default: aes-128-cbc + * Default: des-ede3-cbc * Values: ('aes-128-cbc', 'des-ede3-cbc') * version : :ref:`Str` diff --git a/doc/conf.py b/doc/conf.py index ab6806a3d..db5e5678d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -68,7 +68,7 @@ exclude_patterns = [ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'default' +html_theme = 'sphinx_book_theme' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/doc/designs/expired_certificate_pruning.md b/doc/designs/expired_certificate_pruning.md new file mode 100644 index 000000000..8947f67f8 --- /dev/null +++ b/doc/designs/expired_certificate_pruning.md @@ -0,0 +1,315 @@ +# Expired Certificate Pruning + +## Overview + +https://pagure.io/dogtagpki/issue/1750 + +When using short-lived certs and regular issuance, the expired certs can build up in the PKI database and cause issues with replication, performance and overall database size. + +PKI has provided a new feature in 11.3.0, pruning, which is a job that can be executed on a schedule or manually to remove expired certificates and requests. + +Random Serial Numbers v3 (RSNv3) is mandatory to enable pruning. + +Both pruning and RSNv3 require PKI 11.3.0 or higher. + +## Use Cases + +ACME certificates in particular are generally short-lived and expired certificates can build up quickly in a dynamic environment. An example is a CI system that requests one or more certificates per run. These will build up infinitely without a way to remove the expired certificates. + +Another case is simply a very long-lived installation. Over time as hosts come and go certificates build up. + +## How to Use + +https://github.com/dogtagpki/pki/wiki/Configuring-CA-Database-Pruning provides a thorough description of the capabilities of the pruning job. + +The default configuration is to remove expired certificates and incomplete requests after 30 days. + +Pruning is disabled by default. + +Configuration is a four-step process: + +1. Configure the expiration thresholds +2. Enable the job +3. Schedule the job +4. Restart the CA + +The job will be scheduled to use the PKI built-in cron-like timer. It is configured nearly identically to `crontab(5)`. On execution it will remove certificates and requests that fall outside the configured thresholds. LDAP search/time limits can be used to control how many are removed at once. + +In addition to the automated schedule it is possible to manually run the pruning job. + +The tool will not restart the CA. It will be left as an exercise for the user, who will be notified as needed. + +### Where to use + +The pruning configuration is not replicated. It should not be necessary to enable this task on all IPA servers, or more than one. + +Running the task simultaneously on multiple servers has a few downsides: + +* Additional stress on the LDAP server searching for expired certificates and requests +* Unnecessary replication load deleting the same entries on multiple servers + +While enabling this on a single server represents a single-point-of-failure there should be no catastrophic consequences other than expired certificates and requests potentially building up. This can be cleared by enabling pruning on a different server. Depending on the size of the backlog this could take a couple of executions to catch up. + +## Design + +There are several operations, most of which act locally and one of which uses the PKI REST API. + +1. Updating the job configuration (enable, thresholds, etc). This will be done by running the `pki-server ca-config-set` command which modifies CS.cfg directly per the PKI wiki. A restart is required. + +2. Retrieving the current configuration for display. The `pki-server ca-config-find` command returns the entire configuration so the results will need to be filtered. + +3. Managing the job. This can be done using the REST API, https://github.com/dogtagpki/pki/wiki/PKI-REST-API . Operations include enabling the job and triggering it to run now. + +Theoretically for operations 1 and 2 we could use existing code to manually update `CS.cfg` and retrieve values. For future-proofing purposes calling `pki-server` is probably the better long-term option given the limited number of times this will be used. Configuration is likely to be one and done. + +There are four values each that can be managed for pruning certificates and requests: + +* expired cert/incomplete request time +* time unit +* LDAP search size limit +* LDAP search time limit (in seconds) + +The first two configure when an expired certificate or incomplete request will be deleted. The unit can be one of: minute, hour, day, year. By default it is 30 days. + +The LDAP limits control how many entries are returned and how long the search can take. By default it is 1000 entries and unlimited time (0 == unlimited, unit is seconds). + +### Configuration settings + +The configuration values will be set by running `pki-server ca-config-set` This will ensure best forward compatibility. The options are case-sensitive and not validated by the CA until restart. The values are not applied until the CA is restarted. + +### Configuring job execution time + +The CA provides a cron-like interface for scheduling jobs. To configure the job to run at midnight on the first of every month the PKI equivalent command-line is: + +``` +pki-server ca-config-set jobsScheduler.job.pruning.cron `"0 0 1 * *"` +``` + +This will be the default when pruning is enabled. A separate configuration option will be available for fine-tuning execution time. + +The format is defined https://access.redhat.com/documentation/en-us/red_hat_certificate_system/9/html/administration_guide/setting_up_specific_jobs#Frequency_Settings_for_Automated_Jobs + +### REST Authentication and Authorization + +The REST API for pruning is documented at https://github.com/dogtagpki/pki/wiki/PKI-Start-Job-REST-API + +A PKI job can define an owner that can manage the job over the REST API. We will automatically define the owner as `ipara` when pruning is enabled. + +Manually running the job will be done using the PKI REST API. Authentication to this API for our purposes is done at the `/ca/rest/account/login` endpoint. A cookie is returned which will be used in any subsequent calls. The IPA RA agent certificate will be used for authentication and authorization. + +### Commands + +This will be implemented in the ipa-acme-manage command. While strictly not completely ACME-related this is the primary driver for pruning. + +A new verb will be added, pruning, to be used for enabling and configuring pruning. + +### Enabling pruning + +`# ipa-acme-manage pruning --enable` + +Enabling the job will call + +`# pki-server ca-config-set jobsScheduler.job.pruning.enabled true` + +This will also set jobsScheduler.job.pruning.cron to `"0 0 1 * *"` if it has not already been set. + +Additionally it will set the job owner to `ipara` with: + +`# pki-server ca-config-set jobsScheduler.job.pruning.owner ipara` + +Disabling the job will call + +`# pki-server ca-config-unset jobsScheduler.job.pruning.enabled` + +### Cron settings + +To modify the cron settings: + +`# ipa-acme-manage pruning --cron="Minute Hour Day_of_month Month_of_year Day_of_week"` + +Validation of the value will be: +* each of the options is an integer +* minute is within 0-59 +* hour is within 0-23 +* day of month is within 0-31 +* month of year is within 1-12 +* day of week is within 0-6 + +No validation of setting February 31st will be done. That will be left to PKI. Buyer beware. + +### Disabling pruning + +`# ipa-acme-manage pruning --disable` + +This will remove the configuration option for `jobsScheduler.job.pruning.cron` just to be sure it no longer runs. + +### Configuration + +#### Pruning certificates + +`# ipa-acme-manage pruning --certretention=VALUE --certretentionunit=UNIT` + +will be the equivalent of: + +`# pki-server ca-config-set jobsScheduler.job.pruning.certRetentionTime 30` + +`# pki-server ca-config-set jobsScheduler.job.pruning.certRetentionUnit day` + +The unit will always be required when modifying the time. + +`# ipa-acme-manage pruning --certsearchsizelimit=VALUE --certsearchtimelimit=VALUE` + +will be the equivalent of: + +`# pki-server ca-config-set jobsScheduler.job.pruning.certSearchSizeLimit 1000` + +`# pki-server ca-config-set jobsScheduler.job.pruning.certSearchTimeLimit 0` + +A value of 0 for searchtimelimit is unlimited. + +#### Pruning requests + +`# ipa-acme-manage pruning --requestretention=VALUE --requestretentionunit=UNIT` + +will be the equivalent of: + +`# pki-server ca-config-set jobsScheduler.job.pruning.requestRetentionTime 30` + +`# pki-server ca-config-set jobsScheduler.job.pruning.requestRetentionUnit day` + +The unit will always be required when modifying the time. + +`# ipa-acme-manage pruning --requestsearchsizelimit=VALUE --requestsearchtimelimit=VALUE` + + +will be the equivalent of: + +`# pki-server ca-config-set jobsScheduler.job.pruning.requestSearchSizeLimit 1000` + +`# pki-server ca-config-set jobsScheduler.job.pruning.requestSearchTimeLimit 0` + +A value of 0 for searchtimelimit is unlimited. + +These options set the client-side limits. The server imposes its own search size and look through limits. This can be tuned for the uid=pkidbuser,ou=people,o=ipaca user via https://access.redhat.com/documentation/en-us/red_hat_directory_server/11/html/administration_guide/ldapsearch-ex-complex-range + +### Showing the Configuration + +To display the current configuration run `pki-server ca-config-find` and filter the results to only those that contain `jobsScheduler.job.pruning`. + +Default values are not included so will need to be set by `ipa-acme-manage` before displaying. + +Output may look something like: + +```console +# ipa-acme-manage pruning --config-show +Enabled: TRUE +Certificate retention time: 30 days +Certificate search size limit: 1000 +Certificate search time limit: 0 +Request retention time: 30 days +Request search size limit: 1000 +Request search time limit: 0 +Cron: 0 0 1 * * +``` + +### Manual pruning + +`# ipa-acme-manage pruning --run` + +This is useful for testing the configuration or if the user wants to use the system cron or systemd timers for handling automation. + +## Implementation + +For online REST operations (login, run job) we will use the `ipaserver/plugins/dogtag.py::RestClient` class to manage the requests. This will take care of the authentication cookie, etc. +The class uses dogtag.https_request() will can take PEM cert and key files as arguments. These will be used for authentication. + +For the non-REST operations (configuration, cron settings) the tool will fork out to pki-server ca-config-set. + +### UI + +This will only be configurable on the command-line. + +### CLI + +Overview of the CLI commands. Example: + + +| Command | Options | +| --- | ----- | +| ipa-acme-manage pruning | --enable | +| ipa-acme-manage pruning | --disable | +| ipa-acme-manage pruning | --cron=`"0 0 1 * *"` | +| ipa-acme-manage pruning | --certretention=30 --certretentionunit=day | +| ipa-acme-manage pruning | --certsearchsizelimit=1000 --certsearchtimelimit=0 | +| ipa-acme-manage pruning | --requestretention=30 --requestretentionunit=day | +| ipa-acme-manage pruning | --requestsearchsizelimit=1000 --requestsearchtimelimit=0 | +| ipa-acme-manage pruning | --config-show | +| ipa-acme-manage pruning | --run | + +ipa-acme-manage can only be run as root. + +### Configuration + +Configuration changes will be made to /etc/pki/pki-tomcat/ca/CS.cfg + +## Upgrade + +No expected impact on upgrades. + +## Test plan + +Testing will consist of: + +* Use the default configuration +* enabling the pruning job +* issue one or more certificates +* move time forward +1 days after expiration +* manually running the job +* validating that the certificates are removed + +For size/time limit testing, create a large number of certificates/requests and set the search limit to a low value, then ensure that the number of deleted certs is equal to the search limit. Testing timelimit in this way may be less predictable as it may require a massive number of entries to find to timeout on a non-busy server. + +## Troubleshooting and debugging + +The PKI debug log will contain job information. + +``` +2022-12-08 21:14:25 [https-jsse-nio-8443-exec-8] INFO: JobService: Starting job pruning +2022-12-08 21:14:25 [https-jsse-nio-8443-exec-8] INFO: JobService: - principal: null +2022-12-08 21:14:51 [https-jsse-nio-8443-exec-10] INFO: JobService: Starting job pruning 2022-12-08 21:14:51 [https-jsse-nio-8443-exec-10] INFO: JobService: - principal: null +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: Authenticating certificate chain: +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - CN=IPA RA,O=EXAMPLE.TEST +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - CN=Certificate Authority,O=EXAMPLE.TEST +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: LDAPSession: Retrieving cn=19072098145751813471503860299601579276,ou=certificateRepository, ou=ca,o=ipaca +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: CertUserDBAuthentication: UID ipara authenticated. +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: User ipara authenticated +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: UGSubsystem: Retrieving user uid=ipara,ou=People,o=ipaca +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: User DN: uid=ipara,ou=people,o=ipaca +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: Roles: +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - Certificate Manager Agents +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - Registration Manager Agents +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - Security Domain Administrators +2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - Enterprise ACME Administrators +2022-12-08 21:15:24 [https-jsse-nio-8443-exec-12] INFO: JobService: Starting job pruning +2022-12-08 21:15:24 [https-jsse-nio-8443-exec-12] INFO: JobService: - principal: GenericPrincipal[ipara(Certificate Manager Agents,Enterprise ACME Administrators,Registration Manager Agents,Security Domain Administrators,)] +2022-12-08 21:15:24 [https-jsse-nio-8443-exec-12] INFO: JobsScheduler: Starting job pruning +2022-12-08 21:15:24 [pruning] INFO: PruningJob: Running pruning job at Thu Dec 08 21:15:24 UTC 2022 +2022-12-08 21:15:24 [pruning] INFO: PruningJob: Pruning certs expired before Tue Nov 08 21:15:24 UTC 2022 +2022-12-08 21:15:24 [pruning] INFO: PruningJob: - filter: (&(x509Cert.notAfter<=1667942124527)(!(x509Cert.notAfter=1667942124527))) +2022-12-08 21:15:24 [pruning] INFO: LDAPSession: Searching ou=certificateRepository, ou=ca,o=ipaca for (&(notAfter<=20221108211524Z)(!(notAfter=20221108211524Z))) +2022-12-08 21:15:24 [pruning] INFO: PruningJob: Pruning incomplete requests last modified before Tue Nov 08 21:15:24 UTC 2022 +2022-12-08 21:15:24 [pruning] INFO: PruningJob: - filter: (&(!(requestState=complete))(requestModifyTime<=1667942124527)(!(requestModifyTime=1667942124527))) +2022-12-08 21:15:24 [pruning] INFO: LDAPSession: Searching ou=ca, ou=requests,o=ipaca for (&(!(requestState=complete))(dateOfModify<=20221108211524Z)(!(dateOfModify=20221108211524Z))) +``` + +### Manual execution fails with Forbidden + +If manually running pruning fails with a message like: + +```console +# ipa-acme-manage pruning --run +CalledProcessError(Command ['pki', '-C', '/tmp/tmppyyd3hfq/pwdfile.txt', '-d', '/tmp/tmppyyd3hfq', '-n', 'CN=IPA RA,O=EXAMPLE.TEST', 'ca-job-start', 'pruning'] returned non-zero exit status 255: 'PKIException: Forbidden\n') +The ipa-acme-manage command failed. +``` + +You probably forgot to restart the CA after enabling pruning. diff --git a/doc/designs/index.rst b/doc/designs/index.rst index 570e526fe..39c16228c 100644 --- a/doc/designs/index.rst +++ b/doc/designs/index.rst @@ -14,6 +14,7 @@ FreeIPA design documentation hsm.md krb-ticket-policy.md extdom-plugin-protocol.md + expired_certificate_pruning.md expiring-password-notification.md ldap_grace_period.md ldap_pam_passthrough.md @@ -28,3 +29,5 @@ FreeIPA design documentation external-idp/idp-api.md random-serial-numbers.md client-install-pkinit.md + prci_checker.md + rbcd.md diff --git a/doc/designs/prci_checker.md b/doc/designs/prci_checker.md new file mode 100644 index 000000000..08dc62d4c --- /dev/null +++ b/doc/designs/prci_checker.md @@ -0,0 +1,241 @@ +# FreeIPA Pull Request CI (PR-CI) checker tool + +[PR-CI checker](https://github.com/freeipa/freeipa/blob/master/ipatests/prci_definitions/prci_checker.py) is a developer tool (not shipped along FreeIPA) which checks that FreeIPA PR-CI definition files follow a pre-defined convention such as having the correct naming pattern, requirements and arguments. + +The prci_definitions directory contains multiple test definition files: +- For gating: Only a subset of tests, the ones that are executed for each pull request. +- For temp commit: This is a template allowing to run a single test, usually to demonstrate that changes done to this test are working. +- For nightly tests. There are some general purpose nightlies (for instance on the master branch, we have a nightly run for fedora latest, another one for fedora previous, another one with selinux etc...) or more specialized ones, to test integration with the latest code of specific components (389ds, sssd or pki). The general purpose nightlies execute all the tests, whereas the specific nightlies execute only a subset of tests, the ones more relevant for the component. + + +The main purpose of the tool is to check the format of newly added or modified jobs in the PR-CI definitions. + +## Basic usage + +**To check all the definitions**: + +``` bash +$ python3 ipatests/prci_definitions/prci_checker.py +BEGINNING PRCI JOB DEFINITIONS CHECKS +[File] nightly_previous [Jobs] 149 +[File] nightly_latest_pki [Jobs] 75 +[File] gating [Jobs] 24 +[File] nightly_rawhide [Jobs] 149 +[File] nightly_latest_389ds [Jobs] 45 +[File] nightly_latest [Jobs] 149 +[File] nightly_latest_selinux [Jobs] 149 +[File] nightly_latest_testing [Jobs] 149 +[File] nightly_latest_sssd [Jobs] 16 +[File] nightly_latest_testing_selinux [Jobs] 149 +CHECKS FINISHED SUCCESSFULLY +``` + +**alternatively:** + +``` bash +$ make yamllint +[...] +Check PRCI definitions +----------- +/usr/bin/python ./ipatests/prci_definitions/prci_checker.py -d ./ipatests/prci_definitions -s ./ipatests/prci_definitions/prci_jobs_spec.yaml; +BEGINNING PRCI JOB DEFINITIONS CHECKS +[File] nightly_previous [Jobs] 149 +[...] +[File] nightly_latest_testing_selinux [Jobs] 149 +CHECKS FINISHED SUCCESSFULLY +----------- +``` + +**To check a specific file:** + +``` bash +$ python3 ipatests/prci_definitions/prci_checker.py -f ipatests/prci_definitions/gating.yaml +BEGINNING PRCI JOB DEFINITIONS CHECKS +[File] gating [Jobs] 24 +CHECKS FINISHED SUCCESSFULLY +``` + +## Tool specification file + +Most part of the checks carried out by the script are described in the specification file [prci_jobs_spec.yaml](https://github.com/freeipa/freeipa/blob/master/ipatests/prci_definitions/prci_jobs_spec.yaml). + +The yaml file contains supported classes, definitions that should have the same number of jobs, and format specification for each file. + +**File content can vary according to the different needs in every branch**. [Example](https://github.com/freeipa/freeipa/blob/ipa-4-10/ipatests/prci_definitions/prci_jobs_spec.yaml) (taken from master branch): + +``` yaml +# Specification file for PRCI definitions used by prci_checker script + +# List of supported test-run classes for non-build jobs +classes: + - "RunPytest" + - "RunPytest2" + - "RunPytest3" + - "RunWebuiTests" + - "RunADTests" + +# (Optional) Definition files that should contain the same number of jobs +fixed_n_jobs: + - nightly_latest + - nightly_latest_selinux + - nightly_latest_testing + - nightly_latest_testing_selinux + - nightly_previous + - nightly_rawhide + +# Info specific to prci definition files +# 'job_prefix' field is mandatory +# 'update_packages', 'selinux_enforcing', 'enable_testing_repo' and +# 'copr_defined' are supported but optional boolean fields (if not specified, +# false value is assumed). +# New definitions specifications may be added anytime +prci_job_spec: + gating: + job_prefix: 'fedora-latest/' + nightly_latest: + job_prefix: 'fedora-latest/' + nightly_latest_389ds: + job_prefix: '389ds-fedora/' + update_packages: True + copr_defined: True + nightly_latest_pki: + job_prefix: 'pki-fedora/' + update_packages: True + copr_defined: True + nightly_latest_selinux: + job_prefix: 'fedora-latest/' + selinux_enforcing: True + nightly_latest_testing: + job_prefix: 'testing-fedora/' + update_packages: True + enable_testing_repo: True + nightly_latest_testing_selinux: + job_prefix: 'testing-fedora/' + selinux_enforcing: True + update_packages: True + enable_testing_repo: True + nightly_previous: + job_prefix: 'fedora-previous/' + nightly_rawhide: + job_prefix: 'fedora-rawhide/' + update_packages: True + nightly_latest_sssd: + job_prefix: 'sssd-fedora/' + update_packages: True + copr_defined: True +``` + +Let's see how the file specific checks work. Currently the supported fields are: + +Required: +- `job_prefix` + +Optional: +- `update_packages` +- `selinux_enforcing` +- `enable_testing_repo` +- `copr_defined` + +Let's take an example with `nightly_latest_389ds` definition: +``` yaml +nightly_latest_389ds: + job_prefix: '389ds-fedora/' + update_packages: True + copr_defined: True +``` + +The specifications shown above mean that every job defined in nightly_latest_389ds must: +- Have a name starting with `389ds-fedora/` +- Define `update_packages: True` and `copr_defined: True`
+ + > **Reason**: Since the file is testing with a copr repo for 389ds, the test must call dnf update in order to update the package to the version provided in the copr repo. Otherwise they + would run with a wrong version of 389ds and would not properly test the integration. Likewise, if they define update_packages but do not set any copr repo, the wrong packages would be used. + +On top of the above requirements, job class should also be one of the supported (listed in prci_jobs_spec.yaml). + +For instance, the following would be a well formed job: +``` yaml +389ds-fedora/simple_replication: + requires: [389ds-fedora/build] + priority: 50 + job: + class: RunPytest + args: + build_url: '{389ds-fedora/build_url}' + update_packages: True + copr: '@389ds/389-ds-base-nightly' + test_suite: test_integration/test_simple_replication.py + template: *ci-master-latest + timeout: 3600 + topology: *master_1repl +``` + + +## Error cases examples + +After adding new jobs to the definition or editing the content, it is common that a developer has made some mistakes following the convention. This checker will help us correcting these errors. Examples: + +### Wrong or unsupported class: + +``` bash +$ python3 ipatests/prci_definitions/prci_checker.py -f ipatests/prci_definitions/gating.yaml +BEGINNING PRCI JOB DEFINITIONS CHECKS +[File] gating [Jobs] 24 +ERROR: In job 'fedora-latest/test_installation_TestInstallMaster': + 'class' field should be defined with one of the supported: ['RunPytest', 'RunPytest2', 'RunPytest3', 'RunWebuiTests', 'RunADTests'] +CHECKS FINISHED WITH ERRORS +``` + +### Wrong job prefix in gating: + +``` bash +$ python3 ipatests/prci_definitions/prci_checker.py -f ipatests/prci_definitions/gating.yaml +BEGINNING PRCI JOB DEFINITIONS CHECKS +[File] gating [Jobs] 24 +ERROR: In job 'fedora-latdest/test_installation_TestInstallMaster': + Job name should start with prefix 'fedora-latest/' +CHECKS FINISHED WITH ERRORS +``` + +### Wrong or missing parameter values. +E.g. +1. Missing `selinux_enforcing: True` in selinux job definition: + +``` bash +$ python3 ipatests/prci_definitions/prci_checker.py -f ipatests/prci_definitions/nightly_latest_selinux.yaml +BEGINNING PRCI JOB DEFINITIONS CHECKS +[File] nightly_latest_selinux [Jobs] 149 +ERROR: In job 'fedora-latest/simple_replication': + Job field "selinux_enforcing" should be defined as: "selinux_enforcing: True" +CHECKS FINISHED WITH ERRORS +``` + +2. Field `topology` is not defined with one of the pre-defined templates: + +``` bash +$ python prci_checker.py -f gating.yaml +BEGINNING PRCI JOB DEFINITIONS CHECKS +[File] gating [Jobs] 24 +ERROR: In job 'fedora-latest/test_external_ca_TestSelfExternalSelf': + 'topology' field should be defined with one of the pre-defined topologies +CHECKS FINISHED WITH ERRORS +``` + +### Uneven number of jobs between definition files defined by spec file: + +``` bash +$ python3 ipatests/prci_definitions/prci_checker.py +BEGINNING PRCI JOB DEFINITIONS CHECKS +[File] nightly_latest_pki [Jobs] 75 +[File] nightly_latest [Jobs] 148 +[File] nightly_latest_testing [Jobs] 149 +[File] nightly_rawhide [Jobs] 149 +[File] gating [Jobs] 24 +[File] nightly_latest_selinux [Jobs] 149 +[File] nightly_latest_testing_selinux [Jobs] 149 +[File] nightly_latest_sssd [Jobs] 16 +[File] nightly_latest_389ds [Jobs] 45 +[File] nightly_previous [Jobs] 149 +ERROR: Following PRCI definitions should have the same number of jobs: ['nightly_latest', 'nightly_latest_testing', 'nightly_rawhide', 'nightly_latest_selinux', 'nightly_latest_testing_selinux', 'nightly_previous'] +CHECKS FINISHED WITH ERRORS +``` diff --git a/doc/designs/rbcd.md b/doc/designs/rbcd.md new file mode 100644 index 000000000..c3665ed8f --- /dev/null +++ b/doc/designs/rbcd.md @@ -0,0 +1,502 @@ +# Constrained delegation for Kerberos services + +## Overview + +The purpose of this document is to describe an integration of two constrained +delegation mechanisms FreeIPA provides for Kerberos services: + +- general constrained delegation, available since FreeIPA 3.0.0; +- resource-based constrained delegation, introduced with this design document. + +Both constrained delegation mechanisms apply when Kerberos services implement +S4U2Proxy extensions as described in +[MS-SFU](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/3bff5864-8135-400e-bdd9-33b552051d94) +specification. MIT Kerberos project has its own page that describes +[Services for User](http://k5wiki.kerberos.org/wiki/Projects/Services4User) integration. +FreeIPA work relies on the MIT Kerberos facilities to support S4U extensions, +including S4U2Proxy. + +A general constrained delegation mechanism described here for the sake of +completeness. The description is based on the original design document published +originally at [FreeIPA wiki page](https://www.freeipa.org/page/V4/Service_Constraint_Delegation). + +A general overview of a constrained delegation from Microsoft point of view can +be found in [this document](https://learn.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview). + +## Introduction + +Services for User extensions were introduced as a part of Kerberos +implementation in Microsoft's Active Directory. They aim to achieve two +specific goals: + +- allow Kerberos services to accept requests authenticated via a different + protocol. A Kerberos service can ask the Kerberos KDC to issue a ticket to + itself on behalf of a user, thus performing a protocol transition. The + resulting service ticket is issued to the service itself, hence S4U2Self + extension name. + +- allow a Kerberos service to request a service ticket to a different + Kerberos service on behalf of the original user, hence S4U2Proxy extension + name. The original service ticket must be forwardable. The resulting ticket + can be presented in the communication to that different Kerberos service and + will show both the original user principal and a Kerberos service operating on + its behalf. + +The S4U2Proxy feature eliminates the need for the user to delegate their ticket +granting ticket (TGT). FreeIPA uses the S4U2Proxy feature to allow the web +server framework to obtain an LDAP service ticket on the user's behalf. +Similarly, it is also used by the FreeIPA's trust to Active Directory feature +to allow the web server framework to obtain an SMB service ticket on the user's +behalf when configuring Samba and a trust to Active Directory through Samba. + +Kerberos KDC has control over the issuance of service tickets for both S4U2Self +and S4U2Proxy extensions. The usage of S4U2Proxy is called "constrained +delegation"; the two mechanisms that represent constrained delegation usage +have different rules associated with them. + +The access control for general constrained delegation is controlled by several +LDAP entries, rules and targets, contained in `cn=s4u2proxy,cn=etc,$SUFFIX`. + +Rule LDAP entry defines two elements: + +- Kerberos principals to be impersonated (defaults to every principal), + +- Kerberos services that can impersonate them. + +Target LDAP entry defines the list of Kerberos services to which the +impersonator Kerberos services can delegate credentials. + +These rules are controlled by the administrators of FreeIPA and cannot be +controlled by the services themselves. + +The access control for the resource-based constrained delegation rules is +placed within the LDAP entries of the target Kerberos services. Kerberos +service which supports resource-based constrained delegation will only be able +to request a service ticket to a Kerberos service that explicitly allows this +service to ask for a constrained delegation for itself. The rules are +controlled by the services' administrators (by default, the host service +controls services associated with the host). This reduces an administrative +overhead and delegates decision-making to the application administrators. + +## Use cases + +The table below summarizes three types of the Kerberos delegation approaches. + +A 'forest' concept in the table is an Active Directory term. FreeIPA does not +have a mechanism to place multiple AD-like domains into the same forest. All +systems which deployed to the same FreeIPA deployment are part of the same +FreeIPA domain and the same FreeIPA forest. In terms of Active Directory, +FreeIPA forest represents a single Active Directory domain, the root domain of +the forest. In Kerberos terms all these domains represent separate Kerberos +realms, within or across multiple forests. + +Impersonator account in the table corresponds to the application which is +using the delegated credential. In case of a constrained delegation, it is an +application performing S4U2Proxy request. + +Resource-based constrained delegation is only supported when FreeIPA is +compiled against MIT Kerberos 1.19 or later. + +| | TGT forwarding, unconstrained (by policy) | General constrained delegation | Resource-based constrained delegation | +|---|---|---|---| +|Delegation attributes set on and managed by admin of | Impersonator account (to anyone) | Impersonator account (to a list of resources) | Resource account (to a list of impersonators)| +|Delegation within a domain, client from the local forest | yes | yes | yes | +|Delegation within a domain, client from another forest | yes [1] | yes | yes | +|Delegation across a domain trust within the same forest, client from the local forest | yes | no | yes | +|Delegation across a domain trust within the same forest, client from another forest | yes [1] | no | yes | +|Delegation across forest trust, client from the forest of the impersonator | yes | no | yes | +|Delegation across forest trust, client from the forest of the resource | yes [1] | no | no [2] | + +- [1] With Windows updates in 2019, tgt-forwarding when the client and + impersonator are in different forests no longer works unless explicitly + allowed. Microsoft has [issued a guidance](https://support.microsoft.com/en-us/help/4490425/updates-to-tgt-delegation-across-incoming-trusts-in-windows-server) + that details the behavior. Additionally, there is a Microsoft Word document + describing [a KDC behavior](https://aka.ms/kcdpaper). + +- [2] Refer to the KDC paper from above for the description of "round-trip + authentication across trusts". + +### General constrained delegation + +General constrained delegation is often utilized in a multi-service environment +where a frontend service acts on behalf of a user against backend services. + +For example, the server side implementation of IPA API framework uses the +delegation of a ticket presented to the web service to act on behalf of this +user when talking to LDAP service. + +### Use cases for resource-based constrained delegation + +Typical use case is to allow users from the trusted Active Directory forest to +access their network shares while logging into FreeIPA client systems. NFS +server would be enrolled either into Active Directory or the FreeIPA +deployment, FreeIPA client system would be enrolled into FreeIPA deployment. +On FreeIPA client, a user's home directory would be configured to automount NFS +share for the user and use GSSAPI authentication with the help of GSSProxy. +GSSProxy can be configured to use both S4U2Self and S4U2Proxy. This use case is +described in detail in [GSSProxy documentation](https://github.com/gssapi/gssproxy/blob/main/docs/NFS.md#user-impersonation-via-constrained-delegation). + +When NFS server is located in the same Kerberos realm as the FreeIPA client +system, this use case can be implemented with general constrained delegation. + +When the target service (NFS server) and the proxy service (NFS client) are in +different realms, MS-SFU specification prevents issuance of a service ticket +using S4U2Proxy extension unless there is a resource-based constrained +delegation rule defined for the target service, as outlined in the [MS-SFU 3.2.5.2.3](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/dd1b47f9-580c-4c4e-8f34-4485b9728331). + +As a result, in order to allow delegation of user credentials across the forest +boundary, resource-based constrained delegation must be supported both by the +impersonating (proxy) service and by the KDC of the user forest. + +## Design + +MS-SFU specification defines that for full support of all S4U functionality an +account database needs to support four elements of information for each +principal, as outlined in [MS-SFU 3.2.1](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/0b4d13c4-d459-4598-8f08-1584ca1e24c9). + +FreeIPA account database is not compatible with Active Directory on LDAP level, +thus implementation is slightly different. + +### Unconstrained delegation + +IPA API provides a way to record unconstrained delegation permission in both +host and service command families. The following commands have option +`--ok-as-delegate=BOOL`: + +- `ipa host-add` and `ipa service-add` +- `ipa host-mod` and `ipa service-mod` + +### S4U2Self design + +Kerberos service is allowed to request a service ticket to itself on behalf of +any user. However, to make it usable for S4U2Proxy (constrained delegation), +the service ticket must be forwardable. In such case the Kerberos service would +be able to impersonate user and requires an explicit administrative permission. + +IPA API provides a way to record this permission in both host and service +command families. The following commands have option +`--ok-to-auth-as-delegate=BOOL`: + +- `ipa host-add` and `ipa service-add` +- `ipa host-mod` and `ipa service-mod` + +This flag is equivalent to MS-SFU's `TrustedToAuthenticationForDelegation` +boolean setting. + +### General constrained delegation design + +General constrained delegation uses two objects: a rule and a target. +All entries are stored in the same LDAP container and the only real +distinguishing feature between a rule and a target is the objectClass +`ipaKrb5DelegationACL`: + +- a rule will have these objectClasses: `top`, `groupOfPrincipals`, + `ipaKrb5DelegationACL`. + +- a target will have these objectClasses: `top`, `groupOfPrincipals`. + +Kerberos KDC database driver (KDB) uses a special filter to exclude +`ipaKrb5DelegationACL` when searching for the target. + +Both a rule and a target specify affected principals with `memberPrincipal` +attribute. + +This combination of rules and targets allows FreeIPA to implement an equivalent +of MS-SFU's `ServicesAllowedToSendForwardedTicketsTo` information. + +Management of the general constrained delegation rules and targets is done with +`ipa servicedelegation` commands. + +|Command |Description | +|--------------------------------------|------------------------------------------------------------| +|servicedelegationrule-add |Create a new service delegation rule. | +|servicedelegationrule-add-member |Add member to a named service delegation rule. | +|servicedelegationrule-add-target |Add target to a named service delegation rule. | +|servicedelegationrule-del |Delete service delegation. | +|servicedelegationrule-find |Search for service delegations rule. | +|servicedelegationrule-remove-member |Remove member from a named service delegation rule. | +|servicedelegationrule-remove-target |Remove target from a named service delegation rule. | +|servicedelegationrule-show |Display information about a named service delegation rule. | +|servicedelegationtarget-add |Create a new service delegation target. | +|servicedelegationtarget-add-member |Add member to a named service delegation target. | +|servicedelegationtarget-del |Delete service delegation target. | +|servicedelegationtarget-find |Search for service delegation target. | +|servicedelegationtarget-remove-member |Remove member from a named service delegation target. | +|servicedelegationtarget-show |Display information about a named service delegation target.| + +### Resource-based constrained delegation design + +Resource-based constrained delegation stores information in the target service +LDAP entry. This information is represented with `memberPrincipal` attribute +and is allowed with objectClass `resourceDelegation`. If a Kerberos principal +is mentioned in the `memberPrincipal` attribute of the LDAP entry and +objectClass `resourceDelegation` is present in the same entry, KDB driver will +use information from the `memberPrincipal` attribute to check whether a service +asking for S4U2Proxy extension is allowed to send a forwarded user ticket to +this service. + +This approach allows implementing MS-SFU's `ServicesAllowedToReceiveForwardedTicketsFrom` +information. + +Management of the resource-based constrained delegation is integrated into `ipa +host` and `ipa service` commands. + +|Command |Description | +|--------------------------------|------------------------------------------------------------| +|service-add-delegation |Add new resource delegation to a service | +|service-allow-add-delegation |Allow users, groups, hosts or host groups to handle a resource delegation of this service.| +|service-disallow-add-delegation |Disallow users, groups, hosts or host groups to handle a resource delegation of this service.| +|service-remove-delegation |Remove resource delegation from a service| +|host-add-delegation |Add new resource delegation to a host| +|host-allow-add-delegation |Allow users, groups, hosts or host groups to handle a resource delegation of this host.| +|host-disallow-add-delegation |Disallow users, groups, hosts or host groups to handle a resource delegation of this host.| +|host-remove-delegation |Remove resource delegation from a host| + +The `*-allow-add-delegation` and `*-disallow-add-delegation` commands aim to +provide a way to extend list of actors allowed defining delegation access +control. By default, only host and service owners (the host and service +themselves, as well as those objects defined by `managedBy` attribute) allowed +to control the delegation. Additional users, groups, hosts or host groups can +be allowed to set the delegation ACL. The purpose of these commands is to allow +a flexible management without giving a control over the whole host or service +entry. + +### Implementation + +#### IPA API commands + +In both general constrained delegation and resource-based constrained +delegation rules, targets, and delegation permission details are expressed with +`memberPrincipal` attribute. Since IPA's standard `LDAPAddMember` and +`LDAPRemoveMember` classes operate on DNs for the members, they need to be +overridden to represent Kerberos principals. The principal might be not present +in the IPA realm and thus cannot be represented as an LDAP object to which DN +could be constructed. + +##### Management of a general constrained delegation + +In case of general constrained delegation a special handling is added to +`LDAPAddMember` and `LDAPRemoveMember` classes to handle `memberPrincipal`. +The add/remove methods assume, and require via asserts, that all members be a +DN. `get_member_dns()` needs to ignore any `memberPrincipal` values and return +only the DN-based values when adding targets to rules to let the standard +mechanics of `LDAP*Member` do their work. + +In order to handle the `memberPrincipal` values a `post_callback()` is required. +This also means that there be at worst two writes per membership update. +Given that this feature is not expected to be frequently used then speed and +efficiency are not a factor. + +Similarly, we enforce that only a target is a member of a rule, and not +another rule. That would be an undefined relationship. To do this each member +needs to be retrieved and evaluated before adding as a member. + +A referential integrity rule is needed for `ipaallowedtarget`. + +A referential integrity rule is needed, but is not possible, for +`memberPrincipal`. It is not possible because it is not a DN. This adds the +potential to have dangling pointers. In practice, this has not been a problem +for S4U2Proxy usage as administrators rarely add the constrained delegation +rules. + +The ACL system also provides a means of limiting which user's a ticket may be +obtained for using the `ipaAllowToImpersonate` attribute. This is not +implemented. + +In order to maintain basic functionality, FreeIPA must have entries for +S4U2Proxy operations between IPA API framework, LDAP service, and CIFS service +on IPA server. These entries are `ipa-http-delegation` rule and +`ipa-ldap-delegation-targets` and `ipa-cifs-delegation-targets` targets. + +To grant this access, two LDAP entries are required. The first is a +rule which defines the ACL: + +``` + dn: cn=ipa-http-delegation,... + objectClass: ipaKrb5DelegationACL + objectClass: groupOfPrincipals + cn: ipa-http-delegation + memberPrincipal: HTTP/ipaserver.example.com@EXAMPLE.COM + ipaAllowedTarget: cn=ipa-ldap-delegation-targets,... +``` + +The second LDAP entry is a target of this rule which defines which principals +may be obtained: + +``` + dn: cn=ipa-ldap-delegation-targets,... + objectClass: groupOfPrincipals + cn: ipa-ldap-delegation-targets + memberPrincipal: ldap/ipaserver.example.com@EXAMPLE.COM +``` + +Both types of entries contain members in the form of `memberPrincipal`. In the +case of a rule these are the members that the rule applies to. In the case of a +target the members are the targets of the delegation. In this case the rule has +a member of `HTTP/ipaserver.example.com@EXAMPLE.COM` and a rule with a member +of `ldap/ipaserver.example.com@EXAMPLE.COM` which means that the HTTP principal +can obtain an LDAP service ticket on behalf of the bound user. + +The same approach is used to allow the IPA API framework to obtain a service +ticket on behalf of a user to Samba when a trust to Active Directory is +established. In this case, instead of `ldap/ipaserver.example.com@EXAMPLE.COM`, +a target principal of `cifs/ipaserver.example.com@EXAMPLE.COM` is used. + +These two rules are configured by default in the FreeIPA deployment. + +##### Resource-based constrained delegation + +Resource-based constrained delegation relies on a `memberPrincipal` attribute +in the target service's LDAP object. To manage this attribute, we extend +`LDAPAddAttribute` and `LDAPRemoveAttribute` classes. Both classes were added +after general constrained delegation was implemented and present a better +abstraction to handle member principals. + +To control validity of the member principals, a method that checks realms +against a list of trusted domains is added. This allows to set up +resource-based constrained delegation for cross-forest services. + +Access control for resource-based constrained delegation is performed in the +following way. A service can modify own delegation list and specify which +Kerberos principals are allowed to delegate to the service. Host where service +is located can manage the service as well. + +Administrators can grant other users, groups, hosts, or services permissions to +handle resource-based constrained delegation of a host or a service. + +#### Kerberos KDC implementation + +KDB API provides two callbacks for the database drivers to implement access +control checks for constrained delegation. + +General constrained delegation callback `check_allowed_to_delegate()` allows +checking whether a server is allowed to obtain tickets from client to a target +service. This is implemented by loading constrained delegation LDAP rules and +targets associated with the target service and the proxy server and checking +that they match. + +Resource-based constrained delegation callback `allowed_to_delegate_from()` +allows checking whether a target service allows a server to delegate a ticket. +This is implemented in two parts: + +- first, `memberPrincipal` attribute in the principal is loaded and added to TL + data of the principal object in KDC under `KRB5_TL_CONSTRAINED_DELEGATION_ACL` type. + +- second, the resource-based constrained delegation callback retrieves + `KRB5_TL_CONSTRAINED_DELEGATION_ACL` TL data and validates that a server is + present in the list of principals. + +Since `KRB5_TL_CONSTRAINED_DELEGATION_ACL` TL data might be present in the +Kerberos principal KDC object, destructor for the Kerberos principal is +extended to free the associated memory. + +Finally, KDB driver follows requirements for [MS-SFU 3.2.5.1.2](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/ad98268b-f75b-42c3-b09b-959282770642) +and adds SIDs `S-1-18-1` or `S-1-18-2` to the MS-PAC structure's `extraSids` +field depending on how identity was verified: + +* for non-S4U2Self operation initial PAC structure population includes a SID + `S-1-18-1`, as a `AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY`, + +* for S4U operation, instead, a SID `S-1-18-2` is added, as a `SERVICE_ASSERTED_IDENTITY`. + +### Test Plan + +General constrained delegation is already used by the IPA management framework +and thus being tested with every IPA API call. + +For resource-based constrained delegation cases defined in the use case summary +table. Since FreeIPA currently does not have support for IPA to IPA trust and +does not provide a working two-way trust with Active Directory, it is not +possible to test a scenario where RBCD is applied cross-realm by FreeIPA itself +but the proxy service is in a trusted realm. When IPA to IPA trust or proper +two-way trust to Active Directory would be implemented, this scenario could be +tested. + +Thus, a primary RBCD scenario to test is an interoperability with another +RBCD-enabled realm (e.g. Active Directory) where IPA client is used to +initiate the S4U2Proxy operation against a resource (service) in a trusted +realm. In this case Kerberos library on the IPA client should set RBCD support +flag in the PAC structure and trigger S4U2Proxy request. A trusted realm's KDC +will do its check and allow or deny the access request. + +#### Usage examples for RBCD + +##### Setup RBCD for a service + +Let's consider a case where a web frontend needs to connect to an internal +SMB server running on another IPA server on behalf of a user. This is similar +to a default setup in FreeIPA with general constrained delegation but on a +different host and using a different service. + +* a host `web-service.example.test` would run a web server and use +`HTTP/web-service.example.test` service principal. + +* a host `file.example.test` would be a Samba server running on IPA-enrolled + client. Its SMB server uses `cifs/file.example.test` service principal. + +In RBCD model, the control over who can delegate user resources to the service +would be defined at the service side, in this case at `cifs/file.example.test`. +An RBCD access control for `cifs/file.example.test` would need to mention +`HTTP/web-service.example.test` principal to allow the web server to delegate +user's credentials to the Samba server. + +Example 1: Administrator can set RBCD ACL directly: +``` +$ kinit admin +$ ipa service-add-delegation cifs/file.example.test HTTP/web-service.example.test +``` + +Example 2: Host `file.example.test` can use a host keytab to define RBCD ACL +directly because a host always manages the services running on it: +``` +# kinit -k +# ipa service-add-delegation cifs/file.example.test HTTP/web-service.example.test +``` + +Example 3: Allow users from a group `storage-admins` to define RBCD ACLs to +`cifs/file.example.test`: +``` +$ kinit admin +$ ipa service-allow-add-delegation cifs/file.example.test --groups=storage-admins +``` + +Then, a user `some-user` from `storage-admins` group can add a delegation ACL: +``` +$ kinit some-user +$ ipa service-add-delegation cifs/file.example.test HTTP/web-service.example.test +``` + +Example 4: Remove permission to add RBCD ACLs for `cifs/file.example.test` from +members of the `storage-admins` group: +``` +$ kinit admin +$ ipa service-disallow-add-delegation cifs/file.example.test --groups=storage-admins +``` + +Now a user `some-user` from `storage-admins` group cannot add a delegation ACL: +``` +$ kinit some-user +$ ipa service-add-delegation cifs/file.example.test HTTP/web-service.example.test +.. ERROR .. +``` + +Example 5: Test RBCD access by service `HTTP/web-service.example.test` to +`cifs/file.example.test`. In this example we assume that an RBCD ACL created in +examples 1-3 exists, there is a keytab `/path/to/web-service.keytab` for +`HTTP/web-service.example.test`, and a `cifs/file.example.test` service was +created with `ipa-install-samba` tool which ensures a keytab was obtained for +Samba service as well. The presence of keytabs ensures corresponding Kerberos +services have all needed Kerberos keys so that service tickets can be created +by KDC. + +In the example below we are delegating user `some-user` credentials to the +service `cifs/file.example.test`. First, we pretend our web service has +authenticated the user with some mechanism. Then we aquire a service ticket to +ourselves (`HTTP/web-service.example.test`) with the help of `kvno -U username` +command. Finally, we use `kvno -P` option to ask for S4U2Proxy operation and +specify for which services tickets will be asked using constrained delegation. + +``` +# kvno -U some-user -k /path/to/web-service.keytab \ + -P HTTP/web-service.example.test cifs/file.example.test +``` diff --git a/doc/requirements.txt b/doc/requirements.txt index 011822d54..cdaa42658 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,6 +1,7 @@ wheel sphinx > 3.0 +sphinx-book-theme # convert markdown to rest # m2r2 fork is active in development and works with diff --git a/doc/workshop/12-external-idp-support.rst b/doc/workshop/12-external-idp-support.rst index 6164d5337..145170395 100644 --- a/doc/workshop/12-external-idp-support.rst +++ b/doc/workshop/12-external-idp-support.rst @@ -112,7 +112,7 @@ suitable, individual parameters can also be added:: ipa help idp-add Usage: ipa [global-options] idp-add NAME [options] - Add a new Identity Provider server. + Add a new Identity Provider reference. Options: -h, --help show this help message and exit --auth-uri=STR OAuth 2.0 authorization endpoint @@ -370,9 +370,9 @@ The following command adds IdP reference named ``keycloak`` as IPA administrator --client-id ipa_oidc_client \ --secret ----------------------------------------- - Added Identity Provider server "keycloak" + Added Identity Provider reference "keycloak" ----------------------------------------- - Identity Provider server name: keycloak + Identity Provider reference name: keycloak Authorization URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/auth Device authorization URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/auth/device Token URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/token diff --git a/freeipa.spec.in b/freeipa.spec.in index f09741d7a..3e23bbfe9 100755 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -66,12 +66,11 @@ %if 0%{?rhel} %global package_name ipa %global alt_name freeipa -%global krb5_version 1.18.2-2 -%global krb5_kdb_version 8.0 +%global krb5_version 1.20.1-1 +%global krb5_kdb_version 9.0 # 0.7.16: https://github.com/drkjam/netaddr/issues/71 %global python_netaddr_version 0.7.19 -# Require 4.7.0 which brings Python 3 bindings -%global samba_version 4.12.3-12 +%global samba_version 4.17.4-101 %global slapi_nis_version 0.56.4 %global python_ldap_version 3.1.0-1 %if 0%{?rhel} < 9 @@ -79,9 +78,9 @@ %global ds_version 1.4.3.16-12 %global selinux_policy_version 3.14.3-107 %else -%global ds_version 2.0.3-3 -# TBD update selinux_policy_version when BZ#2114902 is fixed -%global selinux_policy_version 3.14.3-52 +# DNA interval enabled +%global ds_version 2.0.5-1 +%global selinux_policy_version 38.1.1-1 %endif # Fix for TLS 1.3 PHA, RHBZ#1775158 @@ -95,8 +94,6 @@ # Fedora %global package_name freeipa %global alt_name ipa -# Fix for CVE-2020-28196 -%global krb5_version 1.18.2-29 # 0.7.16: https://github.com/drkjam/netaddr/issues/71 %global python_netaddr_version 0.7.16 # Require 4.7.0 which brings Python 3 bindings @@ -112,7 +109,15 @@ %endif %global slapi_nis_version 0.56.5 +%if 0%{?fedora} < 38 +# Fix for CVE-2020-28196 +%global krb5_version 1.18.2-29 %global krb5_kdb_version 8.0 +%else +# Fix for CVE-2020-28196 +%global krb5_version 1.20.1-3 +%global krb5_kdb_version 9.0 +%endif # fix for segfault in python3-ldap, https://pagure.io/freeipa/issue/7324 %global python_ldap_version 3.1.0-1 @@ -173,8 +178,7 @@ # RHEL 8.2+, F32+ has 3.58 %global nss_version 3.44.0-4 - -%define krb5_base_version %(LC_ALL=C /usr/bin/pkgconf --modversion krb5 | grep -Eo '^[^.]+\.[^.]+' || echo %krb5_version) +%define krb5_base_version %(LC_ALL=C /usr/bin/pkgconf --modversion krb5 2>/dev/null | grep -Eo '^[^.]+\.[^.]+' || echo %krb5_version) %global kdcproxy_version 0.4-3 %if 0%{?fedora} >= 33 || 0%{?rhel} >= 9 @@ -222,12 +226,20 @@ Version: %{IPA_VERSION} Release: 0%{?rc_version:.%rc_version}%{?dist} Summary: The Identity, Policy and Audit system -License: GPLv3+ +License: GPL-3.0-or-later URL: http://www.freeipa.org/ Source0: https://releases.pagure.org/freeipa/freeipa-%{version}%{?rc_version}.tar.gz # Only use detached signature for the distribution builds. If it is a developer build, skip it %if %{NON_DEVELOPER_BUILD} Source1: https://releases.pagure.org/freeipa/freeipa-%{version}%{?rc_version}.tar.gz.asc +# https://www.freeipa.org/page/Verify_Release_Signature +# +# The following commands can be used to fetch the signing key via fingerprint +# and extract it: +# fpr=0E63D716D76AC080A4A33513F40800B6298EB963 +# gpg --keyserver keys.openpgp.org --receive-keys $fpr +# gpg --armor --export-options export-minimal --export $fpr >gpgkey-$fpr.asc +Source2: gpgkey-0E63D716D76AC080A4A33513F40800B6298EB963.asc %endif # RHEL spec file only: START: Change branding to IPA and Identity Management @@ -239,10 +251,8 @@ Source1: https://releases.pagure.org/freeipa/freeipa-%{version}%{?rc_vers # RHEL spec file only: START %if %{NON_DEVELOPER_BUILD} %if 0%{?rhel} == 8 -Patch0001: 0001_util_Fix_client-only_build-upstream_5273.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch -Patch1002: 1002-4.8.0-Remove-csrgen.patch -Patch1003: 1003-Revert-WebUI-use-python3-rjsmin-to-minify-JavaScript.patch +Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch %endif %if 0%{?rhel} == 9 Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch @@ -250,9 +260,6 @@ Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch %endif # RHEL spec file only: END -# For the timestamp trick in patch application -BuildRequires: diffstat - BuildRequires: openldap-devel # For KDB DAL version, make explicit dependency so that increase of version # will cause the build to fail due to unsatisfied dependencies. @@ -270,6 +277,7 @@ BuildRequires: jansson-devel %endif BuildRequires: popt-devel BuildRequires: gcc +BuildRequires: gnupg2 BuildRequires: make BuildRequires: pkgconfig BuildRequires: pkgconf @@ -298,7 +306,12 @@ BuildRequires: libpwquality-devel BuildRequires: libsss_idmap-devel BuildRequires: libsss_certmap-devel BuildRequires: libsss_nss_idmap-devel >= %{sssd_version} +%if 0%{?fedora} >= 39 || 0%{?rhel} >= 10 +# Do not use nodejs20 on fedora < 39, https://pagure.io/freeipa/issue/9374 BuildRequires: nodejs(abi) +%else +BuildRequires: nodejs(abi) < 111 +%endif # use old dependency on RHEL 8 for now %if 0%{?fedora} >= 31 || 0%{?rhel} >= 9 BuildRequires: python3-rjsmin @@ -389,7 +402,6 @@ BuildRequires: python3-libsss_nss_idmap BuildRequires: python3-lxml BuildRequires: python3-netaddr >= %{python_netaddr_version} BuildRequires: python3-netifaces -BuildRequires: python3-paste BuildRequires: python3-pki >= %{pki_version} BuildRequires: python3-polib BuildRequires: python3-pyasn1 @@ -400,6 +412,7 @@ BuildRequires: python3-pylint BuildRequires: python3-pytest-multihost BuildRequires: python3-pytest-sourceorder BuildRequires: python3-qrcode-core >= 5.0.0 +BuildRequires: python3-pyOpenSSL BuildRequires: python3-samba BuildRequires: python3-six BuildRequires: python3-sss @@ -449,7 +462,6 @@ Requires: nss-tools >= %{nss_version} Requires(post): krb5-server >= %{krb5_version} Requires(post): krb5-server >= %{krb5_base_version} Requires: krb5-kdb-version = %{krb5_kdb_version} -Requires: krb5-pkinit-openssl >= %{krb5_version} Requires: cyrus-sasl-gssapi%{?_isa} Requires: chrony Requires: httpd >= %{httpd_version} @@ -481,7 +493,7 @@ Requires: policycoreutils >= 2.1.12-5 Requires: tar Requires(pre): certmonger >= %{certmonger_version} Requires(pre): 389-ds-base >= %{ds_version} -Requires: fontawesome-fonts +Requires: font(fontawesome) Requires: open-sans-fonts %if 0%{?fedora} >= 32 || 0%{?rhel} >= 9 # https://pagure.io/freeipa/issue/8632 @@ -675,6 +687,8 @@ Requires: python3-sssdconfig >= %{sssd_version} Requires: cyrus-sasl-gssapi%{?_isa} Requires: chrony Requires: krb5-workstation >= %{krb5_version} +# support pkinit with client install +Requires: krb5-pkinit-openssl >= %{krb5_version} # authselect: sssd profile with-subid %if 0%{?fedora} >= 36 Requires: authselect >= 1.4.0 @@ -693,6 +707,7 @@ Requires: jansson %endif Requires: sssd-ipa >= %{sssd_version} Requires: sssd-idp >= %{sssd_version} +Requires: sssd-krb5 >= %{sssd_version} Requires: certmonger >= %{certmonger_version} Requires: nss-tools >= %{nss_version} Requires: bind-utils @@ -869,6 +884,7 @@ Requires: python3-netifaces >= 0.10.4 Requires: python3-pyasn1 >= 0.3.2-2 Requires: python3-pyasn1-modules >= 0.3.2-2 Requires: python3-pyusb +Requires: python3-pyOpenSSL Requires: python3-qrcode-core >= 5.0.0 Requires: python3-requests Requires: python3-six @@ -975,22 +991,12 @@ Custom SELinux policy module for FreeIPA %prep -# Update timestamps on the files touched by a patch, to avoid non-equal -# .pyc/.pyo files across the multilib peers within a build, where "Level" -# is the patch prefix option (e.g. -p1) -# Taken from specfile for sssd and python-simplejson -UpdateTimestamps() { - Level=$1 - PatchFile=$2 +# Verify release signature +%if %{NON_DEVELOPER_BUILD} +%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' +%endif - # Locate the affected files: - for f in $(diffstat $Level -l $PatchFile); do - # Set the files to have the same timestamp as that of the patch: - touch -c -r $PatchFile $f - done -} - -%setup -n freeipa-%{version}%{?rc_version} -q +%autosetup -n freeipa-%{version}%{?rc_version} -N -p1 # To allow proper application patches to the stripped po files, strip originals pushd po @@ -1000,10 +1006,7 @@ for i in *.po ; do done popd -for p in %patches ; do - %__patch -p1 -i $p - UpdateTimestamps -p1 $p -done +%autopatch -p1 %build # PATH is workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1005235 @@ -1256,10 +1259,8 @@ if [ $1 -gt 1 ] ; then test -f '/var/lib/ipa-client/sysrestore/sysrestore.index' && restore=$(wc -l '/var/lib/ipa-client/sysrestore/sysrestore.index' | awk '{print $1}') if [ -f '/etc/sssd/sssd.conf' -a $restore -ge 2 ]; then - if ! grep -E -q '/var/lib/sss/pubconf/krb5.include.d/' /etc/krb5.conf 2>/dev/null ; then - echo "includedir /var/lib/sss/pubconf/krb5.include.d/" > /etc/krb5.conf.ipanew - cat /etc/krb5.conf >> /etc/krb5.conf.ipanew - mv -Z /etc/krb5.conf.ipanew /etc/krb5.conf + if grep -E -q '/var/lib/sss/pubconf/krb5.include.d/' /etc/krb5.conf 2>/dev/null ; then + sed -i '\;includedir /var/lib/sss/pubconf/krb5.include.d;d' /etc/krb5.conf fi fi diff --git a/gpgkey-0E63D716D76AC080A4A33513F40800B6298EB963.asc b/gpgkey-0E63D716D76AC080A4A33513F40800B6298EB963.asc new file mode 100644 index 000000000..48498637a --- /dev/null +++ b/gpgkey-0E63D716D76AC080A4A33513F40800B6298EB963.asc @@ -0,0 +1,272 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=MITl +-----END PGP PUBLIC KEY BLOCK----- diff --git a/install/migration/migration.py b/install/migration/migration.py index b3f3fc8a3..d96d7a806 100644 --- a/install/migration/migration.py +++ b/install/migration/migration.py @@ -21,7 +21,7 @@ Password migration script """ from __future__ import absolute_import -import cgi +from urllib.parse import parse_qs import errno import logging import os.path @@ -80,10 +80,28 @@ def application(environ, start_response): if not content_type.startswith('application/x-www-form-urlencoded'): return bad_request(start_response) - form_data = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ) - if 'username' not in form_data or 'password' not in form_data: + try: + length = int(environ.get("CONTENT_LENGTH")) + except (ValueError, TypeError): return bad_request(start_response) + query_string = environ["wsgi.input"].read(length).decode("utf-8") + + try: + query_dict = parse_qs(query_string) + except Exception: + return bad_request(start_response) + + user_query = query_dict.get("username", None) + if user_query is None or len(user_query) != 1: + return bad_request(start_response) + username = user_query[0] + + password_query = query_dict.get("password", None) + if password_query is None or len(password_query) != 1: + return bad_request(start_response) + password = password_query[0] + status = '200 Success' response_headers = [] result = 'error' @@ -93,8 +111,7 @@ def application(environ, start_response): api = create_api(mode=None) api.bootstrap(context='server', confdir=paths.ETC_IPA, in_server=True) try: - bind(api.env.ldap_uri, api.env.basedn, - form_data['username'].value, form_data['password'].value) + bind(api.env.ldap_uri, api.env.basedn, username, password) except IOError as err: if err.errno == errno.EPERM: result = 'invalid-password' 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/install/share/bind.named.conf.template b/install/share/bind.named.conf.template index 28c21d0a7..01b77c5ae 100644 --- a/install/share/bind.named.conf.template +++ b/install/share/bind.named.conf.template @@ -58,4 +58,5 @@ dyndb "ipa" "$BIND_LDAP_SO" { server_id "$FQDN"; auth_method "sasl"; sasl_mech "EXTERNAL"; + krb5_keytab "FILE:$NAMED_KEYTAB"; }; diff --git a/install/share/krb5.conf.template b/install/share/krb5.conf.template index 4d417416a..37ec8a4c1 100644 --- a/install/share/krb5.conf.template +++ b/install/share/krb5.conf.template @@ -1,5 +1,4 @@ $INCLUDES -includedir /var/lib/sss/pubconf/krb5.include.d/ [logging] default = FILE:/var/log/krb5libs.log diff --git a/install/tools/ipa-ccache-sweeper.in b/install/tools/ipa-ccache-sweeper.in index 4b304d242..1384e6799 100644 --- a/install/tools/ipa-ccache-sweeper.in +++ b/install/tools/ipa-ccache-sweeper.in @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 # Based heavily on # https://github.com/gssapi/mod_auth_gssapi/blob/master/contrib/sweeper.py diff --git a/install/tools/ipa-compat-manage.in b/install/tools/ipa-compat-manage.in index 1f76eb5f8..459f39fc8 100644 --- a/install/tools/ipa-compat-manage.in +++ b/install/tools/ipa-compat-manage.in @@ -132,7 +132,6 @@ def main(): print("Enabling plugin") # https://github.com/PyCQA/pylint/issues/872 - # pylint: disable=unsupported-assignment-operation if entry is None: ld = LDAPUpdate() if not ld.update(files): @@ -141,7 +140,6 @@ def main(): else: entry['nsslapd-pluginenabled'] = ['on'] api.Backend.ldap2.update_entry(entry) - # pylint: enable=unsupported-assignment-operation except errors.ExecutionError as lde: print("An error occurred while talking to the server.") print(lde) @@ -171,9 +169,7 @@ def main(): else: print("Disabling plugin") - # pylint: disable=unsupported-assignment-operation entry['nsslapd-pluginenabled'] = ['off'] - # pylint: enable=unsupported-assignment-operation api.Backend.ldap2.update_entry(entry) except errors.DatabaseError as dbe: print("An error occurred while talking to the server.") diff --git a/install/tools/ipa-nis-manage.in b/install/tools/ipa-nis-manage.in index 767217266..6b156ce6a 100644 --- a/install/tools/ipa-nis-manage.in +++ b/install/tools/ipa-nis-manage.in @@ -155,9 +155,7 @@ def main(): elif entry.get('nsslapd-pluginenabled', [''])[0].lower() == 'off': print("Enabling plugin") # Already configured, just enable the plugin - # pylint: disable=unsupported-assignment-operation entry['nsslapd-pluginenabled'] = ['on'] - # pylint: enable=unsupported-assignment-operation api.Backend.ldap2.update_entry(entry) else: print("Plugin already Enabled") diff --git a/install/tools/ipa-replica-conncheck.in b/install/tools/ipa-replica-conncheck.in index 948fc5a0c..8eee82483 100644 --- a/install/tools/ipa-replica-conncheck.in +++ b/install/tools/ipa-replica-conncheck.in @@ -45,7 +45,7 @@ import time import threading import traceback from socket import SOCK_STREAM, SOCK_DGRAM -import distutils.spawn +import shutil from ipaplatform.paths import paths import gssapi @@ -62,7 +62,7 @@ class SshExec: def __init__(self, user, addr): self.user = user self.addr = addr - self.cmd = distutils.spawn.find_executable('ssh') + self.cmd = shutil.which('ssh') # Bail if ssh is not installed if self.cmd is None: raise RuntimeError("ssh not installed") diff --git a/install/tools/man/ipa-acme-manage.1 b/install/tools/man/ipa-acme-manage.1 index e15d25bd0..b8383c14f 100644 --- a/install/tools/man/ipa-acme-manage.1 +++ b/install/tools/man/ipa-acme-manage.1 @@ -27,6 +27,89 @@ Disable the ACME service on this host. .TP \fBstatus\fR Display the status of the ACME service. +.TP +\fBpruning\fR +Configure certificate and request pruning. + +.SH "PRUNING" +Pruning is a job that runs in the CA that can remove expired +certificates and certificate requests which have not been issued. +This is particularly important when using short-lived certificates +like those issued with the ACME protocol. Pruning requires that +the IPA server be installed with random serial numbers enabled. + +The CA needs to be restarted after modifying the pruning configuration. + +The job is a cron-like task within the CA that is controlled by a +number of options which dictate how long after the certificate or +request is considered no longer valid and removed from the LDAP +database. + +The cron time and date fields are: +.IP +.ta 1.5i +field allowed values +.br +----- -------------- +.br +minute 0-59 +.br +hour 0-23 +.br +day of month 1-31 +.br +month 1-12 +.br +day of week 0-6 (0 is Sunday) +.br +.PP + +The cron syntax is limited to * or specific numbers. Ranges are not supported. + +.TP +\fB\-\-enable\fR +Enable certificate pruning. +.TP +\fB\-\-disable\fR +Disable certificate pruning. +.TP +\fB\-\-cron=CRON\fR +Configure the pruning cron job. The syntax is similar to crontab(5) syntax. +For example, "0 0 1 * *" schedules the job to run at 12:00am on the first +day of each month. +.TP +\fB\-\-certretention=CERTRETENTION\fR +Certificate retention time. The default is 30. A value of 0 will remove expired certificates with no delay. +.TP +\fB\-\-certretentionunit=CERTRETENTIONUNIT\fR +Certificate retention units. Valid units are: minute, hour, day, year. +The default is days. +.TP +\fB\-\-certsearchsizelimit=CERTSEARCHSIZELIMIT\fR +LDAP search size limit searching for expired certificates. The default is 1000. This is a client-side limit. There may be additional server-side limitations. +.TP +\fB\-\-certsearchtimelimit=CERTSEARCHTIMELIMIT\fR +LDAP search time limit (seconds) searching for expired certificates. The default is 0, no limit. This is a client-side limit. There may be additional server-side limitations. +.TP +\fB\-\-requestretention=REQUESTRETENTION\fR +Request retention time. The default is 30. A value of 0 will remove expired requests with no delay. +.TP +\fB\-\-requestretentionunit=REQUESTRETENTIONUNIT\fR +Request retention units. Valid units are: minute, hour, day, year. +The default is days. +.TP +\fB\-\-requestsearchsizelimit=REQUESTSEARCHSIZELIMIT\fR +LDAP search size limit searching for unfulfilled requests. The default is 1000. There may be additional server-side limitations. +.TP +\fB\-\-requestsearchtimelimit=REQUESTSEARCHTIMELIMIT\fR +LDAP search time limit (seconds) searching for unfulfilled requests. The default is 0, no limit. There may be additional server-side limitations. +.TP +\fB\-\-config\-show\fR +Show the current pruning configuration +.TP +\fB\-\-run\fR +Run the pruning job now. The IPA RA certificate is used to authenticate to the PKI REST backend. + .SH "EXIT STATUS" 0 if the command was successful diff --git a/install/ui/Gruntfile.js b/install/ui/Gruntfile.js index ba4641127..e1a47da63 100644 --- a/install/ui/Gruntfile.js +++ b/install/ui/Gruntfile.js @@ -4,6 +4,14 @@ module.exports = function(grunt) { options: {} }, qunit: { + options: { + puppeteer: { + executablePath: '/usr/bin/chromium-browser', + args: [ + "--allow-file-access-from-files" + ] + }, + }, all: [ 'test/all_tests.html' ] diff --git a/install/ui/test/all_tests.html b/install/ui/test/all_tests.html index c4104fef7..eb548dcc0 100644 --- a/install/ui/test/all_tests.html +++ b/install/ui/test/all_tests.html @@ -6,23 +6,14 @@ - - +