import ipa-4.8.7-14.module+el8.3.0+9419+8502777d
This commit is contained in:
parent
615535485a
commit
6e41b73a3b
@ -0,0 +1,236 @@
|
|||||||
|
From 1441b999d3fe9b4e59fe942294d13480ecee7d94 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
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 <abokovoy@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,27 @@
|
|||||||
|
From 12de9ee69f12f7c0021ea98e9c1163db7d59e5d3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
Date: Wed, 28 Oct 2020 19:37:11 +0200
|
||||||
|
Subject: [PATCH] pylint: remove unused variable
|
||||||
|
|
||||||
|
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,121 @@
|
|||||||
|
From 29262465edf034d521c165e3854e28835d86b98d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
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 <abokovoy@redhat.com>
|
||||||
|
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,76 @@
|
|||||||
|
From d5cca835d5439331c05475d0ad2f993ac6f8b615 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudhir Menon <sumenon@redhat.com>
|
||||||
|
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 <sumenon@redhat.com>
|
||||||
|
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,114 @@
|
|||||||
|
From 1f0702bf9231a4898a2d58325fc51c71fea25047 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
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 <abokovoy@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Reviewed-By: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Reviewed-By: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,57 @@
|
|||||||
|
From 6b224e57672e3f73f93bb9eddd9031e945529a1e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
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 <abokovoy@redhat.com>
|
||||||
|
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -149,7 +149,7 @@
|
|||||||
|
|
||||||
Name: %{package_name}
|
Name: %{package_name}
|
||||||
Version: %{IPA_VERSION}
|
Version: %{IPA_VERSION}
|
||||||
Release: 13%{?dist}
|
Release: 14%{?dist}
|
||||||
Summary: The Identity, Policy and Audit system
|
Summary: The Identity, Policy and Audit system
|
||||||
|
|
||||||
License: GPLv3+
|
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
|
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
|
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
|
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
|
Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch
|
||||||
Patch1002: 1002-4.8.0-Remove-csrgen.patch
|
Patch1002: 1002-4.8.0-Remove-csrgen.patch
|
||||||
Patch1003: 1003-Revert-WebUI-use-python3-rjsmin-to-minify-JavaScript.patch
|
Patch1003: 1003-Revert-WebUI-use-python3-rjsmin-to-minify-JavaScript.patch
|
||||||
@ -1535,6 +1541,20 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Jan 12 2021 Rafael Jeffman <rjeffman@redhat.com> - 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 <twoerner@redhat.com> - 4.8.7-13
|
* Thu Oct 08 2020 Thomas Woerner <twoerner@redhat.com> - 4.8.7-13
|
||||||
- Fix nsslapd-db-lock tuning of BDB backend
|
- Fix nsslapd-db-lock tuning of BDB backend
|
||||||
Resolves: RHBZ#1882472
|
Resolves: RHBZ#1882472
|
||||||
|
Loading…
Reference in New Issue
Block a user