Repository navigation
[#1221] e2e characterization tests for /oauth2 in a non-root realm - #1233
maximthomas wants to merge 6 commits into
Conversation
…2 in a non-root realm Ports realms-test.spec.mjs from the restlet-migration branch and pins what master answers on Restlet: discovery, the token endpoint (client_credentials and password grants), tokeninfo and authorize in a sub-realm with its own provider, client and user, through the nested, legacy, flat and ?realm= spellings, plus the unknown-realm, unrouted-path and unknown-Host answers. The unknown Host's 500 is pinned with a comment naming the target, 400 invalid_request.
…in the token test comment
…ealm and case-insensitive answers
…the scheme of OPENAM_BASE_URL raw() always used node:http with a port-80 fallback. Against an https OPENAM_BASE_URL it wrote plaintext to the TLS port, or connected to :80 when the URL had no port, while every Playwright request in the spec followed the base URL. It now picks node:https for an https base and defaults to port 443. The TLS server name is set to the stand's host, because Node otherwise takes it from the overridden Host header and the unknown-Host legs would fail the certificate's name check. The certificate is still verified: a stand with a self-signed one passes its CA in NODE_EXTRA_CA_CERTS.
…d and flat spellings too The case-insensitivity test upper-cased only the legacy /oauth2/<SUB> segment, which RestletRealmRouter resolves. The nested and flat spellings go through RealmRoutingFactory's Restlet router, the one the move to CHF replaces, so a case-sensitive match there left the test green. Both legs, tokeninfo and the realm-scoped client_credentials grant, now run on the three path spellings, the nested one with root upper-cased too.
vharseko
left a comment
There was a problem hiding this comment.
[P2] Assert that successful token responses contain usable tokens — realms-test.spec.mjs:166–168
expectToken checks that the token fields exist, but never checks their values. A 200 response containing "access_token": null passes all of these assertions; password-grant responses can likewise contain a null refresh_token. The path-spelling and password-grant tests do not consume those tokens afterward, so they would stay green even though the endpoint no longer issues usable credentials. The original tests asserted that the access token was non-empty. Please retain that assertion for each response, and check the refresh token on password-grant responses as well.
|
Addressed the token-value assertion review in 461fe65afe.
Validation: all 91 local OAuth2, UMA and XACML tests passed, including all 10 realm tests, against |
vharseko
left a comment
There was a problem hiding this comment.
The previous finding is addressed. expectToken now requires a non-empty string for every checked access token and for refresh tokens in password-grant responses. I found no further issues in this fix.
CI checks are still queued.
Why
#1221 (a step of #1075) pins the HTTP contract of
/oauth2with e2e tests that pass on master, where Restlet still serves/oauth2. A test that passes unchanged after the move to CHF is that PR's parity proof, and any expectation a move changes must be a divergence listed in that PR.This part covers the non-root-realm deployment shape. No master spec puts a provider, a client and a user in a sub-realm. It adds no production code and no workflow change.
What
One new spec,
e2e/oauth2/realms-test.spec.mjs, with 10 tests. It builds its own sub-realm per worker (provider, confidential client, user) and drives the four realm spellings (/oauth2/realms/root/realms/<sub>,/oauth2/realms/<sub>,/oauth2/<sub>,/oauth2?realm=<sub>) against:?realm=, client authentication on the path spellings, the password grant);?realm=, unknown Host, upper-cased realm segment.The tests are the 10 of
e2e/oauth2/realms-test.spec.mjsat commit b02024a of maximthomas/OpenAM, on the abandonedfeatures/restlet-migrationbranch of the fork, which was written against the CHF port of/oauth2. Where the branch disagrees with master, the test follows master. Fixtures are not touched: the spec imports onlyREDIRECT_URI,basicAuthandsessionContextfromoauth2-fixtures.mjs.Realm and user per worker
The realm name and the user name carry a per-worker suffix. A realm created through
/json/global-config/realmscopies root's data-store config, so its users are written to root's directory, and deleting the realm keeps the user. A fixed name would answer 409 on a second run or from a parallel worker.afterAlldeletes the user, then the realm, only if this worker created them. No 409 is tolerated.Changed expectations
Run verbatim on master, the branch spec had 8 tests green and 2 red. The rewritten spec differs from the branch in these places:
redirect_uriinsidegotosingly encoded (http://app.invalid/cb)gotois the request URL as sent (redirect_uri=http%3A%2F%2Fapp.invalid%2Fcb){"error":"not_found","error_description":"Realm "/nosuchsub" not found"}(flat form without the slash){"code":404,"reason":"Not Found","message":"No mapping organization found for organization identifier: /nosuchsub"}for both forms{"error":"not_found","error_description":"Not Found"}?realm=(bogus,<sub>/nosuch){"error":"invalid_request","error_description":"Invalid realm, <value>"}{code,reason,message}naming the value as giveninvalid_request, two different descriptions by spelling{"code":500,"reason":"Internal Server Error","message":"No mapping organization found for organization identifier: not-a-real-host.invalid"}on all threeThe other tests, and every success answer, hold the branch's values with the exceptions under "tightened" below.
Assertions tightened beyond the branch
All values were recorded from master.
Content-Typeis asserted exactly. Discovery answersapplication/json;charset=UTF-8; the token 200 answers bareapplication/json.{code,reason,message}404 envelope of an unknown realm.profile): the scope validator adds each granted scope as a member valued from the client's attribute of that name. It is part of the pinned member set./oauth2/nosuchsub/..., which the branch never requested. Master answers it with the same 404{code,reason,message}envelope naming/nosuchsub, here thrown byRestletRealmRouter(on the nested and flat spellings byRealmRoutingFactory's Restlet router)./oauth2/<SUB>, matched byRestletRealmRouter, and/oauth2/realms/ROOT/realms/<SUB>and/oauth2/realms/<SUB>, matched byRealmRoutingFactory's Restlet router, which the flip replaces. Each spelling also gains a realm-scoped leg: a client_credentials request gets a 200 token with the sub-realm's client, which exists only in the sub-realm. The branch's tokeninfo leg alone (401invalid_token) would also pass if the segment fell back to root, because tokeninfo is not realm-scoped.Not pinned: the
Server: Restlet-Framework/2.4.4header, and the bodies of unrouted 404 answers, which are framework values.Defects pinned
An unknown
Hostunder a sub-realm is a 500 on master, whatever the spelling, because the failed lookup of the Host's realm surfaces as an internal error. The target is 400invalid_request, a client error. The test pins master's 500 and its comment names the target.Evidence
All runs were local, on a container built
FROMthe published image with the WAR of masterb9cd122c78(no production change after #1219), embedded config and user store, two Playwright runs on one container.e2e/oauth2,e2e/uma,e2e/xacmlwith this one, final versionrealms-testshows 10 passed in both runs.invalid_token) failed on 404; the upper-cased token leg (expected 401) failed on 200.httpRequest.setAttributecalls that hand the realm to the login):RestletRealmRouterinopenam-restlet. Tests 3 and 10 (client authentication on the path spellings, the password grant) are red on the legacy/<sub>leg with 401invalid_client.RealmRoutingFactoryinopenam-rest. Tests 3 and 10 are red on the nested leg with 401invalid_client.?realm=token test stays green through the query fallback.RealmRoutingFactoryanswers 404 for a realm segment that is not lower case,rootstill in any case. Test 9 is red on its nested leg (404 instead of 401invalid_token), after its legacy legs passed. The test stops there; on the same container, for a probe realm, the upper-cased flat spelling answers the same 404, and the lower-case spellings still answer 401.OPENAM_BASE_URL. Through a local TLS proxy in front of the master container, with its self-signed certificate inNODE_EXTRA_CA_CERTS, tests 8 and 9 passed onhttps://…:8443/openamand onhttps://…/openam(port 443). On:8443the previous version failed both withsocket hang up.oauth2realms*and no userrealmuser*is left on the container after any run.CI's
build-dockerruns this spec against an external OpenDJ user store; its result is not in this table.Notes for the flip
The token endpoint's client and resource-owner logins in a path-spelled realm read the realm from the servlet request attribute
realm. On the/realms/...spellings it is written byRealmRoutingFactory's Restlet router, on the legacy/{subrealm}spelling byRestletRealmRouter. A flip that resolves the realm elsewhere has to hand it to the login, or these logins fall back to the host's realm and answer 401invalid_client(tests 3 and 10).?realm=keeps working through the query fallback.The realm segment matches in any case on all three path spellings,
rootincluded (test 9).Part of #1221.