diff --git a/jans-linux-setup/jans_setup/install.py b/jans-linux-setup/jans_setup/install.py index 8b0a4032fb6..79732c000a4 100755 --- a/jans-linux-setup/jans_setup/install.py +++ b/jans-linux-setup/jans_setup/install.py @@ -230,6 +230,9 @@ def uninstall_jans(): if os.path.exists('/opt/opa'): service_list.append('opa') + if os.path.exists('/opt/kc-scheduler'): + service_list.append('kc-scheduler') + for service in service_list: print("Stopping", service) @@ -249,7 +252,7 @@ def uninstall_jans(): os.system('systemctl daemon-reload') os.system('systemctl reset-failed') - remove_list = ['/etc/certs', '/etc/jans', '/opt/amazon-corretto*', '/opt/jre', '/opt/node*', '/opt/jetty*', '/opt/jython*', '/opt/keycloak', '/opt/idp', '/opt/opa'] + remove_list = ['/etc/certs', '/etc/jans', '/opt/amazon-corretto*', '/opt/jre', '/opt/node*', '/opt/jetty*', '/opt/jython*', '/opt/keycloak', '/opt/idp', '/opt/opa', '/opt/kc-scheduler'] if argsp.profile == 'jans': remove_list.append('/opt/opendj') if not argsp.keep_downloads: diff --git a/jans-linux-setup/jans_setup/setup_app/installers/jans.py b/jans-linux-setup/jans_setup/setup_app/installers/jans.py index 598e582ac47..127b6f3f316 100644 --- a/jans-linux-setup/jans_setup/setup_app/installers/jans.py +++ b/jans-linux-setup/jans_setup/setup_app/installers/jans.py @@ -110,6 +110,8 @@ def initialize(self): jansProgress.register(self) Config.install_time_ldap = time.strftime('%Y%m%d%H%M%SZ', time.gmtime(time.time())) + Config.jans_version = base.current_app.app_info['JANS_APP_VERSION'] + if not os.path.exists(Config.distFolder): print("Please ensure that you are running this script inside Jans container.") sys.exit(1) @@ -570,8 +572,7 @@ def secure_files(self): self.run([paths.cmd_chmod, '640', p.as_posix()]) if not Config.installed_instance: - cron_service = 'crond' if base.os_type in ['centos', 'red', 'fedora'] else 'cron' - self.restart(cron_service) + self.restart(base.cron_service) # if we are running inside shiv package, copy site pacakages to /opt/dist/jans-setup-packages and add to sys path @@ -654,6 +655,7 @@ def order_services(self): ('opa', 'install_opa'), ('saml', 'install_jans_saml'), ('jans-keycloak-link', 'install_jans_keycloak_link'), + ('kc-scheduler', 'install_jans_saml'), ] service_listr = service_list[:] service_listr.reverse() diff --git a/jans-linux-setup/jans_setup/setup_app/installers/jans_saml.py b/jans-linux-setup/jans_setup/setup_app/installers/jans_saml.py index 0b08fe0790b..b63ca6f5c6b 100644 --- a/jans-linux-setup/jans_setup/setup_app/installers/jans_saml.py +++ b/jans-linux-setup/jans_setup/setup_app/installers/jans_saml.py @@ -39,6 +39,8 @@ class JansSamlInstaller(JettyInstaller): (os.path.join(Config.dist_jans_dir, 'kc-jans-authn-plugin.jar'), os.path.join(base.current_app.app_info['JANS_MAVEN'], 'maven/io/jans/kc-jans-authn-plugin/{0}/kc-jans-authn-plugin-{0}.jar').format(base.current_app.app_info['jans_version'])), (os.path.join(Config.dist_jans_dir, 'kc-jans-authn-plugin-deps.zip'), os.path.join(base.current_app.app_info['JANS_MAVEN'], 'maven/io/jans/kc-jans-authn-plugin/{0}/kc-jans-authn-plugin-{0}-deps.zip').format(base.current_app.app_info['jans_version'])), (os.path.join(Config.dist_jans_dir, 'kc-saml-plugin.jar'), os.path.join(base.current_app.app_info['JANS_MAVEN'], 'maven/io/jans/jans-config-api/plugins/kc-saml-plugin/{0}/kc-saml-plugin-{0}-distribution.jar').format(base.current_app.app_info['jans_version'])), + (os.path.join(Config.dist_jans_dir, 'kc-jans-scheduler-deps.zip'), os.path.join(base.current_app.app_info['JANS_MAVEN'], 'maven/io/jans/kc-jans-scheduler/{0}/kc-jans-scheduler-{0}-deps.zip').format(base.current_app.app_info['jans_version'])), + (os.path.join(Config.dist_jans_dir, 'kc-jans-scheduler.jar'), os.path.join(base.current_app.app_info['JANS_MAVEN'], 'maven/io/jans/kc-jans-scheduler/{0}/kc-jans-scheduler-{0}.jar').format(base.current_app.app_info['jans_version'])), ] def __init__(self): @@ -75,15 +77,19 @@ def __init__(self): Config.jans_idp_sp_metadata_root_dir = os.path.join(self.idp_config_root_dir, 'sp/metadata') Config.jans_idp_sp_metadata_temp_dir = os.path.join(self.idp_config_root_dir, 'sp/temp_metadata') + Config.scheduler_dir = os.path.join(Config.opt_dir, 'kc-scheduler') + Config.idp_config_hostname = Config.hostname Config.keycloack_hostname = Config.hostname + self.kc_admin_realm = 'master' + self.kc_admin_username = 'admin' def install(self): """installation steps""" self.create_clients() self.install_keycloack() - + self.install_keycloak_scheduler() def render_import_templates(self): self.logIt("Preparing base64 encodings configuration files") @@ -212,12 +218,12 @@ def config_api_idp_plugin_config(self): with tempfile.TemporaryDirectory() as tmp_dir: kc_tmp_config = os.path.join(tmp_dir, 'kcadm-jans.config') - self.run([kcadm_cmd, 'config', 'credentials', '--server', kcm_server_url, '--realm', 'master', '--user', 'admin', '--password', 'admin', '--config', kc_tmp_config], env=env) + self.run([kcadm_cmd, 'config', 'credentials', '--server', kcm_server_url, '--realm', self.kc_admin_realm, '--user', self.kc_admin_username, '--password', 'admin', '--config', kc_tmp_config], env=env) - self.run([kcadm_cmd, 'config', 'credentials', '--server', kcm_server_url, '--realm', 'master', '--user', 'admin', '--password', Config.admin_password, '--config', kc_tmp_config], env=env) + self.run([kcadm_cmd, 'config', 'credentials', '--server', kcm_server_url, '--realm', self.kc_admin_realm, '--user', self.kc_admin_username, '--password', Config.admin_password, '--config', kc_tmp_config], env=env) # Change default password - self.run([kcadm_cmd, 'set-password', '-r', 'master', '--username', 'admin', '--new-password', Config.admin_password, '--config', kc_tmp_config], env=env) + self.run([kcadm_cmd, 'set-password', '-r', self.kc_admin_realm, '--username', self.kc_admin_username, '--new-password', Config.admin_password, '--config', kc_tmp_config], env=env) # create realm self.run([kcadm_cmd, 'create', 'realms', '-f', os.path.join(jans_api_output_dir, jans_api_realm_fn),'--config', kc_tmp_config], env=env) @@ -253,3 +259,61 @@ def config_api_idp_plugin_config(self): # create userstorage provider component self.run([kcadm_cmd, 'create', 'components', '-r', Config.jans_idp_realm, '-f', os.path.join(jans_api_output_dir, jans_userstorage_provider_component_fn), '--config', kc_tmp_config], env=env) + + def install_keycloak_scheduler(self): + + scheduler_templates_dir = os.path.join(self.templates_folder, 'kc-scheduler') + + # create directories + for _ in ('bin', 'conf', 'lib', 'logs'): + self.createDirs(os.path.join(Config.scheduler_dir, _)) + + #unpack libs + base.unpack_zip(self.source_files[7][0], os.path.join(Config.scheduler_dir, 'lib')) + for s_config in ('config.properties', 'logback.xml'): + base.extract_file(base.current_app.jans_zip, f'jans-keycloak-integration/job-scheduler/src/main/resources/{s_config}.sample', os.path.join(Config.scheduler_dir, 'conf')) + os.rename(os.path.join(Config.scheduler_dir, 'conf', f'{s_config}.sample'), os.path.join(Config.scheduler_dir, 'conf', s_config)) + + self.copyFile(self.source_files[8][0], os.path.join(Config.scheduler_dir, 'lib')) + + # configuration rendering identifiers + _, jans_auth_config = self.dbUtils.get_oxAuthConfDynamic() + self.check_clients([('kc_scheduler_api_client_id', '2102.')]) + + rendering_dict = { + 'api_url': f'https://{Config.hostname}/jans-config-api', + 'token_endpoint': jans_auth_config['tokenEndpoint'], + 'client_id': Config.kc_scheduler_api_client_id, + 'client_secret': Config.kc_scheduler_api_client_pw, + 'scopes': '', + 'auth_method': 'basic', + 'keycloak_admin_url': f'https://{Config.idp_config_hostname}/kc', + 'keycloak_admin_realm': self.kc_admin_realm, + 'keycloak_admin_username': self.kc_admin_username, + 'keycloak_admin_password': Config.admin_password, + 'keycloak_client_id': 'admin-cli', + } + + config_properties_fn = os.path.join(Config.scheduler_dir, 'conf','config.properties') + config_properties_s = self.render_template(config_properties_fn, pystring=True, rendering_dict=rendering_dict) + self.writeFile(config_properties_fn, config_properties_s, backup=False) + self.chown(Config.scheduler_dir, Config.jetty_user, Config.jetty_group, recursive=True) + + # render start script + self.renderTemplateInOut( + os.path.join(scheduler_templates_dir, 'kc-scheduler.sh'), + scheduler_templates_dir, + os.path.join(Config.scheduler_dir, 'bin') + ) + + self.run([paths.cmd_chmod, '+x', os.path.join(Config.scheduler_dir, 'bin/kc-scheduler.sh')]) + + # render contab entry and restart cron service + self.renderTemplateInOut( + os.path.join(scheduler_templates_dir, 'kc-scheduler-cron'), + scheduler_templates_dir, + '/etc/cron.d' + ) + + if not Config.installed_instance: + self.restart(base.cron_service) diff --git a/jans-linux-setup/jans_setup/setup_app/utils/base.py b/jans-linux-setup/jans_setup/setup_app/utils/base.py index 5a144c972e6..d906878364a 100644 --- a/jans-linux-setup/jans_setup/setup_app/utils/base.py +++ b/jans-linux-setup/jans_setup/setup_app/utils/base.py @@ -81,6 +81,8 @@ os_name = os_type + os_version deb_sysd_clone = os_name.startswith(('ubuntu', 'debian')) +cron_service = 'crond' if os_type in ['centos', 'red', 'fedora'] else 'cron' + # Determine service path if (os_type in ('centos', 'red', 'fedora', 'suse') and os_initdaemon == 'systemd') or deb_sysd_clone: @@ -373,6 +375,7 @@ def extract_file(zip_file, source, target, ren=False): target_p = Path(target).joinpath(p.name) if not target_p.parent.exists(): target_p.parent.mkdir(parents=True) + logIt(f"Extracting {source} from {zip_file} to {target}") target_p.write_bytes(zip_obj.read(member)) break zip_obj.close() diff --git a/jans-linux-setup/jans_setup/setup_app/utils/setup_utils.py b/jans-linux-setup/jans_setup/setup_app/utils/setup_utils.py index 248096317b9..22de02b4270 100644 --- a/jans-linux-setup/jans_setup/setup_app/utils/setup_utils.py +++ b/jans-linux-setup/jans_setup/setup_app/utils/setup_utils.py @@ -493,9 +493,11 @@ def in_ignoredirs(p): self.logIt("Writing rendered template {}".format(full_output_file)) full_output_file.write_text(rendered_text) - def render_template(self, tmp_fn, pystring=False): + def render_template(self, tmp_fn, pystring=False, rendering_dict=None): template_text = self.readFile(tmp_fn) format_dict = self.merge_dicts(Config.__dict__, Config.templateRenderingDict) + if rendering_dict: + format_dict = self.merge_dicts(format_dict, rendering_dict) for k in format_dict: if isinstance(format_dict[k], bool): format_dict[k] = str(format_dict[k]).lower() diff --git a/jans-linux-setup/jans_setup/static/system/systemd/kc-scheduler.service b/jans-linux-setup/jans_setup/static/system/systemd/kc-scheduler.service new file mode 100644 index 00000000000..2194a99ab65 --- /dev/null +++ b/jans-linux-setup/jans_setup/static/system/systemd/kc-scheduler.service @@ -0,0 +1,15 @@ +[Unit] +Description=Keycloak Scheduler Service +After=kc.service + +[Service] +Type=simple +Environment="JAVA_HOME=%(jre_home)s" +Environment="SCHEDULER_HOME=%(scheduler_dir)s" +Environment="SCHEDULER_VERSION=v%(jans_version)s" +ExecStart=%(scheduler_dir)s/bin/kc-scheduler.sh +User=%(jetty_user)s +Group=%(jetty_group)s + +[Install] +WantedBy=multi-user.target diff --git a/jans-linux-setup/jans_setup/templates/jans-saml/kc-scheduler/kc-scheduler-cron b/jans-linux-setup/jans_setup/templates/jans-saml/kc-scheduler/kc-scheduler-cron new file mode 100644 index 00000000000..27720f53b8a --- /dev/null +++ b/jans-linux-setup/jans_setup/templates/jans-saml/kc-scheduler/kc-scheduler-cron @@ -0,0 +1 @@ +*/10 * * * * %(jetty_user)s %(scheduler_dir)s/bin/kc-scheduler.sh diff --git a/jans-linux-setup/jans_setup/templates/jans-saml/kc-scheduler/kc-scheduler.sh b/jans-linux-setup/jans_setup/templates/jans-saml/kc-scheduler/kc-scheduler.sh new file mode 100644 index 00000000000..9c21d60c518 --- /dev/null +++ b/jans-linux-setup/jans_setup/templates/jans-saml/kc-scheduler/kc-scheduler.sh @@ -0,0 +1,21 @@ +#! /bin/bash + +JAVA_HOME=%(jre_home)s +SCHEDULER_HOME=%(scheduler_dir)s +SCHEDULER_VERSION=v%(jans_version)s + +APP_CONFIG_FILE=${SCHEDULER_HOME}/conf/config.properties +LOG_CONFIG_FILE=${SCHEDULER_HOME}/conf/logback.xml + +if [ -z "$JAVA" ]; then + if [ -n "$JAVA_HOME" ]; then + JAVA="$JAVA_HOME/bin/java" + else + JAVA="java" + fi +fi + +$JAVA -Dapp.config="${APP_CONFIG_FILE}" \ + -Dlogback.configurationFile="${SCHEDULER_HOME}/conf/logback.xml" \ + -Dapp.version=${SCHEDULER_VERSION} -Dapp.home="${SCHEDULER_HOME}" \ + -cp "${SCHEDULER_HOME}/lib/*" io.jans.kc.scheduler.App diff --git a/jans-linux-setup/jans_setup/templates/jans-saml/kc_jans_api/jans.api-user.json b/jans-linux-setup/jans_setup/templates/jans-saml/kc_jans_api/jans.api-user.json index 1980ae48939..fcd869c1aa9 100644 --- a/jans-linux-setup/jans_setup/templates/jans-saml/kc_jans_api/jans.api-user.json +++ b/jans-linux-setup/jans_setup/templates/jans-saml/kc_jans_api/jans.api-user.json @@ -2,7 +2,8 @@ "username": "${jans_idp_user_name}", "firstName": "Jans", "lastName": "API User", + "email": "${admin_email}", "emailVerified": true, "attributes": [], "enabled": true -} \ No newline at end of file +}