Authentication suites

  1. Why the harness owns the identity providers
  2. What is tested
  3. Capabilities
  4. Where tokens come from
  5. Run it yourself
  6. Against a third-party server

Why the harness owns the identity providers

The interesting authentication tests are the negative ones. Does the server refuse a token that is expired, signed by the wrong key, meant for another audience, or signed with alg: none? Does the authorization server refuse a credential whose signature does not verify, or an ID Token from a provider the subject never named? And does the storage answer 401 with a proper WWW-Authenticate challenge? A real identity provider will not mint broken credentials on request, so Touchstone brings its own, and makes each one with exactly one defect. The definitions name these as identities (alice-expired, didkey-bad-signature, oidc-untrusted-issuer); definitions/lws10/identities.yamlld says what each defect is.

What is tested

Area Tests What they exercise
Storage authorization (core/storage_authorization) 19 The 401 challenge and the protected resource metadata it names (RFC 9728), the owner’s access, a non-owner refused, and the access-token negative matrix: expired, not yet valid, issued in the future, wrong audience, wrong issuer, corrupted signature, unknown key, alg: none.
Authorization server (core/authorization_server) 9 RFC 8414 metadata at /.well-known/lws-configuration, with the subject token and identifier types it lists, and RFC 8693 token exchange: a valid exchange, an unknown or missing resource, a missing subject token, and the storage accepting the token it issued.
Access grants (core/access_grants) 17 The access grant service, public and per-agent grants, the grant document and its constraints, an incomplete grant refused, revocation, a grant announced in its inbox, access requests.
OpenID Connect (auth/oidc) 6 Token exchange with an ID Token from the harness’s OpenID Provider, which the subject’s controlled identifier document names, and five defects, including a provider the subject never named.
Controlled Identifiers (auth/cid) 22 Two kinds of subject. With an HTTPS subject (authn-cid-*): token exchange with a self-issued credential whose key the verifier finds in a CID document the harness hosts, embedded or referenced by id, and nine defects, including a kid that names no key, a revoked key and a key another identifier controls. With a did:key subject (authn-cid-didkey-*), whose DID document the verifier derives from the identifier: token exchange and ten defects: signature, alg: none, expired, mismatched claims, an audience without the authorization server, no exp, no iat, no sub, no iss, no client_id.
SAML 2.0 (auth/saml) 3 Token exchange with a signed assertion from the harness identity provider, an altered one, and an unsigned one.

All of them pass against the secured reference deployment, and the self-test loop shows that each negative test fails against a broken twin that accepts what it should refuse.

Capabilities

What a test needs from the deployment, beyond the server itself, is a capability the target declares. A test that needs one the target lacks is inapplicable.

Capability Meaning The target provides
Authentication The storage challenges anonymous requests, and alice and bob are distinct authenticated agents. Tokens for alice and bob (see below), and their CID URLs as cidUrl.alice and cidUrl.bob when grants name them.
HarnessIssuedTokens The storage trusts an authorization server whose signing key the harness holds, so the harness can mint valid tokens with one chosen defect. as.signingKey: the authorization server’s private JWK.
ReachableFixtures The target can reach the harness’s fixture host, which serves the CID and OpenID documents it dereferences. fixtures.baseUrl: the URL the target uses for it, and fixtures.bind if the harness must listen elsewhere.
SamlTrust The authorization server trusts the harness identity provider’s signing key. saml.idpKey: an RSA private JWK, and saml.idpCertificate if the trust is by certificate.

Where tokens come from

alice and bob send Authorization: Bearer <token>, from the first source that applies:

  1. Minted by the harness, with HarnessIssuedTokens: an RFC 9068 access token signed with the authorization server’s key, for the storage the storage’s 401 links to.
  2. Exchanged, when didkey.jwk.<name> gives the identity a P-256 did:key: the engine exchanges a CID-suite credential for that DID subject at the token endpoint, exactly as the token-exchange tests do.
  3. Static, from token.<name> or TOUCHSTONE_TOKEN_<NAME>.
  4. None, on a target that does not declare Authentication.

A fault identity starts from its basis’s token. Three faults need no key, so they apply to any target with real JWTs: a corrupted signature, alg: none, and a re-signature by a key nobody publishes. The others need HarnessIssuedTokens, except Expired, which without it waits for a real token to expire, when that is at most ten minutes away.

The subject credentials of the three suites are minted per test: for CID, a P-256 key per run behind either a did:key (its DID document derived, nothing hosted) or a document the harness hosts, ID Tokens from the harness’s own OpenID Provider (and from a rogue one), and SAML assertions signed with enveloped XML Signature by the JDK’s own XML Signature API.

Run it yourself

The secured reference deployment starts the reference authorization server and a reference storage that trusts it, and writes a target registry that declares all four capabilities. Build once (./mvnw -q clean install -DskipTests), then start it from the repository root:

./mvnw -q -pl harness-fixtures exec:java \
  -Dexec.mainClass=com.ebremer.touchstone.fixtures.SecuredRefScenarioMain \
  -Dexec.args=targets-secured.yaml

The command writes targets-secured.yaml to the repository root; Git ignores that file, which holds throwaway keys. It prints the two servers’ addresses and keeps running. In a second terminal:

touchstone run --target secured-ref --targets targets-secured.yaml --module auth
[passed      ] MUST   auth/oidc/manifest#authn-oidc-valid-id-token (381 ms)
[passed      ] MUST   auth/oidc/manifest#authn-oidc-expired-id-token (206 ms)
[passed      ] MUST   auth/oidc/manifest#authn-oidc-alg-none (189 ms)
...
[passed      ] MUST   auth/cid/manifest#authn-cid-didkey-valid-credential (300 ms)
...
31 passed, 0 failed, 0 cantTell, 0 inapplicable  (target secured-ref, run 5759ac9a)
conformant: no MUST test failed or ended cantTell

Leave out --module to run all 219 definitions against it.

Key rotation during a session is tested at fixture level: after the authorization server retires its signing key, a token that was valid stops validating.

Against a third-party server

  • Storage authorization. With real tokens for alice and bob as TOUCHSTONE_TOKEN_ALICE and TOUCHSTONE_TOKEN_BOB, declare Authentication. The challenge, owner and non-owner tests apply, and so do the three signature faults if the tokens are JWTs. The other faults need HarnessIssuedTokens, which only a deployment whose authorization server shares its key with the harness can declare; the self-test loop shows those tests can tell a compliant server from a broken one.
  • Token exchange and did:key subjects. A did:key needs no trust set up in advance and nothing the server must reach, so the authorization server tests and the CID suite’s did:key-subject tests apply to any server whose metadata lists did:key among its subject identifier types. They are inapplicable otherwise.
  • CID with an HTTPS subject, and OpenID Connect. The authorization server must reach the harness’s fixture host: declare ReachableFixtures and set fixtures.baseUrl to the harness’s address as the server sees it.
  • SAML. The authorization server must trust the harness identity provider: declare SamlTrust, give its key as saml.idpKey, and configure the server to trust it.

Targets and credentials shows the registry entries.


Back to top

Touchstone: conformance testing for W3C Linked Web Storage. Source on GitHub.
This site uses Just the Docs, a documentation theme for Jekyll.