-
-
Notifications
You must be signed in to change notification settings - Fork 45
Make REST context path configurable via openidm.context.path system property
#142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
0a882f0
f935409
81b026f
5e4f102
9d963ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| /* | ||
| * The contents of this file are subject to the terms of the Common Development and | ||
| * Distribution License (the License). You may not use this file except in compliance with the | ||
| * License. | ||
| * | ||
| * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the | ||
| * specific language governing permission and limitations under the License. | ||
| * | ||
| * When distributing Covered Software, include this CDDL Header Notice in each file and include | ||
| * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL | ||
| * Header, with the fields enclosed by brackets [] replaced by your own identifying | ||
| * information: "Portions copyright [year] [name of copyright owner]". | ||
| * | ||
| * Copyright 2025-2026 3A Systems LLC. | ||
| */ | ||
|
|
||
| package org.forgerock.openidm.servlet.internal; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
| import org.testng.annotations.AfterMethod; | ||
| import org.testng.annotations.Test; | ||
|
|
||
| /** | ||
| * Unit tests for {@link ServletComponent} context path configuration. | ||
| */ | ||
| public class ServletComponentTest { | ||
|
|
||
| @AfterMethod | ||
| public void clearSystemProperty() { | ||
| System.clearProperty(ServletComponent.OPENIDM_CONTEXT_PATH_PROPERTY); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDefaultServletAlias() { | ||
| // When no system property is set, should return the default /openidm | ||
| System.clearProperty(ServletComponent.OPENIDM_CONTEXT_PATH_PROPERTY); | ||
| assertThat(ServletComponent.getServletAlias()).isEqualTo("/openidm"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testCustomServletAlias() { | ||
| // When system property is set to /myidm, should return /myidm | ||
| System.setProperty(ServletComponent.OPENIDM_CONTEXT_PATH_PROPERTY, "/myidm"); | ||
| assertThat(ServletComponent.getServletAlias()).isEqualTo("/myidm"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testServletAliasWithoutLeadingSlash() { | ||
| // Should add leading slash if missing | ||
| System.setProperty(ServletComponent.OPENIDM_CONTEXT_PATH_PROPERTY, "myidm"); | ||
| assertThat(ServletComponent.getServletAlias()).isEqualTo("/myidm"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testServletAliasWithTrailingSlash() { | ||
| // Should remove trailing slash | ||
| System.setProperty(ServletComponent.OPENIDM_CONTEXT_PATH_PROPERTY, "/myidm/"); | ||
| assertThat(ServletComponent.getServletAlias()).isEqualTo("/myidm"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testServletAliasConstants() { | ||
| assertThat(ServletComponent.OPENIDM_CONTEXT_PATH_PROPERTY).isEqualTo("openidm.context.path"); | ||
| assertThat(ServletComponent.OPENIDM_CONTEXT_PATH_DEFAULT).isEqualTo("/openidm"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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!: | ||||||||||||||||||||||
|
|
@@ -152,6 +152,35 @@ felix.fileinstall.enableConfigSave=false | |||||||||||||||||||||
| ---- | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| [#configuring-rest-context-path] | ||||||||||||||||||||||
| ==== Configuring the REST Context Path | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| By default, the OpenIDM REST API is available under the `/openidm` context path (for example, `\https://localhost:8443/openidm/`). You can change this base path by setting the `openidm.context.path` system property. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| To set a custom REST context path, edit the `conf/system.properties` file and uncomment or add the following line, replacing `/openidm` with your preferred path: | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| [source] | ||||||||||||||||||||||
| ---- | ||||||||||||||||||||||
| openidm.context.path=/openidm | ||||||||||||||||||||||
| ---- | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Alternatively, you can pass the property as a JVM argument when starting OpenIDM: | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| [source, console] | ||||||||||||||||||||||
| ---- | ||||||||||||||||||||||
| $ OPENIDM_OPTS="-Dopenidm.context.path=/myidm" ./startup.sh | ||||||||||||||||||||||
| ---- | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| The path must begin with a `/` and must not end with `/`. If the value provided does not start with a `/`, one is added automatically. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| 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. | ||||||||||||||||||||||
|
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. | |
| 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. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |||||
| * information: "Portions copyright [year] [name of copyright owner]". | ||||||
| * | ||||||
| * Copyright 2011-2016 ForgeRock AS. | ||||||
| * Portions copyright 2026 3A Systems LLC. | ||||||
| */ | ||||||
| package org.forgerock.openidm.shell.impl; | ||||||
|
|
||||||
|
|
@@ -57,10 +58,33 @@ public class RemoteCommandScope extends CustomCommandScope { | |||||
| private static final String IDM_PORT_DESC = "Port of OpenIDM REST service. This will override any port in --url."; | ||||||
| private static final String IDM_PORT_METAVAR = "PORT"; | ||||||
|
|
||||||
| /** System property for configuring the REST context path. */ | ||||||
| private static final String OPENIDM_CONTEXT_PATH_PROPERTY = "openidm.context.path"; | ||||||
|
|
||||||
| /** 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; | ||||||
| private static final String IDM_URL_METAVAR = "URL"; | ||||||
|
|
||||||
| /** | ||||||
| * Returns the effective default IDM URL, reading the {@code openidm.context.path} system | ||||||
| * property (default: {@code /openidm}) to construct the URL. | ||||||
| */ | ||||||
| private static String getEffectiveIdmUrl(String url) { | ||||||
| if (!IDM_URL_DEFAULT.equals(url)) { | ||||||
| return url; | ||||||
| } | ||||||
| String contextPath = System.getProperty(OPENIDM_CONTEXT_PATH_PROPERTY, "/openidm"); | ||||||
| if (!contextPath.startsWith("/")) { | ||||||
| contextPath = "/" + contextPath; | ||||||
| } | ||||||
| if (contextPath.endsWith("/")) { | ||||||
| contextPath = contextPath.substring(0, contextPath.length() - 1); | ||||||
| } | ||||||
| return "http://localhost:8080" + contextPath + "/"; | ||||||
| } | ||||||
|
|
||||||
| private static final String USER_PASS_DESC = "Server user and password"; | ||||||
| private static final String USER_PASS_METAVAR = "USER[:PASSWORD]"; | ||||||
| private static final String USER_PASS_DEFAULT = ""; | ||||||
|
|
@@ -144,7 +168,7 @@ private static String getPassword(final String userPass) { | |||||
| */ | ||||||
| private static String getUrl(final String url) { | ||||||
| if (isNotBlank(url)) { | ||||||
| return url.endsWith("/") ? url : url + "/"; | ||||||
| return getEffectiveIdmUrl(url.endsWith("/") ? url : url + "/"); | ||||||
|
||||||
| return getEffectiveIdmUrl(url.endsWith("/") ? url : url + "/"); | |
| return url.endsWith("/") ? url : url + "/"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
openidm.context.pathproperty name/default and the path-normalization logic are now duplicated in multiple modules/classes (e.g., this component,ServletRegistrationSingleton, andRemoteCommandScope). 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 orServerConstants/IdentityServer) and reusing it from all call sites.