diff --git a/SOURCES/0022-rpcserver-fallback-to-non-armored-kinit-in-case-of-trusted-domains_rhbz#1914821.patch b/SOURCES/0022-rpcserver-fallback-to-non-armored-kinit-in-case-of-trusted-domains_rhbz#1914821.patch new file mode 100644 index 0000000..e382b47 --- /dev/null +++ b/SOURCES/0022-rpcserver-fallback-to-non-armored-kinit-in-case-of-trusted-domains_rhbz#1914821.patch @@ -0,0 +1,236 @@ +From 1441b999d3fe9b4e59fe942294d13480ecee7d94 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 28 Oct 2020 17:46:56 +0200 +Subject: [PATCH] rpcserver: fallback to non-armored kinit in case of trusted + domains + +MIT Kerberos implements FAST negotiation as specified in RFC 6806 +section 11. The implementation relies on the caller to provide a hint +whether FAST armoring must be used. + +FAST armor can only be used when both client and KDC have a shared +secret. When KDC is from a trusted domain, there is no way to have a +shared secret between a generic Kerberos client and that KDC. + +[MS-KILE] section 3.2.5.4 'Using FAST When the Realm Supports FAST' +allows KILE clients (Kerberos clients) to have local settings that +direct it to enforce use of FAST. This is equal to the current +implementation of 'kinit' utility in MIT Kerberos requiring to use FAST +if armor cache (option '-T') is provided. + +[MS-KILE] section 3.3.5.7.4 defines a way for a computer from a +different realm to use compound identity TGS-REQ to create FAST TGS-REQ +explicitly armored with the computer's TGT. However, this method is not +available to IPA framework as we don't have access to the IPA server's +host key. In addition, 'kinit' utility does not support this method. + +Active Directory has a policy to force use of FAST when client +advertizes its use. Since we cannot know in advance whether a principal +to obtain initial credentials for belongs to our realm or to a trusted +one due to enterprise principal canonicalization, we have to try to +kinit. Right now we fail unconditionally if FAST couldn't be used and +libkrb5 communication with a KDC from the user realm (e.g. from a +trusted forest) causes enforcement of a FAST. + +In the latter case, as we cannot use FAST anyway, try to kinit again +without advertizing FAST. This works even in the situations when FAST +enforcement is enabled on Active Directory side: if client doesn't +advertize FAST capability, it is not required. Additionally, FAST cannot +be used for any practical need for a trusted domain's users yet. + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipalib/errors.py | 6 ++ + ipaserver/rpcserver.py | 94 ++++++++++++++++--------- + ipatests/test_integration/test_trust.py | 21 ++++++ + 3 files changed, 86 insertions(+), 35 deletions(-) + +diff --git a/ipalib/errors.py b/ipalib/errors.py +index 1b17ca7ed..fa51e15c0 100644 +--- a/ipalib/errors.py ++++ b/ipalib/errors.py +@@ -245,6 +245,12 @@ class PluginModuleError(PrivateError): + format = '%(name)s is not a valid plugin module' + + ++class KrbPrincipalWrongFAST(PrivateError): ++ """ ++ Raised when it is not possible to use our FAST armor for kinit ++ """ ++ format = '%(principal)s cannot use Anonymous PKINIT as a FAST armor' ++ + ############################################################################## + # Public errors: + +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 181295471..ed775170e 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -46,9 +46,11 @@ from ipalib.capabilities import VERSION_WITHOUT_CAPABILITIES + from ipalib.frontend import Local + from ipalib.install.kinit import kinit_armor, kinit_password + from ipalib.backend import Executioner +-from ipalib.errors import (PublicError, InternalError, JSONError, ++from ipalib.errors import ( ++ PublicError, InternalError, JSONError, + CCacheError, RefererError, InvalidSessionPassword, NotFound, ACIError, +- ExecutionError, PasswordExpired, KrbPrincipalExpired, UserLocked) ++ ExecutionError, PasswordExpired, KrbPrincipalExpired, KrbPrincipalWrongFAST, ++ UserLocked) + from ipalib.request import context, destroy_context + from ipalib.rpc import (xml_dumps, xml_loads, + json_encode_binary, json_decode_binary) +@@ -957,6 +959,34 @@ class login_password(Backend, KerberosSession): + self.api.Backend.wsgi_dispatch.mount(self, self.key) + + def __call__(self, environ, start_response): ++ def attempt_kinit(user_principal, password, ++ ipa_ccache_name, use_armor=True): ++ try: ++ # try to remove in case an old file was there ++ os.unlink(ipa_ccache_name) ++ except OSError: ++ pass ++ try: ++ self.kinit(user_principal, password, ++ ipa_ccache_name, use_armor=use_armor) ++ except PasswordExpired as e: ++ return self.unauthorized(environ, start_response, ++ str(e), 'password-expired') ++ except InvalidSessionPassword as e: ++ return self.unauthorized(environ, start_response, ++ str(e), 'invalid-password') ++ except KrbPrincipalExpired as e: ++ return self.unauthorized(environ, ++ start_response, ++ str(e), ++ 'krbprincipal-expired') ++ except UserLocked as e: ++ return self.unauthorized(environ, ++ start_response, ++ str(e), ++ 'user-locked') ++ return None ++ + logger.debug('WSGI login_password.__call__:') + + # Get the user and password parameters from the request +@@ -1007,26 +1037,14 @@ class login_password(Backend, KerberosSession): + ipa_ccache_name = os.path.join(paths.IPA_CCACHES, + 'kinit_{}'.format(os.getpid())) + try: +- # try to remove in case an old file was there +- os.unlink(ipa_ccache_name) +- except OSError: +- pass +- try: +- self.kinit(user_principal, password, ipa_ccache_name) +- except PasswordExpired as e: +- return self.unauthorized(environ, start_response, str(e), 'password-expired') +- except InvalidSessionPassword as e: +- return self.unauthorized(environ, start_response, str(e), 'invalid-password') +- except KrbPrincipalExpired as e: +- return self.unauthorized(environ, +- start_response, +- str(e), +- 'krbprincipal-expired') +- except UserLocked as e: +- return self.unauthorized(environ, +- start_response, +- str(e), +- 'user-locked') ++ result = attempt_kinit(user_principal, password, ++ ipa_ccache_name, use_armor=True) ++ except KrbPrincipalWrongFAST: ++ result = attempt_kinit(user_principal, password, ++ ipa_ccache_name, use_armor=False) ++ ++ if result is not None: ++ return result + + result = self.finalize_kerberos_acquisition('login_password', + ipa_ccache_name, environ, +@@ -1038,21 +1056,24 @@ class login_password(Backend, KerberosSession): + pass + return result + +- def kinit(self, principal, password, ccache_name): +- # get anonymous ccache as an armor for FAST to enable OTP auth +- armor_path = os.path.join(paths.IPA_CCACHES, +- "armor_{}".format(os.getpid())) ++ def kinit(self, principal, password, ccache_name, use_armor=True): ++ if use_armor: ++ # get anonymous ccache as an armor for FAST to enable OTP auth ++ armor_path = os.path.join(paths.IPA_CCACHES, ++ "armor_{}".format(os.getpid())) + +- logger.debug('Obtaining armor in ccache %s', armor_path) ++ logger.debug('Obtaining armor in ccache %s', armor_path) + +- try: +- kinit_armor( +- armor_path, +- pkinit_anchors=[paths.KDC_CERT, paths.KDC_CA_BUNDLE_PEM], +- ) +- except RuntimeError as e: +- logger.error("Failed to obtain armor cache") +- # We try to continue w/o armor, 2FA will be impacted ++ try: ++ kinit_armor( ++ armor_path, ++ pkinit_anchors=[paths.KDC_CERT, paths.KDC_CA_BUNDLE_PEM], ++ ) ++ except RuntimeError as e: ++ logger.error("Failed to obtain armor cache") ++ # We try to continue w/o armor, 2FA will be impacted ++ armor_path = None ++ else: + armor_path = None + + try: +@@ -1080,6 +1101,9 @@ class login_password(Backend, KerberosSession): + 'while getting initial credentials') in str(e): + raise UserLocked(principal=principal, + message=unicode(e)) ++ elif ('kinit: Error constructing AP-REQ armor: ' ++ 'Matching credential not found') in str(e): ++ raise KrbPrincipalWrongFAST(principal=principal) + raise InvalidSessionPassword(principal=principal, + message=unicode(e)) + +diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py +index a6a055c2a..bec918a31 100644 +--- a/ipatests/test_integration/test_trust.py ++++ b/ipatests/test_integration/test_trust.py +@@ -175,6 +175,27 @@ class TestTrust(BaseTestTrust): + tasks.kdestroy_all(self.master) + tasks.kinit_admin(self.master) + ++ def test_password_login_as_aduser(self): ++ """Test if AD user can login with password to Web UI""" ++ ad_admin = 'Administrator@%s' % self.ad_domain ++ ++ tasks.kdestroy_all(self.master) ++ user_and_password = ('user=%s&password=%s' % ++ (ad_admin, self.master.config.ad_admin_password)) ++ host = self.master.hostname ++ cmd_args = [ ++ paths.BIN_CURL, ++ '-v', ++ '-H', 'referer:https://{}/ipa'.format(host), ++ '-H', 'Content-Type:application/x-www-form-urlencoded', ++ '-H', 'Accept:text/plain', ++ '--cacert', paths.IPA_CA_CRT, ++ '--data', user_and_password, ++ 'https://{}/ipa/session/login_password'.format(host)] ++ result = self.master.run_command(cmd_args) ++ assert "Set-Cookie: ipa_session=MagBearerToken" in result.stdout_text ++ tasks.kinit_admin(self.master) ++ + def test_ipauser_authentication_with_nonposix_trust(self): + ipauser = u'tuser' + original_passwd = 'Secret123' +-- +2.29.2 + diff --git a/SOURCES/0023-pylint-remove-unused-variable_rhbz#1914821.patch b/SOURCES/0023-pylint-remove-unused-variable_rhbz#1914821.patch new file mode 100644 index 0000000..91596b6 --- /dev/null +++ b/SOURCES/0023-pylint-remove-unused-variable_rhbz#1914821.patch @@ -0,0 +1,27 @@ +From 12de9ee69f12f7c0021ea98e9c1163db7d59e5d3 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 28 Oct 2020 19:37:11 +0200 +Subject: [PATCH] pylint: remove unused variable + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipaserver/rpcserver.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 27850e867..181295471 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -972,7 +972,7 @@ class login_password(Backend, KerberosSession): + + try: + query_dict = parse_qs(query_string) +- except Exception as e: ++ except Exception: + return self.bad_request(environ, start_response, "cannot parse query data") + + user = query_dict.get('user', None) +-- +2.29.2 + diff --git a/SOURCES/0024-wgi-plugins.py-ignore-empty-plugin-directories_rhbz#1895910.patch b/SOURCES/0024-wgi-plugins.py-ignore-empty-plugin-directories_rhbz#1895910.patch new file mode 100644 index 0000000..432aa61 --- /dev/null +++ b/SOURCES/0024-wgi-plugins.py-ignore-empty-plugin-directories_rhbz#1895910.patch @@ -0,0 +1,121 @@ +From 29262465edf034d521c165e3854e28835d86b98d Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 6 Nov 2020 09:53:35 +0200 +Subject: [PATCH] wgi/plugins.py: ignore empty plugin directories + +Dynamic plugin registry returns as a plugin any folder within the +plugins directory. Web UI then attempts to load for each plugin 'foo' a +JavaScript file named 'foo/foo.js'. The problem is that if 'foo/foo.js' +does not exist, Web UI breaks and it is impossible to recover until the +empty folder is removed or 'foo/foo.js' (even empty) is created at the +server side. + +Check that 'foo/foo.js' actual exists when including a plugin into the +registry. + +Test the registry generator by creating fake plugins and removing them +during the test. + +Fixes: https://pagure.io/freeipa/issue/8567 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +--- + install/wsgi/plugins.py | 5 +- + ipatests/test_ipaserver/test_jsplugins.py | 68 +++++++++++++++++++++++ + 2 files changed, 72 insertions(+), 1 deletion(-) + create mode 100644 ipatests/test_ipaserver/test_jsplugins.py + +diff --git a/install/wsgi/plugins.py b/install/wsgi/plugins.py +index f80cfb9fe..4c43e7f87 100644 +--- a/install/wsgi/plugins.py ++++ b/install/wsgi/plugins.py +@@ -36,7 +36,10 @@ def get_plugin_index(): + + dirs = os.listdir(paths.IPA_JS_PLUGINS_DIR) + index = 'define([],function(){return[' +- index += ','.join("'"+x+"'" for x in dirs) ++ for x in dirs: ++ p = os.path.join(paths.IPA_JS_PLUGINS_DIR, x, x + '.js') ++ if os.path.exists(p): ++ index += "'" + x + "'," + index += '];});' + return index.encode('utf-8') + +diff --git a/ipatests/test_ipaserver/test_jsplugins.py b/ipatests/test_ipaserver/test_jsplugins.py +new file mode 100644 +index 000000000..354e6992c +--- /dev/null ++++ b/ipatests/test_ipaserver/test_jsplugins.py +@@ -0,0 +1,68 @@ ++# Copyright (C) 2020 FreeIPA Contributors see COPYING for license ++ ++import os ++import pytest ++ ++from ipatests.test_ipaserver.httptest import Unauthorized_HTTP_test ++from ipatests.util import assert_equal, assert_not_equal ++from ipaplatform.paths import paths ++ ++ ++@pytest.mark.tier1 ++class test_jsplugins(Unauthorized_HTTP_test): ++ app_uri = '/ipa/ui/js/freeipa/plugins.js' ++ jsplugins = (('foo', 'foo.js'), ('bar', '')) ++ content_type = 'application/javascript' ++ ++ def test_jsplugins(self): ++ empty_response = "define([],function(){return[];});" ++ ++ # Step 1: make sure default response has no additional plugins ++ response = self.send_request(method='GET') ++ assert_equal(response.status, 200) ++ response_data = response.read().decode(encoding='utf-8') ++ assert_equal(response_data, empty_response) ++ ++ # Step 2: add fake plugins ++ try: ++ for (d, f) in self.jsplugins: ++ dir = os.path.join(paths.IPA_JS_PLUGINS_DIR, d) ++ if not os.path.exists(dir): ++ os.mkdir(dir, 0o755) ++ if f: ++ with open(os.path.join(dir, f), 'w') as js: ++ js.write("/* test js plugin */") ++ ++ except OSError as e: ++ pytest.skip( ++ 'Cannot set up test JS plugin: %s' % e ++ ) ++ ++ # Step 3: query plugins to see if our plugins exist ++ response = self.send_request(method='GET') ++ assert_equal(response.status, 200) ++ response_data = response.read().decode(encoding='utf-8') ++ assert_not_equal(response_data, empty_response) ++ for (d, f) in self.jsplugins: ++ if f: ++ assert "'" + d + "'" in response_data ++ else: ++ assert "'" + d + "'" not in response_data ++ ++ # Step 4: remove fake plugins ++ try: ++ for (d, f) in self.jsplugins: ++ dir = os.path.join(paths.IPA_JS_PLUGINS_DIR, d) ++ file = os.path.join(dir, f) ++ if f and os.path.exists(file): ++ os.unlink(file) ++ if os.path.exists(dir): ++ os.rmdir(dir) ++ except OSError: ++ pass ++ ++ # Step 5: make sure default response has no additional plugins ++ response = self.send_request(method='GET') ++ assert_equal(response.status, 200) ++ response_data = response.read().decode(encoding='utf-8') ++ assert_equal(response_data, empty_response) +-- +2.29.2 + diff --git a/SOURCES/0025-ipatests-support-subordinate-upn-suffixes_rhbz#1914823.patch b/SOURCES/0025-ipatests-support-subordinate-upn-suffixes_rhbz#1914823.patch new file mode 100644 index 0000000..1ffa594 --- /dev/null +++ b/SOURCES/0025-ipatests-support-subordinate-upn-suffixes_rhbz#1914823.patch @@ -0,0 +1,76 @@ +From d5cca835d5439331c05475d0ad2f993ac6f8b615 Mon Sep 17 00:00:00 2001 +From: Sudhir Menon +Date: Wed, 11 Nov 2020 14:55:32 +0530 +Subject: [PATCH] ipatests: support subordinate upn suffixes + +This test adds new UPN Suffix on the AD side +within the ad.test subtree i.e new.ad.test and this +UPN is then assigned to aduser and then try to +kinit using aduser along with the UPN set, to ensure +that the kinit succeeds + +Signed-off-by: Sudhir Menon +Reviewed-By: Alexander Bokovoy +--- + ipatests/test_integration/test_trust.py | 45 +++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py +index 7e4dbcc6e..31349ced7 100644 +--- a/ipatests/test_integration/test_trust.py ++++ b/ipatests/test_integration/test_trust.py +@@ -245,6 +245,51 @@ class TestTrust(BaseTestTrust): + self.master.run_command(['kinit', '-C', '-E', self.upn_principal], + stdin_text=self.upn_password) + ++ def test_subordinate_suffix(self): ++ """Test subordinate UPN Suffixes""" ++ tasks.configure_dns_for_trust(self.master, self.ad) ++ tasks.establish_trust_with_ad( ++ self.master, self.ad_domain, ++ extra_args=['--range-type', 'ipa-ad-trust']) ++ # Clear all UPN Suffixes ++ ps_cmd = "Get-ADForest | Set-ADForest -UPNSuffixes $null" ++ self.ad.run_command(["powershell", "-c", ps_cmd]) ++ result = self.master.run_command(["ipa", "trust-show", self.ad_domain]) ++ assert ( ++ "ipantadditionalsuffixes: {}".format(self.upn_suffix) ++ not in result.stdout_text ++ ) ++ # Run Get-ADForest ++ ps_cmd1 = "Get-ADForest" ++ self.ad.run_command(["powershell", "-c", ps_cmd1]) ++ # Add new UPN for AD ++ ps_cmd2 = ( ++ 'Get-ADForest | Set-ADForest -UPNSuffixes ' ++ '@{add="new.ad.test", "upn.dom"}' ++ ) ++ self.ad.run_command(["powershell", "-c", ps_cmd2]) ++ self.ad.run_command(["powershell", "-c", ps_cmd1]) ++ self.master.run_command( ++ ["ipa", "trust-fetch-domains", self.ad_domain], ++ raiseonerr=False) ++ self.master.run_command(["ipa", "trust-show", self.ad_domain]) ++ # Set UPN for the aduser ++ ps_cmd3 = ( ++ 'set-aduser -UserPrincipalName ' ++ 'Administrator@new.ad.test -Identity Administrator' ++ ) ++ self.ad.run_command(["powershell", "-c", ps_cmd3]) ++ # kinit to IPA using AD user Administrator@new.ad.test ++ result = self.master.run_command( ++ ["getent", "passwd", "Administrator@new.ad.test"] ++ ) ++ assert result.returncode == 0 ++ self.master.run_command( ++ ["kinit", "-E", "Administrator@new.ad.test"], ++ stdin_text="Secret123", ++ ) ++ tasks.kdestroy_all(self.master) ++ + def test_remove_nonposix_trust(self): + self.remove_trust(self.ad) + tasks.unconfigure_dns_for_trust(self.master, self.ad) +-- +2.29.2 + diff --git a/SOURCES/0026-ipa-kdb-support-subordinate-superior-UPN-suffixes_rhbz#1914823.patch b/SOURCES/0026-ipa-kdb-support-subordinate-superior-UPN-suffixes_rhbz#1914823.patch new file mode 100644 index 0000000..19adf2b --- /dev/null +++ b/SOURCES/0026-ipa-kdb-support-subordinate-superior-UPN-suffixes_rhbz#1914823.patch @@ -0,0 +1,114 @@ +From 1f0702bf9231a4898a2d58325fc51c71fea25047 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 23 Oct 2020 18:45:09 +0300 +Subject: [PATCH] ipa-kdb: support subordinate/superior UPN suffixes + +[MS-ADTS] 6.1.6.9.3.2 requires msDS-TrustForestTrustInfo attribute of +trusted domain information in Active Directory to conform certain rules. +One side-effect of those rules is that list of UPN suffixes reported +through the netr_DsRGetForestTrustInformation function is dynamically +filtered to deduplicate subordinate suffixes. + +It means that if list of UPN suffixes contains the following top level +names (TLNs): + + fabrikam.com + sub.fabrikam.com + +then netr_DsRGetForestTrustInformation would only return 'fabrikam.com' +as the TLN, fully filtering 'sub.fabrikam.com'. + +IPA KDB driver used exact comparison of the UPN suffixes so any +subordinate had to be specified exactly. + +Modify logic so that if exact check does not succeed, we validate a +realm to test being a subordinate of the known UPN suffixes. The +subordinate check is done by making sure UPN suffix is at the end of the +test realm and is immediately preceded with a dot. + +Because the function to check suffixes potentially called for every +Kerberos principal, precalculate and cache length for each UPN suffix at +the time we retrieve the list of them. + +Fixes: https://pagure.io/freeipa/issue/8554 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Rob Crittenden +Reviewed-By: Robbie Harwood +Reviewed-By: Rob Crittenden +Reviewed-By: Robbie Harwood +--- + daemons/ipa-kdb/ipa_kdb_mspac.c | 30 +++++++++++++++++++++++++ + daemons/ipa-kdb/ipa_kdb_mspac_private.h | 1 + + 2 files changed, 31 insertions(+) + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 29dadc183..692f542c9 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -2393,6 +2393,7 @@ void ipadb_mspac_struct_free(struct ipadb_mspac **mspac) + free((*mspac)->trusts[i].upn_suffixes[j]); + } + free((*mspac)->trusts[i].upn_suffixes); ++ free((*mspac)->trusts[i].upn_suffixes_len); + } + } + free((*mspac)->trusts); +@@ -2603,6 +2604,24 @@ krb5_error_code ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx) + } + } + ++ t[n].upn_suffixes_len = NULL; ++ if (t[n].upn_suffixes != NULL) { ++ size_t len = 0; ++ ++ for (; t[n].upn_suffixes[len] != NULL; len++); ++ ++ if (len != 0) { ++ t[n].upn_suffixes_len = calloc(n, sizeof(size_t)); ++ if (t[n].upn_suffixes_len == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ for (i = 0; i < len; i++) { ++ t[n].upn_suffixes_len[i] = strlen(t[n].upn_suffixes[i]); ++ } ++ } ++ } ++ + ret = ipadb_ldap_attr_to_strlist(lc, le, "ipaNTSIDBlacklistIncoming", + &sid_blacklist_incoming); + +@@ -2972,6 +2991,17 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + result = strncasecmp(test_realm, + ipactx->mspac->trusts[i].upn_suffixes[j], + size) == 0; ++ if (!result) { ++ /* if UPN suffix did not match exactly, find if it is ++ * superior to the test_realm, e.g. if test_realm ends ++ * with the UPN suffix prefixed with dot*/ ++ size_t len = ipactx->mspac->trusts[i].upn_suffixes_len[j]; ++ if ((size > len) && (test_realm[size - len - 1] == '.')) { ++ result = strncasecmp(test_realm + (size - len), ++ ipactx->mspac->trusts[i].upn_suffixes[j], ++ len) == 0; ++ } ++ } + if (result) + break; + } +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_private.h b/daemons/ipa-kdb/ipa_kdb_mspac_private.h +index 30382d2ee..b21aa163f 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac_private.h ++++ b/daemons/ipa-kdb/ipa_kdb_mspac_private.h +@@ -48,6 +48,7 @@ struct ipadb_adtrusts { + struct ipadb_adtrusts *parent; + char *parent_name; + char **upn_suffixes; ++ size_t *upn_suffixes_len; + }; + + int string_to_sid(const char *str, struct dom_sid *sid); +-- +2.29.2 + diff --git a/SOURCES/0027-ad-trust-accept-subordinate-domains-of-the-forest-trust-root_rhbz#1914823.patch b/SOURCES/0027-ad-trust-accept-subordinate-domains-of-the-forest-trust-root_rhbz#1914823.patch new file mode 100644 index 0000000..f8be726 --- /dev/null +++ b/SOURCES/0027-ad-trust-accept-subordinate-domains-of-the-forest-trust-root_rhbz#1914823.patch @@ -0,0 +1,57 @@ +From 6b224e57672e3f73f93bb9eddd9031e945529a1e Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Tue, 24 Nov 2020 16:03:36 +0200 +Subject: [PATCH] ad trust: accept subordinate domains of the forest trust root + +Commit 8b6d1ab854387840f7526d6d59ddc7102231957f added support for +subordinate UPN suffixes but missed the case where subordinate UPN is a +subdomain of the forest root domain and not mentioned in the UPN +suffixes list. + +Correct this situation by applying the same check to the trusted domain +name as well. + +Fixes: https://pagure.io/freeipa/issue/8554 +Signed-off-by: Alexander Bokovoy +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-kdb/ipa_kdb_mspac.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index f2bd60e11..c6ac593ca 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -2976,10 +2976,20 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + + /* Iterate through list of trusts and check if input realm belongs to any of the trust */ + for(i = 0 ; i < ipactx->mspac->num_trusts ; i++) { ++ size_t len = 0; + result = strncasecmp(test_realm, + ipactx->mspac->trusts[i].domain_name, + size) == 0; + ++ if (!result) { ++ len = strlen(ipactx->mspac->trusts[i].domain_name); ++ if ((size > len) && (test_realm[size - len - 1] == '.')) { ++ result = strncasecmp(test_realm + (size - len), ++ ipactx->mspac->trusts[i].domain_name, ++ len) == 0; ++ } ++ } ++ + if (!result && (ipactx->mspac->trusts[i].flat_name != NULL)) { + result = strncasecmp(test_realm, + ipactx->mspac->trusts[i].flat_name, +@@ -2995,7 +3005,7 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + /* if UPN suffix did not match exactly, find if it is + * superior to the test_realm, e.g. if test_realm ends + * with the UPN suffix prefixed with dot*/ +- size_t len = ipactx->mspac->trusts[i].upn_suffixes_len[j]; ++ len = ipactx->mspac->trusts[i].upn_suffixes_len[j]; + if ((size > len) && (test_realm[size - len - 1] == '.')) { + result = strncasecmp(test_realm + (size - len), + ipactx->mspac->trusts[i].upn_suffixes[j], +-- +2.29.2 + diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec index 0bd2c8f..54eed1a 100644 --- a/SPECS/ipa.spec +++ b/SPECS/ipa.spec @@ -149,7 +149,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 13%{?dist} +Release: 14%{?dist} Summary: The Identity, Policy and Audit system License: GPLv3+ @@ -185,6 +185,12 @@ Patch0018: 0018-dogtaginstance.py-add-debug-to-pkispawn_rhbz#1879604.patch Patch0019: 0019-SELinux-add-dedicated-policy-for-ipa-pki-retrieve-key-ipatests-enhance-TestSubCAkeyReplication_rhbz#1870202.patch Patch0020: 0020-SELinux-do-not-double-define-node_t-and-pki_tomcat_c_rhbz#1870202.patch Patch0021: 0021-Fix-nsslapd-db-lock-tuning-of-BDB-backend_rhbz#1882472.patch +Patch0022: 0022-rpcserver-fallback-to-non-armored-kinit-in-case-of-trusted-domains_rhbz#1914821.patch +Patch0023: 0023-pylint-remove-unused-variable_rhbz#1914821.patch +Patch0024: 0024-wgi-plugins.py-ignore-empty-plugin-directories_rhbz#1895910.patch +Patch0025: 0025-ipatests-support-subordinate-upn-suffixes_rhbz#1914823.patch +Patch0026: 0026-ipa-kdb-support-subordinate-superior-UPN-suffixes_rhbz#1914823.patch +Patch0027: 0027-ad-trust-accept-subordinate-domains-of-the-forest-trust-root_rhbz#1914823.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 @@ -862,7 +868,6 @@ export PATH=/usr/bin:/usr/sbin:$PATH export PYTHON=%{__python3} %configure --with-vendor-suffix=-%{release} \ - --with-ipaplatform=rhel \ %{enable_server_option} \ %{with_ipatests_option} \ %{linter_options} @@ -1536,6 +1541,20 @@ fi %changelog +* Tue Jan 12 2021 Rafael Jeffman - 4.8.7-14 +- wgi/plugins.py: ignore empty plugin directories + Resolves: RHBZ#1895910 +- rpcserver: fallback to non-armored kinit in case of trusted domains + Resolves: RHBZ#1914821 +- pylint: remove unused variable + Resolves: RHBZ#1914821 +- ipa-kdb: support subordinate/superior UPN suffixes + Resolves: RHBZ#1914823 +- ad trust: accept subordinate domains of the forest trust root + Resolves: RHBZ#1914823 +- ipatests: support subordinate upn suffixes + Resolves: RHBZ#1914823 + * Thu Oct 08 2020 Thomas Woerner - 4.8.7-13 - Fix nsslapd-db-lock tuning of BDB backend Resolves: RHBZ#1882472