Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ packages:
ref: v0.50.0

- name: keycloak-identity-config
path: ../
path: ../../
ref: dev

- name: core-base
path: ../uds-core/build/
path: ../../uds-core/build/
# renovate: datasource=github-tags depName=defenseunicorns/uds-core versioning=semver
ref: 0.38.0
overrides:
Expand Down Expand Up @@ -60,7 +60,7 @@ packages:
- grafana.admin.{{ .Values.domain }}

- name: core-identity-authorization
path: ../uds-core/build/
path: ../../uds-core/build/
# renovate: datasource=github-tags depName=defenseunicorns/uds-core versioning=semver
ref: 0.38.0
overrides:
Expand Down Expand Up @@ -92,6 +92,6 @@ packages:
value: "-XX:MaxRAMPercentage=70 -XX:MinRAMPercentage=70 -XX:InitialRAMPercentage=50 -XX:MaxRAM=1G"

- name: core-monitoring
path: ../uds-core/build/
path: ../../uds-core/build/
# renovate: datasource=github-tags depName=defenseunicorns/uds-core versioning=semver
ref: 0.38.0
57 changes: 57 additions & 0 deletions bundles/theme-customizations/uds-bundle.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright 2025 Defense Unicorns
# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial

kind: UDSBundle
metadata:
name: theme-customization-tests
description: A UDS Bundle designed to be deployed on top of `uds-bundle-k3d-core-slim-dev` to test theme customization
version: "dev"

packages:
- name: core-identity-authorization
path: ../../uds-core/build/
# renovate: datasource=github-tags depName=defenseunicorns/uds-core versioning=semver
ref: 0.38.0
overrides:
keycloak:
keycloak:
variables:
- name: KEYCLOAK_CONFIG_IMAGE
description: "The keycloak config image to deploy plugin and initial setup configuration"
path: configImage
values:
- path: themeCustomizations
value:
resources:
images:
- name: background.jpg
configmap:
name: keycloak-theme-overrides
- name: logo.svg
configmap:
name: keycloak-theme-overrides
- name: footer.png
configmap:
name: keycloak-theme-overrides
- name: favicon.svg
configmap:
name: keycloak-theme-overrides
- path: realmInitEnv
value:
GOOGLE_IDP_ENABLED: true
GOOGLE_IDP_ID: "C01881u7t"
GOOGLE_IDP_SIGNING_CERT: "MIIDdDCCAlygAwIBAgIGAXkza8/+MA0GCSqGSIb3DQEBCwUAMHsxFDASBgNVBAoTC0dvb2dsZSBJbmMuMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MQ8wDQYDVQQDEwZHb29nbGUxGDAWBgNVBAsTD0dvb2dsZSBGb3IgV29yazELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEwHhcNMjEwNTAzMTgwOTMzWhcNMjYwNTAyMTgwOTMzWjB7MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEPMA0GA1UEAxMGR29vZ2xlMRgwFgYDVQQLEw9Hb29nbGUgRm9yIFdvcmsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu9en1CO4EriCJ5jzss6TqUmtYMXXRBfsSkdnhVvMx0fYOegxy0d8DouUEEITlPW+YPBG1T72kiV9KGtKVw90ff4Y+siNDNrME81w4K3Zjo6VukvATfD05lVzh9JyO0VxdzBpdRXSJqBOVLo38cwVbyTcX5Nk/nHENjDSN7as3UvbXa7eT4Xswy1GARGAZ3MAaLTZn1+Cctn0MDKniQOS6QDryYgKWz8ko/H4T9XCxgjHJVsL6obezaPZF+pibyyVPCuePssuxUbFHF6yiP5rCfAsK6VTv/8pbYGauGpYHDgnM941RtN2ThltORgi+P9i9wQ8VRBQpEm1RvDXOqJ7OwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQB5L26tpco6EgVunmZYBAFiFE+Dhqwvy4J1iKuXApaKhqabeKJ8kBv/pJBnZl7CRF5Pv8dLfhNoNm2BsXbpH91/rhDj9zl/Imkc5ttVGbXbKSBpUaduwBZpsVIX0xCugNPflHFz9kf/zsGWb3X6wO/2eNewj3fr8jNRC/KWQ7otcdqwYbe1BO4yo6FjAIs5L+wCQcc2JjRWgBon4wL25ccX3nH8aMHl4/gz5trKwPqH0/lYcScJmMSRPzHbmd62LlmZE9eWEwuYJ+h8fssTZA9JTMXvkPhg05w2snaM9XdSuXIRo4UtqGpMQC0KRMmwDHbVSluX63wn7iSZD4TGHZGa"
GOOGLE_IDP_NAME_ID_FORMAT: "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
GOOGLE_IDP_CORE_ENTITY_ID: "https://sso.uds.dev/realms/uds"
GOOGLE_IDP_ADMIN_GROUP: "uds-core-dev-admin"
GOOGLE_IDP_AUDITOR_GROUP: "uds-core-dev-auditor"
- path: realmAuthFlows
value:
USERNAME_PASSWORD_AUTH_ENABLED: true
X509_AUTH_ENABLED: true
SOCIAL_AUTH_ENABLED: true
OTP_ENABLED: true
- path: env[0]
value:
name: JAVA_OPTS_KC_HEAP
value: "-XX:MaxRAMPercentage=70 -XX:MinRAMPercentage=70 -XX:InitialRAMPercentage=50 -XX:MaxRAM=1G"
50 changes: 49 additions & 1 deletion docs/reference/UDS Core/IdAM/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,62 @@ See [Testing custom image in UDS Core](https://uds.defenseunicorns.com/reference

Once `uds-core` has sucessfully deployed with your new image, viewing the Keycloak pod can provide insight into a successful deployment or not. Also describing the Keycloak pod, should display your new image being pulled instead of the default image defined [here](https://github.com/defenseunicorns/uds-core/blob/main/src/keycloak/chart/values.yaml#L10) in the events section.

### Branding customizations

The UDS Identity Config supports a limited and opinionated set of branding customizations. This includes:

* Changing the logo
* Changing the footer image
* Changing the favicon
* Changing the background image

These customizations require overriding the Keycloak Helm Chart provided by the UDS Core. Here's an example:

```yaml
packages:
- name: core
repository: oci://ghcr.io/defenseunicorns/packages/uds/core
ref: x.x.x
overrides:
keycloak:
keycloak:
values:
- path: themeCustomizations
value:
resources:
images:
- name: background.jpg
configmap:
name: keycloak-theme-overrides
- name: logo.svg
configmap:
name: keycloak-theme-overrides
- name: footer.png
configmap:
name: keycloak-theme-overrides
- name: favicon.svg
configmap:
name: keycloak-theme-overrides
```

The configuration supports only four potential keys: `background.jpg`, `logo.svg`, `footer.png`, and `favicon.svg` which are expected to exist in the corresponding ConfigMaps. In this example, all four images reside in the same ConfigMap named `keycloak-theme-overrides`. The values of these keys are base64 encoded images hosted as `binaryData` part of the ConfigMap. You can create it using the following command:

```bash
kubectl create configmap keycloak-theme-overrides \
--from-file=background.jpg=path/to/local/directory/background.jpg \
--from-file=logo.svg=path/to/local/directory/logo.svg \
--from-file=footer.png=path/to/local/directory/footer.png \
--from-file=favicon.svg=path/to/local/directory/favicon.svg
```

## Customizing Theme

**Official Theming Docs**

* [Official Keycloak Theme Docs](https://www.keycloak.org/docs/latest/server_development/#_themes)
* [Official Keycloak Theme Github](https://github.com/keycloak/keycloak/tree/b066c59a83c99d757d501d8f5e6061372706d24d/themes/src/main/resources/theme)

Changes can be made to the [src/theme](https://github.com/defenseunicorns/uds-identity-config/tree/main/src/theme) directory. At this time only Account and Login themes are included, but c email, admin, and welcome themes could be added as well.
For other changes beyond these images you will need to build a custom theme and identity-config image. Changes can be made to the [src/theme](https://github.com/defenseunicorns/uds-identity-config/tree/main/src/theme) directory. At this time only Account and Login themes are included, but email, admin, and welcome themes could be added as well.

### Testing Changes

Expand Down
28 changes: 28 additions & 0 deletions src/sync.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,34 @@ cp -fvr theme/* /opt/keycloak/themes/theme/
cp -fv *.jar /opt/keycloak/providers/
cp -fv certs/* /opt/keycloak/conf/truststores

if [ -d /opt/keycloak/theme-overrides ]; then
echo "Applying theme customizations"
if [ -f /opt/keycloak/theme-overrides/logo.svg ]; then
echo "Overriding logo.svg"
cp -fv /opt/keycloak/theme-overrides/logo.svg /opt/keycloak/themes/theme/login/resources/img/logo.svg
cp -fv /opt/keycloak/theme-overrides/logo.svg /opt/keycloak/themes/theme/login/resources/img/uds-logo.svg
cp -fv /opt/keycloak/theme-overrides/logo.svg /opt/keycloak/themes/theme/account/resources/public/logo.svg
cp -fv /opt/keycloak/theme-overrides/logo.svg /opt/keycloak/themes/theme/account/resources/public/uds-logo.svg
fi

if [ -f /opt/keycloak/theme-overrides/favicon.svg ]; then
echo "Overriding favicon.svg"
cp -fv /opt/keycloak/theme-overrides/favicon.svg /opt/keycloak/themes/theme/login/resources/img/favicon.svg
fi

if [ -f /opt/keycloak/theme-overrides/background.jpg ]; then
echo "Overriding background.jpg"
cp -fv /opt/keycloak/theme-overrides/background.jpg /opt/keycloak/themes/theme/login/resources/img/tech-bg.jpg
cp -fv /opt/keycloak/theme-overrides/background.jpg /opt/keycloak/themes/theme/account/resources/public/tech-bg.jpg
fi

if [ -f /opt/keycloak/theme-overrides/footer.png ]; then
echo "Overriding footer.png"
cp -fv /opt/keycloak/theme-overrides/footer.png /opt/keycloak/themes/theme/login/resources/img/full-du-logo.png
cp -fv /opt/keycloak/theme-overrides/footer.png /opt/keycloak/themes/theme/account/resources/public/full-du-logo.png
Comment thread
mjnagel marked this conversation as resolved.
fi
fi

# Check for environment variables and update login theme.properties
{
echo "# Login Theme configurations"
Expand Down
88 changes: 88 additions & 0 deletions src/test/cypress/e2e/theme-customization.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* Copyright 2024 Defense Unicorns
* SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial
*/

describe("Theme customizations", () => {
it("Customization ConfigMap exists", () => {
cy.exec("uds zarf tools kubectl get cm -n keycloak keycloak-theme-overrides").then(result => {
expect(result.stdout).to.contain("keycloak-theme-overrides");
});
});
it("UDS Identity Config has proper Volume Mounts", () => {
cy.exec(
"uds zarf tools kubectl get pod keycloak-0 -n keycloak -o yaml -o jsonpath='{.spec.initContainers[?(@.name==\"uds-config\")].volumeMounts}'",
).then(result => {
expect(result.stdout).to.contain("theme-overrides");
});
});
it("Override files are properly copied", () => {
cy.exec("uds zarf tools kubectl get cm -n keycloak keycloak-theme-overrides -o yaml").then(
result => {
const configMap = result.stdout;
const backgroundJpg = /background\.jpg:\s*(.*)/.exec(configMap)?.[1];
const faviconSvg = /favicon\.svg:\s*(.*)/.exec(configMap)?.[1];
const footerPng = /footer\.png:\s*(.*)/.exec(configMap)?.[1];
const logoSvg = /logo\.svg:\s*(.*)/.exec(configMap)?.[1];

expect(backgroundJpg).to.exist;
expect(faviconSvg).to.exist;
expect(footerPng).to.exist;
expect(logoSvg).to.exist;

// logo.svg tests
cy.exec(
"uds zarf tools kubectl exec keycloak-0 -n keycloak -- cat /opt/keycloak/themes/theme/login/resources/img/logo.svg | base64 -w 0",
).then(result => {
expect(result.stdout).to.equal(logoSvg);
});
cy.exec(
"uds zarf tools kubectl exec keycloak-0 -n keycloak -- cat /opt/keycloak/themes/theme/login/resources/img/uds-logo.svg | base64 -w 0",
).then(result => {
expect(result.stdout).to.equal(logoSvg);
});
cy.exec(
"uds zarf tools kubectl exec keycloak-0 -n keycloak -- cat /opt/keycloak/themes/theme/account/resources/public/logo.svg | base64 -w 0",
).then(result => {
expect(result.stdout).to.equal(logoSvg);
});
cy.exec(
"uds zarf tools kubectl exec keycloak-0 -n keycloak -- cat /opt/keycloak/themes/theme/account/resources/public/uds-logo.svg | base64 -w 0",
).then(result => {
expect(result.stdout).to.equal(logoSvg);
});

// background.jpg tests
cy.exec(
"uds zarf tools kubectl exec keycloak-0 -n keycloak -- cat /opt/keycloak/themes/theme/login/resources/img/tech-bg.jpg | base64 -w 0",
).then(result => {
expect(result.stdout).to.equal(backgroundJpg);
});
cy.exec(
"uds zarf tools kubectl exec keycloak-0 -n keycloak -- cat /opt/keycloak/themes/theme/account/resources/public/tech-bg.jpg | base64 -w 0",
).then(result => {
expect(result.stdout).to.equal(backgroundJpg);
});

// favicon.svg tests
cy.exec(
"uds zarf tools kubectl exec keycloak-0 -n keycloak -- cat /opt/keycloak/themes/theme/login/resources/img/favicon.svg | base64 -w 0",
).then(result => {
expect(result.stdout).to.equal(faviconSvg);
});

// footer.png tests
cy.exec(
"uds zarf tools kubectl exec keycloak-0 -n keycloak -- cat /opt/keycloak/themes/theme/login/resources/img/full-du-logo.png | base64 -w 0",
).then(result => {
expect(result.stdout).to.equal(footerPng);
});
cy.exec(
"uds zarf tools kubectl exec keycloak-0 -n keycloak -- cat /opt/keycloak/themes/theme/login/resources/img/full-du-logo.png | base64 -w 0",
).then(result => {
expect(result.stdout).to.equal(footerPng);
});
},
);
});
});
5 changes: 3 additions & 2 deletions src/test/cypress/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
"main": "index.js",
"scripts": {
"cy.open": "cypress open",
"cy.run": "cross-env USE_CAC=true cypress run --spec 'e2e/registration.cy.ts' && cross-env USE_CAC=false cypress run --spec 'e2e/**/*.cy.ts,!e2e/registration.cy.ts'",
"cy.run": "cross-env USE_CAC=true cypress run --spec 'e2e/registration.cy.ts' && cross-env USE_CAC=false cypress run --spec 'e2e/**/*.cy.ts,!e2e/registration.cy.ts,!e2e/theme-customization.cy.ts'",
"cy.run:registration": "cross-env USE_CAC=true cypress run --spec 'e2e/registration.cy.ts'",
"cy.run:others": "cross-env USE_CAC=false cypress run --spec 'e2e/**/*.cy.ts,!e2e/registration.cy.ts'",
"cy.run:theme-customization": "cross-env cypress run --spec 'e2e/theme-customization.cy.ts'",
"cy.run:others": "cross-env USE_CAC=false cypress run --spec 'e2e/**/*.cy.ts,!e2e/registration.cy.ts,!e2e/theme-customization.cy.ts'",
"prettier": "prettier --write **/*.ts"
},
"devDependencies": {
Expand Down
20 changes: 18 additions & 2 deletions tasks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ tasks:
- task: uds-core-gateway-cacert
- task: build-deploy-custom-slim
- task: cypress-tests
- task: theme-customization-tests

- name: grafana-group-auth-build-deploy
description: Configure existing uds-core/grafana package for group authz, build, deploy grafana
Expand All @@ -144,8 +145,8 @@ tasks:
- cmd: uds zarf package create . --confirm --set=IDENTITY_CONFIG_IMG=uds-core-config:keycloak --no-progress
- cmd: cd uds-core && uds run create:single-layer && uds run create:single-layer-callable --set LAYER=identity-authorization
- task: grafana-group-auth-build-deploy
- cmd: uds create bundles --confirm --no-progress
- cmd: uds deploy bundles/uds-bundle-k3d-core-slim-dev-*.tar.zst --set=core-identity-authorization.KEYCLOAK_CONFIG_IMAGE=uds-core-config:keycloak --set=core-base.PEPR_KEYCLOAK_CLIENT_STRATEGY=${PEPR_KEYCLOAK_CLIENT_STRATEGY} --confirm --no-progress
- cmd: uds create bundles/k3d-core-slim-dev --confirm --no-progress
- cmd: uds deploy bundles/k3d-core-slim-dev/uds-bundle-k3d-core-slim-dev-*.tar.zst --set=core-identity-authorization.KEYCLOAK_CONFIG_IMAGE=uds-core-config:keycloak --set=core-base.PEPR_KEYCLOAK_CLIENT_STRATEGY=${PEPR_KEYCLOAK_CLIENT_STRATEGY} --confirm --no-progress

- name: cypress-tests
description: "Run all cypress tests ( requires an existing deployed UDS Core Identity )"
Expand All @@ -154,6 +155,21 @@ tasks:
npm --prefix src/test/cypress install
PEPR_KEYCLOAK_CLIENT_STRATEGY=${PEPR_KEYCLOAK_CLIENT_STRATEGY} npm --prefix src/test/cypress run cy.run

- name: theme-customization-tests
description: "Runs theme customization tests ( requires an existing deployed UDS Core Identity )"
actions:
- description: "Create theme customization resources"
cmd: uds zarf tools kubectl apply -f tasks/theme-customization-configmap.yaml
- description: "Create the theme customization bundle"
cmd: uds create bundles/theme-customizations --confirm --no-progress
- description: "Deploy the theme customization bundle"
cmd: uds deploy bundles/theme-customizations/uds-bundle-theme-customization-tests-*.tar.zst --set=core-identity-authorization.KEYCLOAK_CONFIG_IMAGE=uds-core-config:keycloak --confirm --no-progress
- description: "Run the theme customization tests"
cmd: |
# Should already be done... but just in case
npm --prefix src/test/cypress install
npm --prefix src/test/cypress run cy.run:theme-customization

- name: license
actions:
- description: Lint for the SPDX license identifier being in source files
Expand Down
13 changes: 13 additions & 0 deletions tasks/theme-customization-configmap.yaml

Large diffs are not rendered by default.