Commit 5431712b authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Added basic support for keycloak

parent 1ce87143
......@@ -15,4 +15,5 @@ local/
target/
*.swp
*.vscode
.vscode/
nomad.yaml
......@@ -13,6 +13,7 @@
"fetch": "^1.1.0",
"file-saver": "^2.0.0",
"html-to-react": "^1.3.3",
"keycloak-js": "^6.0.0",
"marked": "^0.6.0",
"material-ui-chip-input": "^1.0.0-beta.14",
"material-ui-flat-pagination": "^3.2.0",
......@@ -28,6 +29,7 @@
"react-dropzone": "^5.0.1",
"react-highlight": "^0.12.0",
"react-json-view": "^1.19.1",
"react-keycloak": "^6.1.0",
"react-router-dom": "^4.3.1",
"react-router-hash-link": "^1.2.0",
"react-scripts": "1.1.4",
......
......@@ -6,6 +6,7 @@ import { compose } from 'recompose'
import { Button, DialogTitle, DialogContent, DialogContentText, TextField, DialogActions,
Dialog, FormGroup } from '@material-ui/core'
import { withApi } from './api'
import { withKeycloak } from 'react-keycloak'
class LoginLogout extends React.Component {
static propTypes = {
......@@ -18,7 +19,8 @@ class LoginLogout extends React.Component {
variant: PropTypes.string,
color: PropTypes.string,
onLoggedIn: PropTypes.func,
onLoggedOut: PropTypes.func
onLoggedOut: PropTypes.func,
keycloak: PropTypes.object.isRequired
}
static styles = theme => ({
......@@ -102,7 +104,13 @@ class LoginLogout extends React.Component {
}
render() {
const { classes, user, variant, color, isLoggingIn } = this.props
const { classes, variant, color, isLoggingIn, keycloak } = this.props
let user = null
if (keycloak.authenticated) {
user = {}
}
const { failure } = this.state
if (user) {
return (
......@@ -113,7 +121,7 @@ class LoginLogout extends React.Component {
<Button
className={classes.button}
variant={variant} color={color}
onClick={this.handleLogout}
onClick={() => keycloak.logout()}
>Logout</Button>
</div>
)
......@@ -121,8 +129,7 @@ class LoginLogout extends React.Component {
return (
<div className={classes.root}>
<Button
className={isLoggingIn ? classes.buttonDisabled : classes.button} variant={variant} color={color} disabled={isLoggingIn}
onClick={() => this.setState({loginDialogOpen: true})}
className={classes.button} variant={variant} color={color} onClick={() => keycloak.login()}
>Login</Button>
<Dialog
disableBackdropClick disableEscapeKeyDown
......@@ -184,4 +191,4 @@ class LoginLogout extends React.Component {
}
}
export default compose(withApi(false), withStyles(LoginLogout.styles))(LoginLogout)
export default compose(withKeycloak, withApi(false), withStyles(LoginLogout.styles))(LoginLogout)
......@@ -9,14 +9,24 @@ import { Router } from 'react-router-dom'
import history from './history'
import PiwikReactRouter from 'piwik-react-router'
import { sendTrackingData, matomoUrl, matomoSiteId } from './config'
import Keycloak from 'keycloak-js'
import { KeycloakProvider } from 'react-keycloak'
const matomo = sendTrackingData ? PiwikReactRouter({
url: matomoUrl,
siteId: matomoSiteId
}) : null
const keycloak = Keycloak({
url: 'http://localhost:8002/auth',
realm: 'fairdi_nomad_test',
clientId: 'nomad_gui_dev'
})
ReactDOM.render(
<Router history={sendTrackingData ? matomo.connectToHistory(history) : history}>
<App />
</Router>, document.getElementById('root'))
<KeycloakProvider keycloak={keycloak} initConfig={{onLoad: 'check-sso'}} >
<Router history={sendTrackingData ? matomo.connectToHistory(history) : history}>
<App />
</Router>
</KeycloakProvider>, document.getElementById('root'))
registerServiceWorker()
......@@ -3922,7 +3922,7 @@ hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0:
version "2.5.5"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
hoist-non-react-statics@^3.0.0:
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
dependencies:
......@@ -4985,6 +4985,14 @@ jsx-ast-utils@^2.0.0, jsx-ast-utils@^2.0.1:
dependencies:
array-includes "^3.0.3"
keycloak-js@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/keycloak-js/-/keycloak-js-6.0.1.tgz#329a5e77210dfc4a7d4acf96f95dd0132455bea3"
keycloak@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/keycloak/-/keycloak-1.2.0.tgz#2ff4cc57102842f2eecc2f4bb206306596d7b025"
keycode@^2.1.7, keycode@^2.1.9:
version "2.2.0"
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04"
......@@ -6380,6 +6388,14 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0,
loose-envify "^1.3.1"
object-assign "^4.1.1"
prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.8.1"
proxy-addr@~2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93"
......@@ -6632,6 +6648,10 @@ react-is@^16.3.2, react-is@^16.6.3, react-is@^16.7.0:
version "16.7.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa"
react-is@^16.8.1:
version "16.9.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.9.0.tgz#21ca9561399aad0ff1a7701c01683e8ca981edcb"
react-json-view@^1.19.1:
version "1.19.1"
resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.19.1.tgz#95d8e59e024f08a25e5dc8f076ae304eed97cf5c"
......@@ -6641,6 +6661,13 @@ react-json-view@^1.19.1:
react-lifecycles-compat "^3.0.4"
react-textarea-autosize "^6.1.0"
react-keycloak@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/react-keycloak/-/react-keycloak-6.1.0.tgz#672eed832de231e981a717413dc10286dbe701f2"
dependencies:
hoist-non-react-statics "^3.3.0"
prop-types "^15.7.2"
react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
......
......@@ -124,6 +124,15 @@ repository_db = NomadConfig(
mode='fairdi'
)
keycloak = NomadConfig(
server_url='http://localhost:8002/auth/',
realm_name='fairdi_nomad_test',
username='admin',
password='password',
client_id='nomad_api',
client_secret_key='0f9ec82f-a1dc-4405-a80e-593160aeea42'
)
mongo = NomadConfig(
host='localhost',
port=27017,
......
......@@ -32,6 +32,7 @@ from mongoengine import connect
from passlib.hash import bcrypt
import smtplib
from email.mime.text import MIMEText
import keycloak
from nomad import config, utils
......@@ -48,6 +49,11 @@ repository_db = None
repository_db_conn = None
""" The repository postgres db sqlalchemy connection. """
keycloak_oidc_client = None
""" The keycode OpenID connect client. """
keycloak_admin_client = None
""" The keycode admin client. """
def setup():
"""
......@@ -108,6 +114,26 @@ def setup_elastic():
return elastic_client
def setup_keycloak():
""" Creates a keycloak client. """
global keycloak_oidc_client
global keycloak_admin_client
keycloak_oidc_client = keycloak.KeycloakOpenID(
server_url=config.keycloak.server_url,
client_id=config.keycloak.client_id,
realm_name=config.keycloak.realm_name,
client_secret_key=config.keycloak.client_secret_key)
keycloak_admin_client = keycloak.KeycloakAdmin(
server_url=config.keycloak.server_url,
username=config.keycloak.username,
password=config.keycloak.password,
realm_name='master',
verify=True)
keycloak_admin_client.realm_name = config.keycloak.realm_name
def setup_repository_db(**kwargs):
""" Creates a connection and stores it in the module variables. """
repo_args = dict(readonly=False)
......@@ -424,12 +450,12 @@ def send_mail(name: str, email: str, message: str, subject: str):
msg = MIMEText(message)
msg['Subject'] = subject
msg['From'] = 'The nomad team <%s>' % config.mail.from_address
msg['From'] = 'The NOMAD team <%s>' % config.mail.from_address
msg['To'] = name
to_addrs = [email]
if config.mail.cc_address is not None:
msg['Cc'] = 'The nomad team <%s>' % config.mail.cc_address
msg['Cc'] = 'The NOMAD team <%s>' % config.mail.cc_address
to_addrs.append(config.mail.cc_address)
try:
......@@ -438,3 +464,21 @@ def send_mail(name: str, email: str, message: str, subject: str):
logger.error('Could not send email', exc_info=e)
server.quit()
if __name__ == '__main__':
import logging, time
config.console_log_level = logging.DEBUG
setup_logging()
setup_keycloak()
token = keycloak_oidc_client.token(
username='sheldon.cooper@nomad-coe.eu', password='password')
while True:
print(keycloak_oidc_client.userinfo(token['access_token']))
keycloak_user_id = keycloak_admin_client.get_user_id('sheldon.cooper@nomad-coe.eu')
print(keycloak_admin_client.get_user(keycloak_user_id))
time.sleep(5)
......@@ -112,7 +112,10 @@ class LogstashHandler(logstash.TCPLogstashHandler):
def filter(self, record):
if super().filter(record):
is_structlog = record.msg.startswith('{') and record.msg.endswith('}')
is_structlog = False
if isinstance(record.msg, str):
is_structlog = record.msg.startswith('{') and record.msg.endswith('}')
if is_structlog:
return True
else:
......
......@@ -50,12 +50,6 @@ services:
ports:
- 8000:8000
# NOMAD-coe search api
coeapi:
restart: 'no'
ports:
- 8111:8111
# nomad gui
gui:
restart: 'no'
......
......@@ -15,6 +15,10 @@
version: '3.4'
services:
# keycloak for user management
keycloak:
volumes:
- /nomad/fairdi/db/keycloak:/opt/jboss/keycloak/standalone
postgres:
ports:
......
......@@ -19,6 +19,7 @@ x-common-variables: &nomad_backend_env
NOMAD_LOGSTASH_HOST: elk
NOMAD_ELASTIC_HOST: elastic
NOMAD_MONGO_HOST: mongo
NOMAD_KEYCLOAK_HOST: keycloak
services:
# postgres for NOMAD-coe repository API and GUI
......@@ -32,6 +33,20 @@ services:
volumes:
- nomad_postgres:/var/lib/postgresql/data
# keycload for user management
keycloak:
restart: always
image: jboss/keycloak
container_name: nomad_keycloak
environment:
DB_VENDOR: "h2"
KEYCLOAK_USER: "admin"
KEYCLOAK_PASSWORD: "password"
volumes:
- nomad_keycloak:/opt/jboss/keycloak/standalone
ports:
- 8002:8080
# broker for celery
rabbitmq:
restart: always
......@@ -74,6 +89,7 @@ services:
<<: *nomad_backend_env
NOMAD_SERVICE: nomad_worker
links:
- keycloak
- postgres
- rabbitmq
- elastic
......@@ -95,6 +111,7 @@ services:
NOMAD_SERVICES_API_SECRET: ${API_SECRET}
NOMAD_SERVICE: nomad_api
links:
- keycloak
- postgres
- rabbitmq
- elastic
......@@ -103,18 +120,6 @@ services:
- ${VOLUME_BINDS}/fs:/app/.volumes/fs
command: python -m gunicorn.app.wsgiapp -w 4 --log-config ops/gunicorn.log.conf -b 0.0.0.0:8000 --timeout 300 nomad.api:app
# NOMAD-coe search api
coeapi:
restart: always
image: gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-fair/coe-repowebservice:latest
container_name: nomad_coeapi
environment:
REPO_DB_JDBC_URL: jdbc:postgresql://postgres:5432/nomad
REPO_ELASTIC_URL: elasticsearch://elastic:9200
links:
- postgres
- elastic
# nomad gui
gui:
restart: always
......@@ -137,6 +142,7 @@ services:
command: nginx -g 'daemon off;'
volumes:
nomad_keycloak:
nomad_postgres:
nomad_mongo:
nomad_elastic:
......
......@@ -48,6 +48,7 @@ pyyaml
tabulate
cachetools
zipfile37
python-keycloak
# dev/ops related
setuptools
......
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