Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jans-linux-setup): keycloak scheduler service #8425

Merged
merged 10 commits into from
May 6, 2024
Merged
5 changes: 4 additions & 1 deletion jans-linux-setup/jans_setup/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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:
Expand Down
6 changes: 4 additions & 2 deletions jans-linux-setup/jans_setup/setup_app/installers/jans.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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()
Expand Down
72 changes: 68 additions & 4 deletions jans-linux-setup/jans_setup/setup_app/installers/jans_saml.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
3 changes: 3 additions & 0 deletions jans-linux-setup/jans_setup/setup_app/utils/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*/10 * * * * %(jetty_user)s %(scheduler_dir)s/bin/kc-scheduler.sh
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"username": "${jans_idp_user_name}",
"firstName": "Jans",
"lastName": "API User",
"email": "${admin_email}",
"emailVerified": true,
"attributes": [],
"enabled": true
}
}