Skip to content

JAXB3 Migration - #1023

Open
maximthomas wants to merge 35 commits into
OpenIdentityPlatform:masterfrom
maximthomas:features/jaxb3-update-2026-05-19
Open

maximthomas wants to merge 35 commits into
OpenIdentityPlatform:masterfrom
maximthomas:features/jaxb3-update-2026-05-19

Conversation

@maximthomas

@maximthomas maximthomas commented May 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Moves the generated federation schema classes from JAXB 1 to JAXB 3 (jakarta.xml.bind), which removes the last JAXB 1 runtime from OpenAM. It then fixes the call sites that relied on JAXB 1 shapes.

Build and dependencies

  • openam-saml2-schema, openam-liberty-schema and openam-wsfederation-schema no longer commit JAXB 1 xjc output. That removes 2,443 generated Java files and the bgm.ser grammar caches. The classes are now generated at build time from src/main/xsd by org.jvnet.jaxb:jaxb-maven-plugin 3.0.2.
  • The root pom manages jakarta.xml.bind:jakarta.xml.bind-api 3.0.1 and org.glassfish.jaxb:jaxb-runtime 3.0.2. The PR removes jaxb1-impl, javax.xml.bind:jaxb-api, com.sun.xml.bind:jaxb-core and com.sun.xml.bind:jaxb-impl, and the client SDK shading now includes the JAXB 3 artifacts. The shaded runtime does not yet serve the federation JAXBContexts in the client SDK, which was already the case with JAXB 1; see Client SDK: shaded JAXB runtime is not found through jaxb.properties #1185.
  • The 38 remaining jaxb.properties files now point at org.glassfish.jaxb.runtime.v2.ContextFactory, and three are deleted.
  • The XACML 3 schema classes (com.sun.identity.entitlement.xacml3.core) move from javax.xml.bind to jakarta.xml.bind.
  • com.sun.xml.bind.util.ListImpl and ProxyListImpl are removed from the default openam.deserialisation.classes.whitelist, because those classes no longer ship.

Deliberate schema change

BaseConfigType changes from abstract="true" to abstract="false" in three XSDs: the SAML2 and WS-Fed entity-config-schema.xsd and idff-entity-config-schema.xsd. JAXB 3 models IDPSSOConfig, SPSSOConfig and the other config elements as JAXBElement<BaseConfigType> instead of generating a subtype for each, so the code has to instantiate BaseConfigType directly. These XSDs are only used for code generation. Nothing validates stored configuration against them at runtime.

Call-site migration

JAXB 3 differs from JAXB 1 in six ways that affect existing code, and the call sites were updated for each:

  • Element wrappers. Generated *Element classes are now JAXBElement subclasses, not subtypes of their content type. Lists of elements are unwrapped with getValue(), and bare types without @XmlRootElement are marshalled through ObjectFactory.create*Element(...). This fixes ClassCastExceptions and NullPointerExceptions in single logout, attribute query, WS-Fed and ID-FF circle-of-trust updates, OpenFM workflows and console metadata import, and marshalling failures in Liberty IDPP and Discovery. The Fedlet's header.jspf, included by its index.jsp and fedletSampleApp.jsp, now reads the SSO and ACS endpoints through getValue() as well; before that, Jasper failed to compile both pages.
  • Nullable optional booleans. Optional boolean attributes without a schema default are now nullable Boolean. The SSO, ACS and metadata guards read them through Boolean.TRUE.equals(...), so an absent attribute still means false.
  • DOM attribute values. xs:anyType attribute values unmarshal to DOM nodes instead of strings. SAML2Utils.getAttributeValueString returns their text, which restores attribute query value matching and IDP proxy authn-context matching.
  • Whitespace in mixed content. Mixed-content lists (KeyInfo, EncryptionMethod) keep whitespace text. KeySize and X509Data are now looked up by type instead of by index.
  • Default namespace. The JAXB 1 runtime bound the namespace of the marshalled element to the default namespace. JAXB 3 gives it a generated prefix and declares every namespace on the root element. SAML2MetaUtils now asks for the JAXB 1 layout. Exported metadata therefore keeps the unprefixed RoleDescriptor of an attribute query descriptor in the metadata namespace, and CreateFedlet finds the <EntityConfig it edits. The export also declares the query prefix on that RoleDescriptor again, because the import, in this release and in earlier ones, parses the element on its own.
  • Error recovery. The JAXB 3 unmarshaller drops an unexpected element and carries on, where JAXB 1 rejected the document. SAML2MetaUtils, IDFFMetaUtils and WSFederationMetaUtils now fail on the first error. Importing metadata that has, for example, a KeyDescriptor in the wrong namespace fails again instead of losing the certificate. JAXB 3 still does not report a missing required element, which JAXB 1 did. The Liberty ID-WSF unmarshallers (soapbinding.Utils, Discovery, IDPP) stay lenient.

Upgrade impact

This breaks binary compatibility for custom code compiled against the generated federation types, KeyUtil.getKeyDescriptor(s), or the DiscoEntryHandler plugin interface. The upgrade guide documents the change in chap-upgrade-servers.adoc.

Tests

  • Unit tests:
    • KeyUtilTest (SAML2 and ID-FF): KeySize and X509Data lookup in indented metadata, including KeyUtil.getKeySize, which the console now uses.
    • IDPSSOUtilTest: ACS fallback when isDefault is absent.
    • SAML2MetaUtilsTest: unmarshal round-trips, export and re-import of an attribute query descriptor, the unprefixed EntityConfig root, and rejection of unexpected elements.
    • IDFFMetaUtilsTest, WSFederationMetaUtilsTest: rejection of unexpected elements.
    • WSFederationMetaUtilsTest: token-signing certificate and entity-config attributes.
    • SLOLocationTest, SAML2UtilsTest.
    • DSTRequestHandlerTest: EncryptedResourceID marshalling.
    • IDPPBaseContainerTest: gMonthDay values.
    • DiscoEntryHandlerImplUtilsTest: reading back stored discovery entries.
  • E2E: the new e2e/sts/rest-sts-test.spec.mjs publishes a REST STS instance and translates an OpenAM token into a SAML2 assertion in the built WAR.

Not covered

  • The default build does not precompile JSPs, so CI does not compile the JSP changes. The Fedlet header.jspf was checked by compiling its declarations against the generated classes, not in a deployed Fedlet. The sample JSPs under openam-federation/OpenFM/src/main/samples still use JAXB 1 accessors; no build packages them.
  • A mixed-version site was checked only by a manual probe during review: SAML2, ID-FF and WS-Fed entity config and metadata and a Liberty DiscoEntry written by JAXB 1 read back unchanged under JAXB 3, and the other way round. No automated test covers it.
  • Metadata served to external partners such as ADFS was not checked byte for byte against the JAXB 1 output (namespace prefixes, XML declaration).

@maximthomas
maximthomas requested a review from vharseko May 21, 2026 10:13
@vharseko vharseko linked an issue May 27, 2026 that may be closed by this pull request
@vharseko vharseko added this to the 16.2.0 milestone Jun 1, 2026
vharseko added 11 commits June 20, 2026 12:56
… after JAXB3 migration

getIDPSSOConfigOrSPSSOConfig() now returns List<JAXBElement<BaseConfigType>>,
but removeFromEntityConfig still cast elements directly to BaseConfigType /
AttributeType. Unwrap via getValue(), mirroring addToEntityConfig.
…B3 migration

getSingleLogoutService() returns List<SingleLogoutServiceElement> (JAXBElement
wrappers); unwrap to List<EndpointType> before LogoutUtil.doLogout().
Unwrap the SingleLogoutService wrapper list to List<EndpointType> before
LogoutUtil.doLogout(). The wrapper-expecting getSLOServiceLocation() path is
left unchanged.
…r JAXB3 migration

convertAttributes() added the AttributeValueElement wrapper instead of its
content to the list passed to setAttributeValueString(), which casts each
element to String. Add the unwrapped value.
…ws after JAXB3 migration

getIDPSSOConfigOrSPSSOConfigOrAuthnAuthorityConfig() returns
List<JAXBElement<BaseConfigType>>; unwrap via getValue() before use.
…ter JAXB3 migration

getUse() returns null when the optional use attribute is absent (one key for
both signing and encryption); guard before calling value().
… migration

SingleLogoutService / NameIDMappingService / AuthnQueryService /
AssertionIDRequestService endpoints were created with createAttributeServiceType(),
which injects a spurious xsi:type="AttributeServiceType" on marshal. Use
createEndpointType().
…DFFCOTUtils after JAXB3 migration

getAffiliationDescriptorConfig() is null for ordinary SP/IDP entities; guard the
wrapper before getValue() in add/remove EntityConfig.
…ements after JAXB3 migration

Optional JAXB elements are now possibly-null JAXBElement wrappers. Add a
null-safe jaxbValue() helper in IDPPBaseContainer and use it across the IDPP
container read-back methods.
…nt after JAXB3 migration

getIDPSSODescriptor() can return null for an unknown issuer; reject with
InvalidGrantException instead of dereferencing the null wrapper.
AttributeValueElement.getValue() returns the scalar content (not a List) for
string-valued attributes, so the "instanceof List" guard silently skipped
context matching. Normalize scalar and list content to restore the previous
getContent() behaviour.

@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.

PR #1023 "JAXB3 Migration" — fix registry

Branch tip after follow-up work: f168117cc6 (11 commits on top of 63ff4448ae).
PR: #1023


Root cause (common to all 11 fixes)

The migration moves XML binding from JAXB 1.0 / javax.xml.bind to JAXB 3.0 / jakarta.xml.bind and stops checking generated classes into the repo — they are now generated at build time (jaxb-maven-plugin). In doing so the shape of the generated API changes, which breaks consumer code in three ways that compile but fail at runtime:

  1. Global XML elements are now JAXBElement<T> wrappers.
    A getter that used to return the concrete type now returns a wrapper, so callers must call .getValue().

    • Any remaining raw cast (Type) iter.next() or enhanced-for for (Type x : rawList) over a list of wrappers → ClassCastException. It only compiles because the list is declared as a raw List.
  2. Optional elements are now nullable wrappers.
    A getXxx().getValue() chain on an absent (optional) element → NullPointerException, and the existing if (x != null) guard below becomes dead code.

  3. ObjectFactory.createXxx() factory methods now take a value argument.
    Passing the subtype AttributeServiceType into a factory whose declared value type is EndpointType makes JAXB emit a spurious xsi:type="AttributeServiceType" on marshal → invalid SAML2 metadata.


Commit registry

# Commit File(s) Type Essence
1 dac13f3c06 WSFederationCOTUtils.java CCE remove path not migrated
2 9e8cad2dd5 SAML2SingleLogoutHandler.java CCE wrappers into doLogout(List<EndpointType>)
3 ea473f7fc0 SPSingleLogout.java CCE same in SP SLO
4 6a4d81419b AttributeQueryUtil.java CCE wrapper added instead of value
5 3435063154 GetCircleOfTrusts.java, ImportSAML2MetaData.java CCE raw cast to BaseConfigType
6 271ad11235 SAMLv2ModelImpl.java NPE getUse() == null
7 faf0be2e7e SAMLv2ModelImpl.java XML spurious xsi:type on endpoints
8 d9d4b8e13e IDFFCOTUtils.java NPE no affiliation config
9 5aa4d1c5e3 7× IDPP* containers NPE optional Liberty PP elements
10 f77dbb76bd Saml2GrantTypeHandler.java NPE unknown issuer
11 f168117cc6 SAML2IDPProxyFRImpl.java logic silently disabled context matching

Per-fix detail

1. dac13f3c06 — WSFederationCOTUtils.removeFromEntityConfig (CCE)

File: openam-federation-library/.../wsfederation/meta/WSFederationCOTUtils.java
Problem: getIDPSSOConfigOrSPSSOConfig() returns List<JAXBElement<BaseConfigType>>. addToEntityConfig was migrated to .getValue(), but the sibling removeFromEntityConfig was not: it still did (BaseConfigType) iter.next() and (AttributeType) iter2.next(). Removing a WS-Fed entity from a circle of trust → CCE.
Fix: generics + .getValue(), mirroring the add method.

2. 9e8cad2dd5 — Multi-protocol SOAP single logout (CCE)

File: .../multiprotocol/SAML2SingleLogoutHandler.java
Problem: getSingleLogoutService() → List<SingleLogoutServiceElement> (which are JAXBElement<EndpointType>). The list is passed to LogoutUtil.doLogout(List<EndpointType>), whose for (EndpointType e : list) → CCE. Sibling paths (IDPSessionListener/SPSessionListener) were fixed; this one was missed.
Fix: .stream().map(JAXBElement::getValue).collect(...) before doLogout.

3. ea473f7fc0 — SP single logout (CCE)

File: .../saml2/profile/SPSingleLogout.java
Problem: same wrapper list passed into doLogout(List<EndpointType>).
Fix: unwrap to List<EndpointType>. The second slosList (feeds getSLOServiceLocation, which expects the wrappers) is intentionally left unchanged.

4. 6a4d81419b — SAML2 attribute query conversion (CCE)

File: .../saml2/profile/AttributeQueryUtil.java
Problem: convertAttributes() added the wrapper AttributeValueElement instead of its content. The list goes to setAttributeValueString(), which does (String) iter.next() → CCE. The computed content was unused.
Fix: add content (the unwrapped value).

5. 3435063154 — OpenFM workflows (CCE)

Files: OpenFM/.../workflow/GetCircleOfTrusts.java, ImportSAML2MetaData.java
Problem: getIDPSSOConfigOrSPSSOConfigOrAuthnAuthorityConfig() → List<JAXBElement<BaseConfigType>>, but the code did (BaseConfigType) config.iterator().next() → CCE when resolving the realm for a hosted entity.
Fix: generics + .getValue().

6. 271ad11235 — KeyDescriptor without use (NPE)

File: openam-console/.../federation/model/SAMLv2ModelImpl.java
Problem: keyOne.getValue().getUse().value() — getUse() is null when a <KeyDescriptor> omits the optional use attribute (one key for both signing and encryption). The next line if (type == null ...) was written for exactly that null case but is now unreachable. NPE when viewing the entity in the console.
Fix: null guard before .value().

7. faf0be2e7e — invalid metadata endpoints (XML)

File: openam-console/.../federation/model/SAMLv2ModelImpl.java
Problem: SingleLogoutService / NameIDMappingService / AuthnQueryService / AssertionIDRequestService endpoints were built with createAttributeServiceType(). Since AttributeServiceType extends EndpointType, marshalling injects a spurious xsi:type="AttributeServiceType" → off-schema metadata. 8 sites.
Fix: createEndpointType(). The two legitimate createAttributeServiceElement(createAttributeServiceType()) sites are left untouched.

8. d9d4b8e13e — IDFFCOTUtils without affiliation config (NPE)

File: .../federation/meta/IDFFCOTUtils.java
Problem: getAffiliationDescriptorConfig().getValue() — for ordinary SP/IDP entities the getter is null, so .getValue() fails before the dead if (affiConfig != null) check. 2 sites (add/remove EntityConfig).
Fix: null-check the wrapper before .getValue().

9. 5aa4d1c5e3 — Liberty Personal Profile containers (NPE)

Files: IDPPBaseContainer.java + IDPPFacade, IDPPDemographics, IDPPLegalIdentity, IDPPEmploymentIdentity, IDPPCommonName, IDPPAddressCard
Problem: read-back methods (getXxxMap/createAddressCard) do obj.getXxx().getValue() on optional PP elements; for absent ones (common, e.g. middle name) → NPE. The old code stored the nullable value and downstream getAttributeMap handled null fine.
Fix: add protected static <T> T jaxbValue(JAXBElement<T>) to the base class and apply it at every read site.

10. f77dbb76bd — OAuth2 SAML2 bearer, unknown issuer (NPE)

File: openam-oauth2-saml2/.../core/Saml2GrantTypeHandler.java
Problem: metaManager.getIDPSSODescriptor(...) can return null for an unknown issuer; idpSsoDescriptor.getValue() → NPE. Previously null was handled gracefully (clean rejection). This turns a rejection into an uncaught exception.
Fix: null-check the descriptor → InvalidGrantException("Unknown assertion issuer").

11. f168117cc6 — IDP proxy: authn-context matching (logic)

File: .../saml2/plugins/SAML2IDPProxyFRImpl.java
Problem: AttributeValueElement.getValue() returns a scalar (String) for string-valued attributes, not a List, so the instanceof List guard silently skipped the whole proxy-IDP authn-context selection block (a silent regression, no error).
Fix: normalize scalar and list content to List, restoring the previous getContent() behaviour.


Verification

  • Build (JDK 26 / Maven 3.9.16) of the affected modules — BUILD SUCCESS:
    Federation Library, OpenFM, Admin Console, OAuth2-SAML2.
  • Schema modules (saml2/liberty/wsfederation/xacml3) build and generate classes correctly.
  • The cumulative diff of all 11 commits is byte-identical to the patch that was built and verified.
  • Push to the PR branch was a fast-forward (63ff4448ae..f168117cc6).

Still to verify manually (not covered by compilation)

  • JSPs (not compile-checked): SA_IDP.jsp, SA_SP.jsp, spSingleLogoutInit.jsp, realmSelection.jsp.
  • Functionally: SAML2 SLO (SOAP + multi-protocol), attribute query, COT add/remove (SAML2 / WS-Fed / IDFF), Liberty Personal Profile, OAuth2 SAML2 bearer.

vharseko added 2 commits June 20, 2026 14:07
- RestAuthNameValueOutputCallbackHandler.java: keep correct NameValueOutputCallback Javadoc
- ResourceOwnerSessionValidator.java: merge copyright attributions
@vharseko vharseko added the refactoring Code cleanup, refactor, dead-code or dependency removal label Jul 8, 2026

@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.

Review: JAXB 1.x → JAXB 3 migration

Deep review of the full diff vs merge base 0ee32ac4 (2,787 files, +4,327/−541,024). The build/codegen architecture was verified empirically (regenerated all three schema modules offline with the PR's plugin config and bindings, plus an unmarshal/marshal runtime probe with jaxb-runtime 3.0.2 on the PR's own test resources). The remaining findings are call-site bugs of the same classes already fixed in the follow-up commits on this branch.

What checks out (verified, not just read)

  • Package parity confirmed: codegen reproduces every deleted JAXB1 package exactly; every class-bearing package gets an ObjectFactory, so all JAXBContext.newInstance(contextPath) call sites resolve. Metadata + entity-config round-trip probe passes.
  • All 31 jaxb.properties correctly rewritten to org.glassfish.jaxb.runtime.v2.ContextFactory (the deprecated jakarta.xml.bind.context.factory key is accepted by the 3.0 ContextFinder).
  • xs:dateTime kept on java.util.Calendar and anyURI on String via globalBindings — avoids the XMLGregorianCalendar break; *Element classes recreated via jxb:class as JAXBElement<T> subclasses; the curation from ~127 to ~35 element classes in saml2 leaves zero dangling references.
  • Prefix-mapper key change to org.glassfish.jaxb.namespacePrefixMapper is correct and required (the old com.sun.xml.bind.* key throws PropertyException on the new runtime — verified).
  • No javax.xml.bind references remain anywhere in main sources. No hand-fixes were lost in the deleted generated code (checked full git history of those files).
  • Nice bonus fixes: the pre-existing iter/iterV bug in AttributeQueryUtil.convertAttributes, null check in Saml2GrantTypeHandler; new SAML2MetaUtilsTest + Playwright REST-STS e2e test.

Blocking bugs

CI is green because it compiles and runs unit tests, but these break at runtime ("needs testing" label is accurate).

WS-Federation — broken entirely

  • WSFederationMetaUtils.getAttributes (~line 231): casts members of List<AttributeElement> to AttributeType → guaranteed ClassCastException. Every WSFed extended-config read funnels through this helper (RPSigninRequest/RPSigninResponse, account/attribute mappers, WSFederationUtils.createSAML11Token).
  • WSFederationMetaUtils.getAttribute (~line 296): avp.getName() now resolves to JAXBElement.getName() returning a QName; equals(String key) is always false → every lookup (SIGNING_CERT_ALIAS, AUTH_URL, ASSERTION_TIME_SKEW, ACTIVE_REQUESTOR_PROFILE_ENABLED, ENDPOINT_BASE_URL, NameID settings) silently returns null. Needs avp.getValue().getName().

IDFF — broken entirely

  • IDFFMetaUtils.getAttributes (lines 297–306): same (AttributeType) cast on a List<AttributeElement> → CCE. This is the central helper for the whole IDFF stack (FSAssertionManager, FSAuthnDecisionHandler, attribute mappers, IDP proxy, …).
  • IDFFCOTUtils.updateCOTAttrInConfig (line 226) / removeCOTNameFromConfig (line 263): (BaseConfigType) and (AttributeType) casts on element lists, and a raw AttributeType added into a List<AttributeElement>. The create path in the same file was migrated; the update helpers were missed — adding/removing an IDFF entity to/from a COT fails whenever the entity has an entity config.
  • federation/key/KeyUtil.getKeyDescriptor (~295–318): kd.getValue().getUse().value() NPEs when use is absent (the following use == null handling is now dead), and the no-match branch returns noUsageKD.getValue() → NPE where the old code returned null to null-tolerant callers.
  • IDFFProviderManager (~128/188/214), LibertyManager (~1276/2025), EncryptedNameIdentifier (~225): .getValue() chained onto nullable getSPDescriptorConfig(...) before the null check → NPE for IDP-only entities; the SP→IDP fallback logic is now dead code.

SAML2 — optional-Boolean unboxing NPEs (highest-impact class)

JAXB1 generated primitive boolean for optional XSD attributes (absent → false); XJC 3 generates nullable Boolean (attributes are use="optional" with no default in the XSDs). Direct unboxing now NPEs whenever the attribute is absent — which is schema-legal and common in third-party metadata:

  • IDPSSOUtil.java:1865, 1953, 2026 — acs.getValue().isIsDefault() looping over all ACS entries of the remote SP; getDefaultACSurl runs on the common no-ACS-in-request path → IDP-side SSO fails for typical third-party SP metadata with any ACS entry lacking isDefault.
  • SPSSOFederate.java:377, 448, 1000; SAML2Utils.java:495 (verifyResponse); IDPArtifactResolution.java:472; IDPSSOUtil.java:3017; UtilProxySAMLAuthenticator.java:161; IDPProxyUtil.java:222; SPACSUtils.java:511; QueryClient.java:811; QueryHandlerServlet.java:421 — isWantAssertionsSigned() / isAuthnRequestsSigned() / isWantAuthnRequestsSigned().
  • isHosted() — same class: SAML2MetaManager.java:1237/1408/1494/1532, SAML2MetaSecurityUtils.java:182/475, IDFFMetaManager.java:837/871, WSFederationMetaManager.java:833/896/982, ImportMetaData.java:192/264/324, OpenFM workflow tasks, console TaskModelImpl. OpenAM always writes the attribute, but hand-imported extended configs may omit it.
  • Systematic fix: Boolean.TRUE.equals(...) at call sites (the PR already does exactly this for isPassive() in UtilProxySAMLAuthenticator), or XSD defaults, or an xjb customization. Note the added test resources set every optional boolean (hosted="1", isDefault="1", …), which is why tests don't catch this class — please add a metadata fixture with the optional attributes omitted.
  • (IDFF metadata side is not affected: lib-arch-metadata.xsd has default="false" — checked.)

SAML2 — other

  • AttributeQueryUtil.isSameAttribute:988 — desired.getName().equals(supported.getName()) compares String to QName (always false) → every AttributeQuery naming specific attributes is rejected with "Attribute name not supported". Needs supported.getValue().getName().
  • SAML2MetaSecurityUtils.setExtendedAttributeValue:565 — (AttributeType) cast on an AttributeElement list → CCE; breaks ssoadm update-entity-keyinfo (the add at line 575 was fixed, the removal loop wasn't).
  • SAML2MetaSecurityUtils.updateProviderKeyInformation:483-495 — .getValue() NPEs before the intended entityNotIDP/entityNotSP errors (now dead code).
  • SAML2ProviderManager (lines ~96, ~167, ~191, ~216) — getSPSSOConfig(...).getValue() NPEs for IDP-only providers; the IDP fallback in all four methods is dead; the catch handles SAML2MetaException only.

Liberty PP / Discovery / WSS Policy

  • WSSPolicyManager (lines 120, 131, 249–250, 302–303): createExactlyOneElement(createPolicyElement()) substitutes the anonymous Policy type where OperatorContentType is expected — the runtime reports SUBSTITUTED_BY_ANONYMOUS_TYPE and marshalling aborts → getPolicy()/getInputPolicy()/getOutputPolicy() always throw. Use createOperatorContentType().
  • IDPPEncryptKey/IDPPSignKey (getContainerObject): bare X509DataType added into KeyInfo content (an @XmlElementRefs list) → MarshalException: missing an @XmlRootElement annotation. Should be of.createX509DataElement(x509DataType) (the read paths in the same files already expect X509DataElement).
  • IDPPLegalIdentity:489 — (AltIDType) cast after instanceof AltIDElement → CCE (AltIDElement extends JAXBElement<AltIDType> now); :105 — createAltIDElement(getAltID(userMap)) is never null, so an empty <AltID/> is always added where the old code added nothing.
  • IDPPDemographics:281 → IDPPBaseContainer.getAttributeMap: List<LanguageElement> members match neither instanceof DSTString nor DSTURI → PP Language values silently dropped on read and potentially wiped on modify.
  • DiscoveryService (~221, ~362): getEncryptedResourceID().getValue() NPEs when both ResourceID variants are absent.

Console

  • ImportEntityModelImpl (~145 createSAMLv2Entity, ~316 createWSFedEntity): (BaseConfigType) config.iterator().next() on List<JAXBElement<BaseConfigType>> → CCE when importing hosted entities with extended metadata via the console (the identical pattern was fixed in OpenFM ImportSAML2MetaData/GetCircleOfTrusts; the console counterpart was missed).
  • SAMLv2ModelImpl:2035, 2096 — (AttributeType) casts → CCE opening the XACML PEP/PDP extended-metadata pages (lines 1605/1676 in the same file show the correct pattern).
  • SAMLv2ModelImpl:1733-1737 — getClass().getName().contains("KeySizeImpl") matches nothing under JAXB3 (no *Impl classes) → encryption key size silently never read. Should be instanceof EncryptionMethodType.KeySize.
  • IDFFModelImpl:497, 565, 1247, 1306, 1494; SAMLv2ModelImpl:2321, 2380 — .getValue() before the null check: first-time access to an IDFF entity's IDP/SP tab now NPEs instead of auto-creating the default extended config; invalid.entity.name errors degraded to NPE.
  • SMDiscoEntryData (~212–267): directives unwrapped to bare DirectiveType and added to an @XmlAnyElement list → MarshalException + element identity (which directive) lost; the read path checks instanceof AuthenticateRequesterElement etc., so the round-trip is broken. Add the JAXBElement wrappers, not their values.

Build / packaging

  • openam-clientsdk/pom.xml (~146): shade includes the non-existent coordinate jakarta.xml.bind:jaxb-api (correct: jakarta.xml.bind:jakarta.xml.bind-api) and omits jaxb-runtime's transitive deps (org.glassfish.jaxb:jaxb-core, com.sun.istack:istack-commons-runtime, org.glassfish.jaxb:txw2, jakarta.activation:jakarta.activation-api) → standalone clientsdk consumers get NoClassDefFoundError on first JAXB use.
  • openam-wsfederation-schema/pom.xml:85-88: leftover com.sun.xml.bind:jaxb1-impl dependency (removed from saml2/liberty poms in this PR) — drags the dead JAXB1 runtime into every WAR. Related: openam-auth-saml2 SAML2ProxyTest.java:26 still imports com.sun.xml.bind.StringInputStream (exists only in jaxb1-impl).

Risks / cleanups (non-blocking)

  • Sweep the .getValue()-before-null-check pattern — beyond the cases above there are ~a dozen more (e.g. SAML2Utils.java:556/2194/3556, SPACSUtils.java:392, IDPSessionListener.java:159, NameIDMapping.java:206, DoManageNameID.java:291, AssertionIDRequestUtil.java:405, multiprotocol IDFFSingleLogoutHandler:226, SingleLogoutManager:689, ValidRelayStateExtractor, DefaultAttributeMapper, ValidWReplyExtractor, ConfigureGoogleApps:94). Formerly handled null-metadata cases now surface as NPEs.
  • BaseConfigType flipped abstract="true" → "false" in three XSDs — necessary for JAXB3 instantiation and only used as codegen input, but worth recording as intentional in the PR description (which is currently empty).
  • Split package: org.w3._2001.xmlschema.Adapter1 is now generated into both the liberty and wsfederation jars (same bytecode; duplicate-class checkers/JPMS will complain). saml2 avoids this via its schema.xsd package-mapping trick — the same could be applied to wsfed.
  • FAMClassLoader (OpenFM): lists now internally inconsistent — classesToBeLoaded says jakarta.xml.bind. but maskedResouces still masks javax/xml/bind/, and com.sun.xml.bind.* (JAXB1 RI) entries remain.
  • Dead JAXB1 cruft to delete with this PR: ~25 bgm.ser grammar caches still packaged in the schema jars; JAXB1 entries in THIRD-PARTY.properties; com.sun.xml.bind.util.ListImpl/ProxyListImpl whitelist entries in IOUtils and serverdefaults.properties:191; root pom <jaxb1.version> property; orphan jaxb.properties in packages with no classes (.../common/jaxb/xmlsec/, parent common/jaxb/).
  • PPRequestHandler: stray junk import org.glassfish.jaxb.core.v2.model.core.ID; getMarshaller().setProperty(...); getMarshaller().marshal(...) uses two different marshaller instances so the prefix mapper never applies (pre-existing).
  • SLOLocationTest: createSingleLogoutServiceElement(of.createAttributeServiceType()) works only because AttributeServiceType extends EndpointType — use createEndpointType().
  • Upgrade note: previously serialized blobs containing JAXB1 com.sun.xml.bind.util.ListImpl instances can no longer deserialize after upgrade (class gone from classpath).

Suggested order of fixes

  1. WSFederationMetaUtils.getAttributes/getAttribute, IDFFMetaUtils.getAttributes, IDFFCOTUtils update helpers (restores WSFed + IDFF).
  2. Systematic optional-Boolean sweep (Boolean.TRUE.equals(...) or XSD defaults) + a test metadata fixture with optional attributes omitted.
  3. .getValue()-before-null-check sweep.
  4. WSSPolicyManager, PP containers, SMDiscoEntryData, console CCEs (ImportEntityModelImpl, SAMLv2ModelImpl).
  5. clientsdk shade config + jaxb1-impl removal.

Resolves the runtime defects found reviewing the JAXB1->JAXB3 migration:
- WSFederation/IDFF metadata helpers: unwrap AttributeElement/JAXBElement
  lists (ClassCastException) and compare element value names, not QNames
- SAML2/WSFed/IDFF: guard optional Boolean metadata attributes with
  Boolean.TRUE.equals(...) (absent attribute is false, not an NPE) on the
  core SSO, artifact, logout and query paths
- KeyUtil/SAML2MetaSecurityUtils/SAML2ProviderManager and ~12 other sites:
  null-check JAXB elements before getValue() so designed null/fallback
  paths run instead of throwing
- Liberty PP, WS-Policy and Disco: marshal element wrappers (not bare
  types) so KeyInfo/Policy/Directive content serialises
- Console: fix entity-import CCEs, XACML PEP/PDP casts, key-size read and
  extended-config auto-creation
- clientsdk shade: correct jakarta.xml.bind-api coordinate and add the
  jaxb-runtime transitive stack
- Build cleanup: drop leftover jaxb1-impl, dead bgm.ser/jaxb.properties,
  jaxb1 THIRD-PARTY entries and jaxb1.version; move wsfed Adapter1 out of
  the split org.w3._2001.xmlschema package
- Add sp-metadata-no-optional-booleans.xml + SAML2MetaUtilsTest coverage
  pinning the nullable-Boolean generated shape
@vharseko

Copy link
Copy Markdown
Member

Fixes pushed — a18c3c1 (addresses the review findings above)

All blocking bugs, risks, and cleanups from the review are now fixed on this branch. Summary mapped to the findings, with verification at the end.

Blocking bugs — fixed

WS-Federation (was broken entirely)

  • WSFederationMetaUtils.getAttributes — unwrap AttributeElement before use (was (AttributeType) cast → CCE).
  • WSFederationMetaUtils.getAttribute — compare avp.getValue().getName() (was JAXBElement.getName() QName, always ≠ String key).

IDFF (was broken entirely)

  • IDFFMetaUtils.getAttributes — unwrap AttributeElement (CCE).
  • IDFFCOTUtils.updateCOTAttrInConfig / removeCOTNameFromConfig — unwrap descriptor-config JAXBElements (handling both the wrapped SP/IDP lists and the unwrapped affiliation entry), unwrap AttributeElement, and add new attributes via createAttributeElement.
  • federation/key/KeyUtil.getKeyDescriptor — null-safe getUse(), and return null instead of noUsageKD.getValue() when there is no match.
  • IDFFProviderManager / LibertyManager / EncryptedNameIdentifier — null-check the config element before getValue() so the IDP fallback runs (was NPE for IDP-only entities).

SAML2 — optional-Boolean unboxing (highest-impact class)
Absent optional attributes are now treated as false via Boolean.TRUE.equals(...) instead of NPE-ing on the nullable Boolean: IDPSSOUtil (ACS isIsDefault, isWantAssertionsSigned), SPSSOFederate, SAML2Utils.verifyResponse, IDPArtifactResolution, UtilProxySAMLAuthenticator, IDPProxyUtil, SPACSUtils, QueryClient, QueryHandlerServlet, AttributeQueryUtil (isSupportsX509Query), and every isHosted() site in SAML2MetaManager / SAML2MetaSecurityUtils / IDFFMetaManager / IDFFMetaSecurityUtils / WSFederationMetaManager / cli ImportMetaData.

SAML2 — other

  • AttributeQueryUtil.isSameAttribute — supported.getValue().getName() (was String.equals(QName), always false).
  • SAML2MetaSecurityUtils.setExtendedAttributeValue — unwrap AttributeElement in the removal loop (CCE); updateProviderKeyInformation — null-check role config/descriptor before getValue() so entityNotIDP/entityNotSP fires.
  • SAML2ProviderManager — restored the SP→IDP fallback via a null-safe unwrap in all four methods.

Liberty PP / Discovery / WS-Policy

  • WSSPolicyManager — pass createOperatorContentType() (was anonymous-type PolicyElement → MarshalException).
  • IDPPEncryptKey / IDPPSignKey — add createX509DataElement(...) wrapper to KeyInfo (was bare X509DataType → MarshalException).
  • IDPPLegalIdentity — ((AltIDElement)…).getValue() (CCE) and add AltID only when non-null.
  • IDPPDemographics / IDPPBaseContainer.getAttributeMap — unwrap JAXBElement list members so Language values survive; also fixed the pre-existing DSTURI loop-var typo.
  • SMDiscoEntryData — put the directive element wrappers into getAny() so the round-trip and read-path instanceof checks work.
  • DiscoveryService — null-safe getEncryptedResourceID().

Console

  • ImportEntityModelImpl — unwrap JAXBElement<BaseConfigType> on hosted-entity import (SAMLv2 + WSFed CCE).
  • SAMLv2ModelImpl — unwrap AttributeElement on the XACML PEP/PDP pages (CCE); replace getClass().getName().contains("KeySizeImpl") with instanceof EncryptionMethodType.KeySize; null-check configs so invalid.entity.name is reachable; Boolean.TRUE.equals(...) on the remaining nullable-Boolean reads.
  • IDFFModelImpl — null-check descriptor/affiliation configs so first-time tabs auto-create the extended config instead of NPE.
  • SAMLv2SPServicesViewBean — render isDefault as false (not "null") when absent.

Build / packaging

  • openam-clientsdk shade — corrected jakarta.xml.bind:jakarta.xml.bind-api and added the jaxb-runtime transitive stack (jaxb-core, istack-commons-runtime, txw2, jakarta.activation-api).
  • Removed leftover com.sun.xml.bind:jaxb1-impl from the wsfederation-schema pom, and migrated SAML2ProxyTest off com.sun.xml.bind.StringInputStream to ByteArrayInputStream.

Risks / cleanups — done

  • Swept the .getValue()-before-null-check pattern across SAML2Utils, SPACSUtils, IDPSessionListener, NameIDMapping, DoManageNameID, AssertionIDRequestUtil, ValidRelayStateExtractor, multiprotocol handlers, DefaultAttributeMapper, ValidWReplyExtractor (null-safe unwrap).
  • BaseConfigType anonymous subclasses → ObjectFactory.createBaseConfigType().
  • Split-package org.w3._2001.xmlschema.Adapter1 in the wsfed jar fixed via a new schema.xsd package binding (verified by regenerating: Adapter1 now lands in com.sun.identity.wsfederation.jaxb.schema, no org.w3._2001.xmlschema classes, compiles clean).
  • FAMClassLoader mask/load lists made jakarta/glassfish-consistent.
  • Deleted dead JAXB1 cruft: 41 bgm.ser, 3 orphan jaxb.properties, jaxb1-impl entries in THIRD-PARTY.properties, <jaxb1.version> in the root pom, and the com.sun.xml.bind.util.* whitelist entries in IOUtils / serverdefaults.properties.
  • PPRequestHandler — dropped the junk import and used a single Marshaller instance so the prefix mapper applies; ConfigureGoogleApps null-guard; CreateWSFedMetaDataTemplate uses the computed ssneUri; normalized jaxb.properties.

New test coverage

sp-metadata-no-optional-booleans.xml + SAML2MetaUtilsTest.optionalBooleanAttributesUnmarshalAsNull pins the JAXB 3 generated shape (isIsDefault()/isWantAssertionsSigned()/isAuthnRequestsSigned() return null when the attribute is absent) — the class of regression the existing fixtures did not exercise, since they set every optional boolean.

Verification

  • Schema regeneration (JAXB 3) + compile of openam-schema/*, openam-shared, openam-federation-library, OpenFM, openam-console, openam-cli-impl, openam-auth-saml2, openam-clientsdk — BUILD SUCCESS on JDK 26.
  • Confirmed the generated IndexedEndpointType.isIsDefault() is a nullable Boolean (the premise of the unboxing bugs).
  • Tests: openam-federation-library 45/45, SAML2ProxyTest 10/10, 0 failures/errors.

Net: 153 files changed (+490 / −336), including the JAXB1 cruft deletions and 2 new files.

@vharseko
vharseko self-requested a review July 14, 2026 12:54
Optional config/metadata getters now return JAXBElement wrappers; several
call sites unwrapped them with a bare .getValue(), throwing NPE on entities
that lack an extended/role config where the pre-migration code degraded
gracefully (null flowed through to a null-tolerant consumer). Add a
null-safe unwrap() helper to SAML2MetaUtils / IDFFMetaUtils and route the
affected sites through it, or guard inline.

HIGH:
- IDPPBaseContainer: unwrap the JAXBElement in the scalar attribute branch
  (mirroring the list branch) so Personal Profile scalar values are no
  longer silently cleared on Modify.
- DiscoveryService.getResourceID: accept and marshal the
  EncryptedResourceIDElement (a JAXBElement) instead of the non-root
  EncryptedResourceIDType, which failed to marshal and misrouted encrypted
  resource-ID lookups to the implied-resource (B2E) path.
- IDFFMetaUtils.getExtendedConfig, SAML2MetaManager (PEP branch guard to
  match the PDP branch), AssertionIDRequestUtil, SPSessionListener,
  AuthnQueryUtil.

MED (unguarded .getValue() on a nullable config getter whose consumer
tolerates null; NPE otherwise escaped an IDFFMetaException-only catch):
- IDPSingleLogout, IDPSessionListener, SPSingleLogout (idpConfig is null
  for all non-SOAP bindings), QueryClient, FSLoginHelper, FSServiceManager,
  FSAttributeStatementHelper, FSPreLogin, FSReturnLogoutServlet,
  FSTerminationReturnServlet, FSPostLogin, FSIDPFinderService,
  FSAssertionManager, FSSingleLogoutHandler.

Cleanup:
- Cache DatatypeFactory in a static field in Time.java.
- Drop the orphaned jaxb.version property and the redundant JAXB version
  pins / commented-out JAXB2 dependency blocks in openam-core.
…ert lookup, PP EncryptedResourceID and null-guard regressions

- LogoutUtil: accept both SingleLogoutServiceElement wrappers and unwrapped
  EndpointType items in getSLOServiceLocation/getSLOResponseServiceLocation
  (fixes session-sync SLO ClassCastException in IDP/SP session listeners)
- WSFederationMetaUtils.findTokenSigningCertificate: unwrap X509DataElement
  in lax any content so remote WS-Fed IdP token signature verification works
- DSTRequestHandler: marshal EncryptedResourceIDType via its element wrapper
  (raw type has no @XmlRootElement) — fixes PP Query/Modify with encrypted
  resource IDs
- SAML2Utils.getAttributeValueString: extract text from anyType-bound
  AttributeValue payloads (DOM nodes after JAXB3); use in SAML2IDPProxyFRImpl
  and AttributeQueryUtil
- IDPPBaseContainer/IDPPAddressCard: unwrap JAXBElement for PP elements
  without generated element classes (AnalyzedName, address-card leaves)
- Null-guard absent extended entity config: SPSessionListener,
  SAML2SingleLogoutHandler, FSServiceManager, FSAssertionManager,
  FSIDPFinderService, FSAccountManager, NameIDMapping
- WSFedPropertiesModelImpl: mutate TokenIssuerName value in place to keep
  extensible attributes
- FAMClassLoader: restore javax/com.sun.xml.bind masks (provided by bundled
  Metro jars); let jakarta JAXB delegate to the webapp classloader
- IDPPBaseContainer.getDSTMonthDay: accept legacy MM-DD directory values
- Tests: SLO location lookups for both list shapes, WS-Fed token certificate
  round-trip, AttributeValue text extraction, EncryptedResourceID marshalling
@vharseko

Copy link
Copy Markdown
Member

Fix report for the review findings

All findings from the review above — high, medium and low — are addressed in d020a36 (22 files, +388/−78).

High severity

  • SAML2 session-sync SLO ClassCastException — LogoutUtil.getSLOServiceLocation and getSLOResponseServiceLocation now normalize each list item via a toEndpointType helper, accepting both the SingleLogoutServiceElement wrappers (all metadata callers) and the unwrapped EndpointType items that IDPSessionListener/SPSessionListener must pass to doLogout. The listeners themselves are unchanged apart from a null guard.
  • WS-Fed token signature verification — the certificate extraction now unwraps X509DataElement in the lax any content (previous instanceof X509DataType could never match). The logic moved to a static WSFederationMetaUtils.findTokenSigningCertificate, with WSFederationMetaManager.getTokenSigningCertificate delegating to it, so it is testable without a configured meta manager.
  • Liberty PP EncryptedResourceID MarshalException — DSTRequestHandler.getResourceID marshals the type through createEncryptedResourceIDElement(...) instead of the bare EncryptedResourceIDType (no @XmlRootElement). Fixing the shared callee covers both the PP Query and Modify paths.

Medium severity

  • AttributeValue DOM payloads — new helper SAML2Utils.getAttributeValueString(Object) unwraps JAXBElements and extracts Node.getTextContent() from the xs:anyType-bound payloads (plain Strings pass through). Applied at all three broken sites: SAML2IDPProxyFRImpl.idpAuthnContextFilter, AttributeQueryUtil.convertAttributes, AttributeQueryUtil.isValueValid.
  • PP Modify rejections — IDPPBaseContainer.getAnalyzedNameMap and the IDPPAddressCard leaf branch (Nick, PostalAddress, L, St, C, PostalCode, LComment) now unwrap the JAXBElement before the instanceof checks, matching the pattern the migration already used in getAttributeMap/getCommonNameMap. The AddressCardElement/AddressElement branches are untouched (those have generated element classes and must stay wrapped).
  • NPE on absent extended entity config — null guards restored in SPSessionListener, SAML2SingleLogoutHandler (an NPE there escaped the per-SP catch and aborted logout for all remaining SPs) and FSServiceManager.getNameRegistrationHandler.

Low severity

  • Null guards restoring the old graceful error paths in NameIDMapping.getEncryptedID, FSAssertionManager, FSIDPFinderService, and FSAccountManager (the explicit NULL_HOSTED_CONFIG error code is reachable again).
  • WSFedPropertiesModelImpl.setGenAttributeValues mutates the existing TokenIssuerName value in place, preserving extensible attributes; the fresh-object path remains as fallback.
  • FAMClassLoader again masks javax.xml.bind./com.sun.xml.bind. (self-supplied by the bundled 2009-era Metro jars) and no longer masks jakarta.xml.bind./org.glassfish.jaxb., which the child jar list cannot provide — jakarta JAXB now delegates to the webapp classloader.
  • IDPPBaseContainer.getDSTMonthDay accepts legacy MM-DD directory values by normalizing them to the --MM-DD gMonthDay lexical form.

Tests added

  • SLOLocationTest — two new tests covering getSLOServiceLocation/getSLOResponseServiceLocation with both the wrapped and the unwrapped list shapes (the exact listener regression).
  • WSFederationMetaUtilsTest (new) — builds Federation metadata with TokenSigningKeyInfo, round-trips it through marshal/unmarshal (producing the X509DataElement wrapper shape seen with real remote metadata) and asserts the certificate bytes are found. Failed before the fix.
  • SAML2UtilsTest — two new tests: text extraction from an unmarshalled EntityAttributes/AttributeValue fragment, and plain/null payload handling.
  • DiscoUtilsTest (new) — locks in that EncryptedResourceID marshals via the element wrapper with the expected qualified name.

Verification

  • Full openam-federation-library test suite: 51/51 pass.
  • openam-federation-library, OpenFM, openam-console, openam-entitlements all compile against the change.

One note for anyone building this branch locally: Maven's --update-snapshots (used by CI-style invocations) pulls pre-migration 16.2.0-SNAPSHOT artifacts from the remote snapshot repository over locally built migrated ones, which produces confusing "interface has no getValue()" compile errors. Build with -nsu after installing the branch's schema modules, or bump the branch version, to avoid the clash.

…te-2026-05-19

# Conflicts:
#	openam-federation/openam-federation-library/src/main/java/com/sun/identity/liberty/ws/interaction/WSPRedirectHandlerServlet.java
JAXB 3 keeps whitespace-only text in @XmlMixed content lists, so casting
index 0 of EncryptionMethod or KeyInfo content threw ClassCastException
for indented metadata, which OpenAM's own templates write.

- saml2 KeyUtil: read KeySize by type in getEncInfo and getPEPEncInfo
- ID-FF KeyUtil.getCert: find X509Data by type in KeyInfo content
- console SAMLv2ModelImpl: cast the matched KeySize, not index 0
- document the JAXB 1 to JAXB 3 API break in the upgrade guide
- fix stale RequestedServiceType Javadoc in DiscoEntryHandler and impls
- parse gMonthDay values with the shared DatatypeFactory in Time
- extract DSTRequestHandler.toDocument so its test reaches the fix
- add tests for KeySize/X509Data lookup, absent isDefault ACS fallback,
  WS-Fed getAttributes and the gMonthDay prefix normalisation
- drop the duplicate copyright line in WSSPolicyManager
getUserDiscoEntries drops every stored entry it cannot unmarshal and
asks the caller to store the rest, so a regression in the JAXB 3
unwrapping would silently delete a user's discovery entries. Cover
read-back with and without an entryID, a malformed entry, and a
write/read round trip through setUserDiscoEntries.
…on metadata

JAXB 3 does not bind the root element's namespace to the default
namespace and declares every namespace on the root element. String
post-processing of SAML2 exports relied on the JAXB 1 layout:

- workaroundAbstractRoleDescriptor wrote the RoleDescriptor of an
  attribute query descriptor in no namespace, so import dropped it
- CreateFedlet.flipHostedParameter no longer found "<EntityConfig " and
  left the remote IdP marked as hosted in the Fedlet bundle
- the import parses each RoleDescriptor on its own, and its xsi:type
  prefix was declared only on the root, so the import failed

SAML2MetaUtils now marshals with the root namespace as the default
namespace, and the export declares the query prefix on the
RoleDescriptor again. ExportMetaData uses the library workaround
instead of its own copy.

The JAXB 3 unmarshaller also recovers from errors by dropping an
unexpected element, where JAXB 1 rejected the document. SAML2MetaUtils,
IDFFMetaUtils and WSFederationMetaUtils now fail on the first error,
so importing metadata with, for example, a KeyDescriptor in the wrong
namespace fails instead of losing the certificate.

- console SAMLv2ModelImpl reads the key size through KeyUtil.getKeySize
- upgrade guide: list the xs:anyType and mixed-content differences
- make the indented ID-FF test fixture schema-valid
- add tests for the export namespace and re-import, the EntityConfig
  root, rejection of unexpected elements and KeyUtil.getKeySize
JAXB 3 keeps the whitespace-only text of mixed-content types, and the
formatted marshaller indents around it again, so every console save or
export and import of SAML2, ID-FF and WS-Fed metadata added blank lines
inside KeyInfo, EncryptionMethod and the other key and method types.
The three metadata utilities now drop that text on unmarshal through
MixedContentWhitespaceListener. Types whose text can be content are
not registered.

An md:RoleDescriptor with an xsi:type JAXB 3 does not know, such as the
WS-Federation roles of AD FS metadata, failed the import because
RoleDescriptorType is abstract. The import now removes every
RoleDescriptor other than an attribute query descriptor before
unmarshalling. It also copies the live NodeList first, so a second
attribute query descriptor is no longer skipped.

When the JAXB package list adds an element in no namespace, JAXB 3
binds the default namespace to "" and prefixes the metadata namespace.
The exported RoleDescriptor now declares the metadata namespace itself,
and CreateFedlet.flipHostedParameter matches a prefixed EntityConfig
root.

- KeyUtil tests put the whitespace back themselves, so they still pin
  the lookup by type
- pin that the Liberty ID-WSF unmarshallers stay lenient
- upgrade guide: say which unmarshallers drop mixed-content whitespace
…te-2026-05-19

# Conflicts:
#	openam-documentation/openam-doc-source/src/main/asciidoc/upgrade-guide/chap-upgrade-servers.adoc
- SAML2IDPProxyFRImpl: the three extension/attribute guards used
  `x != null || !x.isEmpty()`, which dereferences x exactly when it is
  null. Use `&&` (CodeQL java/dereferenced-value-is-always-null).
- IDFFModelImpl: drop the private static supportedSSOProfileList field
  and its initializer; nothing read it, the other uses in the file are
  local variables of the same name (java/unused-container).
- WSFedPropertiesModelImpl: pass the unwrapped baseConfig to
  updateBaseConfig, as the SP branch already does
  (java/local-variable-is-never-read).

All three were already flagged on master; the migration rewrote the
lines, so CodeQL reported them again on the pull request.
@maximthomas maximthomas added java Pull requests that update java code dependencies Pull requests that update a dependency file build saml SAML / SAML2 federation labels Oct 19, 2026
maximthomas added a commit that referenced this pull request Oct 20, 2026
…lder (#1186)

Since `ubuntu-latest` moved to the `ubuntu-26.04` runner image,
`build-maven` fails in `openam-core-rest` on every Ubuntu leg (JDK 11,
17, 21, 25, 27). It was first seen in run
[39217607024](https://github.com/OpenIdentityPlatform/OpenAM/actions/runs/39217607024)
on #1023, whose changes do not touch this module: `openam-core-rest`
there is identical to `master` (d75bdb8). The same tests were green
on `ubuntu-24.04` three days earlier, and are green on macOS and Windows
in the failing run.

## Cause

`InjectorHolder` builds its injector once per JVM, from the module
loader `InjectorConfiguration` holds at that moment. The modules on this
test classpath cannot be built (`No implementation for
NotificationBroker was bound`). The first test that touches
`InjectorHolder` with the default loader therefore leaves the class
unusable for the rest of the fork.

`SessionResourceV2Test.setUp` constructs a real `AMIdentity`. Its
constructor asks `InjectorHolder` for a `RepoAuditorFactory` and
swallows the failure (`AMIdentity.java:190`).
`IdentityResourceNotificationTest` and `SessionResourceTest` installed
an empty loader, but in `@BeforeClass`, which only helped when they ran
before `SessionResourceV2Test`. Surefire runs the classes in file-system
order, and on `ubuntu-26.04` that order puts `SessionResourceV2Test`
first:

- `IdentityResourceNotificationTest.setupMocks:155` fails with
`NoClassDefFoundError: Could not initialize class
org.forgerock.guice.core.InjectorHolder`, through
`IdentityServicesImpl.<clinit>`.
- That `@BeforeMethod` fails after `RealmTestHelper.setupRealmClass()`,
so the `@AfterMethod` teardown never runs. As a result,
`OathDevicesResourceTest`, `PushDevicesResourceTest`,
`TrustedDevicesResourceTest` and `SmsResourceProviderTest` fail with
`Previously setup Realm class - forgot to call teardown`.

## Change

Test code only.

- `IdentityResourceNotificationTest` installs the empty loader from
`@BeforeSuite(alwaysRun = true)` instead of `@BeforeClass`.
`openam-core-rest` sets no `forkCount`, `parallel` or `suiteXmlFiles`,
so surefire runs all its classes in one TestNG suite, and every
`@BeforeSuite` method runs before the first test, whatever order the
classes are in. The tests get the same empty injector they got on the
green runs. Only the moment the loader is installed changes.
- `SessionResourceTest` and `SessionResourceV2Test` no longer build a
real `AMIdentity`, whose constructor reached `InjectorHolder`. They
return a mock with `getName()` and `getRealm()` stubbed, the only two
getters the session code reads, and they no longer install a loader.
- The `IdentityResourceNotificationTest` javadoc states the limits of
the hook: TestNG instantiates every test class before any `@BeforeSuite`
method runs, and the hook covers the other classes only while the module
runs as one TestNG suite in one JVM.

## Tests

`mvn -o -pl openam-core-rest test -Dsurefire.runOrder=<order>`, run
locally on macOS:

- `reversealphabetical` at `master` puts `session.SessionResourceV2Test`
ahead of `IdentityResourceNotificationTest`, as on `ubuntu-26.04`.
Result: `IdentityResourceNotificationTest.setupMocks` fails with the CI
error, caused at `SessionResourceV2Test.setUp:112`. The default order is
green at `master`.
- With the first version of this change (5f9ef67, a `@BeforeSuite`
hook in all three classes), `reversealphabetical`, `alphabetical`,
`filesystem` and `random` with seeds 1, 42 and 20261019 all pass: 446
passed, 0 failed, 0 skipped each, including
`IdentityResourceNotificationTest` 8/8, `SessionResourceTest` 33/33 and
`SessionResourceV2Test` 26/26.
- Each of the three classes alone (`-Dtest=<class>`) passes.
- At 0c41e0a (after review): `reversealphabetical`, the default order
and `-DreuseForks=false` (53 classes, each in its own JVM) all pass,
446/0/0. With the `IdentityResourceNotificationTest` hook put back on
`@BeforeClass`, `reversealphabetical` still passes (446/0), so neither
session class reaches `InjectorHolder`. With `SessionResourceV2Test`
building a real `AMIdentity` again, the same run fails as on
`ubuntu-26.04`.

Locally, the `ubuntu-26.04` order is only approximated by
`reversealphabetical`. This PR's own CI run checks the real image.
maximthomas and others added 2 commits October 20, 2026 18:08
…te-2026-05-19

Conflicts with the GHSA series on master:
- SAML2Utils.isSPProfileBindingSupported: keep master's null check on the SP
  descriptor and the JAXB 3 endpoint list type.
- SPACSUtils: keep master's GHSA-3j2f comment and the getValue() unwrap.
- ValidRelayStateExtractor (SAML2), ValidWReplyExtractor (WS-Fed): keep master's
  role resolution through the getSPSSOConfig/getIDPSSOConfig seams, and unwrap
  the JAXB 3 config element inside the seams so they still return BaseConfigType.
- LibertyManager, SAML2UtilsTest: keep the imports and tests of both sides.
- chap-upgrade-servers.adoc: keep master's PKCE and SAML 1.x notes and the
  JAXB 3 note as separate blocks.
- Copyright header lines: take master's.

Master code that merged cleanly but was written against JAXB 1:
- SPACSUtils.getResponseFromArtifact: unwrap the SP descriptor and read the
  nullable WantAssertionsSigned with Boolean.TRUE.equals.
- ID-FF ValidRelayStateExtractor: unwrap SP/IDP descriptor configs.
- Tests (SAML2UtilsTest, FSPostLoginTest, HostedProviderFixture,
  LibertyManagerTest, the three relay state / wreply extractor tests): build
  the config and descriptor wrappers the way JAXB 3 returns them, with entity
  config attributes as AttributeElement.
@vharseko

Copy link
Copy Markdown
Member

@maximthomas Merged current master (4d5cca0, the 16.1.4 release with the GHSA series) into the branch to clear the conflicts: 564e8ff. As with the earlier updates it is a merge rather than a rebase, so your commits are unchanged and the push was a fast-forward.

Conflicts

  • Copyright header lines (ResourceOwnerSessionValidator, IOUtils, SA_SP.jsp, spSingleLogoutInit.jsp, realmSelection.jsp, the two extractors): master's lines.
  • SAML2Utils.isSPProfileBindingSupported: master's null check on the SP descriptor, with this branch's JAXB 3 endpoint list type.
  • SPACSUtils: master's GHSA-3j2f comment, with this branch's getValue() unwrap.
  • SAML2 ValidRelayStateExtractor and WS-Fed ValidWReplyExtractor: master's role resolution through the getSPSSOConfig / getIDPSSOConfig seams (GHSA-2gwf). The seams now unwrap the JAXB 3 config element, so they still return BaseConfigType.
  • LibertyManager, SAML2UtilsTest: the imports and tests of both sides.
  • chap-upgrade-servers.adoc: master's PKCE (GHSA-h93p) and SAML 1.x (GHSA-j56q) notes, and the JAXB 3 note as a separate [IMPORTANT] block.

Master code that merged without conflicts but was written against JAXB 1

  • SPACSUtils.getResponseFromArtifact: spDesc.isWantAssertionsSigned() became Boolean.TRUE.equals(spDesc.getValue().isWantAssertionsSigned()), as elsewhere on this branch.
  • The new ID-FF org.openidentityplatform.openam.federation.plugins.ValidRelayStateExtractor: unwraps SPDescriptorConfigElement / IDPDescriptorConfigElement.
  • Seven test classes from master mocked the *Element classes as if they were the config types: SAML2UtilsTest, FSPostLoginTest, HostedProviderFixture, LibertyManagerTest, and the SAML2 and ID-FF ValidRelayStateExtractorTest and ValidWReplyExtractorTest. They now build the wrappers the way JAXB 3 returns them (new SPSSOConfigElement(config), new AttributeElement(attribute), ...). Test data and assertions are unchanged.

The build does not compile JSPs, so I compared their imports by hand after the merge: none were lost, and the JSP changes from master do not touch JAXB types.

Verification

  • test-compile of the 13 modules that use the federation JAXB types (federation library, OpenFM, console, auth-saml2, cli-impl, oauth2, oauth2-saml2, uma, REST STS, token service STS, upgrade, core-rest, shared): BUILD SUCCESS.
  • Tests: federation library 753, OpenFM 50, shared 61, idpdiscovery 20, console 2, all passing.

One leftover, not changed in the merge: SerialStreamScanner.COLLECTION_CLASSES (GHSA-x7wr) still lists com.sun.xml.bind.util.ListImpl and ProxyListImpl, which this branch removes from the deserialisation whitelists. It is harmless, since this branch drops the JAXB 1 runtime they come from, but the entries could be dropped here for consistency.

@vharseko vharseko added tests Test suite: coverage, fixtures, or test infrastructure documentation Documentation, README, or javadoc ui XUI / admin console / end-user UI labels Oct 22, 2026

@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.

Reviewed head 564e8ff383ec6d5c76bffea14f7d78486656d047 against merge base 4d5cca0e5d52a4cad9633f1a042a92a40865cc01, including the complete discussion history and linked issues #980 and #1185.

No new actionable code defects found in the areas reviewed: JAXB element/value conversions, optional metadata values, mixed-content handling, namespace round trips, federation call sites, dependency changes, and the changed server JSPs. Previously resolved findings and the explicitly tracked client SDK limitation in #1185 are not being raised again.

Validation: a fresh local reactor build regenerated the schema classes and passed 62 targeted federation tests on JDK 27 / Maven 3.10.0, with zero failures, errors, or skips. These cover SAML2/ID-FF/WS-Fed metadata, key extraction, SLO endpoint lookup, ACS defaults, attribute values, encrypted resource IDs, and Personal Profile dates. The nine Maven CI matrix jobs and Docker build are also green for this head.

CodeQL remains red. Its critical annotation points to the unchanged deserialization call in IOUtils; this PR only removes the obsolete JAXB 1 classes from that file's whitelist. I did not identify a new deserialization defect introduced by this change.

Integration is currently blocked by a conflict with origin/master (a13a83cb78) in openam-documentation/openam-doc-source/src/main/asciidoc/upgrade-guide/chap-upgrade-servers.adoc. GitHub reports CONFLICTING, and a local merge-tree check confirms the conflict. Validation above applies to the current PR head, not a future conflict resolution.

Limits: this review did not repeat deployed end-to-end or mixed-version upgrade testing. The legacy multiprotocol JSP samples still contain JAXB 1 accessor calls, but I could not establish that the current Maven distribution packages them, so I am recording this as a follow-up caveat rather than a blocking finding.

…te-2026-05-19

# Conflicts:
#	openam-documentation/openam-doc-source/src/main/asciidoc/upgrade-guide/chap-upgrade-servers.adoc
The Fedlet index.jsp and fedletSampleApp.jsp include header.jspf, which
still called getSingleSignOnService(), getAssertionConsumerService(),
getBinding() and getLocation() on the IDPSSODescriptorElement,
SPSSODescriptorElement, SingleSignOnServiceElement and
AssertionConsumerServiceElement wrappers. Under JAXB 3 these are
JAXBElement subclasses without those methods, so Jasper failed to
compile both pages. The default build does not precompile JSPs, so
only a request at runtime showed it. Read the content through
getValue(), as SA_IDP.jsp already does.
@maximthomas

Copy link
Copy Markdown
Contributor Author

Addressed in 756605d and 6af59de:

  • Merged origin/master (a13a83cb78) in 756605d. The only conflict was chap-upgrade-servers.adoc, where both sides appended an [IMPORTANT] block after the SAML v1.x one; kept both, master's three blocks first, then the JAXB 3 block.
  • On the JSP caveat: no pom or assembly references openam-federation/OpenFM/src/main/samples, and neither WAR nor the distribution kit contains those files, so the multiprotocol (and idff/saml2) samples are not shipped. Checking the packaged JSPs for the same pattern found the Fedlet's header.jspf (included by index.jsp and fedletSampleApp.jsp), which still called getSingleSignOnService(), getAssertionConsumerService(), getBinding() and getLocation() on the *Element wrappers. The default build does not precompile JSPs, so this only failed at runtime. Fixed in 6af59de by unwrapping with getValue(); compiling the page's declarations against the generated JAXB 3 classes fails before the fix and passes after it.
  • CodeQL: the failing annotation is alert #8016 at IOUtils.java:361, which is open on master as well; this PR only removes the two JAXB 1 classes from that file's whitelist.

@maximthomas
maximthomas requested a review from vharseko November 3, 2026 07:22

@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.

Reviewed head 6af59de75ac8c986c3dfc014981f806583b06d6e, focusing on the changes since the previous review at 564e8ff383ec6d5c76bffea14f7d78486656d047: the merge of current master (756605d8dd) and the Fedlet JSP fix (6af59de75a). I read the complete PR discussion, including earlier reviews and author replies, and linked issues #980 and #1185.

No new actionable defects found in this follow-up review.

  • The merge conflict is resolved correctly: all three new upgrade notes from master and the JAXB 3 migration note are preserved as separate blocks. The current master (a13a83cb78) is an ancestor of this head, and GitHub reports MERGEABLE.
  • The Fedlet fix correctly unwraps the descriptor and endpoint elements. I compiled both complete consuming pages, index.jsp and fedletSampleApp.jsp, with Tomcat Jasper 10.1.41 against the freshly built JAXB 3 classes: both passed and produced servlet class files. Repeating the same compilation with the pre-fix header.jspf failed on the six obsolete accessor calls in each page, confirming that the fix removes the compilation regression.
  • A fresh Maven reactor build regenerated the federation schemas and passed all 62 selected federation tests on JDK 27 / Maven 3.10.0, with zero failures, errors, or skips.
  • The Maven packaging configuration does not include the legacy OpenFM/src/main/samples tree. The earlier sample-JSP caveat and the separately tracked client SDK limitation in #1185 are not being raised as new findings.

Validation limits: this was a follow-up review of the two new commits and their integration, not a repeat of every earlier migration review. Deployed SSO/SLO, end-to-end flows, and mixed-version upgrades were not exercised. CI for this exact head is still queued or in progress, so its final result remains outstanding.

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

Labels

build dependencies Pull requests that update a dependency file documentation Documentation, README, or javadoc help wanted java Pull requests that update java code needs testing refactoring Code cleanup, refactor, dead-code or dependency removal saml SAML / SAML2 federation tests Test suite: coverage, fixtures, or test infrastructure ui XUI / admin console / end-user UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAM has doubled in size since version 14

3 participants