Skip to content
Open
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 @@ -12,7 +12,7 @@
information: "Portions copyright [year] [name of copyright owner]".

Copyright 2017 ForgeRock AS.
Portions Copyright 2024-2025 3A Systems LLC.
Portions Copyright 2024-2026 3A Systems LLC.
////

:figure-caption!:
Expand Down Expand Up @@ -135,7 +135,7 @@ Audit event publisher configuration file
Authentication configuration file for access to the REST API

`openidm/conf/boot/boot.properties`::
OpenIDM bootstrap properties
OpenIDM bootstrap properties, including HTTP/HTTPS port numbers, keystore and truststore locations, and configuration of the default URL patterns used when registering REST-related servlet filters (for example, `openidm.servlet.alias` and `openidm.selfservice.alias`). These settings do not change the underlying REST servlet alias (which remains `/openidm`). For details, see xref:appendix-jetty.adoc#configuring-rest-context-path["Configuring the REST API Context Path"] and xref:appendix-ports-used.adoc#appendix-ports-used["Ports Used"].

`openidm/conf/cluster.json`::
Configuration file to enable use of this OpenIDM instance in a cluster
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
information: "Portions copyright [year] [name of copyright owner]".

Copyright 2017 ForgeRock AS.
Portions Copyright 2024-2025 3A Systems LLC.
Portions Copyright 2024-2026 3A Systems LLC.
////

:figure-caption!:
Expand Down Expand Up @@ -181,14 +181,41 @@ The HTTP context under which the filter should be registered. The default is `"o
A list of servlet names to which the filter should apply. The default is `"OpenIDM REST"`.

`"urlPatterns"`::
A list of URL patterns to which the filter applies. The default is `["/*"]`.
A list of URL patterns to which the filter applies. When not specified in the filter configuration, the filter is applied to the configured REST servlet URL patterns (by default `["/openidm/*", "/selfservice/*"]`). To change the default patterns for all filters, configure the servlet alias properties in `conf/boot/boot.properties`. See xref:appendix-jetty.adoc#configuring-rest-context-path["Configuring the REST API Context Path"] for details.

`"initParams"`::
Filter configuration initialization parameters that are passed to the servlet filter `init` method. For more information, see link:https://jakarta.ee/specifications/servlet/4.0/apidocs/javax/servlet/filterconfig[https://jakarta.ee/specifications/servlet/4.0/apidocs/javax/servlet/filterconfig, window=\_top].

--


[#configuring-rest-context-path]
=== Configuring the REST API Context Path

By default, the OpenIDM REST API is accessible at `/openidm/` and the Self-Service UI at `/selfservice/`. You can change these context paths without rebuilding the project by setting properties in your `conf/boot/boot.properties` file.

`openidm.servlet.alias`::
The context path for the REST API. Default: `/openidm`. Example: `/myidm`.

Comment on lines +193 to +199
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

This section claims the REST API and Self-Service UI context paths can be changed via conf/boot/boot.properties, but the code changes in this PR only adjust the default servlet-filter urlPatterns and do not update the actual servlet registrations (the REST servlet alias is still hard-coded to /openidm in the API servlet component). As written, users following these instructions will not actually move the REST endpoints and may inadvertently cause filters to no longer apply. Please either implement the alias change end-to-end (servlet registrations + any hard-coded /openidm usages), or reword this section to describe the narrower behavior that’s actually implemented.

Copilot uses AI. Check for mistakes.
`openidm.selfservice.alias`::
The context path for the Self-Service UI. Default: `/selfservice`. Example: `/myselfservice`.

Comment on lines +195 to +202
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

The text refers to the “Self-Service UI” being at /selfservice/ by default. In this distribution, the selfservice UI context root appears to be configured via conf/ui.context-selfservice.json and defaults to "/", while /selfservice is typically a REST sub-resource under /openidm (e.g., /openidm/selfservice/...). Please clarify what /selfservice actually refers to here (UI vs REST), and align the defaults and examples accordingly so operators don’t break links/bookmarks.

Copilot uses AI. Check for mistakes.
For example, to change the REST API base path to `/myidm` and the Self-Service path to `/myselfservice`, add the following to `conf/boot/boot.properties`:

[source, console]
----
openidm.servlet.alias=/myidm
openidm.selfservice.alias=/myselfservice
----

After restarting OpenIDM, the REST API is available at `\https://localhost:8443/myidm/` instead of `\https://localhost:8443/openidm/`.

[NOTE]
====
If you change the REST API context path, make sure to update any servlet filter configurations in `conf/servletfilter-*.json` that use explicit `"urlPatterns"` referencing the old path. Servlet filters that rely on the default URL patterns (no `"urlPatterns"` key in the filter config) are automatically updated when OpenIDM restarts.
====


[#disabling-protocols]
=== Disabling and Enabling Secure Protocols

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
information: "Portions copyright [year] [name of copyright owner]".

Copyright 2017 ForgeRock AS.
Portions Copyright 2024-2025 3A Systems LLC.
Portions Copyright 2024-2026 3A Systems LLC.
////

:figure-caption!:
Expand Down Expand Up @@ -44,3 +44,5 @@ HTTPS access to the REST API, requiring SSL mutual authentication. Clients that
--
The Jetty configuration (in `openidm/conf/jetty.xml`) references the ports that are specified in the `boot.properties` file.

In addition to the port numbers, you can configure the default servlet-filter URL patterns associated with the REST API base context path and the Self-Service UI via `conf/boot/boot.properties`. By default, the REST API servlet is mapped under `/openidm/` and the Self-Service UI under `/selfservice/`; these servlet mappings are defined elsewhere and are not moved by the `boot.properties` settings. The `openidm.servlet.alias` and `openidm.selfservice.alias` properties only influence the filter URL patterns applied to those contexts. For details, see xref:appendix-jetty.adoc#configuring-rest-context-path["Configuring the REST API Context Path"].

7 changes: 6 additions & 1 deletion openidm-servlet-registrator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
~ your own identifying information:
~ "Portions Copyrighted [year] [name of copyright owner]"
~
~ Portions Copyrighted 2024-2025 3A Systems LLC.
~ Portions Copyrighted 2024-2026 3A Systems LLC.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
Expand All @@ -42,6 +42,11 @@
<artifactId>openidm-enhanced-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openidentityplatform.openidm</groupId>
<artifactId>openidm-system</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openidentityplatform.openidm</groupId>
<artifactId>openidm-httpcontext</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Portions Copyrighted 2024-2025 3A Systems LLC.
* Portions Copyrighted 2024-2026 3A Systems LLC.
*/

package org.forgerock.openidm.servletregistration.impl;
Expand Down Expand Up @@ -52,6 +52,7 @@
import org.apache.commons.lang3.StringUtils;
import org.forgerock.json.JsonValue;
import org.forgerock.json.JsonValueException;
import org.forgerock.openidm.core.IdentityServer;
import org.forgerock.openidm.servletregistration.RegisteredFilter;
import org.forgerock.openidm.servletregistration.ServletRegistration;
import org.forgerock.openidm.servletregistration.ServletFilterRegistrator;
Expand Down Expand Up @@ -90,7 +91,12 @@ public class ServletRegistrationSingleton implements ServletRegistration {

private static final String[] DEFAULT_SERVLET_NAME = new String[] { "OpenIDM REST" };

private static final String[] DEFAULT_SERVLET_URL_PATTERNS = new String[] { "/openidm/*", "/selfservice/*" };
private static final String PROP_SERVLET_ALIAS = "openidm.servlet.alias";
private static final String PROP_SELFSERVICE_ALIAS = "openidm.selfservice.alias";
private static final String DEFAULT_SERVLET_ALIAS = "/openidm";
private static final String DEFAULT_SELFSERVICE_ALIAS = "/selfservice";

private String[] defaultServletUrlPatterns = new String[] { "/openidm/*", "/selfservice/*" };

// Context of this scr component
private BundleContext bundleContext;
Expand All @@ -113,6 +119,15 @@ public class ServletRegistrationSingleton implements ServletRegistration {
public void activate(ComponentContext context) {
bundleContext = context.getBundleContext();
sharedContext = webContainer.createDefaultSharedHttpContext();

String servletAlias = IdentityServer.getInstance().getProperty(PROP_SERVLET_ALIAS, DEFAULT_SERVLET_ALIAS);
String selfServiceAlias = IdentityServer.getInstance().getProperty(PROP_SELFSERVICE_ALIAS, DEFAULT_SELFSERVICE_ALIAS);

servletAlias = sanitizeAlias(servletAlias, DEFAULT_SERVLET_ALIAS);
selfServiceAlias = sanitizeAlias(selfServiceAlias, DEFAULT_SELFSERVICE_ALIAS);

defaultServletUrlPatterns = new String[] { servletAlias + "/*", selfServiceAlias + "/*" };
logger.info("REST servlet URL patterns configured: {}, {}", servletAlias + "/*", selfServiceAlias + "/*");
Comment on lines +123 to +130
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

The new boot.properties aliases are only used to build default filter urlPatterns here; they do not change where the REST servlet is actually registered (it remains hard-coded elsewhere, e.g., the API servlet registers at "/openidm"). If an operator sets openidm.servlet.alias, filters relying on the default patterns will stop applying to the real REST endpoints, which can break integrations and potentially bypass expected filter behavior. Either wire these properties into the servlet registration path(s) as well (and update any other components that hard-code /openidm), or rename/re-scope the properties and docs to clearly state they affect only default servlet-filter URL patterns.

Copilot uses AI. Check for mistakes.
}

/**
Expand All @@ -125,6 +140,55 @@ public void deactivate(ComponentContext context) {
bundleContext = null;
}

private String sanitizeAlias(String alias, String defaultAlias) {
if (alias == null || alias.trim().isEmpty()) {
logger.warn("Configured alias is empty; using default: {}", defaultAlias);
return normalizeAlias(defaultAlias);
}
alias = alias.trim();
if (alias.contains("..")) {
logger.warn("Configured alias '{}' contains invalid sequence '..'; using default: {}", alias, defaultAlias);
return normalizeAlias(defaultAlias);
}
return normalizeAlias(alias);
}

/**
* Normalizes an alias so that it is safe to use when building URL patterns
* via {@code alias + "/*"}.
* <ul>
* <li>Ensures a leading "/".</li>
* <li>Strips a trailing "/*" if present.</li>
* <li>Strips a single trailing "/" when the alias length is greater than 1.</li>
* <li>Maps "/" to the empty string so the resulting pattern becomes exactly "/*".</li>
* </ul>
*
* @param alias the raw alias value (non-null, already trimmed).
* @return a normalized alias suitable for concatenation with "/*".
*/
private String normalizeAlias(String alias) {
// Ensure leading slash
if (!alias.startsWith("/")) {
alias = "/" + alias;
}

// Special-case: root context should result in "/*" when patterns are built.
if ("/".equals(alias)) {
return "";
}

// Strip trailing "/*" if present
if (alias.endsWith("/*")) {
alias = alias.substring(0, alias.length() - 2);
}

// Strip a single trailing "/" (but avoid turning "/" into empty; handled above)
if (alias.length() > 1 && alias.endsWith("/")) {
alias = alias.substring(0, alias.length() - 1);
}
return alias;
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -212,7 +276,7 @@ public URL apply(JsonValue jsonValue) throws JsonValueException {

// URL patterns to apply the filter to, e.g. one could also add "/openidmui/*");
List<String> urlPatterns = config.get(SERVLET_FILTER_URL_PATTERNS)
.defaultTo(Arrays.asList(DEFAULT_SERVLET_URL_PATTERNS))
.defaultTo(Arrays.asList(defaultServletUrlPatterns))
.asList(String.class);

// Filter init params, a string to string map
Expand Down
13 changes: 13 additions & 0 deletions openidm-zip/src/main/resources/conf/boot/boot.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Portions Copyright 2026 3A Systems LLC.

openidm.port.http=8080
openidm.port.https=8443
openidm.port.mutualauth=8444
Expand Down Expand Up @@ -64,3 +66,14 @@ javascript.exception.debug.info=false
# valid values: SSLv3, TLSv1, TLSv1.1, TLSv1.2
# defaults to TLSv1.2 if not specified
#openidm.external.rest.tls.version=TLSv1.1

# Base path used when building default servlet-filter URL patterns for the REST API.
# Note: this does NOT change the core REST servlet context path, which remains /openidm.
# Example override: /myidm
#openidm.servlet.alias=/openidm

# Base path used when building default servlet-filter URL patterns for self-service REST endpoints.
# Note: this does NOT control the Self-service UI context root; that is configured in
# conf/ui.context-selfservice.json (default "/").
# Example override: /selfservice
#openidm.selfservice.alias=/selfservice
Loading