Compare commits
6 Commits
c8-stream-
...
changed/a8
Author | SHA1 | Date |
---|---|---|
eabdullin | e82ab6efc0 | |
eabdullin | 697efbdf54 | |
eabdullin | dcaff175fe | |
eabdullin | 6d235cb833 | |
Andrew Lukoshko | e4d8b700db | |
Andrew Lukoshko | 0b2668538c |
|
@ -0,0 +1,71 @@
|
|||
From a8d81b5005ea15a35d0d63330b922037de3ca253 Mon Sep 17 00:00:00 2001
|
||||
From: David Sloboda <david.x.sloboda@oracle.com>
|
||||
Date: Fri, 30 Jun 2023 15:37:34 +0200
|
||||
Subject: [PATCH] OLERRATA-43634 - Support for PAC extended KDC signature
|
||||
|
||||
In November 2022, Microsoft introduced a new PAC signature type called
|
||||
"extended KDC signature" (or "full PAC checksum"). This new PAC
|
||||
signature will be required by default by Active Directory in July 2023
|
||||
for S4U requests, and opt-out will no longer be possible after October
|
||||
2023.
|
||||
|
||||
Support for this new signature type was added to MIT krb5, but it relies
|
||||
on the new KDB API introduced in krb5 1.20. For older MIT krb5 versions,
|
||||
the code generating extended KDC signatures cannot be backported as it
|
||||
is without backporting the full new KDB API code too. This would have
|
||||
too much impact to be done.
|
||||
|
||||
As a consequence, krb5 packages for Fedora 37, CentOS 8 Stream, and RHEL
|
||||
8 will include a downstream-only update adding the
|
||||
krb5_pac_full_sign_compat() function, which can be used in combination
|
||||
with the prior to 1.20 KDB API to generate PAC extended KDC signatures.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9373
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Signed-off-by: David Sloboda <david.x.sloboda@oracle.com>
|
||||
---
|
||||
diff -Nuar freeipa-4.9.11.orig/daemons/ipa-kdb/ipa_kdb_mspac_v6.c freeipa-4.9.11/daemons/ipa-kdb/ipa_kdb_mspac_v6.c
|
||||
--- freeipa-4.9.11.orig/daemons/ipa-kdb/ipa_kdb_mspac_v6.c 2022-11-25 17:16:11.352773047 +0100
|
||||
+++ freeipa-4.9.11/daemons/ipa-kdb/ipa_kdb_mspac_v6.c 2023-06-30 14:58:17.198538781 +0200
|
||||
@@ -176,11 +176,21 @@
|
||||
|
||||
/* 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 -Nuar freeipa-4.9.11.orig/server.m4 freeipa-4.9.11/server.m4
|
||||
--- freeipa-4.9.11.orig/server.m4 2022-11-25 17:16:11.353773052 +0100
|
||||
+++ freeipa-4.9.11/server.m4 2023-06-30 14:59:52.845995040 +0200
|
||||
@@ -91,6 +91,15 @@
|
||||
[have_kdb_issue_pac=no], [#include <kdb.h>])
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
+dnl - Check for KRB5 krb5_kdc_sign_ticket function
|
||||
+dnl ---------------------------------------------------------------------------
|
||||
+
|
||||
+AC_CHECK_LIB(krb5, krb5_pac_full_sign_compat,
|
||||
+ [AC_DEFINE([HAVE_KRB5_PAC_FULL_SIGN_COMPAT], [1],
|
||||
+ [krb5_pac_full_sign_compat() is available.])],
|
||||
+ [AC_MSG_NOTICE([krb5_pac_full_sign_compat() is not available])])
|
||||
+
|
||||
+dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for UUID library
|
||||
dnl ---------------------------------------------------------------------------
|
||||
PKG_CHECK_MODULES([UUID], [uuid])
|
|
@ -0,0 +1,85 @@
|
|||
From c84c59c66f1b22ebc671960cae90088a024d2d62 Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Aug 01 2023 11:31:09 +0000
|
||||
Subject: ipa-kdb: fix error handling of is_master_host()
|
||||
|
||||
|
||||
Adding proper error handling to the is_master_host() function to allow
|
||||
it to make the difference between the absence of a master host object
|
||||
and a connection failure. This will keep the krb5kdc daemon from
|
||||
continuing to run with a NULL LDAP context.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9422
|
||||
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index 83b507c..1558e2b 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -401,27 +401,29 @@ static krb5_error_code ipadb_add_asserted_identity(struct ipadb_context *ipactx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static bool is_master_host(struct ipadb_context *ipactx, const char *fqdn)
|
||||
+static krb5_error_code
|
||||
+is_master_host(struct ipadb_context *ipactx, const char *fqdn, bool *result)
|
||||
{
|
||||
- int ret;
|
||||
+ int err;
|
||||
char *master_host_base = NULL;
|
||||
- LDAPMessage *result = NULL;
|
||||
- krb5_error_code err;
|
||||
+ LDAPMessage *ldap_res = NULL;
|
||||
|
||||
- ret = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s",
|
||||
+ err = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s",
|
||||
fqdn, ipactx->base);
|
||||
- if (ret == -1) {
|
||||
- return false;
|
||||
- }
|
||||
+ if (err == -1)
|
||||
+ return ENOMEM;
|
||||
+
|
||||
err = ipadb_simple_search(ipactx, master_host_base, LDAP_SCOPE_BASE,
|
||||
- NULL, NULL, &result);
|
||||
+ NULL, NULL, &ldap_res);
|
||||
free(master_host_base);
|
||||
- ldap_msgfree(result);
|
||||
- if (err == 0) {
|
||||
- return true;
|
||||
- }
|
||||
+ ldap_msgfree(ldap_res);
|
||||
+ if (err != KRB5_KDB_NOENTRY && err != 0)
|
||||
+ return err;
|
||||
+
|
||||
+ if (result)
|
||||
+ *result = err != KRB5_KDB_NOENTRY;
|
||||
|
||||
- return false;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
@@ -692,9 +694,14 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
if ((is_host || is_service)) {
|
||||
/* it is either host or service, so get the hostname first */
|
||||
char *sep = strchr(info3->base.account_name.string, '/');
|
||||
- bool is_master = is_master_host(
|
||||
- ipactx,
|
||||
- sep ? sep + 1 : info3->base.account_name.string);
|
||||
+ bool is_master;
|
||||
+
|
||||
+ ret = is_master_host(ipactx,
|
||||
+ sep ? sep + 1 : info3->base.account_name.string,
|
||||
+ &is_master);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
if (is_master) {
|
||||
/* Well known RID of domain controllers group */
|
||||
if (info3->base.rid == 0) {
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
From d394afc1210a21378c018d0ff93d400a57324289 Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Mon, 25 Sep 2023 15:14:03 +0200
|
||||
Subject: [PATCH] ipa-kdb: Make AD-SIGNEDPATH optional with krb5 DAL 8 and
|
||||
older
|
||||
|
||||
Since krb5 1.20, the PAC is generated by default, and the AD-SIGNEDPATH
|
||||
authdata is no longer generated. However, on krb5 versions prior to
|
||||
1.20, the KDC still expects an AD-SIGNEDPATH when verifying a
|
||||
constrained delegation (S4U2Proxy) TGS-REQ. In IPA's case this
|
||||
requirement is not needed, because the PAC signatures are already
|
||||
fulfilling this role.
|
||||
|
||||
CentOS and RHEL downstream releases of krb5 will include the
|
||||
"optional_ad_signedpath" KDB string attribute allowing to disable the
|
||||
AD-SIGNEDPATH requirement in case the PAC is present.
|
||||
|
||||
This commit sets the "optional_ad_signedpath" string attribute to "true"
|
||||
systematically on the TGS principal if the database abstract layer (DAL)
|
||||
of krb5 is version 8 or older (prior to krb5 1.20).
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9448
|
||||
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb_principals.c | 38 ++++++++++++++++++++++++++--
|
||||
1 file changed, 36 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
index e95cb453c..fadb132ed 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
@@ -113,6 +113,10 @@ static char *std_principal_obj_classes[] = {
|
||||
|
||||
#define DEFAULT_TL_DATA_CONTENT "\x00\x00\x00\x00principal@UNINITIALIZED"
|
||||
|
||||
+#ifndef KRB5_KDB_SK_OPTIONAL_AD_SIGNEDPATH
|
||||
+#define KRB5_KDB_SK_OPTIONAL_AD_SIGNEDPATH "optional_ad_signedpath"
|
||||
+#endif
|
||||
+
|
||||
static int ipadb_ldap_attr_to_tl_data(LDAP *lcontext, LDAPMessage *le,
|
||||
char *attrname,
|
||||
krb5_tl_data **result, int *num)
|
||||
@@ -178,6 +182,25 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+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 ipadb_set_tl_data(krb5_db_entry *entry,
|
||||
krb5_int16 type,
|
||||
krb5_ui_2 length,
|
||||
@@ -1647,11 +1670,22 @@ 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 KRB5_KDB_DAL_MAJOR_VERSION <= 8
|
||||
+ /* If TGS principal, some virtual attributes may be added */
|
||||
+ if (is_tgs_princ(kcontext, (*entry)->princ)) {
|
||||
+ kerr = krb5_dbe_set_string(kcontext, *entry,
|
||||
+ KRB5_KDB_SK_OPTIONAL_AD_SIGNEDPATH,
|
||||
+ "true");
|
||||
}
|
||||
+#endif
|
||||
|
||||
- return dbget_alias(kcontext, ipactx, search_for, flags, entry);
|
||||
+ return kerr;
|
||||
}
|
||||
|
||||
void ipadb_free_principal_e_data(krb5_context kcontext, krb5_octet *e_data)
|
||||
--
|
||||
2.41.0
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
From 13778d88ca2ac73b729821bdea844172a18c0cb9 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Fri, 6 Oct 2023 20:16:29 +0000
|
||||
Subject: [PATCH] Check the HTTP Referer header on all requests
|
||||
|
||||
The referer was only checked in WSGIExecutioner classes:
|
||||
|
||||
- jsonserver
|
||||
- KerberosWSGIExecutioner
|
||||
- xmlserver
|
||||
- jsonserver_kerb
|
||||
|
||||
This left /i18n_messages, /session/login_kerberos,
|
||||
/session/login_x509, /session/login_password,
|
||||
/session/change_password and /session/sync_token unprotected
|
||||
against CSRF attacks.
|
||||
|
||||
CVE-2023-5455
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaserver/rpcserver.py | 34 +++++++++++++++++++++++++++++++---
|
||||
1 file changed, 31 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
|
||||
index b7116469d73..198fc9e7dba 100644
|
||||
--- a/ipaserver/rpcserver.py
|
||||
+++ b/ipaserver/rpcserver.py
|
||||
@@ -156,6 +156,19 @@ _success_template = """<html>
|
||||
</html>"""
|
||||
|
||||
class HTTP_Status(plugable.Plugin):
|
||||
+ def check_referer(self, environ):
|
||||
+ if "HTTP_REFERER" not in environ:
|
||||
+ logger.error("Rejecting request with missing Referer")
|
||||
+ return False
|
||||
+ if (not environ["HTTP_REFERER"].startswith(
|
||||
+ "https://%s/ipa" % self.api.env.host)
|
||||
+ and not self.env.in_tree):
|
||||
+ logger.error("Rejecting request with bad Referer %s",
|
||||
+ environ["HTTP_REFERER"])
|
||||
+ return False
|
||||
+ logger.debug("Valid Referer %s", environ["HTTP_REFERER"])
|
||||
+ return True
|
||||
+
|
||||
def not_found(self, environ, start_response, url, message):
|
||||
"""
|
||||
Return a 404 Not Found error.
|
||||
@@ -331,9 +344,6 @@ class wsgi_dispatch(Executioner, HTTP_Status):
|
||||
self.__apps[key] = app
|
||||
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
class WSGIExecutioner(Executioner):
|
||||
"""
|
||||
Base class for execution backends with a WSGI application interface.
|
||||
@@ -897,6 +907,9 @@ class jsonserver_session(jsonserver, KerberosSession):
|
||||
|
||||
logger.debug('WSGI jsonserver_session.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
# Redirect to login if no Kerberos credentials
|
||||
ccache_name = self.get_environ_creds(environ)
|
||||
if ccache_name is None:
|
||||
@@ -949,6 +962,9 @@ class KerberosLogin(Backend, KerberosSession):
|
||||
def __call__(self, environ, start_response):
|
||||
logger.debug('WSGI KerberosLogin.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
# Redirect to login if no Kerberos credentials
|
||||
user_ccache_name = self.get_environ_creds(environ)
|
||||
if user_ccache_name is None:
|
||||
@@ -967,6 +983,9 @@ class login_x509(KerberosLogin):
|
||||
def __call__(self, environ, start_response):
|
||||
logger.debug('WSGI login_x509.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
if 'KRB5CCNAME' not in environ:
|
||||
return self.unauthorized(
|
||||
environ, start_response, 'KRB5CCNAME not set',
|
||||
@@ -1015,6 +1034,9 @@ class login_password(Backend, KerberosSession):
|
||||
|
||||
logger.debug('WSGI login_password.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
# Get the user and password parameters from the request
|
||||
content_type = environ.get('CONTENT_TYPE', '').lower()
|
||||
if not content_type.startswith('application/x-www-form-urlencoded'):
|
||||
@@ -1147,6 +1169,9 @@ class change_password(Backend, HTTP_Status):
|
||||
def __call__(self, environ, start_response):
|
||||
logger.info('WSGI change_password.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
# Get the user and password parameters from the request
|
||||
content_type = environ.get('CONTENT_TYPE', '').lower()
|
||||
if not content_type.startswith('application/x-www-form-urlencoded'):
|
||||
@@ -1364,6 +1389,9 @@ class xmlserver_session(xmlserver, KerberosSession):
|
||||
|
||||
logger.debug('WSGI xmlserver_session.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
ccache_name = environ.get('KRB5CCNAME')
|
||||
|
||||
# Redirect to /ipa/xml if no Kerberos credentials
|
|
@ -0,0 +1,262 @@
|
|||
From a847e2483b4c4832ee5129901da169f4eb0d1392 Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Mon, 9 Oct 2023 15:47:03 +0200
|
||||
Subject: [PATCH] ipa-kdb: Detect and block Bronze-Bit attacks
|
||||
|
||||
The C8S/RHEL8 version of FreeIPA is vulnerable to the Bronze-Bit attack
|
||||
because it does not implement PAC ticket signature to protect the
|
||||
"forwardable" flag. However, it does implement the PAC extended KDC
|
||||
signature, which protects against PAC spoofing.
|
||||
|
||||
Based on information available in the PAC and the
|
||||
"ok-to-auth-as-delegate" attribute in the database. It is possible to
|
||||
detect and reject requests where the "forwardable" flag was flipped by
|
||||
the attacker in the evidence ticket.
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb.h | 13 +++
|
||||
daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 6 +
|
||||
daemons/ipa-kdb/ipa_kdb_mspac.c | 173 ++++++++++++++++++++++++++++
|
||||
ipaserver/install/server/install.py | 8 ++
|
||||
4 files changed, 200 insertions(+)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
||||
index 7aa5be4948e..02b2cb6313e 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.h
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.h
|
||||
@@ -367,6 +367,19 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
const char *test_realm, size_t size,
|
||||
char **trusted_realm);
|
||||
|
||||
+/* Try to detect a Bronze-Bit attack based on the content of the request and
|
||||
+ * data from the KDB.
|
||||
+ *
|
||||
+ * context krb5 context
|
||||
+ * request KDB request
|
||||
+ * detected Set to "true" if a bronze bit attack is detected and the
|
||||
+ * pointer is not NULL. Remains unset otherwise.
|
||||
+ * status If the call fails and the pointer is not NULL, set it with a
|
||||
+ * message describing the cause of the failure. */
|
||||
+krb5_error_code
|
||||
+ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
+ bool *detected, const char **status);
|
||||
+
|
||||
/* DELEGATION CHECKS */
|
||||
|
||||
krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
index f2804c9b23a..1032dff0b5c 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
@@ -185,6 +185,12 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
||||
const char **status, krb5_deltat *lifetime_out,
|
||||
krb5_deltat *renew_lifetime_out)
|
||||
{
|
||||
+ krb5_error_code kerr;
|
||||
+
|
||||
+ kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status);
|
||||
+ if (kerr)
|
||||
+ return KRB5KDC_ERR_POLICY;
|
||||
+
|
||||
*status = NULL;
|
||||
*lifetime_out = 0;
|
||||
*renew_lifetime_out = 0;
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index 83cb9914d23..b4e22d4316a 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -3298,3 +3298,176 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
|
||||
return KRB5_KDB_NOENTRY;
|
||||
}
|
||||
+
|
||||
+krb5_error_code
|
||||
+ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
+ bool *detected, const char **status)
|
||||
+{
|
||||
+ krb5_error_code kerr;
|
||||
+ const char *st = NULL;
|
||||
+ size_t i, j;
|
||||
+ krb5_ticket *evidence_tkt;
|
||||
+ krb5_authdata **authdata, **ifrel = NULL;
|
||||
+ krb5_pac pac = NULL;
|
||||
+ TALLOC_CTX *tmpctx = NULL;
|
||||
+ krb5_data fullsign = { 0, 0, NULL }, linfo_blob = { 0, 0, NULL };
|
||||
+ DATA_BLOB linfo_data;
|
||||
+ struct PAC_LOGON_INFO_CTR linfo;
|
||||
+ enum ndr_err_code ndr_err;
|
||||
+ struct dom_sid asserted_identity_sid;
|
||||
+ bool evtkt_is_s4u2self = false;
|
||||
+ krb5_db_entry *proxy_entry = NULL;
|
||||
+
|
||||
+ /* If no additional ticket, this is not a constrained delegateion request.
|
||||
+ * Skip checks. */
|
||||
+ if (!(request->kdc_options & KDC_OPT_CNAME_IN_ADDL_TKT)) {
|
||||
+ kerr = 0;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ evidence_tkt = request->second_ticket[0];
|
||||
+
|
||||
+ /* No need to check the Forwardable flag. If it was not set, this request
|
||||
+ * would have failed earlier. */
|
||||
+
|
||||
+ /* We only support general constrained delegation (not RBCD), which is not
|
||||
+ * available for cross-realms. */
|
||||
+ if (!krb5_realm_compare(context, evidence_tkt->server, request->server)) {
|
||||
+ st = "S4U2PROXY_NOT_SUPPORTED_FOR_CROSS_REALMS";
|
||||
+ kerr = ENOTSUP;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ authdata = evidence_tkt->enc_part2->authorization_data;
|
||||
+
|
||||
+ /* Search for the PAC. */
|
||||
+ for (i = 0; authdata != NULL && authdata[i] != NULL; i++) {
|
||||
+ if (authdata[i]->ad_type != KRB5_AUTHDATA_IF_RELEVANT)
|
||||
+ continue;
|
||||
+
|
||||
+ kerr = krb5_decode_authdata_container(context,
|
||||
+ KRB5_AUTHDATA_IF_RELEVANT,
|
||||
+ authdata[i], &ifrel);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_CANNOT_DECODE_EVIDENCE_TKT_AUTHDATA";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; ifrel[j] != NULL; j++) {
|
||||
+ if (ifrel[j]->ad_type == KRB5_AUTHDATA_WIN2K_PAC)
|
||||
+ break;
|
||||
+ }
|
||||
+ if (ifrel[j] != NULL)
|
||||
+ break;
|
||||
+
|
||||
+ krb5_free_authdata(context, ifrel);
|
||||
+ ifrel = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (ifrel == NULL) {
|
||||
+ st = "S4U2PROXY_EVIDENCE_TKT_WITHOUT_PAC";
|
||||
+ kerr = ENOENT;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Parse the PAC. */
|
||||
+ kerr = krb5_pac_parse(context, ifrel[j]->contents, ifrel[j]->length, &pac);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_CANNOT_DECODE_EVICENCE_TKT_PAC";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Check that the PAC extanded KDC signature is present. If it is, it was
|
||||
+ * already tested.
|
||||
+ * If absent, the context of the PAC cannot be trusted. */
|
||||
+ kerr = krb5_pac_get_buffer(context, pac, KRB5_PAC_FULL_CHECKSUM, &fullsign);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_MISSING_EXTENDED_KDC_SIGN_IN_EVIDENCE_TKT_PAC";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Get the PAC Logon Info. */
|
||||
+ kerr = krb5_pac_get_buffer(context, pac, KRB5_PAC_LOGON_INFO, &linfo_blob);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_NO_PAC_LOGON_INFO_IN_EVIDENCE_TKT";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Parse the PAC Logon Info. */
|
||||
+ tmpctx = talloc_new(NULL);
|
||||
+ if (!tmpctx) {
|
||||
+ st = "OUT_OF_MEMORY";
|
||||
+ kerr = ENOMEM;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ linfo_data.length = linfo_blob.length;
|
||||
+ linfo_data.data = (uint8_t *)linfo_blob.data;
|
||||
+ ndr_err = ndr_pull_union_blob(&linfo_data, tmpctx, &linfo,
|
||||
+ PAC_TYPE_LOGON_INFO,
|
||||
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
|
||||
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
+ st = "S4U2PROXY_CANNOT_PARSE_ENVIDENCE_TKT_PAC_LOGON_INFO";
|
||||
+ kerr = EINVAL;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Check that the extra SIDs array is not empty. */
|
||||
+ if (linfo.info->info3.sidcount == 0) {
|
||||
+ st = "S4U2PROXY_NO_EXTRA_SID";
|
||||
+ kerr = ENOENT;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Search for the S-1-18-2 domain SID, which indicates the ticket was
|
||||
+ * obtained using S4U2Self */
|
||||
+ kerr = ipadb_string_to_sid("S-1-18-2", &asserted_identity_sid);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_CANNOT_CREATE_ASSERTED_IDENTITY_SID";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < linfo.info->info3.sidcount; i++) {
|
||||
+ if (dom_sid_check(&asserted_identity_sid,
|
||||
+ linfo.info->info3.sids[0].sid, true)) {
|
||||
+ evtkt_is_s4u2self = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If the ticket was obtained using S4U2Self, the proxy principal entry must
|
||||
+ * have the "ok_to_auth_as_delegate" attribute set to true. */
|
||||
+ if (evtkt_is_s4u2self) {
|
||||
+ kerr = ipadb_get_principal(context, evidence_tkt->server, 0,
|
||||
+ &proxy_entry);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_CANNOT_FIND_PROXY_PRINCIPAL";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ if (!(proxy_entry->attributes & KRB5_KDB_OK_TO_AUTH_AS_DELEGATE)) {
|
||||
+ /* This evidence ticket cannot be forwardable given the privileges
|
||||
+ * of the proxy principal.
|
||||
+ * This is a Bronze Bit attack. */
|
||||
+ if (detected)
|
||||
+ *detected = true;
|
||||
+ st = "S4U2PROXY_BRONZE_BIT_ATTACK_DETECTED";
|
||||
+ kerr = EBADE;
|
||||
+ goto end;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ kerr = 0;
|
||||
+
|
||||
+end:
|
||||
+ if (st && status)
|
||||
+ *status = st;
|
||||
+
|
||||
+ krb5_free_authdata(context, ifrel);
|
||||
+ krb5_pac_free(context, pac);
|
||||
+ krb5_free_data_contents(context, &linfo_blob);
|
||||
+ krb5_free_data_contents(context, &fullsign);
|
||||
+ talloc_free(tmpctx);
|
||||
+ ipadb_free_principal(context, proxy_entry);
|
||||
+ return kerr;
|
||||
+}
|
||||
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
|
||||
index 4e4076410f1..bfbb83bcbfa 100644
|
||||
--- a/ipaserver/install/server/install.py
|
||||
+++ b/ipaserver/install/server/install.py
|
||||
@@ -978,6 +978,14 @@ def install(installer):
|
||||
# Set the admin user kerberos password
|
||||
ds.change_admin_password(admin_password)
|
||||
|
||||
+ # Force KDC to refresh the cached value of ipaKrbAuthzData by restarting.
|
||||
+ # ipaKrbAuthzData has to be set with "MS-PAC" to trigger PAC generation,
|
||||
+ # which is required to handle S4U2Proxy with the Bronze-Bit fix.
|
||||
+ # Not doing so would cause API malfunction for around a minute, which is
|
||||
+ # long enough to cause the hereafter client installation to fail.
|
||||
+ service.print_msg("Restarting the KDC")
|
||||
+ krb.restart()
|
||||
+
|
||||
# Call client install script
|
||||
service.print_msg("Configuring client side components")
|
||||
try:
|
|
@ -0,0 +1,356 @@
|
|||
From 86b073a7f03ba0edf4dd91f85b96c89107e9e673 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Thu, 12 Oct 2023 20:34:01 +0000
|
||||
Subject: [PATCH] Integration tests for verifying Referer header in the UI
|
||||
|
||||
Validate that the change_password and login_password endpoints
|
||||
verify the HTTP Referer header. There is some overlap in the
|
||||
tests: belt and suspenders.
|
||||
|
||||
All endpoints except session/login_x509 are covered, sometimes
|
||||
having to rely on expected bad results (see the i18n endpoint).
|
||||
|
||||
session/login_x509 is not tested yet as it requires significant
|
||||
additional setup in order to associate a user certificate with
|
||||
a user entry, etc.
|
||||
|
||||
This can be manually verified by modifying /etc/httpd/conf.d/ipa.conf
|
||||
and adding:
|
||||
|
||||
Satisfy Any
|
||||
Require all granted
|
||||
|
||||
Then comment out Auth and SSLVerify, etc. and restart httpd.
|
||||
|
||||
With a valid Referer will fail with a 401 and log that there is no
|
||||
KRB5CCNAME. This comes after the referer check.
|
||||
|
||||
With an invalid Referer it will fail with a 400 Bad Request as
|
||||
expected.
|
||||
|
||||
CVE-2023-5455
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_ipaserver/httptest.py | 7 +-
|
||||
ipatests/test_ipaserver/test_changepw.py | 12 +-
|
||||
.../test_ipaserver/test_login_password.py | 88 ++++++++++++
|
||||
ipatests/test_ipaserver/test_referer.py | 136 ++++++++++++++++++
|
||||
ipatests/util.py | 4 +-
|
||||
5 files changed, 242 insertions(+), 5 deletions(-)
|
||||
create mode 100644 ipatests/test_ipaserver/test_login_password.py
|
||||
create mode 100644 ipatests/test_ipaserver/test_referer.py
|
||||
|
||||
diff --git a/ipatests/test_ipaserver/httptest.py b/ipatests/test_ipaserver/httptest.py
|
||||
index 6cd034a7196..8924798fc93 100644
|
||||
--- a/ipatests/test_ipaserver/httptest.py
|
||||
+++ b/ipatests/test_ipaserver/httptest.py
|
||||
@@ -36,7 +36,7 @@ class Unauthorized_HTTP_test:
|
||||
content_type = 'application/x-www-form-urlencoded'
|
||||
accept_language = 'en-us'
|
||||
|
||||
- def send_request(self, method='POST', params=None):
|
||||
+ def send_request(self, method='POST', params=None, host=None):
|
||||
"""
|
||||
Send a request to HTTP server
|
||||
|
||||
@@ -45,7 +45,10 @@ class Unauthorized_HTTP_test:
|
||||
if params is not None:
|
||||
if self.content_type == 'application/x-www-form-urlencoded':
|
||||
params = urllib.parse.urlencode(params, True)
|
||||
- url = 'https://' + self.host + self.app_uri
|
||||
+ if host:
|
||||
+ url = 'https://' + host + self.app_uri
|
||||
+ else:
|
||||
+ url = 'https://' + self.host + self.app_uri
|
||||
|
||||
headers = {'Content-Type': self.content_type,
|
||||
'Accept-Language': self.accept_language,
|
||||
diff --git a/ipatests/test_ipaserver/test_changepw.py b/ipatests/test_ipaserver/test_changepw.py
|
||||
index c3a47ab265f..df38ddb3d9e 100644
|
||||
--- a/ipatests/test_ipaserver/test_changepw.py
|
||||
+++ b/ipatests/test_ipaserver/test_changepw.py
|
||||
@@ -53,10 +53,11 @@ class test_changepw(XMLRPC_test, Unauthorized_HTTP_test):
|
||||
|
||||
request.addfinalizer(fin)
|
||||
|
||||
- def _changepw(self, user, old_password, new_password):
|
||||
+ def _changepw(self, user, old_password, new_password, host=None):
|
||||
return self.send_request(params={'user': str(user),
|
||||
'old_password' : str(old_password),
|
||||
'new_password' : str(new_password)},
|
||||
+ host=host
|
||||
)
|
||||
|
||||
def _checkpw(self, user, password):
|
||||
@@ -89,6 +90,15 @@ class test_changepw(XMLRPC_test, Unauthorized_HTTP_test):
|
||||
# make sure that password is NOT changed
|
||||
self._checkpw(testuser, old_password)
|
||||
|
||||
+ def test_invalid_referer(self):
|
||||
+ response = self._changepw(testuser, old_password, new_password,
|
||||
+ 'attacker.test')
|
||||
+
|
||||
+ assert_equal(response.status, 400)
|
||||
+
|
||||
+ # make sure that password is NOT changed
|
||||
+ self._checkpw(testuser, old_password)
|
||||
+
|
||||
def test_pwpolicy_error(self):
|
||||
response = self._changepw(testuser, old_password, '1')
|
||||
|
||||
diff --git a/ipatests/test_ipaserver/test_login_password.py b/ipatests/test_ipaserver/test_login_password.py
|
||||
new file mode 100644
|
||||
index 00000000000..9425cb7977f
|
||||
--- /dev/null
|
||||
+++ b/ipatests/test_ipaserver/test_login_password.py
|
||||
@@ -0,0 +1,88 @@
|
||||
+# Copyright (C) 2023 Red Hat
|
||||
+# see file 'COPYING' for use and warranty information
|
||||
+#
|
||||
+# This program is free software; you can redistribute it and/or modify
|
||||
+# it under the terms of the GNU General Public License as published by
|
||||
+# the Free Software Foundation, either version 3 of the License, or
|
||||
+# (at your option) any later version.
|
||||
+#
|
||||
+# This program is distributed in the hope that it will be useful,
|
||||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+# GNU General Public License for more details.
|
||||
+#
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+import os
|
||||
+import pytest
|
||||
+import uuid
|
||||
+
|
||||
+from ipatests.test_ipaserver.httptest import Unauthorized_HTTP_test
|
||||
+from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test
|
||||
+from ipatests.util import assert_equal
|
||||
+from ipalib import api, errors
|
||||
+from ipapython.ipautil import run
|
||||
+
|
||||
+testuser = u'tuser'
|
||||
+password = u'password'
|
||||
+
|
||||
+
|
||||
+@pytest.mark.tier1
|
||||
+class test_login_password(XMLRPC_test, Unauthorized_HTTP_test):
|
||||
+ app_uri = '/ipa/session/login_password'
|
||||
+
|
||||
+ @pytest.fixture(autouse=True)
|
||||
+ def login_setup(self, request):
|
||||
+ ccache = os.path.join('/tmp', str(uuid.uuid4()))
|
||||
+ try:
|
||||
+ api.Command['user_add'](uid=testuser, givenname=u'Test', sn=u'User')
|
||||
+ api.Command['passwd'](testuser, password=password)
|
||||
+ run(['kinit', testuser], stdin='{0}\n{0}\n{0}\n'.format(password),
|
||||
+ env={"KRB5CCNAME": ccache})
|
||||
+ except errors.ExecutionError as e:
|
||||
+ pytest.skip(
|
||||
+ 'Cannot set up test user: %s' % e
|
||||
+ )
|
||||
+
|
||||
+ def fin():
|
||||
+ try:
|
||||
+ api.Command['user_del']([testuser])
|
||||
+ except errors.NotFound:
|
||||
+ pass
|
||||
+ os.unlink(ccache)
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ def _login(self, user, password, host=None):
|
||||
+ return self.send_request(params={'user': str(user),
|
||||
+ 'password' : str(password)},
|
||||
+ host=host)
|
||||
+
|
||||
+ def test_bad_options(self):
|
||||
+ for params in (
|
||||
+ None, # no params
|
||||
+ {"user": "foo"}, # missing options
|
||||
+ {"user": "foo", "password": ""}, # empty option
|
||||
+ ):
|
||||
+ response = self.send_request(params=params)
|
||||
+ assert_equal(response.status, 400)
|
||||
+ assert_equal(response.reason, 'Bad Request')
|
||||
+
|
||||
+ def test_invalid_auth(self):
|
||||
+ response = self._login(testuser, 'wrongpassword')
|
||||
+
|
||||
+ assert_equal(response.status, 401)
|
||||
+ assert_equal(response.getheader('X-IPA-Rejection-Reason'),
|
||||
+ 'invalid-password')
|
||||
+
|
||||
+ def test_invalid_referer(self):
|
||||
+ response = self._login(testuser, password, 'attacker.test')
|
||||
+
|
||||
+ assert_equal(response.status, 400)
|
||||
+
|
||||
+ def test_success(self):
|
||||
+ response = self._login(testuser, password)
|
||||
+
|
||||
+ assert_equal(response.status, 200)
|
||||
+ assert response.getheader('X-IPA-Rejection-Reason') is None
|
||||
diff --git a/ipatests/test_ipaserver/test_referer.py b/ipatests/test_ipaserver/test_referer.py
|
||||
new file mode 100644
|
||||
index 00000000000..4eade8bbaf3
|
||||
--- /dev/null
|
||||
+++ b/ipatests/test_ipaserver/test_referer.py
|
||||
@@ -0,0 +1,136 @@
|
||||
+# Copyright (C) 2023 Red Hat
|
||||
+# see file 'COPYING' for use and warranty information
|
||||
+#
|
||||
+# This program is free software; you can redistribute it and/or modify
|
||||
+# it under the terms of the GNU General Public License as published by
|
||||
+# the Free Software Foundation, either version 3 of the License, or
|
||||
+# (at your option) any later version.
|
||||
+#
|
||||
+# This program is distributed in the hope that it will be useful,
|
||||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+# GNU General Public License for more details.
|
||||
+#
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+import os
|
||||
+import pytest
|
||||
+import uuid
|
||||
+
|
||||
+from ipatests.test_ipaserver.httptest import Unauthorized_HTTP_test
|
||||
+from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test
|
||||
+from ipatests.util import assert_equal
|
||||
+from ipalib import api, errors
|
||||
+from ipapython.ipautil import run
|
||||
+
|
||||
+testuser = u'tuser'
|
||||
+password = u'password'
|
||||
+
|
||||
+
|
||||
+@pytest.mark.tier1
|
||||
+class test_referer(XMLRPC_test, Unauthorized_HTTP_test):
|
||||
+
|
||||
+ @pytest.fixture(autouse=True)
|
||||
+ def login_setup(self, request):
|
||||
+ ccache = os.path.join('/tmp', str(uuid.uuid4()))
|
||||
+ tokenid = None
|
||||
+ try:
|
||||
+ api.Command['user_add'](uid=testuser, givenname=u'Test', sn=u'User')
|
||||
+ api.Command['passwd'](testuser, password=password)
|
||||
+ run(['kinit', testuser], stdin='{0}\n{0}\n{0}\n'.format(password),
|
||||
+ env={"KRB5CCNAME": ccache})
|
||||
+ result = api.Command["otptoken_add"](
|
||||
+ type='HOTP', description='testotp',
|
||||
+ ipatokenotpalgorithm='sha512', ipatokenowner=testuser,
|
||||
+ ipatokenotpdigits='6')
|
||||
+ tokenid = result['result']['ipatokenuniqueid'][0]
|
||||
+ except errors.ExecutionError as e:
|
||||
+ pytest.skip(
|
||||
+ 'Cannot set up test user: %s' % e
|
||||
+ )
|
||||
+
|
||||
+ def fin():
|
||||
+ try:
|
||||
+ api.Command['user_del']([testuser])
|
||||
+ api.Command['otptoken_del']([tokenid])
|
||||
+ except errors.NotFound:
|
||||
+ pass
|
||||
+ os.unlink(ccache)
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ def _request(self, params={}, host=None):
|
||||
+ # implicit is that self.app_uri is set to the appropriate value
|
||||
+ return self.send_request(params=params, host=host)
|
||||
+
|
||||
+ def test_login_password_valid(self):
|
||||
+ """Valid authentication of a user"""
|
||||
+ self.app_uri = "/ipa/session/login_password"
|
||||
+ response = self._request(
|
||||
+ params={'user': 'tuser', 'password': password})
|
||||
+ assert_equal(response.status, 200, self.app_uri)
|
||||
+
|
||||
+ def test_change_password_valid(self):
|
||||
+ """This actually changes the user password"""
|
||||
+ self.app_uri = "/ipa/session/change_password"
|
||||
+ response = self._request(
|
||||
+ params={'user': 'tuser',
|
||||
+ 'old_password': password,
|
||||
+ 'new_password': 'new_password'}
|
||||
+ )
|
||||
+ assert_equal(response.status, 200, self.app_uri)
|
||||
+
|
||||
+ def test_sync_token_valid(self):
|
||||
+ """We aren't testing that sync works, just that we can get there"""
|
||||
+ self.app_uri = "/ipa/session/sync_token"
|
||||
+ response = self._request(
|
||||
+ params={'user': 'tuser',
|
||||
+ 'first_code': '1234',
|
||||
+ 'second_code': '5678',
|
||||
+ 'password': 'password'})
|
||||
+ assert_equal(response.status, 200, self.app_uri)
|
||||
+
|
||||
+ def test_i18n_messages_valid(self):
|
||||
+ # i18n_messages requires a valid JSON request and we send
|
||||
+ # nothing. If we get a 500 error then it got past the
|
||||
+ # referer check.
|
||||
+ self.app_uri = "/ipa/i18n_messages"
|
||||
+ response = self._request()
|
||||
+ assert_equal(response.status, 500, self.app_uri)
|
||||
+
|
||||
+ # /ipa/session/login_x509 is not tested yet as it requires
|
||||
+ # significant additional setup.
|
||||
+ # This can be manually verified by adding
|
||||
+ # Satisfy Any and Require all granted to the configuration
|
||||
+ # section and comment out all Auth directives. The request
|
||||
+ # will fail and log that there is no KRB5CCNAME which comes
|
||||
+ # after the referer check.
|
||||
+
|
||||
+ def test_endpoints_auth_required(self):
|
||||
+ """Test endpoints that require pre-authorization which will
|
||||
+ fail before we even get to the Referer check
|
||||
+ """
|
||||
+ self.endpoints = {
|
||||
+ "/ipa/xml",
|
||||
+ "/ipa/session/login_kerberos",
|
||||
+ "/ipa/session/json",
|
||||
+ "/ipa/session/xml"
|
||||
+ }
|
||||
+ for self.app_uri in self.endpoints:
|
||||
+ response = self._request(host="attacker.test")
|
||||
+
|
||||
+ # referer is checked after auth
|
||||
+ assert_equal(response.status, 401, self.app_uri)
|
||||
+
|
||||
+ def notest_endpoints_invalid(self):
|
||||
+ """Pass in a bad Referer, expect a 400 Bad Request"""
|
||||
+ self.endpoints = {
|
||||
+ "/ipa/session/login_password",
|
||||
+ "/ipa/session/change_password",
|
||||
+ "/ipa/session/sync_token",
|
||||
+ }
|
||||
+ for self.app_uri in self.endpoints:
|
||||
+ response = self._request(host="attacker.test")
|
||||
+
|
||||
+ assert_equal(response.status, 400, self.app_uri)
|
||||
diff --git a/ipatests/util.py b/ipatests/util.py
|
||||
index 929c3e899c3..61af0c40d07 100644
|
||||
--- a/ipatests/util.py
|
||||
+++ b/ipatests/util.py
|
||||
@@ -163,12 +163,12 @@ class ExceptionNotRaised(Exception):
|
||||
return self.msg % self.expected.__name__
|
||||
|
||||
|
||||
-def assert_equal(val1, val2):
|
||||
+def assert_equal(val1, val2, msg=''):
|
||||
"""
|
||||
Assert ``val1`` and ``val2`` are the same type and of equal value.
|
||||
"""
|
||||
assert type(val1) is type(val2), '%r != %r' % (val1, val2)
|
||||
- assert val1 == val2, '%r != %r' % (val1, val2)
|
||||
+ assert val1 == val2, '%r != %r %r' % (val1, val2, msg)
|
||||
|
||||
|
||||
def assert_not_equal(val1, val2):
|
|
@ -64,7 +64,7 @@
|
|||
%if 0%{?rhel}
|
||||
%global package_name ipa
|
||||
%global alt_name freeipa
|
||||
%global krb5_version 1.18.2-25
|
||||
%global krb5_version 1.18.2-26
|
||||
%global krb5_kdb_version 8.0
|
||||
# 0.7.16: https://github.com/drkjam/netaddr/issues/71
|
||||
%global python_netaddr_version 0.7.19
|
||||
|
@ -189,7 +189,7 @@
|
|||
|
||||
Name: %{package_name}
|
||||
Version: %{IPA_VERSION}
|
||||
Release: 8%{?rc_version:.%rc_version}%{?dist}
|
||||
Release: 11%{?rc_version:.%rc_version}%{?dist}.alma.1
|
||||
Summary: The Identity, Policy and Audit system
|
||||
|
||||
License: GPLv3+
|
||||
|
@ -222,6 +222,17 @@ Patch0010: 0010-Prevent-admin-user-from-being-deleted_rhbz#1921181.patch
|
|||
Patch0011: 0011-Fix-memory-leak-in-the-OTP-last-token-plugin_rhbz#2227783.patch
|
||||
Patch0012: 0012-ipatests-fix-test_topology_rhbz#2232351.patch
|
||||
Patch0013: 0013-Installer-activate-nss-and-pam-services-in-sssd.conf_rhbz#2216532.patch
|
||||
|
||||
# Patches were taken from:
|
||||
# https://gitlab.com/redhat/centos-stream/rpms/ipa/-/commit/5d0ca0e625aea2553a39ae3e56174285cb123f13
|
||||
Patch0014: 0014-ipa-kdb-Make-AD-SIGNEDPATH-optional-with-krb5-DAL-8.patch
|
||||
# https://github.com/freeipa/freeipa/commit/13778d88ca2ac73b729821bdea844172a18c0cb9
|
||||
Patch0015: 0015-CVE-2023-5455.patch
|
||||
# https://github.com/freeipa/freeipa/commit/a847e2483b4c4832ee5129901da169f4eb0d1392
|
||||
Patch0016: 0016-ipa-kdb-Detect-and-block-Bronze-Bit-attacks.patch
|
||||
# https://github.com/freeipa/freeipa/commit/86b073a7f03ba0edf4dd91f85b96c89107e9e673
|
||||
Patch0017: 0017-Integration-tests-for-verifying-Referer.patch
|
||||
|
||||
Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch
|
||||
Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
|
||||
Patch1003: 1003-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch
|
||||
|
@ -1736,6 +1747,14 @@ fi
|
|||
%endif
|
||||
|
||||
%changelog
|
||||
* Mon Jan 15 2024 Eduard Abdullin <eabdullin@almalinux.org> - 4.9.12-11.alma.1
|
||||
- CVE-2023-5455
|
||||
- ipa-kdb: Detect and block Bronze-Bit attacks
|
||||
- Integration tests for verifying Referer header in the UI
|
||||
|
||||
* Wed Nov 14 2023 Eduard Abdullin <eabdullin@almalinux.org> - 4.9.12-9.alma.1
|
||||
- ipa-kdb: Make AD-SIGNEDPATH optional with krb5 DAL 8 and older
|
||||
|
||||
* Thu Aug 31 2023 Rafael Jeffman <rjeffman@redhat.com> - 4.9.12-8
|
||||
- Require krb5 release 1.18.2-25 or later
|
||||
Resolves: RHBZ#2234711
|
||||
|
|
Loading…
Reference in New Issue