diff --git a/SOURCES/0037-Defer-creating-the-final-krb5.conf-on-clients.patch b/SOURCES/0037-Defer-creating-the-final-krb5.conf-on-clients.patch
new file mode 100644
index 0000000..85a68f5
--- /dev/null
+++ b/SOURCES/0037-Defer-creating-the-final-krb5.conf-on-clients.patch
@@ -0,0 +1,485 @@
+From 3eeeb160688eb8502217161e7c4df2aebbd2f704 Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Wed, 15 Mar 2023 11:58:27 +0100
+Subject: [PATCH] Defer creating the final krb5.conf on clients
+
+A temporary krb5.conf is created early during client enrollment
+and was previously used only during the initial ipa-join call.
+The final krb5.conf was written soon afterward.
+
+If there are multiple servers it is possible that the client
+may then choose a different KDC to connect. If the client
+is faster than replication then the client may not exist
+on all servers and therefore enrollment will fail.
+
+This was seen in performance testing of how many simultaneous
+client enrollments are possible.
+
+Use a decorator to wrap the _install() method to ensure the
+temporary files created during installation are cleaned up.
+
+https://pagure.io/freeipa/issue/9228
+
+Signed-off-by: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Stanislav Levin <slev@altlinux.org>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ ipaclient/install/client.py | 389 +++++++++++++++++++-----------------
+ 1 file changed, 202 insertions(+), 187 deletions(-)
+
+diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
+index eb4dc037ead309299121889875e9152ef2c92b7a..0f42937997452e9c37a2c98477638de51cf46b90 100644
+--- a/ipaclient/install/client.py
++++ b/ipaclient/install/client.py
+@@ -93,6 +93,37 @@ cli_basedn = None
+ # end of global variables
+ 
+ 
++def cleanup(func):
++    def inner(options, tdict):
++        # Add some additional options which contain the temporary files
++        # needed during installation.
++        fd, krb_name = tempfile.mkstemp()
++        os.close(fd)
++        ccache_dir = tempfile.mkdtemp(prefix='krbcc')
++
++        tdict['krb_name'] = krb_name
++        tdict['ccache_dir'] = ccache_dir
++
++        func(options, tdict)
++
++        os.environ.pop('KRB5_CONFIG', None)
++
++        try:
++            os.remove(krb_name)
++        except OSError:
++            logger.error("Could not remove %s", krb_name)
++        try:
++            os.rmdir(ccache_dir)
++        except OSError:
++            pass
++        try:
++            os.remove(krb_name + ".ipabkp")
++        except OSError:
++            logger.error("Could not remove %s.ipabkp", krb_name)
++
++    return inner
++
++
+ def remove_file(filename):
+     """
+     Deletes a file. If the file does not exist (OSError 2) does nothing.
+@@ -2388,7 +2419,7 @@ def update_ipa_nssdb():
+ 
+ def install(options):
+     try:
+-        _install(options)
++        _install(options, dict())
+     except ScriptError as e:
+         if e.rval == CLIENT_INSTALL_ERROR:
+             if options.force:
+@@ -2415,12 +2446,16 @@ def install(options):
+             pass
+ 
+ 
+-def _install(options):
++@cleanup
++def _install(options, tdict):
+     env = {'PATH': SECURE_PATH}
+ 
+     fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
+     statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE)
+ 
++    krb_name = tdict['krb_name']
++    ccache_dir = tdict['ccache_dir']
++
+     if not options.on_master:
+         # Try removing old principals from the keytab
+         purge_host_keytab(cli_realm)
+@@ -2476,186 +2511,166 @@ def _install(options):
+     host_principal = 'host/%s@%s' % (hostname, cli_realm)
+     if not options.on_master:
+         nolog = tuple()
+-        # First test out the kerberos configuration
+-        fd, krb_name = tempfile.mkstemp()
+-        os.close(fd)
+-        ccache_dir = tempfile.mkdtemp(prefix='krbcc')
+-        try:
+-            configure_krb5_conf(
+-                cli_realm=cli_realm,
+-                cli_domain=cli_domain,
+-                cli_server=cli_server,
+-                cli_kdc=cli_kdc,
+-                dnsok=False,
+-                filename=krb_name,
+-                client_domain=client_domain,
+-                client_hostname=hostname,
+-                configure_sssd=options.sssd,
+-                force=options.force)
+-            env['KRB5_CONFIG'] = krb_name
+-            ccache_name = os.path.join(ccache_dir, 'ccache')
+-            join_args = [paths.SBIN_IPA_JOIN,
+-                         "-s", cli_server[0],
+-                         "-b", str(realm_to_suffix(cli_realm)),
+-                         "-h", hostname]
+-            if options.debug:
+-                join_args.append("-d")
+-                env['XMLRPC_TRACE_CURL'] = 'yes'
+-            if options.force_join:
+-                join_args.append("-f")
+-            if options.principal is not None:
+-                stdin = None
+-                principal = options.principal
+-                if principal.find('@') == -1:
+-                    principal = '%s@%s' % (principal, cli_realm)
+-                if options.password is not None:
+-                    stdin = options.password
++        configure_krb5_conf(
++            cli_realm=cli_realm,
++            cli_domain=cli_domain,
++            cli_server=cli_server,
++            cli_kdc=cli_kdc,
++            dnsok=False,
++            filename=krb_name,
++            client_domain=client_domain,
++            client_hostname=hostname,
++            configure_sssd=options.sssd,
++            force=options.force)
++        env['KRB5_CONFIG'] = krb_name
++        ccache_name = os.path.join(ccache_dir, 'ccache')
++        join_args = [paths.SBIN_IPA_JOIN,
++                     "-s", cli_server[0],
++                     "-b", str(realm_to_suffix(cli_realm)),
++                     "-h", hostname]
++        if options.debug:
++            join_args.append("-d")
++            env['XMLRPC_TRACE_CURL'] = 'yes'
++        if options.force_join:
++            join_args.append("-f")
++        if options.principal is not None:
++            stdin = None
++            principal = options.principal
++            if principal.find('@') == -1:
++                principal = '%s@%s' % (principal, cli_realm)
++            if options.password is not None:
++                stdin = options.password
++            else:
++                if not options.unattended:
++                    try:
++                        stdin = getpass.getpass(
++                            "Password for %s: " % principal)
++                    except EOFError:
++                        stdin = None
++                    if not stdin:
++                        raise ScriptError(
++                            "Password must be provided for {}.".format(
++                                principal),
++                            rval=CLIENT_INSTALL_ERROR)
+                 else:
+-                    if not options.unattended:
+-                        try:
+-                            stdin = getpass.getpass(
+-                                "Password for %s: " % principal)
+-                        except EOFError:
+-                            stdin = None
+-                        if not stdin:
+-                            raise ScriptError(
+-                                "Password must be provided for {}.".format(
+-                                    principal),
+-                                rval=CLIENT_INSTALL_ERROR)
++                    if sys.stdin.isatty():
++                        logger.error(
++                            "Password must be provided in "
++                            "non-interactive mode.")
++                        logger.info(
++                            "This can be done via "
++                            "echo password | ipa-client-install ... "
++                            "or with the -w option.")
++                        raise ScriptError(rval=CLIENT_INSTALL_ERROR)
+                     else:
+-                        if sys.stdin.isatty():
+-                            logger.error(
+-                                "Password must be provided in "
+-                                "non-interactive mode.")
+-                            logger.info(
+-                                "This can be done via "
+-                                "echo password | ipa-client-install ... "
+-                                "or with the -w option.")
+-                            raise ScriptError(rval=CLIENT_INSTALL_ERROR)
+-                        else:
+-                            stdin = sys.stdin.readline()
++                        stdin = sys.stdin.readline()
+ 
++            try:
++                kinit_password(principal, stdin, ccache_name,
++                               config=krb_name)
++            except RuntimeError as e:
++                print_port_conf_info()
++                raise ScriptError(
++                    "Kerberos authentication failed: {}".format(e),
++                    rval=CLIENT_INSTALL_ERROR)
++        elif options.keytab:
++            join_args.append("-f")
++            if os.path.exists(options.keytab):
+                 try:
+-                    kinit_password(principal, stdin, ccache_name,
+-                                   config=krb_name)
+-                except RuntimeError as e:
++                    kinit_keytab(host_principal,
++                                 options.keytab,
++                                 ccache_name,
++                                 config=krb_name,
++                                 attempts=options.kinit_attempts)
++                except gssapi.exceptions.GSSError as e:
+                     print_port_conf_info()
+                     raise ScriptError(
+                         "Kerberos authentication failed: {}".format(e),
+                         rval=CLIENT_INSTALL_ERROR)
+-            elif options.keytab:
+-                join_args.append("-f")
+-                if os.path.exists(options.keytab):
+-                    try:
+-                        kinit_keytab(host_principal,
+-                                     options.keytab,
+-                                     ccache_name,
+-                                     config=krb_name,
+-                                     attempts=options.kinit_attempts)
+-                    except gssapi.exceptions.GSSError as e:
+-                        print_port_conf_info()
+-                        raise ScriptError(
+-                            "Kerberos authentication failed: {}".format(e),
+-                            rval=CLIENT_INSTALL_ERROR)
+-                else:
+-                    raise ScriptError(
+-                        "Keytab file could not be found: {}".format(
+-                            options.keytab),
+-                        rval=CLIENT_INSTALL_ERROR)
+-            elif options.password:
+-                nolog = (options.password,)
+-                join_args.append("-w")
+-                join_args.append(options.password)
+-            elif options.prompt_password:
+-                if options.unattended:
+-                    raise ScriptError(
+-                        "Password must be provided in non-interactive mode",
+-                        rval=CLIENT_INSTALL_ERROR)
+-                try:
+-                    password = getpass.getpass("Password: ")
+-                except EOFError:
+-                    password = None
+-                if not password:
+-                    raise ScriptError(
+-                        "Password must be provided.",
+-                        rval=CLIENT_INSTALL_ERROR)
+-                join_args.append("-w")
+-                join_args.append(password)
+-                nolog = (password,)
+-
+-            env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = ccache_name
+-            # Get the CA certificate
++            else:
++                raise ScriptError(
++                    "Keytab file could not be found: {}".format(
++                        options.keytab),
++                    rval=CLIENT_INSTALL_ERROR)
++        elif options.password:
++            nolog = (options.password,)
++            join_args.append("-w")
++            join_args.append(options.password)
++        elif options.prompt_password:
++            if options.unattended:
++                raise ScriptError(
++                    "Password must be provided in non-interactive mode",
++                    rval=CLIENT_INSTALL_ERROR)
+             try:
+-                os.environ['KRB5_CONFIG'] = env['KRB5_CONFIG']
+-                get_ca_certs(fstore, options, cli_server[0], cli_basedn,
+-                             cli_realm)
+-                del os.environ['KRB5_CONFIG']
+-            except errors.FileError as e:
+-                logger.error('%s', e)
+-                raise ScriptError(rval=CLIENT_INSTALL_ERROR)
+-            except Exception as e:
+-                logger.error("Cannot obtain CA certificate\n%s", e)
+-                raise ScriptError(rval=CLIENT_INSTALL_ERROR)
++                password = getpass.getpass("Password: ")
++            except EOFError:
++                password = None
++            if not password:
++                raise ScriptError(
++                    "Password must be provided.",
++                    rval=CLIENT_INSTALL_ERROR)
++            join_args.append("-w")
++            join_args.append(password)
++            nolog = (password,)
+ 
+-            # Now join the domain
+-            result = run(
+-                join_args, raiseonerr=False, env=env, nolog=nolog,
+-                capture_error=True)
+-            stderr = result.error_output
++        env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = ccache_name
++        # Get the CA certificate
++        try:
++            os.environ['KRB5_CONFIG'] = env['KRB5_CONFIG']
++            get_ca_certs(fstore, options, cli_server[0], cli_basedn,
++                         cli_realm)
++        except errors.FileError as e:
++            logger.error('%s', e)
++            raise ScriptError(rval=CLIENT_INSTALL_ERROR)
++        except Exception as e:
++            logger.error("Cannot obtain CA certificate\n%s", e)
++            raise ScriptError(rval=CLIENT_INSTALL_ERROR)
+ 
+-            if result.returncode != 0:
+-                logger.error("Joining realm failed: %s", stderr)
+-                if not options.force:
+-                    if result.returncode == 13:
+-                        logger.info(
+-                            "Use --force-join option to override the host "
+-                            "entry on the server and force client enrollment.")
+-                    raise ScriptError(rval=CLIENT_INSTALL_ERROR)
+-                logger.info(
+-                    "Use ipa-getkeytab to obtain a host "
+-                    "principal for this server.")
+-            else:
+-                logger.info("Enrolled in IPA realm %s", cli_realm)
+-
+-            start = stderr.find('Certificate subject base is: ')
+-            if start >= 0:
+-                start = start + 29
+-                subject_base = stderr[start:]
+-                subject_base = subject_base.strip()
+-                subject_base = DN(subject_base)
+-
+-            if options.principal is not None:
+-                run([paths.KDESTROY], raiseonerr=False, env=env)
+-
+-            # Obtain the TGT. We do it with the temporary krb5.conf, so that
+-            # only the KDC we're installing under is contacted.
+-            # Other KDCs might not have replicated the principal yet.
+-            # Once we have the TGT, it's usable on any server.
+-            try:
+-                kinit_keytab(host_principal, paths.KRB5_KEYTAB, CCACHE_FILE,
+-                             config=krb_name,
+-                             attempts=options.kinit_attempts)
+-                env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = CCACHE_FILE
+-            except gssapi.exceptions.GSSError as e:
+-                print_port_conf_info()
+-                logger.error("Failed to obtain host TGT: %s", e)
+-                # failure to get ticket makes it impossible to login and bind
+-                # from sssd to LDAP, abort installation and rollback changes
+-                raise ScriptError(rval=CLIENT_INSTALL_ERROR)
++        # Now join the domain
++        result = run(
++            join_args, raiseonerr=False, env=env, nolog=nolog,
++            capture_error=True)
++        stderr = result.error_output
+ 
+-        finally:
+-            try:
+-                os.remove(krb_name)
+-            except OSError:
+-                logger.error("Could not remove %s", krb_name)
+-            try:
+-                os.rmdir(ccache_dir)
+-            except OSError:
+-                pass
+-            try:
+-                os.remove(krb_name + ".ipabkp")
+-            except OSError:
+-                logger.error("Could not remove %s.ipabkp", krb_name)
++        if result.returncode != 0:
++            logger.error("Joining realm failed: %s", stderr)
++            if not options.force:
++                if result.returncode == 13:
++                    logger.info(
++                        "Use --force-join option to override the host "
++                        "entry on the server and force client enrollment.")
++                raise ScriptError(rval=CLIENT_INSTALL_ERROR)
++            logger.info(
++                "Use ipa-getkeytab to obtain a host "
++                "principal for this server.")
++        else:
++            logger.info("Enrolled in IPA realm %s", cli_realm)
++
++        start = stderr.find('Certificate subject base is: ')
++        if start >= 0:
++            start = start + 29
++            subject_base = stderr[start:]
++            subject_base = subject_base.strip()
++            subject_base = DN(subject_base)
++
++        if options.principal is not None:
++            run([paths.KDESTROY], raiseonerr=False, env=env)
++
++        # Obtain the TGT. We do it with the temporary krb5.conf, so that
++        # only the KDC we're installing under is contacted.
++        # Other KDCs might not have replicated the principal yet.
++        # Once we have the TGT, it's usable on any server.
++        try:
++            kinit_keytab(host_principal, paths.KRB5_KEYTAB, CCACHE_FILE,
++                         config=krb_name,
++                         attempts=options.kinit_attempts)
++            env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = CCACHE_FILE
++        except gssapi.exceptions.GSSError as e:
++            print_port_conf_info()
++            logger.error("Failed to obtain host TGT: %s", e)
++            # failure to get ticket makes it impossible to login and bind
++            # from sssd to LDAP, abort installation and rollback changes
++            raise ScriptError(rval=CLIENT_INSTALL_ERROR)
+ 
+     # Configure ipa.conf
+     if not options.on_master:
+@@ -2692,23 +2707,6 @@ def _install(options):
+             except gssapi.exceptions.GSSError as e:
+                 logger.error("Failed to obtain host TGT: %s", e)
+                 raise ScriptError(rval=CLIENT_INSTALL_ERROR)
+-        else:
+-            # Configure krb5.conf
+-            fstore.backup_file(paths.KRB5_CONF)
+-            configure_krb5_conf(
+-                cli_realm=cli_realm,
+-                cli_domain=cli_domain,
+-                cli_server=cli_server,
+-                cli_kdc=cli_kdc,
+-                dnsok=dnsok,
+-                filename=paths.KRB5_CONF,
+-                client_domain=client_domain,
+-                client_hostname=hostname,
+-                configure_sssd=options.sssd,
+-                force=options.force)
+-
+-            logger.info(
+-                "Configured /etc/krb5.conf for IPA realm %s", cli_realm)
+ 
+         # Clear out any current session keyring information
+         try:
+@@ -3020,6 +3018,23 @@ def _install(options):
+         configure_nisdomain(
+             options=options, domain=cli_domain, statestore=statestore)
+ 
++    # Configure the final krb5.conf
++    if not options.on_master:
++        fstore.backup_file(paths.KRB5_CONF)
++        configure_krb5_conf(
++            cli_realm=cli_realm,
++            cli_domain=cli_domain,
++            cli_server=cli_server,
++            cli_kdc=cli_kdc,
++            dnsok=dnsok,
++            filename=paths.KRB5_CONF,
++            client_domain=client_domain,
++            client_hostname=hostname,
++            configure_sssd=options.sssd,
++            force=options.force)
++
++        logger.info("Configured /etc/krb5.conf for IPA realm %s", cli_realm)
++
+     logger.info('Client configuration complete.')
+ 
+ 
+-- 
+2.39.2
+
diff --git a/SOURCES/0038-Move-client-certificate-request-after-krb5.conf-is-c.patch b/SOURCES/0038-Move-client-certificate-request-after-krb5.conf-is-c.patch
new file mode 100644
index 0000000..857a99c
--- /dev/null
+++ b/SOURCES/0038-Move-client-certificate-request-after-krb5.conf-is-c.patch
@@ -0,0 +1,56 @@
+From b043d78bf300a2ec7aa5cc73eb89c56334c6588e Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Wed, 15 Mar 2023 12:00:46 +0100
+Subject: [PATCH] Move client certificate request after krb5.conf is created
+
+The creation of krb5.conf was moved to the end of the script
+as part of maintaining server affinity during ipa-client-install.
+If the installation is faster than replication then requests
+against some IPA servers may fail because the client entry is
+not yet present.
+
+This is more difficult with certmonger as it will only use
+/etc/krb5.conf. There is no way of knowing, even at the end
+of the client installation, that replication has finished.
+
+Certificate issuance may fail during ipa-client-install but
+certmonger will re-try the request.
+
+Fixes: https://pagure.io/freeipa/issue/9246
+
+Signed-off-by: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Stanislav Levin <slev@altlinux.org>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ ipaclient/install/client.py | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
+index 0f42937997452e9c37a2c98477638de51cf46b90..fed649065c94d2f2623157b825b374b850a4a03e 100644
+--- a/ipaclient/install/client.py
++++ b/ipaclient/install/client.py
+@@ -2836,8 +2836,6 @@ def _install(options, tdict):
+ 
+     if not options.on_master:
+         client_dns(cli_server[0], hostname, options)
+-        configure_certmonger(fstore, subject_base, cli_realm, hostname,
+-                             options, ca_enabled)
+ 
+     update_ssh_keys(hostname, paths.SSH_CONFIG_DIR, options.create_sshfp)
+ 
+@@ -3035,6 +3033,11 @@ def _install(options, tdict):
+ 
+         logger.info("Configured /etc/krb5.conf for IPA realm %s", cli_realm)
+ 
++        # Configure certmonger after krb5.conf is created and last
++        # to give higher chance that the new client is replicated. 
++        configure_certmonger(fstore, subject_base, cli_realm, hostname,
++                             options, ca_enabled)
++
+     logger.info('Client configuration complete.')
+ 
+ 
+-- 
+2.39.2
+
diff --git a/SOURCES/0039-server-install-remove-error-log-about-missing-bkup-f.patch b/SOURCES/0039-server-install-remove-error-log-about-missing-bkup-f.patch
new file mode 100644
index 0000000..63d018e
--- /dev/null
+++ b/SOURCES/0039-server-install-remove-error-log-about-missing-bkup-f.patch
@@ -0,0 +1,56 @@
+From 34e9cfc34a397d2b0e34167fe6ff7cace1c4a020 Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Wed, 15 Mar 2023 12:04:23 +0100
+Subject: [PATCH] server install: remove error log about missing bkup file
+
+The client installer code can be called in 3 different ways:
+- from ipa-client-install CLI
+- from ipa-replica-install CLI if the client is not already installed
+- from ipa-server-install
+
+In the last case, the client installer is called with
+options.on_master=True
+As a result, it's skipping the part that is creating the krb5
+configuration:
+    if not options.on_master:
+        nolog = tuple()
+        configure_krb5_conf(...)
+
+The configure_krb5_conf method is the place where the krb5.conf file is
+backup'ed with the extention ".ipabkp". For a master installation, this
+code is not called and the ipabkp file does not exist => delete raises
+an error.
+
+When delete fails because the file does not exist, no need to log an
+error message.
+
+Fixes: https://pagure.io/freeipa/issue/9306
+Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Stanislav Levin <slev@altlinux.org>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ ipaclient/install/client.py | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
+index fed649065c94d2f2623157b825b374b850a4a03e..6fcb97641b7a9367aa32ff0401653a0e34b12073 100644
+--- a/ipaclient/install/client.py
++++ b/ipaclient/install/client.py
+@@ -116,10 +116,9 @@ def cleanup(func):
+             os.rmdir(ccache_dir)
+         except OSError:
+             pass
+-        try:
+-            os.remove(krb_name + ".ipabkp")
+-        except OSError:
+-            logger.error("Could not remove %s.ipabkp", krb_name)
++        # During master installation, the .ipabkp file is not created
++        # Ignore the delete error if it is "file does not exist"
++        remove_file(krb_name + ".ipabkp")
+ 
+     return inner
+ 
+-- 
+2.39.2
+
diff --git a/SOURCES/0040-ipaserver-deepcopy-objectclasses-list-from-IPA-confi.patch b/SOURCES/0040-ipaserver-deepcopy-objectclasses-list-from-IPA-confi.patch
new file mode 100644
index 0000000..252da38
--- /dev/null
+++ b/SOURCES/0040-ipaserver-deepcopy-objectclasses-list-from-IPA-confi.patch
@@ -0,0 +1,65 @@
+From b813e9ed8807b14d647035a8f8df0002cebe79dd Mon Sep 17 00:00:00 2001
+From: Antonio Torres <antorres@redhat.com>
+Date: Wed, 15 Mar 2023 11:24:06 +0100
+Subject: [PATCH] ipaserver: deepcopy objectclasses list from IPA config
+
+We need to deepcopy the list of default objectlasses from IPA config
+before assigning it to an entry, in order to avoid further modifications of the
+entry affect the cached IPA config.
+
+Fixes: https://pagure.io/freeipa/issue/9349
+Signed-off-by: Antonio Torres <antorres@redhat.com>
+Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
+Reviewed-By: Thomas Woerner <twoerner@redhat.com>
+---
+ ipaserver/plugins/baseldap.py  | 8 ++++----
+ ipaserver/plugins/stageuser.py | 4 ++--
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/ipaserver/plugins/baseldap.py b/ipaserver/plugins/baseldap.py
+index 25449b5aec72cbdbfb57527aa834cc69291398d6..8c041eb26e2c5c905f605f16288f49c4b7a2a274 100644
+--- a/ipaserver/plugins/baseldap.py
++++ b/ipaserver/plugins/baseldap.py
+@@ -796,9 +796,9 @@ class LDAPObject(Object):
+         objectclasses = self.object_class
+         if self.object_class_config:
+             config = ldap.get_ipa_config()
+-            objectclasses = config.get(
++            objectclasses = deepcopy(config.get(
+                 self.object_class_config, objectclasses
+-            )
++            ))
+         objectclasses = objectclasses + self.possible_objectclasses
+         # Get list of available attributes for this object for use
+         # in the ACI UI.
+@@ -1157,9 +1157,9 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
+ 
+         if self.obj.object_class_config:
+             config = ldap.get_ipa_config()
+-            entry_attrs['objectclass'] = config.get(
++            entry_attrs['objectclass'] = deepcopy(config.get(
+                 self.obj.object_class_config, entry_attrs['objectclass']
+-            )
++            ))
+ 
+         if self.obj.uuid_attribute:
+             entry_attrs[self.obj.uuid_attribute] = 'autogenerate'
+diff --git a/ipaserver/plugins/stageuser.py b/ipaserver/plugins/stageuser.py
+index 9591a7dda746db64b9c765140d1ef1fb1ecb2ce7..b3e65b76544ca572b822fb3c85e777bb41d21a2d 100644
+--- a/ipaserver/plugins/stageuser.py
++++ b/ipaserver/plugins/stageuser.py
+@@ -557,9 +557,9 @@ class stageuser_activate(LDAPQuery):
+ 
+         if self.obj.object_class_config:
+             config = ldap.get_ipa_config()
+-            entry_attrs['objectclass'] = config.get(
++            entry_attrs['objectclass'] = deepcopy(config.get(
+                 self.obj.object_class_config, entry_attrs['objectclass']
+-            )
++            ))
+ 
+         return(entry_attrs)
+ 
+-- 
+2.39.2
+
diff --git a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch
index 73d9e4c..5e6669d 100644
--- a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch
+++ b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch
@@ -1,4 +1,4 @@
-From 30f0bf5c45dfa3febbad283a248d942839957c11 Mon Sep 17 00:00:00 2001
+From 312afefae97cf9cdb9cfe2dd4c2e601b96398f2f Mon Sep 17 00:00:00 2001
 From: Jan Cholasta <jcholast@redhat.com>
 Date: Tue, 14 Mar 2017 15:48:07 +0000
 Subject: [PATCH] Change branding to IPA and Identity Management
@@ -1106,5 +1106,5 @@ index 643215985e932cae6e8d954596194032655b25d4..68baa0174ed88ede3f42092fb68150b5
  """) + _("""
  To enable the binddn run the following command to set the password:
 -- 
-2.37.3
+2.39.2
 
diff --git a/SOURCES/1002-Package-copy-schema-to-ca.py.patch b/SOURCES/1002-Package-copy-schema-to-ca.py.patch
index d6b46fb..25153c9 100644
--- a/SOURCES/1002-Package-copy-schema-to-ca.py.patch
+++ b/SOURCES/1002-Package-copy-schema-to-ca.py.patch
@@ -1,4 +1,4 @@
-From eeebacdeaf864935f30221fdaa11ee56f07b7090 Mon Sep 17 00:00:00 2001
+From 647b13eb361f5c47ed48eeb013b5b16c5b721822 Mon Sep 17 00:00:00 2001
 From: Jan Cholasta <jcholast@redhat.com>
 Date: Tue, 14 Mar 2017 16:07:15 +0000
 Subject: [PATCH] Package copy-schema-to-ca.py
@@ -40,5 +40,5 @@ index 922185c4b948fa7a5d1bcab6b2be3b34e99f66d4..8fead26f50cb4f045db6d60f9ca71dd9
  
  
 -- 
-2.37.3
+2.39.2
 
diff --git a/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch b/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch
index df8851a..7ff17c9 100644
--- a/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch
+++ b/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch
@@ -1,4 +1,4 @@
-From f96e4f5e24998cec67417d6401c36116e19fc253 Mon Sep 17 00:00:00 2001
+From b3a5f7efdb263aaa093fa66ca8322dc3e1d0d691 Mon Sep 17 00:00:00 2001
 From: Jan Cholasta <jcholast@redhat.com>
 Date: Wed, 22 Jun 2016 13:53:46 +0200
 Subject: [PATCH] Revert "Increased mod_wsgi socket-timeout"
@@ -24,5 +24,5 @@ index 912a63c2240e0681dfbeeac223a902b15b304716..c5fc518f803d379287043b405efeb46d
  WSGIImportScript /usr/share/ipa/wsgi.py process-group=ipa application-group=ipa
  WSGIScriptAlias /ipa /usr/share/ipa/wsgi.py
 -- 
-2.37.3
+2.39.2
 
diff --git a/SOURCES/1004-Remove-csrgen.patch b/SOURCES/1004-Remove-csrgen.patch
index 8600207..9c51298 100644
--- a/SOURCES/1004-Remove-csrgen.patch
+++ b/SOURCES/1004-Remove-csrgen.patch
@@ -1,4 +1,4 @@
-From 84addcb2cbdd327947a6c5849f31ac2a06177443 Mon Sep 17 00:00:00 2001
+From 857aad5b92ae9b489fa7440cb27e8277150ce563 Mon Sep 17 00:00:00 2001
 From: Jan Cholasta <jcholast@redhat.com>
 Date: Thu, 16 Mar 2017 09:44:21 +0000
 Subject: [PATCH] Remove csrgen
@@ -403,5 +403,5 @@ index 79111ab686b4fe25227796509b3cd3fcb54af728..00000000000000000000000000000000
 @@ -1 +0,0 @@
 -{{ options|join(";") }}
 -- 
-2.37.3
+2.39.2
 
diff --git a/SOURCES/1005-Removing-filesystem-encoding-check.patch b/SOURCES/1005-Removing-filesystem-encoding-check.patch
index ec4d5bf..3caf84c 100644
--- a/SOURCES/1005-Removing-filesystem-encoding-check.patch
+++ b/SOURCES/1005-Removing-filesystem-encoding-check.patch
@@ -1,4 +1,4 @@
-From b4fc9155939f8ac9e356a9a3601f1625bade1d16 Mon Sep 17 00:00:00 2001
+From 3cd6a0d933544b98b6f0ead1c5f7ff1f8e131e80 Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= <tdudlak@redhat.com>
 Date: Fri, 10 Aug 2018 13:16:38 +0200
 Subject: [PATCH] Removing filesystem encoding check
@@ -126,5 +126,5 @@ index b660532bd6e8db964b8287845ed1b5ebbcb43b9b..60309c58f250a263c8c3d13b0b47773b
  IPA_NOT_CONFIGURED = b'IPA is not configured on this system'
  IPA_CLIENT_NOT_CONFIGURED = b'IPA client is not configured on this system'
 -- 
-2.37.3
+2.39.2
 
diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec
index 0873eb5..769224f 100644
--- a/SPECS/ipa.spec
+++ b/SPECS/ipa.spec
@@ -103,7 +103,7 @@
 
 Name:           ipa
 Version:        %{IPA_VERSION}
-Release:        5%{?dist}.12
+Release:        5%{?dist}.14
 Summary:        The Identity, Policy and Audit system
 
 Group:          System Environment/Base
@@ -111,9 +111,9 @@ License:        GPLv3+
 URL:            http://www.freeipa.org/
 Source0:        https://releases.pagure.org/freeipa/freeipa-%{version}.tar.gz
 # RHEL spec file only: START: Change branding to IPA and Identity Management
-#Source1:        header-logo.png
-#Source2:        login-screen-background.jpg
-#Source4:        product-name.png
+Source1:        header-logo.png
+Source2:        login-screen-background.jpg
+Source4:        product-name.png
 # RHEL spec file only: END: Change branding to IPA and Identity Management
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
@@ -154,6 +154,10 @@ Patch0033:      0033-ipa-otptoken-sync-return-error-when-sync-fails.patch
 Patch0034:      0034-ipatests-add-negative-test-for-otptoken-sync.patch
 Patch0035:      0035-ipatests-python2-does-not-support-f-strings.patch
 Patch0036:      0036-Fix-otptoken_sync-plugin.patch
+Patch0037:      0037-Defer-creating-the-final-krb5.conf-on-clients.patch
+Patch0038:      0038-Move-client-certificate-request-after-krb5.conf-is-c.patch
+Patch0039:      0039-server-install-remove-error-log-about-missing-bkup-f.patch
+Patch0040:      0040-ipaserver-deepcopy-objectclasses-list-from-IPA-confi.patch
 Patch1001:      1001-Change-branding-to-IPA-and-Identity-Management.patch
 Patch1002:      1002-Package-copy-schema-to-ca.py.patch
 Patch1003:      1003-Revert-Increased-mod_wsgi-socket-timeout.patch
@@ -410,10 +414,7 @@ Requires: oddjob
 Requires: gssproxy >= 0.7.0-2
 # 1.15.2: FindByNameAndCertificate (https://pagure.io/SSSD/sssd/issue/3050)
 Requires: sssd-dbus >= 1.15.2
-
-%if 0%{?centos} == 0
 Requires: system-logos >= 70.7.0
-%endif
 
 Provides: %{alt_name}-server = %{version}
 Conflicts: %{alt_name}-server
@@ -970,9 +971,9 @@ cp -r %{_builddir}/freeipa-%{version} %{_builddir}/freeipa-%{version}-python3
 # with_python3
 
 # RHEL spec file only: START: Change branding to IPA and Identity Management
-#cp %SOURCE1 install/ui/images/header-logo.png
-#cp %SOURCE2 install/ui/images/login-screen-background.jpg
-#cp %SOURCE4 install/ui/images/product-name.png
+cp %SOURCE1 install/ui/images/header-logo.png
+cp %SOURCE2 install/ui/images/login-screen-background.jpg
+cp %SOURCE4 install/ui/images/product-name.png
 # RHEL spec file only: END: Change branding to IPA and Identity Management
 
 
@@ -996,8 +997,7 @@ find \
 %configure --with-vendor-suffix=-%{release} \
            %{enable_server_option} \
            %{with_ipatests_option} \
-           %{linter_options} \
-           --with-ipaplatform=rhel
+           %{linter_options}
 
 %make_build
 
@@ -1018,8 +1018,7 @@ find \
 %configure --with-vendor-suffix=-%{release} \
            %{enable_server_option} \
            %{with_ipatests_option} \
-           %{linter_options} \
-           --with-ipaplatform=rhel
+           %{linter_options}
 popd
 %endif
 # with_python3
@@ -1106,11 +1105,9 @@ ln -s %{_bindir}/ipa-test-task-%{python2_version} %{buildroot}%{_bindir}/ipa-tes
 # remove files which are useful only for make uninstall
 find %{buildroot} -wholename '*/site-packages/*/install_files.txt' -exec rm {} \;
 
-%if 0%{?centos} == 0
 # RHEL spec file only: START: Replace login-screen-logo.png with a symlink
 ln -sf %{_datadir}/pixmaps/fedora-gdm-logo.png %{buildroot}%{_usr}/share/ipa/ui/images/login-screen-logo.png
 # RHEL spec file only: END: Replace login-screen-logo.png with a symlink
-%endif
 
 %find_lang %{gettext_domain}
 
@@ -1767,8 +1764,15 @@ fi
 
 
 %changelog
-* Wed Nov 02 2022 CentOS Sources <bugs@centos.org> - 4.6.8-5.el7.centos.12
-- Roll in CentOS Branding
+* Thu Mar 23 2023 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.8-5.el7_9.14
+- Resolves: 2180919 [rhel-7] Sequence processing failures for group_add using server context
+  - ipaserver: deepcopy objectclasses list from IPA config
+
+* Mon Mar 20 2023 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.8-5.el7_9.13
+- Resolves: 2148249 - ipa-client-install does not maintain server affinity during installation
+  - Defer creating the final krb5.conf on clients
+  - Move client certificate request after krb5.conf is created
+  - server install: remove error log about missing bkup file
 
 * Wed Oct 5 2022 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.8-5.el7_9.12
 - Resolves: 2084223 - 'ipa idview-show idviewname' & IPA WebUI takes longer time to return the results