Skip to content

Make REST context path configurable via openidm.context.path system property#142

Open
Copilot wants to merge 15 commits intomasterfrom
copilot/make-rest-context-path-configurable
Open

Make REST context path configurable via openidm.context.path system property#142
Copilot wants to merge 15 commits intomasterfrom
copilot/make-rest-context-path-configurable

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 31, 2026

  • Previous commits (copyright, etc.)
  • Add ServerConstants.normalizeContextPath() static utility and use it everywhere (ServletComponent, ServletRegistrationSingleton, RemoteCommandScope)
  • Fix ResourceServlet.handleIndexHtml: use ServerConstants.normalizeContextPath(), Matcher.quoteReplacement, proper JS escaping
  • Update RemoteCommandScope.IDM_URL_DESC to mention computed default from openidm.context.path
  • Update chap-configuration.adoc to describe the runtime window.__openidm_context_path injection mechanism
Original prompt

Problem

The REST context path /openidm is hardcoded throughout the entire codebase — in Java backend, JavaScript UI delegates, servlet registration, CLI tools, and documentation. This makes it impossible to change the REST API base path (e.g., to /myidm) without modifying source code.

As shown in the screenshot, there are 101+ matches in 53+ JS files alone for the hardcoded "/openidm" string:

image1

Requirements

  1. Make the REST context path configurable via a system property (e.g., openidm.context.path) with default value /openidm.
  2. Apply changes to both REST API and UI (openidm-ui) so they use the configured path.
  3. Update documentation to describe the new configuration parameter.
  4. Add automated tests for both the default (/openidm) and a custom value (e.g., /myidm).

Detailed Plan

1. Backend (Java)

1.1. Add system property support in ServerConstants or IdentityServer

  • Add a constant for the system property name: openidm.context.path
  • Add a static method to retrieve the configured context path (defaulting to /openidm)
  • Ensure it always starts with / and does not end with /

1.2. Refactor ServletComponent.java

File: openidm-api-servlet/src/main/java/org/forgerock/openidm/servlet/internal/ServletComponent.java

  • Replace private static final String SERVLET_ALIAS = "/openidm"; with a dynamic lookup:
    private static String getServletAlias() {
        return System.getProperty("openidm.context.path", "/openidm");
    }
  • Use this method in activate() instead of the constant.

1.3. Refactor ServletRegistrationSingleton.java

File: openidm-servlet-registrator/src/main/java/org/forgerock/openidm/servletregistration/impl/ServletRegistrationSingleton.java

  • Replace hardcoded DEFAULT_SERVLET_URL_PATTERNS = new String[] { "/openidm/*", "/selfservice/*" } to use the configurable context path:
    private static String[] getDefaultServletUrlPatterns() {
        String contextPath = System.getProperty("openidm.context.path", "/openidm");
        return new String[] { contextPath + "/*", "/selfservice/*" };
    }

1.4. Refactor RemoteCommandScope.java

File: openidm-shell/src/main/java/org/forgerock/openidm/shell/impl/RemoteCommandScope.java

  • Replace IDM_URL_DEFAULT = "http://localhost:8080/openidm/" to use the system property.

1.5. Add the property to default system.properties / boot.properties

File: openidm-zip/src/main/resources/conf/system.properties (or equivalent)

  • Add: openidm.context.path=/openidm

2. Frontend (JavaScript UI — openidm-ui)

2.1. Expose context path as a global constant

  • Add a configurable context path constant (e.g., in Constants.js or a new config module) that the UI reads. The backend should expose the configured context path, for example via an initial config endpoint or by injecting it into the HTML page template.
  • Alternatively, add a contextPath field to the existing Constants object that defaults to "/openidm" and can be overridden.

2.2. Refactor all UI delegate files

Replace all hardcoded "/openidm" and "/openidm/..." references with the configurable constant. Key files include (but are not limited to):

openidm-ui-admin delegates:

  • ReconDelegate.jsserviceUrl: "/openidm/recon/", "/openidm/audit/recon", "/openidm/" + link.targetObjectId
  • SchedulerDelegate.jsconstants.host + "/openidm/scheduler/job"
  • ExternalAccessDelegate.jsconstants.host + "/openidm/endpoint/oauthproxy", constants.host + "/openidm/external/rest"
  • ClusterDelegate.jsconstants.host + "/openidm"
  • WorkflowDelegate.jsconstants.host + "/openidm/workflow/processdefinition"
  • ScriptDelegate.jsconstants.host + "/openidm/script"
  • ConnectorDelegate.js — uses "/openidm/system"
  • AuditDelegate.js — uses "/openidm/audit/"
  • MaintenanceDelegate.js — uses "/openidm/maintenance"

openidm-ui-admin views/models:

  • ProcessInstanceView.jsurl: "/openidm/workflow/processinstance", "/openidm/workflow/processdefinition", "/openidm/managed/user", "/openidm/repo/internal/user", "/openidm/workflow/processinstance/", "/openidm/workflow/processdefinition/"
  • ProcessDefinitionView.jsurl: "/openidm/workflow/processdefinition", "/openidm/workflow/processdefinition/"
  • AdminValidators.jsif (v === "/openidm" || v === "/admin" || v === "/system")
  • SettingsView.jsConstants.host + "/openidm/maintenance"

openidm-ui-common delegates:

  • SystemHealthDelegate.jsconstants.host + "/openidm/health"
  • SocialDelegate.jsConstants.host + "/openidm/identityProviders", serviceUrl: "/openidm/authentication"
  • SearchDelegate.jsconstants.host + "/openidm"
  • InternalUserDelegate.jsconstants.host + "/openidm/repo/internal/user"
  • ConfigDelegate.js — likely uses "/openidm/config"
  • ResourceDelegate.js — likely uses "/openidm/"

**Pattern...

This pull request was created from Copilot chat.

Copilot AI changed the title [WIP] Make REST context path configurable via system property Make REST context path configurable via openidm.context.path system property Mar 31, 2026
Copilot AI requested a review from vharseko March 31, 2026 10:42
@vharseko vharseko marked this pull request as ready for review March 31, 2026 16:37
@vharseko vharseko requested a review from Copilot March 31, 2026 16:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to remove hardcoded /openidm REST base-path usage by introducing a configurable REST context path via the openidm.context.path system property (defaulting to /openidm), and refactoring backend/CLI/UI call sites and docs to use that configuration.

Changes:

  • Add backend support for a configurable servlet alias and default servlet-filter URL patterns based on openidm.context.path.
  • Refactor many UI delegates/views to build REST URLs using Constants.context instead of hardcoding /openidm.
  • Add/extend docs and add automated tests for the default context path.

Reviewed changes

Copilot reviewed 42 out of 42 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
openidm-zip/src/main/resources/conf/system.properties Documents the new openidm.context.path setting (commented example).
openidm-ui/openidm-ui-common/src/test/qunit/tests/org/forgerock/openidm/ui/common/util/ConstantsTest.js Adds QUnit assertions for the default Constants.context value and derived prefix.
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/workflow/WorkflowDelegate.js Replaces hardcoded /openidm/... workflow endpoints with "/" + constants.context + ....
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/notifications/NotificationDelegate.js Uses constants.context when building the notifications endpoint URL.
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/delegates/SystemHealthDelegate.js Uses constants.context for health endpoint base URL.
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/delegates/SocialDelegate.js Uses Constants.context for identityProviders/authentication endpoints.
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/delegates/SearchDelegate.js Uses constants.context for the search delegate base URL.
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/delegates/ResourceDelegate.js Uses constants.context for the resource delegate base URL and linkedView endpoint.
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/delegates/PolicyDelegate.js Uses constants.context for policy endpoint base URL.
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/delegates/InternalUserDelegate.js Uses constants.context for internal user repo URL.
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/delegates/InfoDelegate.js Uses constants.context for /info/ endpoint base URL.
openidm-ui/openidm-ui-common/src/main/js/org/forgerock/openidm/ui/common/delegates/ConfigDelegate.js Uses constants.context for /config endpoint base URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/workflow/TaskListView.js Uses constants.context for workflow task URLs.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/workflow/TaskInstanceView.js Uses constants.context for task/process/user model URLs.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/workflow/ProcessListView.js Uses constants.context for process-definition query URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/workflow/ProcessInstanceView.js Uses constants.context for workflow and repo/internal/user and diagram URLs.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/workflow/ProcessHistoryView.js Uses constants.context for workflow history URLs.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/workflow/ProcessDefinitionView.js Uses constants.context for process-definition and diagram URLs.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/workflow/ProcessDefinitionsView.js Uses constants.context for process-definition list/query URLs.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/workflow/ActiveProcessesView.js Uses constants.context for active process URLs and queries.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/user/EditUserView.js Uses constants.context for managed user reset password endpoint.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/settings/SettingsView.js Uses Constants.context for maintenance delegate base URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/mapping/util/MappingUtils.js Uses constants.context for repo/links deletion command endpoint.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/mapping/association/DataAssociationManagementView.js Uses constants.context for reconResults endpoint; adds Constants dependency.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/WorkflowDelegate.js Uses constants.context for workflow processdefinition delegate base URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/SyncDelegate.js Uses constants.context for sync and repo/link endpoints and mappingDetails endpoint.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/SecurityDelegate.js Uses constants.context for security delegate base URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/ScriptDelegate.js Uses constants.context for script delegate base URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/SchedulerDelegate.js Uses constants.context for scheduler/job delegate base URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/ReconDelegate.js Uses constants.context for recon and audit/recon and target object URLs.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/MaintenanceDelegate.js Uses constants.context for maintenance delegate base URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/ExternalAccessDelegate.js Uses constants.context for oauthproxy and external/rest endpoints.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/ConnectorDelegate.js Uses constants.context for system endpoint base URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/ClusterDelegate.js Uses constants.context for base cluster delegate URL.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/delegates/AuditDelegate.js Uses constants.context for audit delegate base URL.
openidm-ui/openidm-ui-admin/src/main/js/config/validators/AdminValidators.js Treats "/" + constants.context as a reserved URL value; updates error message accordingly.
openidm-shell/src/main/java/org/forgerock/openidm/shell/impl/RemoteCommandScope.java Builds the default CLI URL using openidm.context.path when the default URL value is used.
openidm-servlet-registrator/src/main/java/org/forgerock/openidm/servletregistration/impl/ServletRegistrationSingleton.java Derives default servlet-filter URL patterns from openidm.context.path (instead of hardcoded /openidm/*).
openidm-doc/src/main/asciidoc/integrators-guide/chap-configuration.adoc Documents the new openidm.context.path property and configuration examples.
openidm-doc/src/main/asciidoc/integrators-guide/appendix-rest.adoc Adds note that /openidm in examples is the default and can be changed via openidm.context.path.
openidm-api-servlet/src/test/java/org/forgerock/openidm/servlet/internal/ServletComponentTest.java Adds unit tests for default/custom/normalized servlet alias based on system property.
openidm-api-servlet/src/main/java/org/forgerock/openidm/servlet/internal/ServletComponent.java Registers the REST servlet under an alias derived from openidm.context.path (normalized).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +176 to +180
After changing this property, the REST API will be accessible under the new path, for example `\https://localhost:8443/myidm/config`, and the Admin UI and Self-Service UI will automatically use the configured path for all API calls.

[NOTE]
====
Changing the context path affects all REST API endpoints, the Admin UI, and the Self-Service UI. Ensure that any external integrations, load balancer rules, or documentation referring to the `/openidm` path are updated accordingly.
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The statement that the Admin UI and Self-Service UI will “automatically use the configured path for all API calls” appears inaccurate with the current UI implementation: openidm-ui-common/.../util/Constants.js still hardcodes commonConstants.context = "openidm", so changing -Dopenidm.context.path on the JVM won’t update the UI’s REST base path unless additional wiring is added (for example, injecting the context into the UI at runtime or deriving it from window.location). Please either implement that wiring or adjust this documentation to describe the actual behavior/requirements for the UI.

Suggested change
After changing this property, the REST API will be accessible under the new path, for example `\https://localhost:8443/myidm/config`, and the Admin UI and Self-Service UI will automatically use the configured path for all API calls.
[NOTE]
====
Changing the context path affects all REST API endpoints, the Admin UI, and the Self-Service UI. Ensure that any external integrations, load balancer rules, or documentation referring to the `/openidm` path are updated accordingly.
After changing this property, the REST API will be accessible under the new path, for example `\https://localhost:8443/myidm/config`. The Admin UI and Self-Service UI, however, are implemented with a default context path of `/openidm` for their REST calls. To use a custom context path with the UIs, you must either deploy them behind a reverse proxy that maps the public path (for example `/myidm`) to `/openidm` on the OpenIDM server, or customize and rebuild the UI so that it derives the REST base path from the runtime context (for example, `window.location`) or from injected configuration that matches `openidm.context.path`.
[NOTE]
====
Changing the context path affects all REST API endpoints. If you expose the Admin UI or Self-Service UI under a custom path, ensure that any external integrations, load balancer rules, or documentation referring to the `/openidm` path are updated accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +9
QUnit.test("Constants.context defaults to 'openidm'", function (assert) {
assert.equal(Constants.context, "openidm",
"The default context should be 'openidm'");
});
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests only verify the hardcoded default (Constants.context === "openidm"). The PR goal is configurable REST context paths; please add coverage for a non-default value as well (e.g., verifying delegates build URLs correctly when the context is overridden), which will require providing a supported way to set/override Constants.context in tests and in runtime.

Copilot uses AI. Check for mistakes.
private static String getUrl(final String url) {
if (isNotBlank(url)) {
return url.endsWith("/") ? url : url + "/";
return getEffectiveIdmUrl(url.endsWith("/") ? url : url + "/");
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getUrl() now always runs the value through getEffectiveIdmUrl(...), which will replace the URL with one derived from openidm.context.path whenever the normalized URL equals IDM_URL_DEFAULT. This means a user explicitly passing --url http://localhost:8080/openidm/ (or .../openidm which gets normalized) can be unexpectedly overridden by the system property. --url should take precedence over the system property; consider only applying getEffectiveIdmUrl when the --url option was not explicitly provided (e.g., by using a sentinel absentValue and treating blank as ‘use default’).

Suggested change
return getEffectiveIdmUrl(url.endsWith("/") ? url : url + "/");
return url.endsWith("/") ? url : url + "/";

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +100
static final String OPENIDM_CONTEXT_PATH_PROPERTY = "openidm.context.path";

/** Default REST context path. */
static final String OPENIDM_CONTEXT_PATH_DEFAULT = "/openidm";
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The openidm.context.path property name/default and the path-normalization logic are now duplicated in multiple modules/classes (e.g., this component, ServletRegistrationSingleton, and RemoteCommandScope). To avoid drift (e.g., different trimming/validation rules over time), consider centralizing the constant + normalization in a shared location (such as a core utility or ServerConstants/IdentityServer) and reusing it from all call sites.

Suggested change
static final String OPENIDM_CONTEXT_PATH_PROPERTY = "openidm.context.path";
/** Default REST context path. */
static final String OPENIDM_CONTEXT_PATH_DEFAULT = "/openidm";
static final String OPENIDM_CONTEXT_PATH_PROPERTY = ServerConstants.OPENIDM_CONTEXT_PATH_PROPERTY;
/** Default REST context path. */
static final String OPENIDM_CONTEXT_PATH_DEFAULT = ServerConstants.OPENIDM_CONTEXT_PATH_DEFAULT;

Copilot uses AI. Check for mistakes.
@vharseko
Copy link
Copy Markdown
Member

vharseko commented Apr 1, 2026

@copilot apply changes based on the comments in this thread

…e, fix docs accuracy, add test

Agent-Logs-Url: https://github.com/OpenIdentityPlatform/OpenIDM/sessions/8b607db5-2e23-4d3b-99ac-d17b133b6198

Co-authored-by: vharseko <6818498+vharseko@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 1, 2026

@copilot apply changes based on the comments in this thread

Applied all four review changes in commit fdd7eeb:

  1. Centralized constants (OPENIDM_CONTEXT_PATH_PROPERTY / OPENIDM_CONTEXT_PATH_DEFAULT) in ServerConstants.java; ServletComponent, ServletRegistrationSingleton, and RemoteCommandScope now reference them. Added openidm-system dependency to openidm-servlet-registrator/pom.xml.

  2. Fixed --url precedence in RemoteCommandScope: changed absentValue for all --url @Parameter annotations from IDM_URL_DEFAULT to "" (sentinel for "not provided"). getUrl() now uses the user's explicit URL as-is; the system property is only consulted when no --url was given.

  3. Fixed chap-configuration.adoc: removed the inaccurate claim that UIs auto-use the configured path. Now correctly describes that UIs hardcode /openidm and a reverse proxy or UI rebuild is needed for custom paths.

  4. Added ConstantsTest.js test: added a test verifying that Constants.context can be overridden to a custom value (the mechanism all the delegates rely on).

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • central.sonatype.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/OpenIDM/OpenIDM org.codehaus.plexus.classworlds.launcher.Launcher -f pom.xml -B -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip (dns block)
  • maven.alfresco.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/OpenIDM/OpenIDM org.codehaus.plexus.classworlds.launcher.Launcher -f pom.xml -B -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip (dns block)
  • repository.jboss.org
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/OpenIDM/OpenIDM org.codehaus.plexus.classworlds.launcher.Launcher -f pom.xml -B -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip (dns block)
  • www.eclipse.org
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.24.3/x64/codeql/tools/linux64/java/bin/java /opt/hostedtoolcache/CodeQL/2.24.3/x64/codeql/tools/linux64/java/bin/java -jar /opt/hostedtoolcache/CodeQL/2.24.3/x64/codeql/xml/tools/xml-extractor.jar --fileList=/tmp/codeql-scratch-dd852eba2a5d9229/dbs/java/working/files-to-index8987160489757239532.list --sourceArchiveDir=/tmp/codeql-scratch-dd852eba2a5d9229/dbs/java/src --outputDir=/tmp/codeql-scratch-dd852eba2a5d9229/dbs/java/trap/java --global tnet/tools/bash committer.name (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@vharseko
Copy link
Copy Markdown
Member

vharseko commented Apr 1, 2026

@copilot merge from master

Copilot stopped work on behalf of vharseko due to an error April 1, 2026 17:57
@vharseko
Copy link
Copy Markdown
Member

vharseko commented Apr 1, 2026

@copilot merge from master

…ontext-path-configurable

# Conflicts:
#	openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/settings/SettingsView.js

Co-authored-by: vharseko <6818498+vharseko@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 8, 2026

@copilot merge from master

Merged origin/master (through commit 261adbd) into the branch in commit c545b24. One conflict in SettingsView.js was resolved by accepting master's removal of the dead maintenance mode code.

@vharseko
Copy link
Copy Markdown
Member

vharseko commented Apr 8, 2026

@copilot merge from master

…ontext-path-configurable

Co-authored-by: vharseko <6818498+vharseko@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 8, 2026

@copilot merge from master

Merged origin/master (commit 1df435f — Playwright UI smoke tests) into the branch in commit 341483c. Clean merge, no conflicts.

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vharseko <6818498+vharseko@users.noreply.github.com>
Co-authored-by: Valery Kharseko <vharseko@3a-systems.ru>
…m_context_path (#154)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vharseko <6818498+vharseko@users.noreply.github.com>
…tml, and ConstantsTest.js

Agent-Logs-Url: https://github.com/OpenIdentityPlatform/OpenIDM/sessions/10e899b2-073e-4968-af0f-5ca9d8f62f90

Co-authored-by: vharseko <6818498+vharseko@users.noreply.github.com>
@vharseko vharseko requested review from Copilot and maximthomas and removed request for vharseko April 9, 2026 17:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 48 out of 48 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

openidm-ui/openidm-ui-common/src/test/qunit/tests/org/forgerock/openidm/ui/common/util/ConstantsTest.js:1

  • These tests don’t validate the actual behavior of org/forgerock/openidm/ui/common/util/Constants, because they compute contextValue locally rather than asserting what Constants.context becomes when window.__openidm_context_path is set/unset. Since the module reads window.__openidm_context_path at definition time, setting it after Constants has already been loaded won’t exercise the production logic. Restructure the tests to set/unset window.__openidm_context_path before requiring the module (or force a module reload/reset in the test harness), then assert on Constants.context.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +180 to +203
String contextPath = System.getProperty(
ServerConstants.OPENIDM_CONTEXT_PATH_PROPERTY,
ServerConstants.OPENIDM_CONTEXT_PATH_DEFAULT);
// Strip leading slash — the UI Constants.context value does not use it
String contextValue = contextPath.startsWith("/") ? contextPath.substring(1) : contextPath;

byte[] raw;
try (InputStream is = url.openStream()) {
raw = is.readAllBytes();
}
String html = new String(raw, StandardCharsets.UTF_8);

// Inject a tiny script right before </head> so it is available before RequireJS loads.
// Escape characters that could break out of the JS string or the script tag.
String safeContextValue = contextValue
.replace("&", "&amp;")
.replace("<", "\\u003c")
.replace(">", "\\u003e")
.replace("\"", "\\\"")
.replace("'", "\\'");
String injection = "<script>window.__openidm_context_path=\""
+ safeContextValue + "\";</script>\n</head>";
// replaceFirst to guard against malformed HTML with multiple </head> tags
html = html.replaceFirst("</head>", injection);
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String.replaceFirst treats the replacement string specially (backslashes and $ have meaning). This means the intended \\u003c/\\u003e escaping can be broken (backslashes may be dropped), and a context path containing $ could throw or produce unintended output. Also, contextValue does not strip a trailing /, so -Dopenidm.context.path=/myidm/ will inject myidm/ and the UI will build URLs with double slashes (e.g. //workflow/...). Fix by (1) normalizing contextPath the same way the backend does (add leading / if missing, remove trailing /, then strip the leading / for the UI value), and (2) avoiding regex replacement pitfalls by using a literal insertion approach or quoting the replacement string (e.g., via Matcher.quoteReplacement). Additionally, replacing & with &amp; changes the value inside a JS string; prefer proper JS-string escaping (or JSON string encoding) instead of HTML entities.

Copilot uses AI. Check for mistakes.
/** Compile-time default URL used in CLI parameter annotations. */
private static final String IDM_URL_DEFAULT = "http://localhost:8080/openidm/";

private static final String IDM_URL_DESC = "URL of OpenIDM REST service. Default " + IDM_URL_DEFAULT;
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CLI help text is now misleading: the effective default URL is derived from openidm.context.path (via getEffectiveIdmUrl()), but IDM_URL_DESC still advertises the hardcoded /openidm/ default. Update the descriptor to reflect that the default is computed and can change with -Dopenidm.context.path, otherwise users will be guided to the wrong URL when using a custom context path.

Suggested change
private static final String IDM_URL_DESC = "URL of OpenIDM REST service. Default " + IDM_URL_DEFAULT;
private static final String IDM_URL_DESC =
"URL of OpenIDM REST service. Default: http://localhost:8080 plus the effective "
+ "context path (derived from -Dopenidm.context.path; default context path: "
+ "/openidm).";

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +177
After changing this property, the REST API will be accessible under the new path, for example `\https://localhost:8443/myidm/config`. The Admin UI and Self-Service UI, however, are implemented with a default context path of `/openidm` for their REST calls. To use a custom context path with the UIs, you must either deploy them behind a reverse proxy that maps the public path (for example `/myidm`) to `/openidm` on the OpenIDM server, or customize and rebuild the UI so that it derives the REST base path from the runtime context or from injected configuration that matches `openidm.context.path`.

Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This paragraph is now incorrect given the code changes in this PR: ResourceServlet injects window.__openidm_context_path into index.html, and openidm-ui reads it in Constants.js, so the Admin UI/Self-Service UI should be able to follow a custom context path without requiring a reverse proxy or a rebuild (as long as the UI is served by ResourceServlet). Please update the documentation to describe the new injection mechanism, and clarify any remaining constraints (e.g., if this only works when the UI is served by OpenIDM vs. hosted separately).

Suggested change
After changing this property, the REST API will be accessible under the new path, for example `\https://localhost:8443/myidm/config`. The Admin UI and Self-Service UI, however, are implemented with a default context path of `/openidm` for their REST calls. To use a custom context path with the UIs, you must either deploy them behind a reverse proxy that maps the public path (for example `/myidm`) to `/openidm` on the OpenIDM server, or customize and rebuild the UI so that it derives the REST base path from the runtime context or from injected configuration that matches `openidm.context.path`.
After changing this property, the REST API will be accessible under the new path, for example `\https://localhost:8443/myidm/config`. When the Admin UI or Self-Service UI is served by OpenIDM, `ResourceServlet` injects the effective context path into `index.html`, and the UI uses that injected value for its REST calls. In this deployment model, the UIs follow a custom `openidm.context.path` without requiring a reverse proxy or a rebuild.
If you host the UI separately instead of serving it through OpenIDM, this runtime injection does not occur. In that case, you must provide equivalent runtime configuration for the UI, or use another deployment mechanism such as a reverse proxy or a custom build that targets the desired context path.

Copilot uses AI. Check for mistakes.
Comment on lines +162 to +176
/**
* Returns the servlet alias (REST context path) from the system property
* {@code openidm.context.path}, defaulting to {@code /openidm}.
*/
static String getServletAlias() {
String path = System.getProperty(OPENIDM_CONTEXT_PATH_PROPERTY, OPENIDM_CONTEXT_PATH_DEFAULT);
if (!path.startsWith("/")) {
path = "/" + path;
}
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
return path;
}

Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Context-path normalization logic (leading / + trimming trailing /) is duplicated across multiple components in this PR (e.g., servlet component, servlet registrator, CLI default URL, UI index injection). To reduce drift and edge-case inconsistencies (like the trailing-slash UI issue), consider centralizing normalization in a single helper (e.g., a ServerConstants#getNormalizedContextPath() utility) and reusing it everywhere.

Suggested change
/**
* Returns the servlet alias (REST context path) from the system property
* {@code openidm.context.path}, defaulting to {@code /openidm}.
*/
static String getServletAlias() {
String path = System.getProperty(OPENIDM_CONTEXT_PATH_PROPERTY, OPENIDM_CONTEXT_PATH_DEFAULT);
if (!path.startsWith("/")) {
path = "/" + path;
}
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
return path;
}
private static String normalizeContextPath(String path) {
if (!path.startsWith("/")) {
path = "/" + path;
}
if (path.endsWith("/") && path.length() > 1) {
path = path.substring(0, path.length() - 1);
}
return path;
}
/**
* Returns the servlet alias (REST context path) from the system property
* {@code openidm.context.path}, defaulting to {@code /openidm}.
*/
static String getServletAlias() {
return normalizeContextPath(
System.getProperty(OPENIDM_CONTEXT_PATH_PROPERTY, OPENIDM_CONTEXT_PATH_DEFAULT));
}

Copilot uses AI. Check for mistakes.
@vharseko
Copy link
Copy Markdown
Member

vharseko commented Apr 9, 2026

@copilot apply changes based on the comments in this thread

Copilot AI and others added 2 commits April 9, 2026 17:40
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 9, 2026

@copilot apply changes based on the comments in this thread

Applied all four review changes in commit dd454b8 (with a minor follow-up in e2e87ac):

  1. Centralized normalizeContextPath() in ServerConstants.java — all call sites (ServletComponent, ServletRegistrationSingleton, RemoteCommandScope, ResourceServlet) now delegate to ServerConstants.normalizeContextPath() instead of duplicating the trim/leading-slash logic.

  2. Fixed ResourceServlet.handleIndexHtml:

    • Uses ServerConstants.normalizeContextPath() so a trailing / in openidm.context.path can no longer produce double-slashes in UI URLs.
    • Wraps the injection string with Matcher.quoteReplacement() to prevent $ or \ in the context value from being mis-interpreted by the regex engine.
    • Corrected JS-string escaping: backslash is escaped first, " is escaped, < and > use Unicode escapes; removed the incorrect &amp; HTML-entity encoding and the unnecessary \/ forward-slash escape.
  3. Updated IDM_URL_DESC in RemoteCommandScope to say the default URL is derived from -Dopenidm.context.path rather than always being /openidm.

  4. Updated chap-configuration.adoc to accurately describe the runtime injection mechanism: when the UI is served by OpenIDM, ResourceServlet injects window.__openidm_context_path and the UI follows the configured path automatically; separately-hosted UIs need a reverse proxy or custom build.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • central.sonatype.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/OpenIDM/OpenIDM org.codehaus.plexus.classworlds.launcher.Launcher -f pom.xml -B -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip (dns block)
  • maven.alfresco.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/OpenIDM/OpenIDM org.codehaus.plexus.classworlds.launcher.Launcher -f pom.xml -B -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip (dns block)
  • repository.jboss.org
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/OpenIDM/OpenIDM org.codehaus.plexus.classworlds.launcher.Launcher -f pom.xml -B -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip (dns block)
  • www.eclipse.org
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/java/bin/java /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/java/bin/java -jar /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/xml/tools/xml-extractor.jar --fileList=/tmp/codeql-scratch-dd852eba2a5d9229/dbs/java/working/files-to-index13201574234377955113.list --sourceArchiveDir=/tmp/codeql-scratch-dd852eba2a5d9229/dbs/java/src --outputDir=/tmp/codeql-scratch-dd852eba2a5d9229/dbs/java/trap/java (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from vharseko April 9, 2026 17:46
@vharseko vharseko removed their request for review April 9, 2026 18:01
…ilures (#155)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vharseko <6818498+vharseko@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants