Files
rose-ash/lib/identity/tests/clients.sx
giles 9860582b4a
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
identity: OAuth client registry — public/confidential clients + redirect allow-list (11 tests)
clients.sx (RFC 6749 §2) — confidential clients must present the correct
secret at the token endpoint (wrong → invalid_client); public clients are
identified but not authenticated; redirect_uris are pre-registered and
checked by exact-match valid_redirect (§3.1.2.2 + Security BCP). Standalone
module for now; wiring confidential-client auth into oauth exchange is a
follow-up. New tests/clients.sx. 149/149.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 02:03:44 +00:00

109 lines
4.6 KiB
Plaintext

;; identity/tests/clients.sx — OAuth client registry: registration,
;; public vs confidential authentication, and redirect_uri allow-listing.
(define id-clients-test-count 0)
(define id-clients-test-pass 0)
(define id-clients-test-fails (list))
(define
id-clients-test
(fn
(name actual expected)
(set! id-clients-test-count (+ id-clients-test-count 1))
(if
(= actual expected)
(set! id-clients-test-pass (+ id-clients-test-pass 1))
(append! id-clients-test-fails {:name name :expected expected :actual actual}))))
(define idc-ev erlang-eval-ast)
(define idcnm (fn (v) (get v :name)))
(identity-load-clients!)
;; ── registration + lookup ────────────────────────────────────────
(id-clients-test
"a registered client looks up its type"
(idcnm
(idc-ev
"C = identity_clients:start(),\n identity_clients:register(C, app1, confidential, s3cret, [uri1]),\n case identity_clients:lookup(C, app1) of\n {ok, Type, _} -> Type;\n {error, W} -> W\n end"))
"confidential")
(id-clients-test
"registering the same client twice is an error"
(idcnm
(idc-ev
"C = identity_clients:start(),\n identity_clients:register(C, app1, confidential, s3cret, [uri1]),\n case identity_clients:register(C, app1, public, none, [uri1]) of\n ok -> ok;\n {error, W} -> W\n end"))
"exists")
(id-clients-test
"looking up an unregistered client is unknown_client"
(idcnm
(idc-ev
"C = identity_clients:start(),\n case identity_clients:lookup(C, ghost) of\n {ok, _, _} -> found;\n {error, W} -> W\n end"))
"unknown_client")
;; ── confidential client authentication ───────────────────────────
(id-clients-test
"a confidential client authenticates with the right secret"
(idcnm
(idc-ev
"C = identity_clients:start(),\n identity_clients:register(C, app1, confidential, s3cret, [uri1]),\n case identity_clients:authenticate(C, app1, s3cret) of\n {ok, Kind} -> Kind;\n {error, W} -> W\n end"))
"confidential")
(id-clients-test
"a confidential client with the wrong secret is invalid_client"
(idcnm
(idc-ev
"C = identity_clients:start(),\n identity_clients:register(C, app1, confidential, s3cret, [uri1]),\n case identity_clients:authenticate(C, app1, wrongsecret) of\n {ok, _} -> accepted;\n {error, W} -> W\n end"))
"invalid_client")
(id-clients-test
"a public client needs no secret to authenticate"
(idcnm
(idc-ev
"C = identity_clients:start(),\n identity_clients:register(C, spa, public, none, [uri1]),\n case identity_clients:authenticate(C, spa, anything) of\n {ok, Kind} -> Kind;\n {error, W} -> W\n end"))
"public")
(id-clients-test
"authenticating an unknown client is unknown_client"
(idcnm
(idc-ev
"C = identity_clients:start(),\n case identity_clients:authenticate(C, ghost, x) of\n {ok, _} -> accepted;\n {error, W} -> W\n end"))
"unknown_client")
;; ── redirect_uri allow-listing ───────────────────────────────────
(id-clients-test
"a registered redirect_uri is valid"
(idcnm
(idc-ev
"C = identity_clients:start(),\n identity_clients:register(C, app1, confidential, s3cret, [uri1, uri2]),\n case identity_clients:valid_redirect(C, app1, uri1) of\n true -> yes;\n false -> no\n end"))
"yes")
(id-clients-test
"a second registered redirect_uri is also valid"
(idcnm
(idc-ev
"C = identity_clients:start(),\n identity_clients:register(C, app1, confidential, s3cret, [uri1, uri2]),\n case identity_clients:valid_redirect(C, app1, uri2) of\n true -> yes;\n false -> no\n end"))
"yes")
(id-clients-test
"an unregistered redirect_uri is rejected"
(idcnm
(idc-ev
"C = identity_clients:start(),\n identity_clients:register(C, app1, confidential, s3cret, [uri1]),\n case identity_clients:valid_redirect(C, app1, evil_uri) of\n true -> yes;\n false -> no\n end"))
"no")
(id-clients-test
"redirect validation for an unknown client is rejected"
(idcnm
(idc-ev
"C = identity_clients:start(),\n case identity_clients:valid_redirect(C, ghost, uri1) of\n true -> yes;\n false -> no\n end"))
"no")
(define
id-clients-test-summary
(str "clients " id-clients-test-pass "/" id-clients-test-count))