How To
ForgeRock Identity Platform
Does not apply to Identity Cloud

How do I remove admin UI access in AM (All versions)?

Last updated Jan 16, 2023

The purpose of this article is to provide information on removing admin UI access in AM to secure your deployment.


8 readers recommend this article

Background information

The old JATO console has been removed in AM 7.

In AM 6.x, AM uses a mix of the old JATO console (Classic UI) and the new XUI JavaScript®-based administration pages, although the end user pages are all XUI-based.

The changes described in this article apply to both the XUI administrative pages and the JATO console (Classic UI).

Note

As with any customizations, we strongly recommend testing the procedure in your own development environment first and ensuring you have up to date backups and recovery plans in case you encounter any issues.

Removing admin UI access

There are three approaches to removing admin UI access and securing AM:

  • Allowlist approach - configure your load balancer or proxy with only the URLs that are allowed. An allowlist is more secure as it ensures only specific endpoints are exposed; however, you risk affecting existing behavior unless you test carefully.
  • Denylist approach - create a list of URLs that should be blocked. A denylist is easier to apply to existing setups and ensure that current behavior is unaffected.
  • Remove the /console directory (AM 6.x)

An allowlist on a load balancer or proxy could be used in combination with a denylist elsewhere in the infrastructure. For example, a denylist rule could be created to deny access to /json/users/amadmin, which would effectively prevent the amAdmin user from being able to login.

Allowlist approach

The recommended way of creating an allowlist is as follows:

  1. Establish all use cases involving AM.
  2. Test these use cases against AM servers in a load balanced pool. During testing, you can use browser developer tools such as those in Chrome™, tools such as Wireshark or the logs on a load balancer to analyze the endpoints used in each use case. This will give you a list of all endpoints used.
  3. Update this list of endpoints to include any sub-realms in use.
  4. Add the following endpoints to this list if you use SAML 2 functionality; these should suffice in most cases, but you should test them in your environment to be sure: saml2/jsp/<all paths> SSORedirect/<all paths> IDPSloRedirect/<all paths> Consumer/<all paths> ArtifactResolver/<all paths> IDPSloPOST/<all paths> IDPSloSoap/<all paths> idpsaehandler/<all paths>
  5. Configure your load balancer or proxy to only allow this list of endpoints.

Example using HAProxy

This example demonstrates creating an allowlist in HAProxy where the following endpoints are used for the purposes of authentication and showing user components in the XUI:

UI/Login json/realms/root/authenticate json/realms/root/serverinfo/* XUI/<all paths> json/realms/root/users/<all paths> json/realms/root/users?_action=idFromSession json/realms/root/sessions?_action=getMaxIdle json/realms/root/sessions/<all paths>?_action=validate json/realms/rooton/sessions/<all paths>?_action=logout

This example has one sub-realm called customers, resulting in these additional endpoints:

json/realms/root/realms/customers/authenticate json/realms/root/realms/customers/users/<all paths> json/realms/root/realms/customers/serverinfo/*

The following shows the configuration required in HAProxy (haproxy.cfg) to block these example endpoints plus the ones identified above for SAML 2 functionality in AM 7.1 and later:

global log 127.0.0.1 local0 log 127.0.0.1 local1 notice defaults log global mode http option httplog option dontlognull retries 3 option redispatch maxconn 2000 timeout connect 5000 timeout client 50000 timeout server 50000 frontend fe bind am.example.com:8443 default_backend be acl wl_topRealm path / acl wl_topRealm path /am/ acl wl_topRealm path /am/UI/Login acl wl_topRealm path /am/json/realms/root/authenticate acl wl_topRealm path /am/json/realms/root/serverinfo/* acl wl_topRealm path_beg /am/XUI/ acl wl_topRealm path_beg /am/json/realms/root/users/ acl wl_customersRealm path_beg /am/json/realms/root/realms/customers/users/ acl wl_customersRealm path /am/json/realms/root/realms/customers/authenticate acl wl_customersRealm path /am/json/realms/root/realms/customers/serverinfo/* acl wl_user_idFromSession path /am/json/realms/root/users acl wl_user_idFromSession urlp(_action) idFromSession acl wl_sessions_getMaxIdle path /am/json/realms/root/sessions acl wl_sessions_getMaxIdle urlp(_action) getMaxIdle acl wl_sessions_validateLogout path_beg /am/json/realms/root/sessions/ acl wl_sessions_validateLogout urlp(_action) validate acl wl_sessions_validateLogout urlp(_action) logout acl wl_saml2 path_beg /am/saml2/jsp/ acl wl_saml2 path_beg /am/SSORedirect/ acl wl_saml2 path_beg /am/IDPSloRedirect/ acl wl_saml2 path_beg /am/Consumer/ acl wl_saml2 path_beg /am/ArtifactResolver/ acl wl_saml2 path_beg /am/IDPSloPOST/ acl wl_saml2 path_beg /am/IDPSloSoap/ acl wl_saml2 path_beg /am/idpsaehandler/ http-request deny unless wl_topRealm or wl_customersRealm or wl_user_idFromSession or wl_sessions_getMaxIdle or wl_sessions_validateLogout or wl_saml2 backend be option httpchk GET /am/json/health/live cookie amlbcookie #insert nocache balance roundrobin server am1 am1.example.com:443 cookie 01 id 1000 check inter 2000 rise 2 fall 2 server am2 am2.example.com:8443 cookie 02 id 1001 check inter 2000 rise 2 fall 2

Denylist approach

Caution

The following URLs are provided as a starting point only and you should perform your own security auditing and testing to ensure it meets your needs. Although this is a comprehensive list, it may not prevent administrative access to some endpoints.

The URLs listed below still provide all user functionality, such as profile changes and self-service, namely against the /users endpoint. You should be particularly careful with this endpoint (and the realm specific version) because it has specific uses. Some examples of these uses are as follows:

  • GET json/realms/root/users?_queryId=* - this is used to enumerate users. It would only ever be used by an administrator.
  • GET json/realms/root/users?_action=idFromSession - this is used in all login scenarios (user and admin) with the XUI.
  • GET/POST/PUT json/realms/root/users/{username} - this could be used by both a user (on their username only) and an administrator, depending on the context.

The following URLs can be blocked in a proxy, web application firewall (WAF) or load balancer to prevent access to the administrative REST endpoints in AM:

  • Rest Endpoints (with json/realms/root part removed):
REST endpoint AM 7.x AM 6.5.x AM 6
/applications Yes Yes Yes
/*/applications Yes Yes Yes
/applications/* Yes Yes Yes
/*/applications/* Yes Yes Yes
/applicationtypes Yes Yes Yes
/applicationtypes/* Yes Yes Yes
/conditiontypes Yes Yes Yes
/conditiontypes/* Yes Yes Yes
/decisioncombiners Yes Yes Yes
/decisioncombiners/* Yes Yes Yes
/global-audit Yes Yes Yes
/global-config/agents* Yes Yes Yes
/global-config/agents/* Yes Yes Yes
/global-config/authentication* Yes Yes Yes
/global-config/authentication/* Yes Yes Yes
/global-config/realms* Yes Yes Yes
/global-config/secrets* Yes Yes --
/global-config/secrets/* Yes Yes --
/global-config/servers* Yes Yes Yes
/global-config/servers/* Yes Yes Yes
/global-config/services* Yes Yes Yes
/global-config/services/* Yes Yes Yes
/global-config/sites* Yes Yes Yes
/global-config/webhooks* Yes Yes Yes
/policies Yes Yes Yes
/*/policies Yes Yes Yes
/policies/* Yes Yes Yes
/*/policies/* Yes Yes Yes
/*/realm-audit Yes Yes Yes
/realm-config/agents* Yes Yes Yes
/*/realm-config/agents Yes Yes Yes
/realm-config/authentication* Yes Yes Yes
/*/realm-config/authentication Yes Yes Yes
/realm-config/federation* Yes Yes Yes
/*/realm-config/federation Yes Yes Yes
/realm-config/saml2* Yes -- --
/*/realm-config/saml2 Yes -- --
/realm-config/secrets* Yes Yes --
/*/realm-config/secrets Yes Yes --
/realm-config/services* Yes Yes Yes
/*/realm-config/services Yes Yes Yes
/realm-config/webhooks* Yes Yes Yes
/*/realm-config/webhooks Yes Yes Yes
/records/* Yes Yes Yes
/resourcetypes Yes Yes Yes
/*/resourcetypes Yes Yes Yes
/resourcetypes/* Yes Yes Yes
/*/resourcetypes/* Yes Yes Yes
/scripts Yes Yes Yes
/*/scripts Yes Yes Yes
/scripts/* Yes Yes Yes
/*/scripts/* Yes Yes Yes
/subjectattributes Yes Yes Yes
/*/subjectattributes Yes Yes Yes
/subjecttypes Yes Yes Yes
/subjecttypes/* Yes Yes Yes
/users/amadmin Yes Yes Yes
  • XUI admin UI endpoints:
    • AM 7 and later: ui-admin/*
    • AM 6.x: XUI/templates/admin/* XUI/org/forgerock/am/ui/admin/*
  • JATO admin console endpoints: console/* realm/* idm/* agentconfig/* sts/* task/* service/* federation/* config/* session/*

Example method of filtering URLs using web.xml

If you are using Apache Tomcat™, you can block these endpoints by setting a <security-constraint> element in the web.xml file (located in the /path/to/tomcat/webapps/am/WEB-INF directory where AM is deployed).

Note

This approach does not prevent redirects from occurring on URL patterns inside of the constraint. It also requires that the endpoints for each realm are defined. Consider applying rules in a reverse proxy or load balancer instead, which will likely offer a more robust solution.

The following example shows the <security-constraint> element set in the web.xml file with all the applicable AM 7 endpoints blocked, where there is one sub-realm called realm-one:

<security-constraint> <web-resource-collection> <web-resource-name >AM restricted URLs</web-resource-name> <url-pattern>/json/realms/root/applications</url-pattern> <url-pattern>/json/realms/root/applications/*</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/applications</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/applications/*</url-pattern> <url-pattern>/json/realms/root/applicationtypes</url-pattern> <url-pattern>/json/realms/root/applicationtypes/*</url-pattern> <url-pattern>/json/realms/root/conditiontypes</url-pattern> <url-pattern>/json/realms/root/conditiontypes/*</url-pattern> <url-pattern>/json/realms/root/decisioncombiners</url-pattern> <url-pattern>/json/realms/root/decisioncombiners/*</url-pattern> <url-pattern>/json/realms/root/global-config/*</url-pattern> <url-pattern>/json/realms/root/policies</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/policies</url-pattern> <url-pattern>/json/realms/root/policies/*</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/policies/*</url-pattern> <url-pattern>/json/realms/root/realm-config/*</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/realm-config/*</url-pattern> <url-pattern>/json/realms/root/records</url-pattern> <url-pattern>/json/realms/root/resourcetypes</url-pattern> <url-pattern>/json/realms/root/resourcetypes/*</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/resourcetypes</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/resourcetypes/*</url-pattern> <url-pattern>/json/realms/root/scripts</url-pattern> <url-pattern>/json/realms/root/scripts/*</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/scripts</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/scripts/*</url-pattern> <url-pattern>/json/realms/root/subjectattributes</url-pattern> <url-pattern>/json/realms/root/realms/realm-one/subjectattributes</url-pattern> <url-pattern>/json/realms/root/subjecttypes</url-pattern> <url-pattern>/json/realms/root/subjecttypes/*</url-pattern> <url-pattern>/json/realms/root/users/amadmin</url-pattern> <url-pattern>/json/realms/root/dashboard/available</url-pattern> <url-pattern>/json/realms/root/realms/root/realms/realm-one/dashboard/available</url-pattern> <url-pattern>/ui-admin/*</url-pattern> </web-resource-collection> <auth-constraint/> </security-constraint>

If you use this example as the basis of your changes, you must replace the realm-one realm name with a realm that you are using and add other endpoints for other realms you may have configured. If you are not using sub-realms, then you can remove these endpoints. Additionally, you should add the required XUI admin UI endpoints and the JATO admin console endpoints in AM 6.x.

Testing

The example bash script provides a means of testing these blocked URLs using repeated curl commands. This script authenticates against AM and then runs various GET calls against the list of URLs defined in endpoints.txt. It then outputs HTTP response codes (200, 400, 401, 403 etc) which indicate the type of response.

The following is an example output from the script:

200 https://am.example.com:8443/am/json/realms/root/policies?_queryId=* 200 https://am.example.com:8443/am/json/realms/root/realms/realm-one/policies?_queryId=* 404 https://am.example.com:8443/am/json/realms/root/policies/example-policy 404 https://am.example.com:8443/am/json/realms/root/realms/realm-one/policies/example-policy

With the URL filters in place, the script should return 403 for all the URLs tested, except for:

  • The /json/realms/root/users endpoint
  • The /console endpoint, which does a redirect (302) to /console/* that is blocked (AM 6.x).

Without any filters in place, the script would return 200 codes, except on queries where no existing object is in place to query. In that case, a 404 (not found) would be returned.

For example, a GET on the endpoint json/realms/root/realms/realm-one/policies/example-policy would return:

  • 403 if it is blocked by a rule in web.xml or on a load balancer, WAF etc.
  • 404 if the URL is not blocked and the policy called “example-policy” does not exist in the realm called “realm-one”.
  • 200 if the URL is not blocked and the policy called “example-policy” does exist in the realm called “realm-one”.

The attached endpoints.sh script and endpoints.txt file can be used as the basis for your own testing. They have been created based on the default endpoints that need blocking in AM 7 with one sub-realm (realm-one) defined. The cli tool jq needs to be installed in order to execute this script. This can be installed using operating system package tools, such as apt-get, yum and brew.

The endpoints.sh file contains the following script, which can be used as the basis for your testing:

#!/bin/bash AM_JSN='Content-Type: application/json' AM_URL='https://am.example.com:8443/am' AM_USR='X-OpenAM-Username: amadmin' AM_PWD='X-OpenAM-Password: cangetinam' AM_TOKEN=$(curl -k -sS -H "${AM_JSN}" -H "${AM_USR}" -H "${AM_PWD}" --request POST "${AM_URL}/json/realms/root/authenticate" | jq .tokenId -r) echo "$AM_TOKEN" while read u; do curl -k -sS -H "${AM_JSN}" -H "iPlanetDirectoryPro: ${AM_TOKEN}" -w "%{http_code} %{url_effective} \n" -o /dev/null --request GET "${AM_URL}/$u" done <endpoints.txt

The endpoints.txt file contains the following URLs, which can be used as a basis for your testing:

json/realms/root/global-config/realms json/realms/root/realm-config/authentication json/realms/root/realms/realm-one/realm-config/authentication json/realms/root/users/amadmin json/realms/root/users?_queryId=* json/realms/root/realms/realm-one/users/demo json/realms/root/realms/realm-one/users?_queryId=* json/realms/root/scripts?_queryId=* json/realms/root/scripts/9de3eb62-f131-4fac-a294-7bd170fd4acb json/realms/root/realms/realm-one/scripts?_queryId=* json/realms/root/realms/realm-one/scripts/9de3eb62-f131-4fac-a294-7bd170fd4acb json/realms/root/policies?_queryId=* json/realms/root/realms/realm-one/policies?_queryId=* json/realms/root/policies/example-policy json/realms/root/realms/realm-one/policies/example-policy json/realms/root/applications?_queryId=* json/realms/root/applications/iPlanetAMWebAgentService json/realms/root/realms/realm-one/applications?_queryId=* json/realms/root/realms/realm-one/applications/iPlanetAMWebAgentService json/realms/root/subjectattributes?_queryId=* json/realms/root/realms/realm-one/subjectattributes?_queryId=* json/realms/root/resourcetypes?_queryId=* json/realms/root/resourcetypes/12345a67-8f0b-123c-45de-6fab78cd01e2 json/realms/root/realms/realm-one/resourcetypes?_queryId=* json/realms/root/realms/realm-one/resourcetypes/12345a67-8f0b-123c-45de-6fab78cd01e2 json/applicationtypes?_queryId=* json/applicationtypes/iPlanetAMWebAgentService json/realms/root/decisioncombiners?_queryId=* json/realms/root/decisioncombiners/DenyOverride json/realms/root/conditiontypes?_queryId=* json/realms/root/conditiontypes/AMIdentityMembership json/realms/root/subjecttypes?_queryId=* json/realms/root/subjecttypes/AND json/realms/root/dashboard/available json/realms/root/realms/realm-one/dashboard/available json/realms/root/realms/realm-one/groups?_queryId=* json/realms/root/realms/realm-one/groups/testgroup json/realms/root/realms/realm-one/agents?_queryId=* json/realms/root/realms/realm-one/agents/testwebagent json/realms/root/records ui-admin/

Remove the /console directory (AM 6.x)

In AM 6.x, the /console directory contains:

  • The legacy JATO admin console, responsible for configuration, federation and some parts of the realm configuration.
  • The user profile and self-service pages when the XUI is disabled.

If you want the above features to be removed from your deployment, you can remove the /console directory from the /path/to/tomcat/webapps/am directory where AM is deployed.

See Also

Best practice for blocking the top level realm in a proxy for AM (All versions)

AM 7 REST API endpoints

AM 6.5 REST API Endpoints

AM 6 REST API Endpoints

Related Training

N/A

Related Issue Tracker IDs

N/A


Copyright and Trademarks Copyright © 2023 ForgeRock, all rights reserved.