Skip to content
This repository was archived by the owner on Jun 23, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 1 addition & 53 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,57 +1,5 @@
FROM tomcat:9-jre17-temurin-focal AS base

ARG GEOSERVER_VERSION="2.28.4"
ENV GEOSERVER_VERSION=$GEOSERVER_VERSION
ENV GEOSERVER_URL="https://sourceforge.net/projects/geoserver/files/GeoServer/${GEOSERVER_VERSION}/geoserver-${GEOSERVER_VERSION}-war.zip"
ENV GEOSERVER_LIB_DIR="/usr/local/tomcat/webapps/geoserver/WEB-INF/lib"
ENV GDAL_PLUGIN_URL="https://sourceforge.net/projects/geoserver/files/GeoServer/${GEOSERVER_VERSION}/extensions/geoserver-${GEOSERVER_VERSION}-gdal-plugin.zip"
ENV CAS_PLUGIN_URL="https://sourceforge.net/projects/geoserver/files/GeoServer/${GEOSERVER_VERSION}/extensions/geoserver-${GEOSERVER_VERSION}-cas-plugin.zip"

RUN apt update && \
apt -y --no-install-recommends install \
gdal-bin \
libgdal-dev \
libgdal-java \
libsqlite3-dev \
sqlite3 \
swig \
unzip \
wget && \
apt clean && \
rm -rf /var/lib/apt/lists/*

FROM base AS download-geoserver
RUN wget -qO /tmp/geoserver-war.zip "${GEOSERVER_URL}" && \
unzip /tmp/geoserver-war.zip -d /tmp/geoserver-war && \
unzip /tmp/geoserver-war/geoserver.war -d /usr/local/tomcat/webapps/geoserver && \
rm -rf /tmp/geoserver*

FROM base AS download-gdal-plugin
RUN wget -qO /tmp/gdal-plugin.zip $GDAL_PLUGIN_URL && \
unzip -o -d /tmp/gdal-plugin /tmp/gdal-plugin.zip && \
rm -f /tmp/gdal-plugin.zip

FROM base AS download-cas-plugin
RUN wget -qO /tmp/cas-plugin.zip $CAS_PLUGIN_URL && \
unzip -o -d /tmp/cas-plugin /tmp/cas-plugin.zip && \
rm -f /tmp/cas-plugin.zip

FROM base AS final
COPY --from=download-geoserver /usr/local/tomcat/webapps/geoserver /usr/local/tomcat/webapps/geoserver
COPY --from=download-cas-plugin /tmp/cas-plugin/*.jar $GEOSERVER_LIB_DIR/
COPY --from=download-gdal-plugin /tmp/gdal-plugin/*.jar $GEOSERVER_LIB_DIR/

# Downgrade the gdal jar so it matches the gdal version installed on the system
RUN rm -f $GEOSERVER_LIB_DIR/gdal-3.2.0.jar && \
cp /usr/share/java/gdal.jar $GEOSERVER_LIB_DIR/gdal-3.0.4.jar

# Ensure libgdalalljni.so is in the load path. If this isn't found, GeoServer will log and warn
# about that on startup.
ENV LD_LIBRARY_PATH="/usr/lib/jni:$LD_LIBRARY_PATH"
ENV GDAL_DATA="/usr/share/gdal"
FROM docker.osgeo.org/geoserver:${GEOSERVER_VERSION}-gdal

Check warning on line 3 in Dockerfile

View workflow job for this annotation

GitHub Actions / docker-build / build (linux/arm64, ubuntu-24.04-arm)

Base image platform does not match expected target platform

InvalidBaseImagePlatform: Base image docker.osgeo.org/geoserver:2.28.4-gdal was pulled with platform "linux/amd64", expected "linux/arm64" for current build

# Redirect the root path to /geoserver/web
# Inspired by https://github.com/geoserver/docker/blob/master/startup.sh
RUN mkdir -p $CATALINA_HOME/webapps/ROOT
COPY files/index.jsp $CATALINA_HOME/webapps/ROOT/
COPY bin/run-tests /usr/local/bin/
85 changes: 84 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,91 @@ services:
app:
build:
args:
- GEOSERVER_VERSION=${GEOSERVER_VERSION:-2.28.0}
- GEOSERVER_VERSION=${GEOSERVER_VERSION:-2.28.4}
context: .
image: ucblib/geoserver:${DOCKER_TAG:-development}
environment:
INSTALL_EXTENSIONS: "true"
STABLE_EXTENSIONS: gdal
COMMUNITY_EXTENSIONS: sec-keycloak,sec-oidc
ROOT_WEBAPP_REDIRECT: "true"
extra_hosts:
- keycloak.localhost:host-gateway
ports:
- 8080:8080
volumes:
- ./geoserver_data:/opt/geoserver_data

postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: keycloak
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak -d keycloak"]
interval: 10s
timeout: 5s
retries: 5
volumes:
- postgres_data:/var/lib/postgresql/data

keycloak:
command: start-dev
depends_on:
postgres:
condition: service_healthy
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
KC_HOSTNAME: "http://keycloak.localhost:8180"
KC_HOSTNAME_STRICT: "false"
KC_HOSTNAME_BACKCHANNEL_DYNAMIC: "true"
KC_HTTP_ENABLED: "true"
KC_HTTP_PORT: "8180"
KC_HEALTH_ENABLED: "true"
KC_LOG_LEVEL: ${KC_LOG_LEVEL:-INFO}
healthcheck:
# curl/wget are not present in the UBI9-based Keycloak image; use /dev/tcp.
# KC_HEALTH_ENABLED=true exposes /health/ready on the management port (9000).
test:
[
"CMD-SHELL",
"exec 3<>/dev/tcp/localhost/9000 && printf 'GET /health/ready HTTP/1.0\\r\\nHost: localhost\\r\\n\\r\\n' >&3 && grep -q 'status.*UP' <&3",
]
interval: 30s
timeout: 10s
retries: 5
start_period: 20s
image: quay.io/keycloak/keycloak:26.1
ports:
- 127.0.0.1:8180:8180
restart: always

keycloak-config:
depends_on:
keycloak:
condition: service_healthy
environment:
KEYCLOAK_URL: http://keycloak:8180
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: admin
KEYCLOAK_AVAILABILITYCHECK_ENABLED: "true"
IMPORT_FILES_LOCATIONS: /config/*
IMPORT_VAR_SUBSTITUTION_ENABLED: "true"
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID}
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET}
OIDC_ADMIN_GROUP: ${OIDC_ADMIN_GROUP}
OIDC_USER_GROUP: ${OIDC_USER_GROUP}
image: adorsys/keycloak-config-cli:latest-26.1.0
restart: on-failure:3
volumes:
- ./keycloak/config:/config

volumes:
geoserver_data:
postgres_data:
6 changes: 6 additions & 0 deletions env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
OIDC_ADMIN_GROUP="cn=edu:berkeley:org:libr:geoserver:admins,ou=campus groups,dc=berkeley,dc=edu"
OIDC_CLIENT_ID=geoserver
OIDC_CLIENT_SECRET=some-secret-hash
OIDC_NAME="keycloak"
OIDC_USER_GROUP="cn=edu:berkeley:org:libr:geoserver:users,ou=campus groups,dc=berkeley,dc=edu"
OIDC_WELL_KNOWN="http://keycloak.localhost:8180/realms/berkeley-local/.well-known/openid-configuration"
102 changes: 102 additions & 0 deletions keycloak/config/berkeley-local.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# keycloak-config-cli realm configuration for local GeoServer development.
# It provides a local Keycloak realm, GeoServer client, and Berkeley-style
# group claims for predictable OIDC testing.
#
# Group names mirror the production LDAP DN format so GeoServer can test the same
# role-mapping shape used against the real IdP.
#
# Secrets are injected at import time via substitution by keycloak-config-cli.
# Set OIDC_CLIENT_SECRET in your .env file — never commit a real secret here.

realm: berkeley-local
enabled: true
displayName: Berkeley Local

clientScopes:
- name: berkeley_edu_groups
description: Berkeley group memberships
protocol: openid-connect
attributes:
include.in.token.scope: "true"
display.on.consent.screen: "false"
protocolMappers:
- name: groups
protocol: openid-connect
protocolMapper: oidc-group-membership-mapper
consentRequired: false
config:
# Match Calnet's behavior by not prepending groups with "/"
full.path: "false"
id.token.claim: "true"
access.token.claim: "true"
introspection.token.claim: "true"
userinfo.token.claim: "true"
claim.name: groups
jsonType.label: String

clients:
- clientId: "$(OIDC_CLIENT_ID)"
name: "$(OIDC_CLIENT_ID)"
enabled: true
rootUrl: "http://localhost:8080"
adminUrl: "http://localhost:8080"
redirectUris:
- "http://localhost:8080/*"
webOrigins:
- "http://localhost:8080"
publicClient: false
secret: "$(OIDC_CLIENT_SECRET)"
standardFlowEnabled: true
directAccessGrantsEnabled: true
serviceAccountsEnabled: true
frontchannelLogout: true
attributes:
backchannel.logout.session.required: "true"
frontchannel.logout.session.required: "true"
defaultClientScopes:
- profile
- email
- berkeley_edu_groups

groups:
- name: "$(OIDC_ADMIN_GROUP)"
- name: "$(OIDC_USER_GROUP)"
- name: cn=edu:berkeley:org:libr:unrelated:group,ou=campus groups,dc=berkeley,dc=edu

users:
- username: testadmin
enabled: true
email: testadmin@example.edu
firstName: Test
lastName: Admin
credentials:
- type: password
value: testadmin
temporary: false
groups:
- "$(OIDC_ADMIN_GROUP)"
- "$(OIDC_USER_GROUP)"

- username: testuser
enabled: true
email: testuser@example.edu
firstName: Test
lastName: User
credentials:
- type: password
value: testuser
temporary: false
groups:
- "$(OIDC_USER_GROUP)"

- username: testpublic
enabled: true
email: testpublic@example.edu
firstName: Test
lastName: Public
credentials:
- type: password
value: testpublic
temporary: false
groups:
- cn=edu:berkeley:org:libr:unrelated:group,ou=campus groups,dc=berkeley,dc=edu
Loading