Skip to content

Add a PingAM 7.5 to OpenAM migration planning guide - #247

Open
maximthomas wants to merge 3 commits into
OpenIdentityPlatform:masterfrom
maximthomas:pingam-to-openam-migration
Open

maximthomas wants to merge 3 commits into
OpenIdentityPlatform:masterfrom
maximthomas:pingam-to-openam-migration

Conversation

@maximthomas

Copy link
Copy Markdown
Contributor

Summary

A new blog post, _posts/2026-10-20-pingam-to-openam-migration.md: a planning guide for teams running PingAM 7.5 and considering a move to OpenAM. It is an architecture- and planning-level overview, not a step-by-step guide.

  • Content: reasons to migrate (licensing by stored identities, chains removed in PingAM 8.0, PingAM 7.5 end of support in April 2027, control over the code); how chains versus trees drive the scope of work; a component-by-component mapping table with effort ratings; what does not carry over (active tokens, encrypted values, two-factor authentication devices, keys and addresses); complexity categories; seven migration steps; a planned three-part follow-up series.
  • Front matter: products: [openam], imageurl: 'openam-og.png', five FAQ items rendered on the page and as FAQPage JSON-LD.
  • Side effect: the post is tagged openam, so it takes the first slot of the "About" list on /openam, and 2024-06-24-openam-openig-websocket drops off that 16-item list.

Verification

Built the site locally with bundle exec jekyll build (Ruby 3.2.3; CI uses 3.1):

  • The post renders at /blog/2026-10-20-pingam-to-openam-migration. <title> is "From PingAM 7.5 to OpenAM: A Migration Plan · Open Identity Platform", and og:image points to the existing assets/img/openam-og.png.
  • The mapping table has 18 rows. The migration steps render as one <ol> with 7 items. No unrendered Liquid is left in the output.
  • The FAQPage (5 questions) and BlogPosting JSON-LD blocks parse as JSON.
  • The post is listed on /, /blog, /openam, feed.xml and sitemap.xml.
  • Internal links and anchors across all 375 built pages resolve. This was checked with a local script that mirrors the workflow's htmlproofer --checks Links step, not with htmlproofer itself; the build check on this PR runs the real one.

A planning-level article for architects and technical leads running
PingAM 7.5: the reasons to migrate, how authentication chains versus
trees drive the scope of work, a component-by-component mapping to
OpenAM with effort ratings, what does not carry over, complexity
categories and the migration steps. The FAQ in the front matter feeds
the FAQPage structured data.

@vharseko vharseko left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the thorough guide — most of the technical claims check out against the OpenAM source (module count, Groovy 2.4, /connect/register, forgerockTwoFactorAuthMandatory default, the skip/oath2faEnabled logic, issuer format, internal links and doc anchors). A few statements are wrong or overstated, though, and two of them would mislead an operator during cutover.

Factual issues

1. Line 107 — "Registering replaces the PingAM profile with a new one, and the old device stops working" is the opposite of what OpenAM does.
AuthenticatorOATH.process() re-reads the stored profile on every call (settings, line 285). In optional mode with an empty oath2faEnabled, beginLogin returns LOGIN_OPTIONAL even when a PingAM profile exists. If the user picks "Register device", a new secret is generated and shown as a QR code, but it stays only in memory (newDevice). At code entry, doLoginSavedDevice authenticates against settings — the existing PingAM profile — and uses newDevice only when settings == null (lines 409–413). It also saves the new device only when settings == null (line 437). Result: codes from the freshly scanned entry are rejected, after three attempts the login fails and setFailureID feeds the lockout counters, and the old PingAM device keeps working. Please describe the real symptom (rejected codes and possible lockouts, old device still valid) instead of "replaced".

2. Line 115 — with the same context path, discovery does not match PingAM except for /register.
OpenAM's discovery document advertises revocation_endpoint as <base>/revoke (OAuth2UrisFactory.getRevocationEndpoint), but the only registered route is /token/revoke (OAuth2RouterProvider, line 146). PingAM uses /oauth2/token/revoke. A client that reads revocation_endpoint from .well-known/openid-configuration will get a 404 after cutover and silently stop revoking tokens. This is an OpenAM bug, now tracked in OpenIdentityPlatform/OpenAM#1195 (affects 16.1.2–16.1.4). Until a release with the fix ships, the post should list it next to /register as a known difference.

3. Lines 103 and 113 — the requirement for "the OpenDJ type rather than Generic LDAPv3" is too narrow.
In idRepoService.xml, the Active Directory, ADAM and Tivoli data store types also list oathDeviceProfiles, sun-fm-saml2-nameid-info and sunAMAuthInvalidAttemptsData. Only Generic LDAPv3 lacks them. As written, an AD-backed deployment (explicitly covered by the identity store row at line 82) could switch its data store to the OpenDJ type and lose the AD-specific behaviour (user object class, unicodePwd handling). Suggest: "any type except Generic LDAPv3 — OpenDJ for PingDS, Active Directory for AD".

4. Line 117 vs. line 149 — "partners and client owners will hardly have to change anything" conflicts with the session cookie rename in step 3.
OpenAM uses the cookie name for the REST session token header too, so custom REST integrations and apps that send or read iPlanetDirectoryPro will break if the renamed cookie is left in place after cutover. Please either note that the cookie name has to be switched back at final cutover or list the affected integrations as something client owners must change.

5. Line 88 — the mapping table misses PingAM script types that OpenAM has no context for.
OpenAM's ScriptContext contains only AUTHENTICATION_SERVER_SIDE, AUTHENTICATION_CLIENT_SIDE, POLICY_CONDITION, OIDC_CLAIMS and OAUTH2_ACCESS_TOKEN_MODIFICATION. Scripted SAML2 IdP attribute mappers and IdP adapters, for example, have to become Java plugins (High), while the SAML row only says "attribute mapping is configured again" (Medium). The OIDC claims and access token modification scripts do carry over but run into the same Groovy 2.4 and binding differences the post describes for authentication scripts. Both deserve a row.

Sourcing

6. Line 49 — "you can use it free of charge only for development and testing" isn't backed by the linked licensing guide.
The guide only says that self-managed software is metered by managed (stored) identities whether they are active or not, and it points to the product terms for entitlements. Please cite the source for the dev/test statement or drop it. A claim about a competitor's commercial terms on the project site should be traceable.

7. Line 51 — the PingAM 8 argument is overstated.
The linked 8.0 changes page says modules and chains can be temporarily re-enabled "only for migration purposes" (org.forgerock.am.authentication.chains.enabled=true, REST only). It does not say they were deprecated in AM 7.0. A PingAM admin who knows about this option will read "means rebuilding them as trees" as an exaggeration. Suggest mentioning that the option exists and is temporary, and either adding a source for the 7.0 deprecation or rewording it.

Site consistency

8. Line 4 — landing-title differs from title. header.html uses landing-title for <title>, og:title, twitter:title, the BlogPosting headline and the listings ("A Migration Plan"), while the H1 and the feed use title ("A Planning Guide"). Other posts keep the two in sync.

9. Line 61 — internal link is absolute (https://www.openidentityplatform.org/forgerock-alternative). htmlproofer runs with --ignore-urls "/^https?:\/\//", so this link is never checked. Use /forgerock-alternative like the /openam link in the same sentence.

10. Line 171 — the vendors CTA has no GA attributes. The other support CTAs (_includes/support-cta.html, index.html) carry data-ga-event="support_cta_click" and a data-ga-location. Without them, leads from this post can't be measured.

11. Line 185 (nit) — a third FAQ rendering loop. support.md and forgerock-alternative.md each have their own page.faq loop, and this would be the third one, in a different style. Consider a shared _includes/faq.html. Fine to leave for a follow-up.

Fixes from the review of the guide, each checked against OpenAM master
and the PingAM 7.5 documentation:

- Two-factor devices: registering in OpenAM's optional mode does not
  replace the PingAM profile. Codes from the new entry are rejected and
  count towards account lockout, and the old device keeps working.
- Endpoints: OpenAM 16.1.2 to 16.1.4 advertise revocation_endpoint as
  /revoke while serving /token/revoke (OpenAM#1195), the second known
  difference next to /register.
- Data store type: any type except Generic LDAPv3 keeps the device,
  NameID and lockout attributes; name Active Directory for AD stores.
- Keeping addresses: integrations that send or read iPlanetDirectoryPro
  are affected by the cookie rename from step 3.
- Mapping table: new rows for OIDC claims and access token modification
  scripts (fewer bindings, modification only for stateless tokens) and
  for SAML 2.0 IdP attribute mapper and adapter scripts, which become
  Java plugins.
- Sourcing: cite the ForgeRock non-production licence instead of an
  unsourced "free of charge", link the AM 7.0 deprecation and mention
  that PingAM 8.0 can re-enable chains temporarily for migration.
- Site: landing-title matches title, the /forgerock-alternative link is
  relative, and the vendors link carries the support_cta_click GA event.
support.md and forgerock-alternative.md each carried the same page.faq
card loop, and the migration guide rendered its FAQ as headings in a
third style. _includes/faq.html now holds the card grid; each page keeps
its own section heading. support.html builds byte-identical, and
forgerock-alternative.html gains only a trailing blank line.
@maximthomas

Copy link
Copy Markdown
Contributor Author

All 11 items are addressed in 1217e3b (content) and 3666a8e (shared FAQ include). I checked each statement against OpenAM master and the PingAM 7.5 docs, and all of them hold.

1. OATH registration (L107). Confirmed in AuthenticatorOATH: doLoginSavedDevice authenticates against the stored profile and saves newDevice only when settings == null, and three failures throw InvalidPasswordException with setFailureID, which AMLoginContext passes to AMAccountLockout. The text now says that registering does not replace the PingAM profile, that codes from the new entry are rejected and count towards lockout when it is enabled, and that the old device keeps working. The sentence about skipping on the code entry screen stays, since removeAllUserDevices deletes the PingAM profile.

2. revocation_endpoint (L115). Listed as the second exception next to /register, with a link to OpenAM#1195. The wording is that /token/revoke is the same in both products and that OpenAM 16.1.2–16.1.4 advertise /revoke in discovery, so a client that takes the address from discovery cannot revoke tokens until a fixed release. 16.1.1 does not advertise revocation_endpoint at all.

3. Data store type (L82, L103, L113). The identity store row now says "OpenDJ for PingDS … or Active Directory for AD", and the other two places say "provided its data store type is not Generic LDAPv3". The Sun DS type (LDAPv3ForAMDS) has the attributes too, so the type list is left out of the sentence.

4. Cookie rename vs. "hardly have to change anything" (L117). Added the exception. REST integrations and applications that send or read iPlanetDirectoryPro have to switch to the new name, unless the name is changed back in OpenAM and its agent profiles once PingAM no longer shares a cookie domain with it.

5. Script types (table). Two new rows:

  • OIDC claims and access token modification scripts, ✅, Medium. They use Groovy 2.4 and have fewer bindings: no claimObjects/requestedTypedClaims for OIDC claims, and no clientProperties/httpClient for token modification. Also, OpenAM runs the modification script only from StatelessTokenStore (the dev guide says "stateless (JWT)"), while PingAM 7.5 modifies both client-side and server-side tokens. A PingAM deployment with CTS-based tokens would lose its modifications silently, so the row says so.
  • SAML 2.0 IdP attribute mapper and adapter scripts, ⛔️, High: rewritten as Java plugins. I left out SP adapter scripts: the PingAM 7.5 SAML reference has script options only for the IdP attribute mapper and the IdP adapter, and the hosted SP adapter is a Java class.

"Five rows … ⛔️" became "Six rows", and the conclusion lists SAML 2.0 scripts among the exceptions.

6. Licensing (L49). The sentence now cites the ForgeRock Non-Production License Agreement. Its §2.1 allows only "evaluating, testing, and demonstrating the NPSS in a non-production environment" and requires a purchased licence for production. It says nothing about the licence being free, so "free of charge" is gone.

7. PingAM 8 (L51). The AM 7.0 deprecation now links to Deprecated functionality, which lists chains and modules under "Deprecated since AM 7.0". The paragraph now mentions that PingAM 8.0 can re-enable them temporarily, only for migration purposes and only through REST, and that Ping plans to remove them completely. The paragraph now ends with "the option only buys time".

8. landing-title (L4). landing-title and landing-title2 now match title. One correction to the premise: no other post sets both title and landing-title. Of the other 143 posts that set landing-title, 137 have an H1 that matches it, so the point about consistency stands.

9. Absolute link (L61). Now /forgerock-alternative.

10. GA attributes (L171). Added through a kramdown IAL: data-ga-event="support_cta_click" data-ga-location="post_pingam_migration". This attribute is now in the rendered <a>. The /support link in 2025-12-18-openam-vs-keycloak.md has the same gap. I left it out of this PR.

11. FAQ loop. Done in this PR. _includes/faq.html holds the card grid, and support.md, forgerock-alternative.md and the post include it, each keeping its own heading. support.html builds byte-identical, and forgerock-alternative.html only gains a trailing blank line. The post's FAQ now renders as the same cards.

Verification: a local bundle exec jekyll build, then htmlproofer 5.2.3 with the workflow's options (--checks Links, same --ignore-urls, --assume-extension .html). 375 files, no errors.

@maximthomas
maximthomas requested a review from vharseko October 23, 2026 06:45

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants