Repository navigation
[#1221] e2e characterization tests for OIDC discovery, JWKS and idtokeninfo - #1222
Merged
maximthomas merged 4 commits intoNov 6, 2026
Conversation
…iscovery, JWKS and idtokeninfo
The provider's codeVerifierEnforced defaults to true and the device flow does not consult it, so the shared provider does enforce PKCE for authorization requests.
…gnature check and unknown-realm discovery Four tests recorded on master: idtokeninfo with a wrong client secret and without client credentials (400 invalid_client), with a forged signature (400 invalid id_token), and discovery under an unknown realm (404). at_hash and c_hash are compared with the left half of the SHA-256 digest of the access token and the code. The authorize and token exchange runs only for the issuance and idtokeninfo tests, so discovery and jwk_uri no longer depend on it. authorizationCodeTokens returns the code next to the token response and fails with the Location when authorize redirects without a code. The RS256 note on the OIDC client names the measured answer.
vharseko
approved these changes
Nov 6, 2026
vharseko
left a comment
Member
There was a problem hiding this comment.
Reviewed PR #1222 at 9fe0246, including the PR description and the scope defined in #1221 and #1075.
No actionable findings. The added fixtures and assertions are consistent with the current Restlet handlers, and the per-spec client avoids interference with the existing OAuth2/UMA clients.
Validation: both changed JavaScript files pass node --check, and git diff --check is clean. I inspected the build-docker job log and confirmed that all 11 OIDC tests passed in the shared run (90 passed, 1 unrelated test skipped). I did not rerun live e2e locally because no OpenAM container was running.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
#1221 (a step of #1075) pins the HTTP contract of
/oauth2with e2e tests that pass on master, where Restlet still serves/oauth2. The endpoint families then move to CHF one PR at a time. A test that passes unchanged after a move is that PR's parity proof, and any expectation a move changes must be a divergence listed in that PR.This is the first part of #1221: OIDC discovery,
connect/jwk_uri, id_token issuance andidtokeninfo. It adds no production code.What
e2e/oauth2/oidc-test.spec.mjs: 11 tests, 7 ported from the branch and 4 new.e2e/common/oauth2-fixtures.mjs: the fixtures they need.The 7 ported tests are lines 1-202 of
e2e/oauth2/oidc-test.spec.mjsat maximthomas/OpenAM@59a89d07cc, the parent ofbccbc9c4d9, which moved/oauth2to CHF on the abandonedfeatures/restlet-migrationbranch of the fork. The other 13 tests of that file coverconnect/checkSessionandconnect/endSessionand come in the next PR, together with their fixtures (post-logout redirect URIs,clientSessionURI, a client without it).Fixtures
OIDC_CLIENT_SECRETandensureOidcClient: a confidential client whose id_tokens are signed with HS256. The secret is long because HS256 signs with it and needs a key of at least 256 bits; a short one makes the token endpoint answer a bareserver_error.pkce,sessionContextandauthorizationCodeTokens: a full authorization_code exchange with an S256 challenge, authenticated by the session cookie./oauth2/authorizedoes not accept theiPlanetDirectoryProheader.authorizationCodeTokensreturns{code, tokens}, so a test can checkc_hashand still compare the token response whole. An authorize redirect without acode(redirect_uri?error=..., the login page) throws with itsLocationinstead of sending no code to the token endpoint.REQUIRED_SCOPESgainsopenidandprofile, soensureProviderConfigadds them to the shared provider's supported scopes. It only ever adds scopes.Not taken from the branch: its
ensureOAuth2ProviderwrotecodeVerifierEnforced: true, but only when it created the provider, so the setting depended on which spec file ran first. This PR leaves the setting as configured. On master it defaults totrueand no fixture changes it;authorizationCodeTokenssends an S256 challenge either way.Changed expectations
None. The branch spec, trimmed to the 7 ported tests and run unchanged against master, passed 7/7. Master's changes since the branch was recorded do not touch these answers.
Assertions tightened beyond the branch
All values were recorded from master.
Content-Typeis asserted exactly. Discovery,connect/jwk_uriand the 200 fromidtokeninfoanswerapplication/json;charset=UTF-8. The two 400 answers ofidtokeninfoanswerapplication/jsonwithout a charset. The branch checkedtoContain("application/json"), and its header comment said Restlet answers bareapplication/json; that holds only for the errors.OPENAM_BASE. The branch checked 7 of them;registration_endpoint,introspection_endpoint,revocation_endpointanddevice_authorization_endpointare new./oauth2/realms/root/.well-known/openid-configurationmust answer the same document as the bare path, compared whole. The branch checked two members. The test is renamed tothe realm-prefixed discovery path answers the same document.keys.access_token,expires_in,id_token,nonce,refresh_token,scope,token_type), andscopeholds exactlyopenidandprofile.idtokeninfoerrors compare the whole body:{"error":"bad_request","error_description":"no id_token in request"}and{"error":"bad_request","error_description":"invalid id_token: not right number of dots, 2"}. The branch checked the second description withtoContain("invalid id_token").at_hashandc_hashare compared with the unpadded base64url left half of the SHA-256 digest of the access token and of the code (HS256). The branch checked that they were present.test.skipon a failed amadmin login is now anexpect, and the demo login is checked too, so a broken setup fails instead of skipping.beforeAllof the issuance/idtokeninfo describe, not at file level. A move that breaks/oauth2/authorizeor/oauth2/access_tokenno longer turns the discovery andconnect/jwk_uritests red.New tests
None of them is on the branch. Each answer was recorded on master, and each test pins the status, the exact
Content-Typeand the whole body.the discovery path of an unknown realm answers 404:/oauth2/realms/root/realms/no-such-realm/.well-known/openid-configurationanswers 404application/json{"code":404,"reason":"Not Found","message":"No mapping organization found for organization identifier: /no-such-realm"}. The realm-prefixed test above only usesroot, so on its own it cannot tell realm routing from a router that drops the realm segment.idtokeninfoclient authentication (idTokenInfoClientAuthenticationEnableddefaults to true, and HS256 is an HMAC algorithm): a wrong client secret and a request without client credentials both answer 400{"error":"invalid_client","error_description":"no registered client matches audience of id_token"}. Master gives a failed client authentication the same description as anaudthat matches no client: theInvalidClientExceptioncatch inIdTokenInfocovers both. This answer is the contract: a move keeps it, or lists the change as a divergence.idtokeninfosignature check: an id_token whose first signature character is flipped answers 400{"error":"bad_request","error_description":"invalid id_token"}.The fixture comment on
idTokenSignedResponseAlgsaid an RS256 client makes idtokeninfo fail withserver_error. Run on master, it answers 400invalid id_token: this client registers no public key. The comment is corrected.Not pinned:
Server: Restlet-Framework/2.4.4, which every one of these answers carries: a framework value.scopes_supported,response_types_supported,subject_types_supportedandid_token_signing_alg_values_supportedstayarrayContaining, as on the branch.scopes_supportedmirrors the shared provider, which the parallel specs widen.How it was checked locally
The image was
FROM openidentityplatform/openam:latestwith the WAR replaced, configured the waybuild-dockerconfigures it (embedded stores locally; CI uses an external OpenDJ user store). The WAR is a local full build of master2a80c16a9a.IdTokenInfocompiled without the client authentication call and without the signature check, patched into a copy of the WAR. 3 failed and 8 passed in both runs. The 3 are the wrong-secret, no-credentials and forged-signature tests, and each got a 200 with the claim set.e2e/oauth2,e2e/umaande2e/xacmltogether (oidc 11, oauth2-test 5, device-flow-test 9, webfinger 11, uma 14, xacml 23), twice on one fresh container: 73 passed in both runs. No master spec turned red next to this one.Part of #1221.