Skip to content

Commit

Permalink
Merge pull request #5 from brown-bnc/multi-pass
Browse files Browse the repository at this point in the history
Add support for multiple unique LDAP providers
  • Loading branch information
broarr authored Jan 7, 2021
2 parents 374b6c1 + 420d1db commit b674df3
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 73 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
xnat-conf.properties
.env
ldap.env
*.properties
52 changes: 38 additions & 14 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
#-----------------------------------------------------------------------------
# ARGS
# Common build arguments
#-----------------------------------------------------------------------------
ARG XNAT_VERSION=1.7.6

#-----------------------------------------------------------------------------
# BUILD
# Build the XNAT web artifact from source
#-----------------------------------------------------------------------------
FROM openjdk:8-jdk-slim as build

ARG XNAT_VERSION

RUN apt-get update && apt-get install -y \
git

RUN cd /root \
&& git clone --depth 1 --branch "${XNAT_VERSION}" https://bitbucket.org/xnatdev/xnat-web

WORKDIR /root/xnat-web
RUN ./gradlew clean war

#-----------------------------------------------------------------------------
# APPLICATION
# Runs the XNAT web application
#-----------------------------------------------------------------------------
FROM tomcat:7-jdk8-openjdk-slim

ARG XNAT_VERSION=1.7.6
ARG XNAT_VERSION

RUN apt-get update && apt-get install -y \
curl \
Expand All @@ -13,35 +40,32 @@ RUN mkdir -p \
/data/xnat/ftp \
/data/xnat/home \
/data/xnat/home/config \
/data/xnat/home/config/auth \
/data/xnat/home/logs \
/data/xnat/home/plugins \
/data/xnat/home/work \
/data/xnat/inbox \
/data/xnat/pipeline \
/data/xnat/prearchive \
/data/xnat/dicom-export
COPY ldap-provider.properties.example /data/xnat/home/config/auth/ldap-provider.properties.example
VOLUME ["/data/xnat/home/config", "/data/xnat/home/config/auth"]

COPY --from=build "/root/xnat-web/build/libs/xnat-web-${XNAT_VERSION}.war" "${CATALINA_HOME}/webapps/ROOT.war"
RUN mkdir -p "${CATALINA_HOME}/webapps/ROOT" \
&& cd "${CATALINA_HOME}/webapps/ROOT" \
&& curl -sLo ROOT.war "https://api.bitbucket.org/2.0/repositories/xnatdev/xnat-web/downloads/xnat-web-${XNAT_VERSION}.war" \
&& jar xf ROOT.war \
&& rm ROOT.war
&& jar xf ../ROOT.war \
&& rm ../ROOT.war

RUN cd /data/xnat/home/plugins \
&& curl -sLO "https://github.com/brown-bnc/ldap-auth-plugin/releases/download/v1.0.1/xnat-ldap-auth-plugin-1.0.0.jar"
&& curl -sLO "https://bitbucket.org/xnatx/ldap-auth-plugin/downloads/xnat-ldap-auth-plugin-1.0.0.jar"

COPY ./docker-entrypoint.sh "${CATALINA_HOME}/bin/docker-entrypoint.sh"

ENV POSTGRES_HOST= POSTGRES_PORT=5432 POSTGRES_DB= POSTGRES_USER= POSTGRES_PASSWORD=
ENV LDAP_HOST= LDAP_USER= LDAP_PASSWORD= LDAP_SEARCH_BASE= LDAP_SEARCH_FILTER=
ENV XNAT_SITE_URL= XNAT_ADMIN_EMAIL=
ENV XNAT_SMTP_HOSTNAME= XNAT_SMTP_USER= XNAT_SMTP_PASSWORD= XNAT_SMTP_PORT= XNAT_SMTP_AUTH=true XNAT_SMTP_START_TLS=true
COPY docker-entrypoint.sh "/usr/local/bin/docker-entrypoint.sh"

# NOTE (BNR): Ports have the following use:
# 8000 - Debug port, only used if debug is set to true
# 8000 - Catalina debug port, only used if debug is set to true
# 8080 - Web port, this is how users connect to XNAT
# 8104 - Scanner port, this is how the scanner connects to XNAT
EXPOSE 8000/tcp 8080/tcp 8104/tcp

ENTRYPOINT ["./bin/docker-entrypoint.sh"]
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["run"]
42 changes: 38 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ versions are supported.
This repository provides two ways of running development versions of XNAT,
via Docker Compose or Kubernetes.

## Building the Docker image

The `docker-compose.yaml` file contains the necessary information to build
the Docker image. There is one argument to the Docker image build,
`$XNAT_VERSION`. The `Dockerfile` leverages a multi-stage build process
that clones the `xnat-web` repository and builds from source. The version
of `xnat-web` cloned depends on `$XNAT_VERSION`. `$XNAT_VERSION` may be a
tag or branch.

To build the Docker image run:

```
$ docker-compose build
```

## Docker Compose

To start the compose stack run:
Expand Down Expand Up @@ -90,10 +105,21 @@ access your development XNAT deployment.

## LDAP

If you desire LDAP authentication, copy `ldap.env.example` to `ldap.env`
and load your LDAP configuration. Then uncomment the `ldap-config` section
in the `kustomization.yaml` file. Similarly, uncomment the `ldap-config`
environment section in `app.yaml` and start the service as above.
Multiple unique LDAP providers are supported. Each LDAP authentication
properties file must be mounted in the `/data/xnat/home/config/auth`
directory. The process varies depending on whether or not you're deploying
with Kubernetes or Docker Swarm.

If deploying with Kubernetes, the LDAP authentication properties files may
be specified as either a `ConfigMap` or `Secret` object. The `ConfigMap` or
`Secret` must then be referenced as a volume, and mounted in the container.

If deploying with Docker Swarm, add the LDAP authentication properties
files as a volume at `/data/xnat/home/config/auth` in the Docker container.

Examples are provided for both Kubernetes and Docker Swarm. Uncomment the
LDAP sections in `app.yaml` and `kustomization.yaml` for Kubernetes.
Uncomment the LDAP section in `docker-compose.yaml` for Docker Swarm.

## Automatic Initialization

Expand All @@ -102,13 +128,21 @@ If you want to skip the initialization page on first launch, provide both
username/password will still be `admin:admin`. If you've provided an LDAP
configuration, the automatic initialization will enable your LDAP provider.

## Manual Configuration

You do not have to rely on the config generation rules detailed above to
configure XNAT. `/data/xnat/home/config` is exposed as a volume. You may
add your custom configs in that directory using the standard volume mount
mechanisms of Kubernetes or Docker Swarm. An example is not provided.

## TODO
* [x] Trim down the `Dockerfile` to bare minimum necessary
* [x] Build and test the image using Docker
* [x] Create a repository, and deployer service account in the DTR
* [x] Create Kubernetes deployment manifest for XNAT
* [x] Deploy to minikube for test
* [x] Deploy to SciDMZ to for test
* [x] Multiple unique LDAP providers
* [ ] Configure TrueNAS storage mounts in the cluster
* [x] Configure Postgres storage for metadata
* [ ] Document the process
Expand Down
14 changes: 11 additions & 3 deletions app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,27 @@ spec:
spec:
containers:
- name: xnat
image: ghcr.io/brown-bnc/xnat:1.7.6
image: ghcr.io/brown-bnc/xnat:1.8.0-TIP-RC3
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: ldap-config
ports:
- name: http
containerPort: 8080
- name: dicom
containerPort: 8104
- name: debug
containerPort: 8000
# NOTE (BNR): Uncomment the following lines to enable LDAP auth
# volumeMounts:
# - name: ldap-provider
# mountPath: "/data/xnat/home/config/auth/ldap-provider.properties"
# subPath: "brownldap-provider.properties"
# readOnly: true
# volumes:
# - name: ldap-provider
# secret:
# secretName: ldap-config
---
apiVersion: v1
kind: Service
Expand Down
17 changes: 10 additions & 7 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
version: "3.5"
services:
xnat:
build: .
image: ghcr.io/brown-bnc/xnat:1.7.6
build:
context: .
args:
XNAT_VERSION: 1.8.0-TIP-RC3
image: ghcr.io/brown-bnc/xnat:1.8.0-TIP-RC3
ports:
- "8000:8000"
- "8080:8080"
Expand All @@ -13,11 +16,11 @@ services:
POSTGRES_DB: "xnat"
POSTGRES_USER: "xnat"
POSTGRES_PASSWORD: "xnat"
LDAP_HOST: "${LDAP_HOST}"
LDAP_USER: "${LDAP_USER}"
LDAP_PASSWORD: "${LDAP_PASSWORD}"
LDAP_SEARCH_BASE: "${LDAP_SEARCH_BASE}"
LDAP_SEARCH_FILTER: "${LDAP_SEARCH_FILTER}"
XNAT_SITE_URL: "http://xnat.local"
XNAT_ADMIN_EMAIL: "[email protected]"
# NOTE (BNR): Uncomment the following lines to enable LDAP
# volumes:
# - "${PWD}/ldap-provider.properties:/data/xnat/home/config/auth/ldap-provider.properties"
postgres:
image: postgres:9
environment:
Expand Down
91 changes: 49 additions & 42 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
set -eo pipefail
shopt -s extglob

generate_config() {
if [ -z "${POSTGRES_HOST}" ] || [ -z "${POSTGRES_PORT}" ] \
|| [ -z "${POSTGRES_DB}" ] || [ -z "${POSTGRES_USER}" ] \
|| [ -z "${POSTGRES_PASSWORD}" ]; then
warn() {
>&2 echo "$@"
}

generate_xnat_conf() {
if [ -z "${POSTGRES_HOST}" ] || [ -z "${POSTGRES_DB}" ] \
|| [ -z "${POSTGRES_USER}" ] || [ -z "${POSTGRES_PASSWORD}" ]; then
echo "Error: Database configuration required" >&2
exit 1
fi

cat > /data/xnat/home/config/xnat-conf.properties << EOF
datasource.driver=org.postgresql.Driver
datasource.url=jdbc:postgresql://${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
datasource.url=jdbc:postgresql://${POSTGRES_HOST}:${POSTGRES_PORT:-5432}/${POSTGRES_DB}
datasource.username=${POSTGRES_USER}
datasource.password=${POSTGRES_PASSWORD}
Expand All @@ -23,32 +27,34 @@ hibernate.cache.use_query_cache=true
EOF
}

generate_auth_config() {
if [ -z "${LDAP_HOST}" ]; then
generate_prefs_init() {
if [ -z "${XNAT_SITE_URL}" ] || [ -z "${XNAT_ADMIN_EMAIL}" ]; then
warn "\$XNAT_SITE_URL or \$XNAT_ADMIN_EMAIL not set. Not generating configs."
return
fi

mkdir -p /data/xnat/home/config/auth
cat > /data/xnat/home/config/auth/ldap-provider.properties << EOF
name=LDAP
provider.id=ldap
auth.method=ldap
address=${LDAP_HOST}
userdn=${LDAP_USER}
password=${LDAP_PASSWORD}
search.base=${LDAP_SEARCH_BASE}
search.filter=${LDAP_SEARCH_FILTER}
auto.enabled=true
auto.verified=true
EOF
}
local email_verification='true'
local auth_providers='["localdb"]'
local auth_configs=(/data/xnat/home/config/auth/!(ldap-provider.properties.example))
local provider_id=''

generate_site_config() {
if [ -z "${XNAT_SITE_URL}" ] || [ -z "${XNAT_ADMIN_EMAIL}" ]; then
return
if [ -z "${XNAT_SMTP_HOSTNAME}" ] || [ -z "${XNAT_SMTP_USER}" ] \
|| [ -z "${XNAT_SMTP_PASSWORD}" ] || [ -z "${XNAT_SMTP_PORT}" ] \
|| [ -z "${XNAT_SMTP_AUTH}" ] || [ -z "${XNAT_SMTP_START_TLS}" ]; then
email_verification="false"
fi

if [ "${#auth_configs[@]}" -gt 0 ]; then
auth_providers='['
for auth_config in "${auth_configs[@]}"; do
provider_id="$(grep 'provider.id=' "${auth_config}" | cut -d= -f2)"
auth_providers="${auth_providers}\"${provider_id}\","
done
auth_providers="${auth_providers}\"localdb\"]"
fi

cat > /data/xnat/home/config/prefs-init.ini << EOF
[siteConfig]
siteUrl=${XNAT_SITE_URL}
adminEmail=${XNAT_ADMIN_EMAIL}
Expand All @@ -59,46 +65,47 @@ ftpPath=/data/xnat/ftp
pipelinePath=/data/xnat/pipeline
prearchivePath=/data/xnat/prearchive
initialized=true
emailVerification=${email_verification}
enabledProviders=${auth_providers}
EOF

if [ -n "${LDAP_HOST}" ]; then
echo "enabledProviders=[\"ldap\",\"localdb\"]" >> /data/xnat/home/config/prefs-init.ini
fi
}

generate_smtp_config() {
if [ -z "${XNAT_SMTP_HOSTNAME}" ] || [ -z "${XNAT_SMTP_USER}" ] \
|| [ -z "${XNAT_SMTP_PASSWORD}" ] || [ -z "${XNAT_SMTP_PORT}" ] \
|| [ -z "${XNAT_SMTP_AUTH}" ] || [ -z "${XNAT_SMTP_START_TLS}" ]; then
return
fi
cat >> /data/xnat/home/config/prefs-init.ini << EOF
[notifications]
smtpEnabled=false
EOF
else
cat >> /data/xnat/home/config/prefs-init.ini << EOF
cat >> /data/xnat/home/config/prefs-init.ini << EOF
[notifications]
hostname=${XNAT_SMTP_HOSTNAME}
username=${XNAT_SMTP_USER}
password=${XNAT_SMTP_PASSWORD}
port=${XNAT_SMTP_PORT}
protocol=smtp
smtpAuth=${XNAT_SMTP_AUTH}
smtpStartTls=${XNAT_SMTP_START_TLS}
smtpAuth=${XNAT_SMTP_AUTH:-true}
smtpStartTls=${XNAT_SMTP_START_TLS:-true}
EOF
fi
}

set_catalina_opts() {
export_catalina_opts() {
CATALINA_OPTS="${CATALINA_OPTS:-} -Dxnat.home=/data/xnat/home"

if [ "${DEBUG:-}" ]; then
CATALINA_OPTS="${CATALINA_OPTS} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000"
fi

export CATALINA_OPTS
}

main() {
generate_config
generate_auth_config
generate_site_config
generate_smtp_config
set_catalina_opts
generate_xnat_conf
generate_prefs_init
export_catalina_opts

export CATALINA_OPTS
exec "${CATALINA_HOME}/bin/catalina.sh" "$@"
Expand Down
8 changes: 5 additions & 3 deletions kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ configMapGenerator:
- POSTGRES_DB=xnat
- POSTGRES_USER=xnat
- POSTGRES_PASSWORD=xnat
secretGenerator:
- name: ldap-config
env: ldap.env
# NOTE (BNR): Uncomment the following lines to enable LDAP
#secretGenerator:
#- name: ldap-config
# files:
# - ldap-provider.properties
10 changes: 10 additions & 0 deletions ldap-provider.properties.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name=
provider.id=ldap
auth.method=ldap
address=
userdn=
password=
search.base=
search.filter=
auto.enabled=true
auto.verified=true

0 comments on commit b674df3

Please sign in to comment.