Commit 46717c2c authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Added keycloak user import. Bcrypt support for keycloak. Minor fixes.

parent 42b2981d
Pipeline #54541 passed with stages
in 14 minutes and 59 seconds
......@@ -91,6 +91,7 @@ tests:
NOMAD_ELASTIC_HOST: elastic
NOMAD_MONGO_HOST: mongo
NOMAD_KEYCLOAK_CLIENT_SECRET: ${CI_KEYCLOAK_TEST_CLIENT_SECRET}
NOMAD_KEYCLOAK_PASSWORD: ${CI_KEYCLOAK_ADMIN_PASSWORD}
script:
- cd /app
- python -m pytest --cov=nomad -sv tests
......
......@@ -15,6 +15,7 @@
import click
import datetime
import elasticsearch.helpers
import json
from nomad import processing as proc, search, datamodel, infrastructure, utils, config
......@@ -137,3 +138,18 @@ def reset(i_know_what_i_am_doing, remove):
infrastructure.reset()
else:
print('Did nothing')
@admin.command(help='Imports users to the configures keycloak realm')
@click.argument('INPUT_FILE', type=str, nargs=1)
def import_users(input_file):
with open(input_file, 'rt') as f:
users = json.load(f)
for user in users:
bcrypt_password = user.pop('bcrypt_password', None)
try:
infrastructure.keycloak.add_user(user, bcrypt_password)
print('Added user %s' % user['email'])
except KeyError as e:
print('Could not add user: %s' % str(e))
......@@ -27,7 +27,7 @@ from mongoengine import connect
import smtplib
from email.mime.text import MIMEText
from keycloak import KeycloakOpenID, KeycloakAdmin
from keycloak.exceptions import KeycloakAuthenticationError
from keycloak.exceptions import KeycloakAuthenticationError, KeycloakGetError
import json
import jwt
from flask import g, request
......@@ -205,6 +205,53 @@ class Keycloak():
# Do not return an error. This is the case were there are no credentials
return None
def add_user(self, user, bcrypt_password=None):
"""
Adds the given :class:`nomad.datamodel.User` instance to the configured keycloak
realm using the keycloak admin API.
"""
from nomad import datamodel
if not isinstance(user, datamodel.User):
if 'user_id' not in user:
user['user_id'] = 'not set'
user = datamodel.User(**user)
keycloak_user = dict(
id=user.user_id if user.user_id != 'not set' else None,
email=user.email,
username=user.email,
firstName=user.first_name,
lastName=user.last_name,
attributes=dict(
affiliation=user.affiliation if user.affiliation is not None else '',
affiliation_address=user.affiliation_address if user.affiliation_address is not None else ''),
createdTimestamp=user.created.timestamp() * 1000 if user.created is not None else None,
enabled=True,
emailVerified=True)
if bcrypt_password is not None:
keycloak_user['credentials'] = [dict(
type='password',
hashedSaltedValue=bcrypt_password,
algorithm='bcrypt')]
keycloak_user = {
key: value for key, value in keycloak_user.items()
if value is not None}
if user.user_id != 'not_set':
try:
self._admin_client.get_user(user.user_id)
raise KeyError('User %s with given id already exists' % user.email)
except KeycloakGetError:
pass
if self._admin_client.get_user_id(user.email) is not None:
raise KeyError('User with email %s already exists' % user.email)
self._admin_client.create_user(keycloak_user)
return None
def get_user(self, user_id: str = None, email: str = None, user=None) -> object:
"""
Retrives all available information about a user from the keycloak admin
......
......@@ -13,4 +13,13 @@ Changes
- added kibana.yml::server.basePath="/nomad/kibana"
The file `elk/kibana_objects.json` contains an export of nomad specific searches,
visualizations, and dashboard.
\ No newline at end of file
visualizations, and dashboard.
### Keycloak
A custom version of [jboss/keycloak](https://hub.docker.com/r/jboss/keycloak/)
- added bcrypt password hashing: [https://github.com/leroyguillaume/keycloak-bcrypt](https://github.com/leroyguillaume/keycloak-bcrypt)
- create admin user if not there
- import test realm on first use
- use H2 database
- change config to allow reverse proxy under custom prefix
\ No newline at end of file
......@@ -4,6 +4,7 @@ ARG prefix='fairdi\/keycloak'
USER jboss
# Change the 'web-context' to allow reverse proxy behind custom path
RUN echo "s/<web-context>auth<\\/web-context>/<web-context>$prefix\\/auth<\\/web-context>/"
RUN sed -i -e "s/<web-context>auth<\\/web-context>/<web-context>$prefix\\/auth<\\/web-context>/" $JBOSS_HOME/standalone/configuration/standalone.xml
RUN sed -i -e "s/<web-context>auth<\\/web-context>/<web-context>$prefix\\/auth<\\/web-context>/" $JBOSS_HOME/standalone/configuration/standalone-ha.xml
......@@ -15,12 +16,16 @@ ENV KEYCLOAK_USER=admin
ENV KEYCLOAK_PASSWORD=$admin_password
ENV KEYCLOAK_IMPORT=/opt/jboss/keycloak/fairdi_nomad_test.json
ENV PROXY_ADDRESS_FORWARDING=true
ENV DB_VENDOR=h2
# Add exported real/client configurations
ADD ./fairdi_nomad_test.json /opt/jboss/keycloak/fairdi_nomad_test.json
ADD ./fairdi_nomad_prod.json /opt/jboss/keycloak/fairdi_nomad_prod.json
# Add a custom theme to mimic the rest of nomad's GUI
ADD ./material_theme /opt/jboss/keycloak/themes/material
# Additing a bcrypt password hashing algorithm to reuse old repo users
RUN curl http://central.maven.org/maven2/org/mindrot/jbcrypt/0.4/jbcrypt-0.4.jar > /tmp/jbcrypt-0.4.jar
RUN /opt/jboss/keycloak/bin/jboss-cli.sh --command="module add --name=org.mindrot.jbcrypt --resources=/tmp/jbcrypt-0.4.jar"
RUN curl -L https://github.com/leroyguillaume/keycloak-bcrypt/releases/download/1.1.0/keycloak-bcrypt-1.1.0.jar > /opt/jboss/keycloak/standalone/deployments/keycloak-bcrypt-1.1.0.jar
\ No newline at end of file
......@@ -74,7 +74,7 @@
<i class="material-icons mdc-text-field__icon" tabindex="-1" role="button">account_balance</i>
<input required id="user.attributes.affiliation_address" class="mdc-text-field__input ${properties.kcInputClass!}" name="user.attributes.affiliation_address" type="text" value="${(account.attributes.affiliation_address!'')}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="user.attributes.affiliation_address" class="mdc-floating-label ${properties.kcLabelClass!}">Affiliation Address</label>
<label for="user.attributes.affiliation_address" class="mdc-floating-label ${properties.kcLabelClass!}">Affiliation address</label>
</div>
<div class="mdc-notched-outline">
<svg>
......
......@@ -89,7 +89,7 @@
<i class="material-icons mdc-text-field__icon" tabindex="-1" role="button">account_balance</i>
<input required id="user.attributes.affiliation_address" class="mdc-text-field__input ${properties.kcInputClass!}" name="user.attributes.affiliation_address" type="text" value="${(register.formData.affiliation_address!'')}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="user.attributes.affiliation_address" class="mdc-floating-label ${properties.kcLabelClass!}">Affiliation Address</label>
<label for="user.attributes.affiliation_address" class="mdc-floating-label ${properties.kcLabelClass!}">Affiliation address</label>
</div>
<div class="mdc-notched-outline">
<svg>
......
This diff is collapsed.
......@@ -18,7 +18,7 @@ services:
# keycloak for user management
keycloak:
volumes:
- /nomad/fairdi/db/keycloak:/opt/jboss/keycloak
- /nomad/fairdi/db/keycloak:/opt/jboss/keycloak/standalone/data
# the search engine
elastic:
......
......@@ -26,10 +26,10 @@ services:
keycloak:
restart: always
build: ../../containers/keycloak/
image: nomad/elk
image: nomad/keycloak
container_name: nomad_keycloak
volumes:
- nomad_keycloak:/opt/jboss/keycloak
- nomad_keycloak:/opt/jboss/keycloak/standalone/data
ports:
- 8002:8080
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment