diff --git a/openidm-doc/src/main/asciidoc/integrators-guide/appendix-file-layout.adoc b/openidm-doc/src/main/asciidoc/integrators-guide/appendix-file-layout.adoc index 054405d052..0847bf40b9 100644 --- a/openidm-doc/src/main/asciidoc/integrators-guide/appendix-file-layout.adoc +++ b/openidm-doc/src/main/asciidoc/integrators-guide/appendix-file-layout.adoc @@ -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!: @@ -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 diff --git a/openidm-doc/src/main/asciidoc/integrators-guide/appendix-jetty.adoc b/openidm-doc/src/main/asciidoc/integrators-guide/appendix-jetty.adoc index 2529bfd07b..674f8d9f1c 100644 --- a/openidm-doc/src/main/asciidoc/integrators-guide/appendix-jetty.adoc +++ b/openidm-doc/src/main/asciidoc/integrators-guide/appendix-jetty.adoc @@ -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!: @@ -181,7 +181,7 @@ 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]. @@ -189,6 +189,36 @@ Filter configuration initialization parameters that are passed to the servlet fi -- +[#configuring-rest-context-path] +=== Configuring Default Servlet-Filter URL Patterns + +OpenIDM servlet filters can be configured to apply to specific URL patterns. When a filter configuration in `conf/servletfilter-*.json` does not specify an explicit `"urlPatterns"` list, OpenIDM builds a default set of patterns from the following `conf/boot/boot.properties` properties: + +`openidm.servlet.alias`:: +Base path used when building default filter URL patterns for REST API endpoints. Default: `/openidm`. Example override: `/myidm`. + +`openidm.selfservice.alias`:: +Base path used when building default filter URL patterns for self-service REST endpoints. Default: `/selfservice`. Example override: `/myselfservice`. + +[IMPORTANT] +==== +These properties only control which URL patterns are applied to servlet filters that do not have an explicit `"urlPatterns"` key in their filter config. They do *not* change the actual REST servlet registration, which remains at `/openidm`. The Self-Service UI context root is configured separately via `conf/ui.context-selfservice.json` (default: `/`). +==== + +For example, to apply default filters to `/myidm/` and `/myselfservice/` instead of the standard paths, add the following to `conf/boot/boot.properties` and restart OpenIDM: + +[source, console] +---- +openidm.servlet.alias=/myidm +openidm.selfservice.alias=/myselfservice +---- + +[NOTE] +==== +Servlet filter configurations in `conf/servletfilter-*.json` that use explicit `"urlPatterns"` are not affected by these properties. Only filters without explicit URL patterns use the values derived from `openidm.servlet.alias` and `openidm.selfservice.alias`. +==== + + [#disabling-protocols] === Disabling and Enabling Secure Protocols diff --git a/openidm-doc/src/main/asciidoc/integrators-guide/appendix-ports-used.adoc b/openidm-doc/src/main/asciidoc/integrators-guide/appendix-ports-used.adoc index 941b277acc..40928796c9 100644 --- a/openidm-doc/src/main/asciidoc/integrators-guide/appendix-ports-used.adoc +++ b/openidm-doc/src/main/asciidoc/integrators-guide/appendix-ports-used.adoc @@ -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!: @@ -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"]. + diff --git a/openidm-servlet-registrator/pom.xml b/openidm-servlet-registrator/pom.xml index f2089487b2..9bd8e16a4c 100644 --- a/openidm-servlet-registrator/pom.xml +++ b/openidm-servlet-registrator/pom.xml @@ -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. --> 4.0.0 @@ -42,6 +42,11 @@ openidm-enhanced-config ${project.version} + + org.openidentityplatform.openidm + openidm-system + ${project.version} + org.openidentityplatform.openidm openidm-httpcontext diff --git a/openidm-servlet-registrator/src/main/java/org/forgerock/openidm/servletregistration/impl/ServletRegistrationSingleton.java b/openidm-servlet-registrator/src/main/java/org/forgerock/openidm/servletregistration/impl/ServletRegistrationSingleton.java index 345ed61151..ce1c6d9d5d 100644 --- a/openidm-servlet-registrator/src/main/java/org/forgerock/openidm/servletregistration/impl/ServletRegistrationSingleton.java +++ b/openidm-servlet-registrator/src/main/java/org/forgerock/openidm/servletregistration/impl/ServletRegistrationSingleton.java @@ -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; @@ -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; @@ -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; @@ -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 + "/*"); } /** @@ -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 + "/*"}. + * + * + * @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} */ @@ -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 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 diff --git a/openidm-zip/src/main/resources/conf/boot/boot.properties b/openidm-zip/src/main/resources/conf/boot/boot.properties index 04324f8194..d2ec78b9d0 100644 --- a/openidm-zip/src/main/resources/conf/boot/boot.properties +++ b/openidm-zip/src/main/resources/conf/boot/boot.properties @@ -1,3 +1,5 @@ +# Portions Copyright 2026 3A Systems LLC. + openidm.port.http=8080 openidm.port.https=8443 openidm.port.mutualauth=8444 @@ -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: /myselfservice +#openidm.selfservice.alias=/myselfservice