diff --git a/SOURCES/0012-Analyzer-Optimize-list-verbose-output.patch b/SOURCES/0012-Analyzer-Optimize-list-verbose-output.patch
new file mode 100644
index 0000000..97db9b4
--- /dev/null
+++ b/SOURCES/0012-Analyzer-Optimize-list-verbose-output.patch
@@ -0,0 +1,141 @@
+From 70e254653edb21923d7565c80704e1ce6865d991 Mon Sep 17 00:00:00 2001
+From: Justin Stephenson <jstephen@redhat.com>
+Date: Wed, 12 Oct 2022 08:48:45 -0400
+Subject: [PATCH] Analyzer: Optimize list verbose output
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Modify the analyzer to parse the responder log file in one pass. This
+avoids repeated parsing of a single log file. This operation will now
+store log lines in a dictionary on a single pass then format and print
+the output accordingly. Does not affect 'list' or 'show' output.
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/tools/analyzer/modules/request.py | 71 ++++++++++++++++++---------
+ 1 file changed, 48 insertions(+), 23 deletions(-)
+
+diff --git a/src/tools/analyzer/modules/request.py b/src/tools/analyzer/modules/request.py
+index b9fe3caf8..15c8e6bfb 100644
+--- a/src/tools/analyzer/modules/request.py
++++ b/src/tools/analyzer/modules/request.py
+@@ -148,36 +148,57 @@ class RequestAnalyzer:
+                 print(line)
+         return found_results
+ 
+-    def print_formatted_verbose(self, source, patterns):
++    def print_formatted_verbose(self, source):
+         """
+-        Parse line and print formatted verbose list_requests output
++        Parse log file and print formatted verbose list_requests output
+ 
+         Args:
+             source (Reader): source Reader object
+-            patterns (list): List of regex patterns to use for
+-                matching lines
+         """
+-        # Get CID number, and print the basic line first
+-        for line in self.matched_line(source, patterns):
+-            cid = self.print_formatted(line)
+-
+-            # Loop through each line with this CID number to extract and
+-            # print the verbose data needed
+-            verbose_patterns = ["(cache_req_send|cache_req_process_input|"
+-                                "cache_req_search_send)"]
+-            for cidline in self.matched_line(source, verbose_patterns):
++        data = {}
++        # collect cid log lines from single run through of parsing the log
++        # into dictionary # (cid, ts) -> logline_output
++        for line in source:
++            if "CID#" not in line:
++                continue
++
++            # parse CID and ts from line, key is a tuple of (cid,ts)
++            fields = line.split("[")
++            # timestamp to the minute, cut off seconds, ms
++            ts = fields[0][:17]
++            result = re.search('CID#[0-9]*', fields[3])
++            cid = result.group(0)
++
++            # if mapping exists, append line to output. Otherwise create new mapping
++            if (cid, ts) in data.keys():
++                data[(cid, ts)] += line
++            else:
++                data[(cid, ts)] = line
++
++        # pretty print the data
++        for k, v in data.items():
++            cr_done = []
++            id_done = []
++            for cidline in v.splitlines():
+                 plugin = ""
+                 name = ""
+                 id = ""
+ 
+-                # skip any lines not pertaining to this CID
+-                if f"CID#{cid}]" not in cidline:
+-                    continue
+-                if "refreshed" in cidline:
+-                    continue
++                # CR number
++                fields = cidline.split("[")
++                cr_field = fields[3][7:]
++                cr = cr_field.split(":")[0][4:]
++                # Client connected, top-level info line
++                if re.search(r'\[cmd', cidline):
++                    self.print_formatted(cidline)
+                 # CR Plugin name
+                 if re.search("cache_req_send", cidline):
+                     plugin = cidline.split('\'')[1]
++                    id_done.clear()
++                    # Extract CR number
++                    fields = cidline.split("[")
++                    cr_field = fields[3][7:]
++                    cr = cr_field.split(":")[0][4:]
+                 # CR Input name
+                 elif re.search("cache_req_process_input", cidline):
+                     name = cidline.rsplit('[')[-1]
+@@ -188,9 +209,14 @@ class RequestAnalyzer:
+                 if plugin:
+                     print("   - " + plugin)
+                 if name:
+-                    print("       - " + name[:-2])
++                    # Avoid duplicate output with the same CR #
++                    if cr not in cr_done:
++                        print("       - " + name[:-1])
++                        cr_done.append(cr)
+                 if (id and ("UID" in cidline or "GID" in cidline)):
+-                    print("       - " + id)
++                    if id not in id_done:
++                        print("       - " + id)
++                        id_done.append(id)
+ 
+     def print_formatted(self, line):
+         """
+@@ -237,7 +263,7 @@ class RequestAnalyzer:
+         logger.info(f"******** Listing {resp} client requests ********")
+         source.set_component(component, False)
+         if args.verbose:
+-            self.print_formatted_verbose(source, patterns)
++            self.print_formatted_verbose(source)
+         else:
+             for line in self.matched_line(source, patterns):
+                 if isinstance(source, Journald):
+@@ -258,8 +284,7 @@ class RequestAnalyzer:
+         be_results = False
+         component = source.Component.NSS
+         resp = "nss"
+-        pattern = [rf'REQ_TRACE.*\[CID #{cid}\]']
+-        pattern.append(rf"\[CID#{cid}\]")
++        pattern = [rf"\[CID#{cid}\]"]
+ 
+         if args.pam:
+             component = source.Component.PAM
+-- 
+2.37.3
+
diff --git a/SOURCES/0013-Analyzer-Ensure-parsed-id-contains-digit.patch b/SOURCES/0013-Analyzer-Ensure-parsed-id-contains-digit.patch
new file mode 100644
index 0000000..aea3aae
--- /dev/null
+++ b/SOURCES/0013-Analyzer-Ensure-parsed-id-contains-digit.patch
@@ -0,0 +1,43 @@
+From 89ea4a5feaf30f80a79ca3ba8166f304cc414e07 Mon Sep 17 00:00:00 2001
+From: Justin Stephenson <jstephen@redhat.com>
+Date: Tue, 15 Nov 2022 12:47:51 -0500
+Subject: [PATCH] Analyzer: Ensure parsed id contains digit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In analyzer list verbose output, we parse the last field of cache_req_search_send() lines.
+Certain log messages need to be filtered out by ensuring the parsed field is
+a digit, such as the last line below.
+
+[cache_req_search_send] (0x0400): [CID#1] CR #1: Looking up GID:1031401119@testrealm.test
+[cache_req_search_send] (0x0400): [CID#1] CR #1: Looking up GID:1031401119@testrealm.test
+[cache_req_search_send] (0x0400): [CID#1] CR #1: Looking up GID:1031401119@domain-zflo.com
+[cache_req_search_send] (0x0400): [CID#1] CR #1: Returning [GID:1031401119@domain-zflo.com] from cache
+
+Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+(cherry picked from commit bfa8d50c479cf8ef7b299eb5848309a3a9ea7f12)
+
+Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
+Reviewed-by: Tomáš Halman <thalman@redhat.com>
+---
+ src/tools/analyzer/modules/request.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/tools/analyzer/modules/request.py b/src/tools/analyzer/modules/request.py
+index 15c8e6bfb..bf279ea75 100644
+--- a/src/tools/analyzer/modules/request.py
++++ b/src/tools/analyzer/modules/request.py
+@@ -214,7 +214,7 @@ class RequestAnalyzer:
+                         print("       - " + name[:-1])
+                         cr_done.append(cr)
+                 if (id and ("UID" in cidline or "GID" in cidline)):
+-                    if id not in id_done:
++                    if id not in id_done and bool(re.search(r'\d', id)):
+                         print("       - " + id)
+                         id_done.append(id)
+ 
+-- 
+2.37.3
+
diff --git a/SOURCES/0014-TOOLS-don-t-export-internal-helpers.patch b/SOURCES/0014-TOOLS-don-t-export-internal-helpers.patch
new file mode 100644
index 0000000..7a5c780
--- /dev/null
+++ b/SOURCES/0014-TOOLS-don-t-export-internal-helpers.patch
@@ -0,0 +1,94 @@
+From 7e23e6394b518dd013c6b03a1a63715899180935 Mon Sep 17 00:00:00 2001
+From: Alexey Tikhonov <atikhono@redhat.com>
+Date: Sun, 6 Nov 2022 11:22:22 +0100
+Subject: [PATCH 14/16] TOOLS: don't export internal helpers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 6ef3aade0394e32540242f902c9f21bb8d6c41f2)
+
+Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+---
+ src/tools/common/sss_tools.c | 16 ++++++++--------
+ src/tools/common/sss_tools.h | 12 ------------
+ 2 files changed, 8 insertions(+), 20 deletions(-)
+
+diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c
+index c066ddc5c..47b85bdd2 100644
+--- a/src/tools/common/sss_tools.c
++++ b/src/tools/common/sss_tools.c
+@@ -178,9 +178,9 @@ static errno_t sss_tool_domains_init(TALLOC_CTX *mem_ctx,
+     return ret;
+ }
+ 
+-errno_t sss_tool_init(TALLOC_CTX *mem_ctx,
+-                      int *argc, const char **argv,
+-                      struct sss_tool_ctx **_tool_ctx)
++static errno_t sss_tool_init(TALLOC_CTX *mem_ctx,
++                             int *argc, const char **argv,
++                             struct sss_tool_ctx **_tool_ctx)
+ {
+     struct sss_tool_ctx *tool_ctx;
+ 
+@@ -235,7 +235,7 @@ static size_t sss_tool_max_length(struct sss_route_cmd *commands)
+     return max;
+ }
+ 
+-void sss_tool_usage(const char *tool_name, struct sss_route_cmd *commands)
++static void sss_tool_usage(const char *tool_name, struct sss_route_cmd *commands)
+ {
+     int min_len;
+     int i;
+@@ -304,10 +304,10 @@ done:
+     return ret;
+ }
+ 
+-errno_t sss_tool_route(int argc, const char **argv,
+-                       struct sss_tool_ctx *tool_ctx,
+-                       struct sss_route_cmd *commands,
+-                       void *pvt)
++static errno_t sss_tool_route(int argc, const char **argv,
++                              struct sss_tool_ctx *tool_ctx,
++                              struct sss_route_cmd *commands,
++                              void *pvt)
+ {
+     struct sss_cmdline cmdline;
+     const char *cmd;
+diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h
+index 0e4308ee6..578186633 100644
+--- a/src/tools/common/sss_tools.h
++++ b/src/tools/common/sss_tools.h
+@@ -35,10 +35,6 @@ struct sss_tool_ctx {
+     struct sss_domain_info *domains;
+ };
+ 
+-errno_t sss_tool_init(TALLOC_CTX *mem_ctx,
+-                      int *argc, const char **argv,
+-                      struct sss_tool_ctx **_tool_ctx);
+-
+ struct sss_cmdline {
+     const char *exec; /* argv[0] */
+     const char *command; /* command name */
+@@ -69,14 +65,6 @@ struct sss_route_cmd {
+     int flags;
+ };
+ 
+-void sss_tool_usage(const char *tool_name,
+-                    struct sss_route_cmd *commands);
+-
+-errno_t sss_tool_route(int argc, const char **argv,
+-                       struct sss_tool_ctx *tool_ctx,
+-                       struct sss_route_cmd *commands,
+-                       void *pvt);
+-
+ typedef errno_t (*sss_popt_fn)(poptContext pc, char option, void *pvt);
+ 
+ enum sss_tool_opt {
+-- 
+2.37.3
+
diff --git a/SOURCES/0015-TOOLS-fixed-handling-of-init-error.patch b/SOURCES/0015-TOOLS-fixed-handling-of-init-error.patch
new file mode 100644
index 0000000..45c291a
--- /dev/null
+++ b/SOURCES/0015-TOOLS-fixed-handling-of-init-error.patch
@@ -0,0 +1,71 @@
+From bd16242ef6780fd2808bf03f79eda5d940094bc5 Mon Sep 17 00:00:00 2001
+From: Alexey Tikhonov <atikhono@redhat.com>
+Date: Sun, 6 Nov 2022 12:25:37 +0100
+Subject: [PATCH 15/16] TOOLS: fixed handling of init error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Before execution of `tool_cmd_init()` `init_err` wasn't set,
+so `sss_tools_handles_init_error()` check was a no-op.
+
+Consequently, a proper check after `tool_cmd_init()` was missing.
+
+Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 7af46ba0e925da61b7b4003c3fa6d51c05c1116e)
+
+Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+---
+ src/tools/common/sss_tools.c | 17 ++++-------------
+ src/tools/common/sss_tools.h |  1 -
+ 2 files changed, 4 insertions(+), 14 deletions(-)
+
+diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c
+index 47b85bdd2..38ae88306 100644
+--- a/src/tools/common/sss_tools.c
++++ b/src/tools/common/sss_tools.c
+@@ -336,22 +336,13 @@ static errno_t sss_tool_route(int argc, const char **argv,
+             cmdline.argc = argc - 2;
+             cmdline.argv = argv + 2;
+ 
+-            if (!sss_tools_handles_init_error(&commands[i], tool_ctx->init_err)) {
+-                DEBUG(SSSDBG_FATAL_FAILURE,
+-                      "Command %s does not handle initialization error [%d] %s\n",
+-                      cmdline.command, tool_ctx->init_err,
+-                      sss_strerror(tool_ctx->init_err));
+-                return tool_ctx->init_err;
+-            }
+-
+             if (!tool_ctx->print_help) {
+                 ret = tool_cmd_init(tool_ctx, &commands[i]);
+-                if (ret == ERR_SYSDB_VERSION_TOO_OLD) {
+-                    tool_ctx->init_err = ret;
+-                } else if (ret != EOK) {
++
++                if (!sss_tools_handles_init_error(&commands[i], ret)) {
+                     DEBUG(SSSDBG_FATAL_FAILURE,
+-                          "Command initialization failed [%d] %s\n",
+-                          ret, sss_strerror(ret));
++                          "Command %s does not handle initialization error [%d] %s\n",
++                          cmdline.command, ret, sss_strerror(ret));
+                     return ret;
+                 }
+             }
+diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h
+index 578186633..75dc15391 100644
+--- a/src/tools/common/sss_tools.h
++++ b/src/tools/common/sss_tools.h
+@@ -30,7 +30,6 @@ struct sss_tool_ctx {
+     struct confdb_ctx *confdb;
+ 
+     bool print_help;
+-    errno_t init_err;
+     char *default_domain;
+     struct sss_domain_info *domains;
+ };
+-- 
+2.37.3
+
diff --git a/SOURCES/0016-SSSCTL-don-t-require-root-for-analyze-cmd.patch b/SOURCES/0016-SSSCTL-don-t-require-root-for-analyze-cmd.patch
new file mode 100644
index 0000000..698472c
--- /dev/null
+++ b/SOURCES/0016-SSSCTL-don-t-require-root-for-analyze-cmd.patch
@@ -0,0 +1,89 @@
+From 66c318d212d56e26f303fc52d5fecbde4a6b9589 Mon Sep 17 00:00:00 2001
+From: Alexey Tikhonov <atikhono@redhat.com>
+Date: Thu, 10 Nov 2022 22:18:06 +0100
+Subject: [PATCH 16/16] SSSCTL: don't require 'root' for "analyze" cmd
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+:relnote: `sssctl analyze` tool doesn't require anymore to be run under root.
+
+Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 99791400bec1054cf0081884e013a3cbed75fe8a)
+
+Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+---
+ src/tools/common/sss_tools.c | 16 +++++++++-------
+ src/tools/common/sss_tools.h |  3 ++-
+ src/tools/sssctl/sssctl.c    |  2 +-
+ 3 files changed, 12 insertions(+), 9 deletions(-)
+
+diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c
+index 38ae88306..d16de7c4d 100644
+--- a/src/tools/common/sss_tools.c
++++ b/src/tools/common/sss_tools.c
+@@ -267,6 +267,15 @@ static int tool_cmd_init(struct sss_tool_ctx *tool_ctx,
+                          struct sss_route_cmd *command)
+ {
+     int ret;
++    uid_t uid;
++
++    if (!(command->flags & SSS_TOOL_FLAG_SKIP_ROOT_CHECK)) {
++        uid = getuid();
++        if (uid != 0) {
++            ERROR("'%s' must be run as root\n", command->command);
++            return EXIT_FAILURE;
++        }
++    }
+ 
+     if (command->flags & SSS_TOOL_FLAG_SKIP_CMD_INIT) {
+         return EOK;
+@@ -515,15 +524,8 @@ int sss_tool_main(int argc, const char **argv,
+                   void *pvt)
+ {
+     struct sss_tool_ctx *tool_ctx;
+-    uid_t uid;
+     errno_t ret;
+ 
+-    uid = getuid();
+-    if (uid != 0) {
+-        ERROR("%1$s must be run as root\n", argv[0]);
+-        return EXIT_FAILURE;
+-    }
+-
+     ret = sss_tool_init(NULL, &argc, argv, &tool_ctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tool context\n");
+diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h
+index 75dc15391..24dd4b559 100644
+--- a/src/tools/common/sss_tools.h
++++ b/src/tools/common/sss_tools.h
+@@ -54,7 +54,8 @@ typedef errno_t
+ #define SSS_TOOL_DELIMITER(message) {"", _(message), 0, NULL, 0}
+ #define SSS_TOOL_LAST {NULL, NULL, 0, NULL, 0}
+ 
+-#define SSS_TOOL_FLAG_SKIP_CMD_INIT 0x01
++#define SSS_TOOL_FLAG_SKIP_CMD_INIT   0x01
++#define SSS_TOOL_FLAG_SKIP_ROOT_CHECK 0x02
+ 
+ struct sss_route_cmd {
+     const char *command;
+diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c
+index f18689f9f..b73d19ffe 100644
+--- a/src/tools/sssctl/sssctl.c
++++ b/src/tools/sssctl/sssctl.c
+@@ -296,7 +296,7 @@ int main(int argc, const char **argv)
+         SSS_TOOL_COMMAND("logs-remove", "Remove existing SSSD log files", 0, sssctl_logs_remove),
+         SSS_TOOL_COMMAND("logs-fetch", "Archive SSSD log files in tarball", 0, sssctl_logs_fetch),
+         SSS_TOOL_COMMAND("debug-level", "Change SSSD debug level", 0, sssctl_debug_level),
+-        SSS_TOOL_COMMAND_FLAGS("analyze", "Analyze logged data", 0, sssctl_analyze, SSS_TOOL_FLAG_SKIP_CMD_INIT),
++        SSS_TOOL_COMMAND_FLAGS("analyze", "Analyze logged data", 0, sssctl_analyze, SSS_TOOL_FLAG_SKIP_CMD_INIT|SSS_TOOL_FLAG_SKIP_ROOT_CHECK),
+ #ifdef HAVE_LIBINI_CONFIG_V1_3
+         SSS_TOOL_DELIMITER("Configuration files tools:"),
+         SSS_TOOL_COMMAND_FLAGS("config-check", "Perform static analysis of SSSD configuration", 0, sssctl_config_check, SSS_TOOL_FLAG_SKIP_CMD_INIT),
+-- 
+2.37.3
+
diff --git a/SOURCES/0017-PAC-allow-to-disable-UPN-check.patch b/SOURCES/0017-PAC-allow-to-disable-UPN-check.patch
new file mode 100644
index 0000000..f5b565d
--- /dev/null
+++ b/SOURCES/0017-PAC-allow-to-disable-UPN-check.patch
@@ -0,0 +1,49 @@
+From a86d1740167031bf6444ff821a201164c11ba09c Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 16 Nov 2022 09:28:54 +0100
+Subject: [PATCH 17/19] PAC: allow to disable UPN check
+
+Currently it was not possible to skip the UPN check which checks if the
+UPN in the PAC and the one stored in SSSD's cache are different.
+Additionally the related debug message will show both principals if they
+differ.
+
+Resolves: https://github.com/SSSD/sssd/issues/6451
+
+(cherry picked from commit 91789449b7a8b20056e1edfedd8f8cf92f7a0a2a)
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+---
+ src/providers/ad/ad_pac_common.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/src/providers/ad/ad_pac_common.c b/src/providers/ad/ad_pac_common.c
+index 0ed817111..79f79b7a7 100644
+--- a/src/providers/ad/ad_pac_common.c
++++ b/src/providers/ad/ad_pac_common.c
+@@ -224,9 +224,19 @@ errno_t check_upn_and_sid_from_user_and_pac(struct ldb_message *msg,
+ 
+         if (user_data != NULL) {
+             if (strcasecmp(user_data, upn_dns_info->upn_name) != 0) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "UPN of user entry and PAC do not match.\n");
+-                return ERR_CHECK_PAC_FAILED;
++                if (pac_check_opts & CHECK_PAC_CHECK_UPN) {
++                    DEBUG(SSSDBG_CRIT_FAILURE, "UPN of user entry [%s] and "
++                                               "PAC [%s] do not match.\n",
++                                               user_data,
++                                               upn_dns_info->upn_name);
++                    return ERR_CHECK_PAC_FAILED;
++                } else {
++                    DEBUG(SSSDBG_IMPORTANT_INFO, "UPN of user entry [%s] and "
++                                                 "PAC [%s] do not match, "
++                                                 "ignored.\n", user_data,
++                                                 upn_dns_info->upn_name);
++                    return EOK;
++                }
+             }
+         }
+ 
+-- 
+2.37.3
+
diff --git a/SOURCES/0018-ipa-do-not-add-guessed-principal-to-the-cache.patch b/SOURCES/0018-ipa-do-not-add-guessed-principal-to-the-cache.patch
new file mode 100644
index 0000000..7ab2783
--- /dev/null
+++ b/SOURCES/0018-ipa-do-not-add-guessed-principal-to-the-cache.patch
@@ -0,0 +1,90 @@
+From 29aa434816ce6ae2aaf3b0bcf24b89f05f426d1b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 22 Nov 2022 13:39:26 +0100
+Subject: [PATCH 18/19] ipa: do not add guessed principal to the cache
+
+Currently on IPA clients a calculated principal based on the user name
+and the Kerberos realm is added to the cached user object. This code is
+quite old and might have been necessary at times when sub-domain support
+was added to SSSD. But since quite some time SSSD is capable of
+generating the principal on the fly during authentication if nothing is
+stored in the cache.
+
+Removing the code makes the cache more consistent with other use-cases,
+e.g. with the IPA server where this attribute is empty, and allows to
+properly detect a missing UPN, e.g. during the PAC validation.
+
+Resolves: https://github.com/SSSD/sssd/issues/6451
+
+(cherry picked from commit b3d7a4f6d4e1d4fa1bd33b296cd4301973f1860c)
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+---
+ src/providers/ipa/ipa_s2n_exop.c | 44 --------------------------------
+ 1 file changed, 44 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index c68c1de26..81927a6b8 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -2467,8 +2467,6 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+     time_t now;
+     struct sss_nss_homedir_ctx homedir_ctx;
+     char *name = NULL;
+-    char *realm;
+-    char *short_name = NULL;
+     char *upn = NULL;
+     gid_t gid;
+     gid_t orig_gid = 0;
+@@ -2607,48 +2605,6 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                 goto done;
+             }
+ 
+-            if (upn == NULL) {
+-                /* We also have to store a fake UPN here, because otherwise the
+-                 * krb5 child later won't be able to properly construct one as
+-                 * the username is fully qualified but the child doesn't have
+-                 * access to the regex to deconstruct it */
+-                /* FIXME: The real UPN is available from the PAC, we should get
+-                 * it from there. */
+-                realm = get_uppercase_realm(tmp_ctx, dom->name);
+-                if (!realm) {
+-                    DEBUG(SSSDBG_OP_FAILURE, "failed to get realm.\n");
+-                    ret = ENOMEM;
+-                    goto done;
+-                }
+-
+-                ret = sss_parse_internal_fqname(tmp_ctx, attrs->a.user.pw_name,
+-                                                &short_name, NULL);
+-                if (ret != EOK) {
+-                    DEBUG(SSSDBG_CRIT_FAILURE,
+-                          "Cannot parse internal name %s\n",
+-                          attrs->a.user.pw_name);
+-                    goto done;
+-                }
+-
+-                upn = talloc_asprintf(tmp_ctx, "%s@%s", short_name, realm);
+-                if (!upn) {
+-                    DEBUG(SSSDBG_OP_FAILURE, "failed to format UPN.\n");
+-                    ret = ENOMEM;
+-                    goto done;
+-                }
+-
+-                /* We might already have the SID or the UPN from other sources
+-                 * hence sysdb_attrs_add_string_safe is used to avoid double
+-                 * entries. */
+-                ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs, SYSDB_UPN,
+-                                                  upn);
+-                if (ret != EOK) {
+-                    DEBUG(SSSDBG_OP_FAILURE,
+-                          "sysdb_attrs_add_string failed.\n");
+-                    goto done;
+-                }
+-            }
+-
+             if (req_input->type == REQ_INP_SECID) {
+                 ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs,
+                                                   SYSDB_SID_STR,
+-- 
+2.37.3
+
diff --git a/SOURCES/0019-pac-relax-default-check.patch b/SOURCES/0019-pac-relax-default-check.patch
new file mode 100644
index 0000000..178a1e2
--- /dev/null
+++ b/SOURCES/0019-pac-relax-default-check.patch
@@ -0,0 +1,164 @@
+From 0e618c36ed74c240f7acd071ccb7bfd405b2d827 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 22 Nov 2022 14:43:21 +0100
+Subject: [PATCH 19/19] pac: relax default check
+
+To avoid issues with the UPN check during PAC validation  when
+'ldap_user_principal' is set to a not existing attribute to skip reading
+user principals a new 'pac_check' option, 'check_upn_allow_missing' is
+added to the default options. With this option only a log message is
+shown but the check will not fail.
+
+Resolves: https://github.com/SSSD/sssd/issues/6451
+
+(cherry picked from commit 51b11db8b99a77ba5ccf6f850c2e81b5a6ee9f79)
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+---
+ src/confdb/confdb.h              |  2 +-
+ src/man/sssd.conf.5.xml          | 30 +++++++++++++++++++++++++++++-
+ src/providers/ad/ad_pac_common.c | 24 ++++++++++++++++++++----
+ src/util/pac_utils.c             | 10 ++++++++++
+ src/util/util.h                  |  2 ++
+ 5 files changed, 62 insertions(+), 6 deletions(-)
+
+diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
+index 83f6be7f9..5fda67585 100644
+--- a/src/confdb/confdb.h
++++ b/src/confdb/confdb.h
+@@ -181,7 +181,7 @@
+ #define CONFDB_PAC_LIFETIME "pac_lifetime"
+ #define CONFDB_PAC_CHECK "pac_check"
+ #define CONFDB_PAC_CHECK_DEFAULT "no_check"
+-#define CONFDB_PAC_CHECK_IPA_AD_DEFAULT "check_upn, check_upn_dns_info_ex"
++#define CONFDB_PAC_CHECK_IPA_AD_DEFAULT "check_upn, check_upn_allow_missing, check_upn_dns_info_ex"
+ 
+ /* InfoPipe */
+ #define CONFDB_IFP_CONF_ENTRY "config/ifp"
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 7a9920815..d9f4a7481 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -2275,6 +2275,34 @@ pam_gssapi_indicators_map = sudo:pkinit, sudo-i:pkinit
+                                     consistent.</para>
+                                 </listitem>
+                             </varlistentry>
++                            <varlistentry>
++                                <term>check_upn_allow_missing</term>
++                                <listitem>
++                                    <para>This option should be used together
++                                    with 'check_upn' and handles the case where
++                                    a UPN is set on the server-side but is not
++                                    read by SSSD. The typical example is a
++                                    FreeIPA domain where 'ldap_user_principal'
++                                    is set to a not existing attribute name.
++                                    This was typically done to work-around
++                                    issues in the handling of enterprise
++                                    principals. But this is fixed since quite
++                                    some time and FreeIPA can handle enterprise
++                                    principals just fine and there is no need
++                                    anymore to set 'ldap_user_principal'.</para>
++                                    <para>Currently this option is set by
++                                    default to avoid regressions in such
++                                    environments. A log message will be added
++                                    to the system log and SSSD's debug log in
++                                    case a UPN is found in the PAC but not in
++                                    SSSD's cache. To avoid this log message it
++                                    would be best to evaluate if the
++                                    'ldap_user_principal' option can be removed.
++                                    If this is not possible, removing
++                                    'check_upn' will skip the test and avoid the
++                                    log message.</para>
++                                </listitem>
++                            </varlistentry>
+                             <varlistentry>
+                                 <term>upn_dns_info_present</term>
+                                 <listitem>
+@@ -2305,7 +2333,7 @@ pam_gssapi_indicators_map = sudo:pkinit, sudo-i:pkinit
+                         </para>
+                         <para>
+                             Default: no_check (AD and IPA provider
+-                            'check_upn, check_upn_dns_info_ex')
++                            'check_upn, check_upn_allow_missing, check_upn_dns_info_ex')
+                         </para>
+                     </listitem>
+                 </varlistentry>
+diff --git a/src/providers/ad/ad_pac_common.c b/src/providers/ad/ad_pac_common.c
+index 79f79b7a7..fcb54cd2c 100644
+--- a/src/providers/ad/ad_pac_common.c
++++ b/src/providers/ad/ad_pac_common.c
+@@ -215,10 +215,26 @@ errno_t check_upn_and_sid_from_user_and_pac(struct ldb_message *msg,
+             DEBUG(SSSDBG_MINOR_FAILURE, "User object does not have a UPN but PAC "
+                       "says otherwise, maybe ldap_user_principal option is set.\n");
+             if (pac_check_opts & CHECK_PAC_CHECK_UPN) {
+-                DEBUG(SSSDBG_CRIT_FAILURE,
+-                      "UPN is missing but PAC UPN check required, "
+-                      "PAC validation failed.\n");
+-                return ERR_CHECK_PAC_FAILED;
++                if (pac_check_opts & CHECK_PAC_CHECK_UPN_ALLOW_MISSING) {
++                    DEBUG(SSSDBG_IMPORTANT_INFO,
++                          "UPN is missing but PAC UPN check required, "
++                          "PAC validation failed. However, "
++                          "'check_upn_allow_missing' is set and the error is "
++                          "ignored. To make this message go away please check "
++                          "why the UPN is not read from the server. In FreeIPA "
++                          "environments 'ldap_user_principal' is most probably "
++                          "set to a non-existing attribute name to avoid "
++                          "issues with enterprise principals. This is not "
++                          "needed anymore with recent versions of FreeIPA.\n");
++                    sss_log(SSS_LOG_CRIT, "PAC validation issue, please check "
++                                          "sssd_pac.log for details");
++                    return EOK;
++                } else {
++                    DEBUG(SSSDBG_CRIT_FAILURE,
++                          "UPN is missing but PAC UPN check required, "
++                          "PAC validation failed.\n");
++                    return ERR_CHECK_PAC_FAILED;
++                }
+             }
+         }
+ 
+diff --git a/src/util/pac_utils.c b/src/util/pac_utils.c
+index c53b0c082..4499d8dfd 100644
+--- a/src/util/pac_utils.c
++++ b/src/util/pac_utils.c
+@@ -64,6 +64,8 @@ static errno_t check_check_pac_opt(const char *inp, uint32_t *check_pac_flags)
+             flags |= CHECK_PAC_CHECK_UPN_DNS_INFO_EX;
+             flags |= CHECK_PAC_UPN_DNS_INFO_PRESENT;
+             flags |= CHECK_PAC_CHECK_UPN;
++        } else if (strcasecmp(list[c], CHECK_PAC_CHECK_UPN_ALLOW_MISSING_STR) == 0) {
++            flags |= CHECK_PAC_CHECK_UPN_ALLOW_MISSING;
+         } else {
+             DEBUG(SSSDBG_OP_FAILURE, "Unknown value [%s] for pac_check.\n",
+                                      list[c]);
+@@ -72,6 +74,14 @@ static errno_t check_check_pac_opt(const char *inp, uint32_t *check_pac_flags)
+         }
+     }
+ 
++    if ((flags & CHECK_PAC_CHECK_UPN_ALLOW_MISSING)
++                && !(flags & CHECK_PAC_CHECK_UPN)) {
++        DEBUG(SSSDBG_CONF_SETTINGS,
++              "pac_check option '%s' is set but '%s' is not set, this means "
++              "the UPN is not checked.\n",
++              CHECK_PAC_CHECK_UPN_ALLOW_MISSING_STR, CHECK_PAC_CHECK_UPN_STR);
++    }
++
+     ret = EOK;
+ 
+ done:
+diff --git a/src/util/util.h b/src/util/util.h
+index 6d9111874..4b2651c2c 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -818,6 +818,8 @@ uint64_t get_spend_time_us(uint64_t st);
+ #define CHECK_PAC_CHECK_UPN_DNS_INFO_EX (1 << 3)
+ #define CHECK_PAC_UPN_DNS_INFO_EX_PRESENT_STR "upn_dns_info_ex_present"
+ #define CHECK_PAC_UPN_DNS_INFO_EX_PRESENT (1 << 4)
++#define CHECK_PAC_CHECK_UPN_ALLOW_MISSING_STR "check_upn_allow_missing"
++#define CHECK_PAC_CHECK_UPN_ALLOW_MISSING (1 << 5)
+ 
+ errno_t get_pac_check_config(struct confdb_ctx *cdb, uint32_t *pac_check_opts);
+ #endif /* __SSSD_UTIL_H__ */
+-- 
+2.37.3
+
diff --git a/SOURCES/0020-oidc_child-escape-scopes.patch b/SOURCES/0020-oidc_child-escape-scopes.patch
new file mode 100644
index 0000000..606eb26
--- /dev/null
+++ b/SOURCES/0020-oidc_child-escape-scopes.patch
@@ -0,0 +1,102 @@
+From ace43c8ce02d19cf536ce35749aa2ed734089189 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 18 Aug 2022 13:55:21 +0200
+Subject: [PATCH 20/23] oidc_child: escape scopes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Before using the user provided scopes in the HTTP request they should be
+properly escaped according to RFC-3986.
+
+Resolves: https://github.com/SSSD/sssd/issues/6146
+
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 12d5c6344ee304c1f3bc155a76ab37fcd20e78cb)
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+---
+ src/oidc_child/oidc_child.c      |  4 ++--
+ src/oidc_child/oidc_child_curl.c | 35 ++++++++++++++++++++++++++++++++
+ src/oidc_child/oidc_child_util.h |  2 ++
+ 3 files changed, 39 insertions(+), 2 deletions(-)
+
+diff --git a/src/oidc_child/oidc_child.c b/src/oidc_child/oidc_child.c
+index e58afccd3..aeeac3595 100644
+--- a/src/oidc_child/oidc_child.c
++++ b/src/oidc_child/oidc_child.c
+@@ -119,9 +119,9 @@ static errno_t set_endpoints(struct devicecode_ctx *dc_ctx,
+     }
+ 
+     if (scope != NULL && *scope != '\0') {
+-        dc_ctx->scope = talloc_strdup(dc_ctx, scope);
++        dc_ctx->scope = url_encode_string(dc_ctx, scope);
+         if (dc_ctx->scope == NULL) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy scopes.\n");
++            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to encode and copy scopes.\n");
+             ret = ENOMEM;
+             goto done;
+         }
+diff --git a/src/oidc_child/oidc_child_curl.c b/src/oidc_child/oidc_child_curl.c
+index 20e17a566..df438e007 100644
+--- a/src/oidc_child/oidc_child_curl.c
++++ b/src/oidc_child/oidc_child_curl.c
+@@ -26,6 +26,41 @@
+ #include <curl/curl.h>
+ #include "oidc_child/oidc_child_util.h"
+ 
++char *url_encode_string(TALLOC_CTX *mem_ctx, const char *inp)
++{
++    CURL *curl_ctx = NULL;
++    char *tmp;
++    char *out = NULL;
++
++    if (inp == NULL) {
++        DEBUG(SSSDBG_TRACE_ALL, "Empty input.\n");
++        return NULL;
++    }
++
++    curl_ctx = curl_easy_init();
++    if (curl_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "Failed to initialize curl.\n");
++        return NULL;
++    }
++
++    tmp = curl_easy_escape(curl_ctx, inp, 0);
++    if (tmp == NULL) {
++        DEBUG(SSSDBG_TRACE_ALL, "curl_easy_escape failed for [%s].\n", inp);
++        goto done;
++    }
++
++    out = talloc_strdup(mem_ctx, tmp);
++    curl_free(tmp);
++    if (out == NULL) {
++        DEBUG(SSSDBG_TRACE_ALL, "talloc_strdup failed.\n");
++        goto done;
++    }
++
++done:
++    curl_easy_cleanup(curl_ctx);
++    return (out);
++}
++
+ /* The curl write_callback will always append the received data. To start a
+  * new string call clean_http_data() before the curl request.*/
+ void clean_http_data(struct devicecode_ctx *dc_ctx)
+diff --git a/src/oidc_child/oidc_child_util.h b/src/oidc_child/oidc_child_util.h
+index c781bf1b1..ae5a72bc2 100644
+--- a/src/oidc_child/oidc_child_util.h
++++ b/src/oidc_child/oidc_child_util.h
+@@ -61,6 +61,8 @@ struct devicecode_ctx {
+ };
+ 
+ /* oidc_child_curl.c */
++char *url_encode_string(TALLOC_CTX *mem_ctx, const char *inp);
++
+ errno_t init_curl(void *p);
+ 
+ void clean_http_data(struct devicecode_ctx *dc_ctx);
+-- 
+2.37.3
+
diff --git a/SOURCES/0021-oidc_child-use-client-secret-if-available-to-get-dev.patch b/SOURCES/0021-oidc_child-use-client-secret-if-available-to-get-dev.patch
new file mode 100644
index 0000000..2a4e9ab
--- /dev/null
+++ b/SOURCES/0021-oidc_child-use-client-secret-if-available-to-get-dev.patch
@@ -0,0 +1,89 @@
+From 3e296c70d56e2aa83ce882d2ac1738f85606fd7a Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 18 Aug 2022 14:01:34 +0200
+Subject: [PATCH 21/23] oidc_child: use client secret if available to get
+ device code
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some IdP have the concept of confidential client, i.e. clients where the
+client's secret can be stored safely by the related application. For a
+confidential client some IdPs expects that the client secret is used in
+all requests together with the client ID although OAuth2 specs currently
+only mention this explicitly for the token request. To make sure the
+device code can be requested in this case the client secret is added to
+the device code request if the secret is provided.
+
+Resolves: https://github.com/SSSD/sssd/issues/6146
+
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit a4d4617efeff871c5d2762e35f9dec57fa24fb1a)
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+---
+ src/oidc_child/oidc_child.c      |  2 +-
+ src/oidc_child/oidc_child_curl.c | 12 +++++++++++-
+ src/oidc_child/oidc_child_util.h |  2 +-
+ 3 files changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/src/oidc_child/oidc_child.c b/src/oidc_child/oidc_child.c
+index aeeac3595..c8d35d5d8 100644
+--- a/src/oidc_child/oidc_child.c
++++ b/src/oidc_child/oidc_child.c
+@@ -454,7 +454,7 @@ int main(int argc, const char *argv[])
+     }
+ 
+     if (opts.get_device_code) {
+-        ret = get_devicecode(dc_ctx, opts.client_id);
++        ret = get_devicecode(dc_ctx, opts.client_id, opts.client_secret);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE, "Failed to get device code.\n");
+             goto done;
+diff --git a/src/oidc_child/oidc_child_curl.c b/src/oidc_child/oidc_child_curl.c
+index df438e007..6e80c3abf 100644
+--- a/src/oidc_child/oidc_child_curl.c
++++ b/src/oidc_child/oidc_child_curl.c
+@@ -428,7 +428,7 @@ done:
+ #define DEFAULT_SCOPE "user"
+ 
+ errno_t get_devicecode(struct devicecode_ctx *dc_ctx,
+-                       const char *client_id)
++                       const char *client_id, const char *client_secret)
+ {
+     int ret;
+ 
+@@ -443,6 +443,16 @@ errno_t get_devicecode(struct devicecode_ctx *dc_ctx,
+         return ENOMEM;
+     }
+ 
++    if (client_secret != NULL) {
++        post_data = talloc_asprintf_append(post_data, "&client_secret=%s",
++                                           client_secret);
++        if (post_data == NULL) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "Failed to add client secret to POST data.\n");
++            return ENOMEM;
++        }
++    }
++
+     clean_http_data(dc_ctx);
+     ret = do_http_request(dc_ctx, dc_ctx->device_authorization_endpoint,
+                           post_data, NULL);
+diff --git a/src/oidc_child/oidc_child_util.h b/src/oidc_child/oidc_child_util.h
+index ae5a72bc2..8b106ae79 100644
+--- a/src/oidc_child/oidc_child_util.h
++++ b/src/oidc_child/oidc_child_util.h
+@@ -73,7 +73,7 @@ errno_t get_openid_configuration(struct devicecode_ctx *dc_ctx,
+ errno_t get_jwks(struct devicecode_ctx *dc_ctx);
+ 
+ errno_t get_devicecode(struct devicecode_ctx *dc_ctx,
+-                       const char *client_id);
++                       const char *client_id, const char *client_secret);
+ 
+ errno_t get_token(TALLOC_CTX *mem_ctx,
+                   struct devicecode_ctx *dc_ctx, const char *client_id,
+-- 
+2.37.3
+
diff --git a/SOURCES/0022-oidc_child-increase-wait-interval-by-5s-if-slow_down.patch b/SOURCES/0022-oidc_child-increase-wait-interval-by-5s-if-slow_down.patch
new file mode 100644
index 0000000..8d2183c
--- /dev/null
+++ b/SOURCES/0022-oidc_child-increase-wait-interval-by-5s-if-slow_down.patch
@@ -0,0 +1,67 @@
+From 55bfa944ad0197ae294d85ac42abf98297fa3a5d Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 18 Aug 2022 14:19:59 +0200
+Subject: [PATCH 22/23] oidc_child: increase wait interval by 5s if 'slow_down'
+ is returned
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+While waiting for the user to authenticate with the IdP oidc_child
+currently only handles the error code 'authorization_pending' and waits
+for the given interval until a new request is send. But there is also
+'slow_down' which should not be treated as fatal error but should just
+increase the waiting time permanently for 5s.
+
+Resolves: https://github.com/SSSD/sssd/issues/6146
+
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 5ed7670766483040211713f8182510775c76b962)
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+---
+ src/oidc_child/oidc_child_curl.c | 8 +++++++-
+ src/oidc_child/oidc_child_json.c | 6 ++++++
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/src/oidc_child/oidc_child_curl.c b/src/oidc_child/oidc_child_curl.c
+index 6e80c3abf..cf0976021 100644
+--- a/src/oidc_child/oidc_child_curl.c
++++ b/src/oidc_child/oidc_child_curl.c
+@@ -378,8 +378,14 @@ errno_t get_token(TALLOC_CTX *mem_ctx,
+             break;
+         }
+ 
+-        sleep(dc_ctx->interval);
+         waiting_time += dc_ctx->interval;
++        if (waiting_time >= dc_ctx->expires_in) {
++            /* Next sleep will end after the request is expired on the
++             * server side, so we can just error out now. */
++            ret = ETIMEDOUT;
++            break;
++        }
++        sleep(dc_ctx->interval);
+     } while (waiting_time < dc_ctx->expires_in);
+ 
+     if (ret != EOK) {
+diff --git a/src/oidc_child/oidc_child_json.c b/src/oidc_child/oidc_child_json.c
+index efc1997aa..a89794c4c 100644
+--- a/src/oidc_child/oidc_child_json.c
++++ b/src/oidc_child/oidc_child_json.c
+@@ -413,6 +413,12 @@ errno_t parse_token_result(struct devicecode_ctx *dc_ctx,
+         if (strcmp(json_string_value(tmp), "authorization_pending") == 0) {
+             json_decref(result);
+             return EAGAIN;
++        } else if (strcmp(json_string_value(tmp), "slow_down") == 0) {
++            /* RFC 8628: "... the interval MUST be increased by 5 seconds for"
++             *           "this and all subsequent requests." */
++            dc_ctx->interval += 5;
++            json_decref(result);
++            return EAGAIN;
+         } else {
+             *error_description = get_json_string(dc_ctx, result,
+                                                  "error_description");
+-- 
+2.37.3
+
diff --git a/SOURCES/0023-oidc_child-add-client-secret-stdin-option.patch b/SOURCES/0023-oidc_child-add-client-secret-stdin-option.patch
new file mode 100644
index 0000000..8ac9ba7
--- /dev/null
+++ b/SOURCES/0023-oidc_child-add-client-secret-stdin-option.patch
@@ -0,0 +1,194 @@
+From 2f3cd781879e7063fcd996389071458587623e1c Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 22 Aug 2022 11:37:07 +0200
+Subject: [PATCH 23/23] oidc_child: add --client-secret-stdin option
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Since there is the use-case of confidential client which requires that
+the client secret must be sent to the IdP we should handle it
+confidentially by not putting it on the command line but sending it via
+stdin.
+
+Resolves: https://github.com/SSSD/sssd/issues/6146
+
+Reviewed-by: Justin Stephenson <jstephen@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 1a475e0c537c905c80406ceb88c7b34e6400bc40)
+
+Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
+---
+ src/oidc_child/oidc_child.c | 89 ++++++++++++++++++++++++++++++++++---
+ 1 file changed, 82 insertions(+), 7 deletions(-)
+
+diff --git a/src/oidc_child/oidc_child.c b/src/oidc_child/oidc_child.c
+index c8d35d5d8..7758cdc25 100644
+--- a/src/oidc_child/oidc_child.c
++++ b/src/oidc_child/oidc_child.c
+@@ -34,7 +34,7 @@
+ #include "util/atomic_io.h"
+ 
+ #define IN_BUF_SIZE 4096
+-static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx)
++static errno_t read_from_stdin(TALLOC_CTX *mem_ctx, char **out)
+ {
+     uint8_t buf[IN_BUF_SIZE];
+     ssize_t len;
+@@ -56,7 +56,7 @@ static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx)
+         return EINVAL;
+     }
+ 
+-    str = talloc_strndup(dc_ctx, (char *) buf, len);
++    str = talloc_strndup(mem_ctx, (char *) buf, len);
+     sss_erase_mem_securely(buf, IN_BUF_SIZE);
+     if (str == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
+@@ -65,21 +65,72 @@ static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx)
+     talloc_set_destructor((void *) str, sss_erase_talloc_mem_securely);
+ 
+     if (strlen(str) != len) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "Input contains additional data, "
+-              "only JSON encoded device code expected.\n");
++        DEBUG(SSSDBG_CRIT_FAILURE, "Input contains additional data.\n");
+         talloc_free(str);
+         return EINVAL;
+     }
+ 
++    *out = str;
++
++    return EOK;
++}
++
++static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx,
++                                           const char **out)
++{
++    char *str;
++    errno_t ret;
++    char *sep;
++
++    ret = read_from_stdin(dc_ctx, &str);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "read_from_stdin failed.\n");
++        return ret;
++    }
++
++    if (out != NULL) {
++        /* expect the client secret in the first line */
++        sep = strchr(str, '\n');
++        if (sep == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "Format error, expecting client secret and JSON data.\n");
++            talloc_free(str);
++            return EINVAL;
++        }
++        *sep = '\0';
++        *out = str;
++        sep++;
++    } else {
++        sep = str;
++    }
++
+     clean_http_data(dc_ctx);
+-    dc_ctx->http_data = str;
++    dc_ctx->http_data = talloc_strdup(dc_ctx, sep);
+ 
+     DEBUG(SSSDBG_TRACE_ALL, "JSON device code: [%s].\n", dc_ctx->http_data);
+ 
+     return EOK;
+ }
+ 
++static errno_t read_client_secret_from_stdin(struct devicecode_ctx *dc_ctx,
++                                             const char **out)
++{
++    char *str;
++    errno_t ret;
++
++    ret = read_from_stdin(dc_ctx, &str);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "read_from_stdin failed.\n");
++        return ret;
++    }
++
++    *out = str;
++
++    DEBUG(SSSDBG_TRACE_ALL, "Client secret: [%s].\n", *out);
++
++    return EOK;
++}
++
+ static errno_t set_endpoints(struct devicecode_ctx *dc_ctx,
+                              const char *device_auth_endpoint,
+                              const char *token_endpoint,
+@@ -210,6 +261,7 @@ struct cli_opts {
+     const char *jwks_uri;
+     const char *scope;
+     const char *client_secret;
++    bool client_secret_stdin;
+     const char *ca_db;
+     const char *user_identifier_attr;
+     bool libcurl_debug;
+@@ -253,6 +305,8 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts)
+         {"client-id", 0, POPT_ARG_STRING, &opts->client_id, 0, _("Client ID"), NULL},
+         {"client-secret", 0, POPT_ARG_STRING, &opts->client_secret, 0,
+                 _("Client secret (if needed)"), NULL},
++        {"client-secret-stdin", 0, POPT_ARG_NONE, NULL, 's',
++                _("Read client secret from standard input"), NULL},
+         {"ca-db", 0, POPT_ARG_STRING, &opts->ca_db, 0,
+                 _("Path to PEM file with CA certificates"), NULL},
+         {"libcurl-debug", 0, POPT_ARG_NONE, NULL, 'c',
+@@ -280,6 +334,9 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts)
+         case 'c':
+             opts->libcurl_debug = true;
+             break;
++        case 's':
++            opts->client_secret_stdin = true;
++            break;
+         default:
+             fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                   poptBadOption(pc, 0), poptStrerror(opt));
+@@ -324,6 +381,12 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts)
+         goto done;
+     }
+ 
++    if (opts->client_secret != NULL && opts->client_secret_stdin) {
++        fprintf(stderr, "\n--client-secret and --client-secret-stdin are "
++                        "mutually exclusive.\n\n");
++        goto done;
++    }
++
+     poptFreeContext(pc);
+     print_usage = false;
+ 
+@@ -454,6 +517,15 @@ int main(int argc, const char *argv[])
+     }
+ 
+     if (opts.get_device_code) {
++        if (opts.client_secret_stdin) {
++            ret = read_client_secret_from_stdin(dc_ctx, &opts.client_secret);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_OP_FAILURE,
++                      "Failed to read client secret from stdin.\n");
++                goto done;
++            }
++        }
++
+         ret = get_devicecode(dc_ctx, opts.client_id, opts.client_secret);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE, "Failed to get device code.\n");
+@@ -463,7 +535,10 @@ int main(int argc, const char *argv[])
+ 
+     if (opts.get_access_token) {
+         if (dc_ctx->device_code == NULL) {
+-            ret = read_device_code_from_stdin(dc_ctx);
++            ret = read_device_code_from_stdin(dc_ctx,
++                                              opts.client_secret_stdin
++                                                           ? &opts.client_secret
++                                                           : NULL);
+             if (ret != EOK) {
+                 DEBUG(SSSDBG_OP_FAILURE,
+                       "Failed to read device code from stdin.\n");
+-- 
+2.37.3
+
diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec
index 1800e3b..4079416 100644
--- a/SPECS/sssd.spec
+++ b/SPECS/sssd.spec
@@ -19,7 +19,7 @@
 
 Name: sssd
 Version: 2.7.3
-Release: 4%{?dist}.1
+Release: 4%{?dist}.3
 Group: Applications/System
 Summary: System Security Services Daemon
 License: GPLv3+
@@ -38,6 +38,18 @@ Patch0008: 0008-RESPONDER-Fix-client-ID-tracking.patch
 Patch0009: 0009-Analyzer-support-parallel-requests-parsing.patch
 Patch0010: 0010-CLIENT-fix-client-fd-leak.patch
 Patch0011: 0011-krb5-respect-krb5_validate-for-PAC-checks.patch
+Patch0012: 0012-Analyzer-Optimize-list-verbose-output.patch
+Patch0013: 0013-Analyzer-Ensure-parsed-id-contains-digit.patch
+Patch0014: 0014-TOOLS-don-t-export-internal-helpers.patch
+Patch0015: 0015-TOOLS-fixed-handling-of-init-error.patch
+Patch0016: 0016-SSSCTL-don-t-require-root-for-analyze-cmd.patch
+Patch0017: 0017-PAC-allow-to-disable-UPN-check.patch
+Patch0018: 0018-ipa-do-not-add-guessed-principal-to-the-cache.patch
+Patch0019: 0019-pac-relax-default-check.patch
+Patch0020: 0020-oidc_child-escape-scopes.patch
+Patch0021: 0021-oidc_child-use-client-secret-if-available-to-get-dev.patch
+Patch0022: 0022-oidc_child-increase-wait-interval-by-5s-if-slow_down.patch
+Patch0023: 0023-oidc_child-add-client-secret-stdin-option.patch
 
 ### Downstream Patches ###
 
@@ -1188,6 +1200,14 @@ fi
 %systemd_postun_with_restart sssd.service
 
 %changelog
+* Thu Dec 15 2022 Alexey Tikhonov <atikhono@redhat.com> - 2.7.3-4.3
+- Resolves: rhbz#2152883 - authenticating against external IdP services okta (native app) with OAuth client secret failed [rhel-8.7.0.z]
+
+* Fri Dec  9 2022 Alexey Tikhonov <atikhono@redhat.com> - 2.7.3-4.2
+- Resolves: rhbz#2139871 - Analyzer: Optimize and remove duplicate messages in verbose list [rhel-8.7.0.z]
+- Resolves: rhbz#2142961 - SSSD: `sssctl analyze` command shouldn't require 'root' privileged [rhel-8.7.0.z]
+- Resolves: rhbz#2148989 - UPN check cannot be disabled explicitly but requires krb5_validate = false' as a work-around [rhel-8.7.0.z]
+
 * Thu Oct 13 2022 Alexey Tikhonov <atikhono@redhat.com> - 2.7.3-4.1
 - Resolves: rhbz#2128544 - Cannot SSH with AD user to ipa-client (`krb5_validate` and `pac_check` settings conflict) [rhel-8.7.0.z]