Catalyst-Plugin-OpenIDConnect

 view release on metacpan or  search on metacpan

CHANGELOG.md  view on Meta::CPAN

  case verified to leave those fields absent.

- **`t/04_store_redis.t`** (updated) — `MockRedis` gained a `getdel` method;
  tests confirm `GETDEL` is used (not `del`), consume returns data, second
  consume returns `undef`. Added PKCE round-trip tests through JSON
  serialization.

- **`t/06_pkce.t`** (new, 11 tests) — unit tests for `_verify_pkce`: correct
  verifier/challenge pair accepted; wrong verifier rejected; verifier too short
  (< 43) rejected; verifier too long (> 128) rejected; verifier with disallowed
  characters rejected; `undef` verifier rejected; `undef` challenge rejected;
  minimum (43-char) and maximum (128-char) length cases accepted; all unreserved
  char types accepted; tampered challenge rejected.

### Documentation

- **`API_REFERENCE.md`** — Authorization endpoint parameter table updated with
  `code_challenge` (Conditional) and `code_challenge_method` rows; token
  endpoint authorization-code grant table updated with `code_verifier`
  (Conditional) row and `client_secret` changed from Required to Conditional.
  New "PKCE-Protected Authorization Code Flow" example section added.
- **`IMPLEMENTATION_GUIDE.md`** — Authorization Code Flow steps updated with
  PKCE parameters; State Store module docs updated with accurate signatures and
  atomic-operation note; login action example updated with safe `back`
  validation; new PKCE subsection added under Security Considerations.
- **`QUICKSTART.md`** — Login action example updated with validated `back`
  redirect pattern.

---

## [0.04] - 2026-04-29 (Security Fix: Open Redirect in Logout Endpoint)

### Security

- **CRIT-1 fixed — Open Redirect in logout endpoint** (`Controller::Root`,
  `Utils::JWT`). The `post_logout_redirect_uri` parameter was previously
  forwarded without any validation, allowing an attacker to redirect victims to
  an arbitrary external URL after logout (phishing / credential harvesting).

  The logout flow now enforces the following rules, in line with OpenID Connect
  RP-Initiated Logout 1.0:

  1. `post_logout_redirect_uri` is rejected with `invalid_request` unless
     `id_token_hint` is also supplied.
  2. The hint token's RSA signature is verified to confirm it was genuinely
     issued by this server. Expiry is intentionally **not** checked — hint
     tokens are frequently expired at logout time by design.
  3. The `aud` claim of the verified hint identifies the requesting client.
     The `post_logout_redirect_uri` is then compared by **exact string match**
     against that client's registered `post_logout_redirect_uris` list.
     Prefix matching and host-only matching are not permitted.
  4. Any mismatch returns an `invalid_request` OAuth error; no redirect is
     issued.
  5. When a redirect is permitted, the optional `state` parameter is appended
     verbatim to the redirect URI as required by the specification.

### Added

- **`JWT::decode_id_token_hint($token)`** — new method on
  `Catalyst::Plugin::OpenIDConnect::Utils::JWT`. Verifies the token signature
  against the configured public key and returns the decoded claims hashref, or
  `undef` if the token is malformed or the signature is invalid. Distinct from
  `verify_token` in that it does not reject expired tokens.

- **`Controller::Root::_allowed_post_logout_uris($client)`** — private helper
  that normalises the `post_logout_redirect_uris` client config field from
  either an arrayref (YAML/JSON config) or a whitespace-delimited string
  (Config::General-style config) into a flat list of URIs.

- **`post_logout_redirect_uris` client config key** — each client may now
  declare a list of permitted post-logout redirect URIs. This key is required
  for clients that use `post_logout_redirect_uri` at the logout endpoint.

### Tests

- **`t/05_logout.t`** (new, 19 tests) — covers `decode_id_token_hint` for valid
  tokens, expired tokens, tampered tokens, wrong-key tokens, and structurally
  invalid JWTs; and `_allowed_post_logout_uris` for arrayref config, string
  config, missing config, and exact-match security semantics (prefix-of-registered
  and extended-path attacks).

### Documentation

- **`API_REFERENCE.md`** — Logout endpoint section rewritten with updated
  parameter table (marking `id_token_hint` as conditionally required), security
  note on exact-match validation, split request/response examples, full error
  response examples, and a client registration code snippet.
- **`README.md`** — Client configuration reference updated with the new
  `post_logout_redirect_uris` field.
- **`IMPLEMENTATION_GUIDE.md`** — Client configuration example and field list
  updated with `post_logout_redirect_uris`.
- **`DEPLOYMENT.md`** — Production `catalyst.conf` example updated with
  `post_logout_redirect_uris`.
- **`QUICKSTART.md`** — Quick-start Perl config example updated with
  `post_logout_redirect_uris`.
- **`example/app.pl`** — Both example clients now include
  `post_logout_redirect_uris`.

---

## [0.03] - 2026-04-24 (FastCGI / Multi-Process Store Support)

### Added

- **Catalyst::Plugin::OpenIDConnect::Role::Store** - New Moose role defining the
  pluggable store interface. Any store backend must `with` this role and implement
  three methods: `create_authorization_code`, `get_authorization_code`,
  `consume_authorization_code`. This decouples the plugin from a specific
  backend implementation.

- **Catalyst::Plugin::OpenIDConnect::Utils::Store::Redis** - Redis-backed store
  implementation for multi-process deployments (FastCGI, pre-forking servers).
  - Stores authorization codes in Redis with native TTL expiry via `SETEX`
  - Lazy Redis connection (opened after `fork()` so each worker has its own socket)
  - Supports `Redis::Fast` (preferred) or `Redis` client, auto-detected at runtime
  - Configurable key prefix for namespace isolation on shared Redis instances
  - Configurable code TTL (default 600 s)
  - Optional Redis `AUTH` password support
  - Blessed user objects serialised via `convert_blessed` JSON encoding

- **Configurable store class in plugin setup** - `Plugin::OpenIDConnect` config



( run in 1.012 second using v1.01-cache-2.11-cpan-995e09ba956 )