Skip to content

MFA hardening: OAuth2 memento guard on recovery, DTO refactors, full OIDC circuit tests - #152

Merged
smarcet merged 13 commits into
feat/mfa-phase1---migrations--and--interfacesfrom
feature/mfa-oauth2-hardening
Aug 12, 2026
Merged

MFA hardening: OAuth2 memento guard on recovery, DTO refactors, full OIDC circuit tests#152
smarcet merged 13 commits into
feat/mfa-phase1---migrations--and--interfacesfrom
feature/mfa-oauth2-hardening

Conversation

@smarcet

@smarcet smarcet commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Hardening and cleanup on top of the 2FA feature (#126), plus repairs to the OIDC protocol test suite.

Fixes

  • verify2FARecovery(): validate the pending OAuth2 client before redeeming a recovery code. The endpoint skipped the resolveClientFromMemento() guard that verify2FA() applies, so with a pending OAuth2 authorization request whose client no longer exists, the single-use recovery code was burned and an IDP session established for an authorization request that could only fail at the /oauth2/auth hop. Covered by a red-green regression test.
  • AuthService::logout(): honor clear_security_ctx = false across the session flush. The Session::flush() hardening from fix(session):Added Session::flush() + Session::regenerate() at the en… #118 wiped the session-backed security context even when the caller asked to keep it (the prompt=login re-authentication path), breaking the login-hint prefill on the login screen. The context is now captured before the flush and re-saved after the session ID regenerate; everything else is still flushed. Covered by AuthServiceLogoutTest (red-green verified).

Refactors

  • MFAConstants: the MFA error_code wire literals, previously duplicated between UserController and TwoFactorRateLimitMiddleware::FAILURE_CODES (where silent drift would break rate-limit failure counting).
  • MFAPendingState DTO: IMFAChallengeStrategy::getPendingState() returns a typed object instead of a string-keyed array.
  • RecoveryCodesStatus DTO: IRecoveryCodeService::getStatus() owns the recovery_codes_remaining/total/low_threshold wire shape consumed by verify2FARecovery() and getProfile() (which each hand-built it with inline config() reads). Additive contract change: the recovery XHR response now also carries recovery_codes_total.

Tests

  • Full OIDC circuit proof for both 2FA endpoints: authorize → login → MFA challenge → verify (OTP / recovery code) → consent screen → AllowOnce → authorization code delivered to the client redirect_uri.
  • OIDCProtocolTestCase repaired: 29 broken → 0 (35/35 green). Two stacked pre-existing causes: seed passwords went stale in 021bee3 (jul 2024) and every login leg silently failed since (errorLogin() also answers 302); and the MFA gate now challenges the seeded super-admin, so enforced groups are cleared in this class (the gate is covered by TwoFactorLoginFlowTest). Also raised testTokenResponseModePost's max_age from 1 to 3200 — it tests response_mode=form_post, not max_age expiry, and the login+consent dance takes longer than 1s.

Test evidence (run inside the idp-app container)

  • TwoFactorLoginFlowTest: 43/43 (237 assertions)
  • OIDCProtocolTestCase: 35/35 (506 assertions, stop-on-failure disabled)
  • tests/unit/: 80/80 (2 pre-existing deprecations)

Summary by CodeRabbit

  • New Features

    • Recovery-code status now consistently shows remaining codes, total codes, and low-code warnings.
    • MFA flows provide standardized error responses for verification failures, invalid recovery codes, rate limits, and expired sessions.
  • Bug Fixes

    • Improved MFA and OAuth authorization reliability by validating clients before verification.
    • Preserved security context when signing out without requesting a full reset.
    • Improved handling of expired or unavailable MFA sessions.
  • Tests

    • Expanded coverage for MFA, recovery codes, OAuth authorization, rate limiting, and logout behavior.

…code

verify2FARecovery() skipped the resolveClientFromMemento() guard that
verify2FA() applies, so with a pending OAuth2 authorization request whose
client no longer exists the single-use recovery code was burned and an IDP
session established for an authorization request that could only fail at
the /oauth2/auth hop. Apply the same guard before redemption; recovery-code
checking itself stays client-agnostic.
The error_code values emitted by UserController's MFA endpoints were
hardcoded strings, duplicated in TwoFactorRateLimitMiddleware::FAILURE_CODES
where a silent drift would break the rate-limit failure counting. Tests keep
asserting the literal wire values on purpose, pinning the contract.
…n array

MFAPendingState (getUserId / getPendingAt / shouldRemember) replaces the
string-keyed array, so callers stop scattering 'user_id'/'remember' literals
and casts, and the shape is enforced by the type system instead of by
convention.
…tatus DTO

verify2FARecovery() and getProfile() each hand-built the
recovery_codes_remaining/total/low_threshold payload with their own config()
reads and magic defaults. IRecoveryCodeService::getStatus() now returns a
RecoveryCodesStatus DTO whose toArray() owns the wire keys, so both call
sites merge the same serialized shape. Side effect: the recovery XHR
response now also carries recovery_codes_total (additive, ignored by the
SPA).
…fy2FARecovery

authorize -> login -> MFA challenge -> verify (OTP / recovery code) ->
redirect_url back to the authorization endpoint (rebuilt from the session
memento) -> consent screen -> AllowOnce -> authorization code delivered to
the client redirect_uri. Locks in that the XHR verify contract composes with
the interactive grant's memento round-trip.

Note: OIDCProtocolTestCase's password-login circuits (e.g. testAuthCode)
predate the MFA gate and post a wrong seed password - broken independently
of this change.
…d + MFA gate)

Two stacked breakages, both predating and unrelated to each individual test:

- 021bee3 (jul 2024) changed the TestSeeder passwords from '1qaz2wsx' to
  '1Qaz2wsx!' without updating this class, so every password login leg has
  silently failed since - errorLogin() also answers 302, so the post-login
  assertion kept passing and tests died downstream instead.
- The MFA gate now challenges the seeded login user (SuperAdminGroup is in
  two_factor.enforced_groups), so even a correct password stops at the 2FA
  challenge. This class exercises the OIDC protocol, not the gate - enforced
  groups are cleared in prepareForTests(); the gate plus the full
  authorize -> MFA -> consent -> code circuit live in TwoFactorLoginFlowTest.

Result: 29 broken -> 3 (32/35 green). The 3 residuals have distinct
pre-existing causes: testConsentLogin and
testGetRefreshTokenWithPromptSetToConsentLogin lose the login hint because
AuthService::logout()'s Session::flush() (4864f50 / #118) wipes the
session-backed security context even when called with clear_security_ctx =
false (prompt=login path); testTokenResponseModePost uses max_age=1 and the
multi-request dance now takes longer than 1s, forcing a re-login.
…lush

The Session::flush() hardening added in #118 wipes the whole session at the
end of logout(), including the session-backed security context - even when
the caller passed clear_security_ctx = false (the prompt=login
re-authentication path in InteractiveGrantType::mustAuthenticateUser()),
which broke the login-hint prefill on the login screen for prompt=login
OIDC requests. Capture the context before the flush and re-save it after
the session ID regenerate; everything else is still flushed, so the #118
hardening stands.
The test exercises response_mode=form_post, not max_age expiry
(testMaxAge1AndWait2 owns that) - with max_age=1 the multi-request
login+consent dance takes longer than 1s and the final authorize hop forced
a re-login instead of delivering the form post. 3200 matches the sibling
circuits. OIDCProtocolTestCase is now fully green: 35/35.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR introduces typed MFA pending state, centralized MFA error codes, recovery-code status responses, OAuth2 client validation, logout security-context preservation, and expanded MFA/OIDC test coverage.

Changes

MFA authentication and recovery flow

Layer / File(s) Summary
Typed MFA and recovery contracts
app/Strategies/MFA/*, app/Services/Auth/*, tests/unit/MFA/*
MFA pending state and recovery-code status now use immutable typed objects with explicit interfaces and serialized status fields.
MFA controller and error handling
app/Http/Controllers/UserController.php, app/Http/Middleware/TwoFactorRateLimitMiddleware.php, app/libs/Auth/MFAConstants.php, app/Services/Auth/*, app/Strategies/*, tests/TwoFactorLoginFlowTest.php
MFA verification, recovery, resend, and profile flows use typed state, shared error constants, OAuth2 client validation, and recovery status metadata.
Logout security-context handling
app/libs/Auth/AuthService.php, tests/unit/AuthServiceLogoutTest.php
logout(false) restores the security context after session renewal, while logout(true) clears it.
MFA and protocol test coverage
tests/TwoFactorLoginFlowTest.php, tests/OIDCProtocolTestCase.php, tests/OAuth2ProtocolTestCase.php, phpunit.xml
Tests cover OAuth2 client validation, MFA retries, rate limits, audit failures, recovery metadata, authorization-code completion, and explicit protocol-suite registration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant UserController
  participant MFAChallengeStrategy
  participant OAuth2Client
  participant RecoveryCodeService
  UserController->>MFAChallengeStrategy: Read pending MFA state
  UserController->>OAuth2Client: Validate pending OAuth2 client
  UserController->>RecoveryCodeService: Redeem recovery code
  RecoveryCodeService-->>UserController: Return recovery status
Loading

Possibly related PRs

Suggested reviewers: romanetar, matiasperrone-exo, caseylocker

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: OAuth2 recovery hardening, MFA DTO refactors, and expanded OIDC tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/mfa-oauth2-hardening

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 PHPStan (2.2.7)

Composer install failed: the CodeRabbit sandbox could not download one or more dependencies.
This usually means the project resolves packages from a private registry, a self-hosted Satis/Repman instance, or an SSH-gated repository that the sandbox cannot reach.
If your project requires private packages, disable the PHPStan tool in your coderabbit settings.

Instead, run PHPStan in a CI/CD pipeline where you can use custom packages — our pipeline remediation tool can use the PHPStan output from your CI/CD pipeline.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-152/

This page is automatically updated on each push to this PR.

@smarcet
smarcet requested review from romanetar and a lite review from Copilot August 11, 2026 20:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…overy

Six tests inside a pending OIDC authorization-code flow, three per endpoint:
- wrong code then correct code: the rejection keeps the pending challenge
  and the OAuth2 memento alive, and the retry completes the full circuit
  (consent -> authorization code).
- consecutive wrong codes up to the rate-limit threshold: every attempt is
  401 without a session, and once the window closes even the CORRECT code
  answers 429 - brute-forcing inside a pending flow buys no extra attempts.
- burned single-use code (used recovery code / redeemed OTP): rejected like
  any invalid code, and the flow still completes afterwards with a fresh
  code (new recovery code / resent OTP).
@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-152/

This page is automatically updated on each push to this PR.

- validator 412s (malformed request, no otp_value / recovery_code)
- vanished pending user -> mfa_session_expired + pending state cleared
- recovery without a pending challenge -> mfa_session_expired
- stale OAuth2 client guard on verify2FA (parity with the recovery test):
  412 before the OTP is redeemed
- audit failure on the FAILED-verify path stays a clean 401 with the
  error_code the rate-limit middleware keys on, for both endpoints

verify2FA line coverage 82.3% -> 95.2%, verify2FARecovery 82.7% -> 94.2%;
the only uncovered lines left are the generic Exception -> 500 catches.
@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-152/

This page is automatically updated on each push to this PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/OIDCProtocolTestCase.php (1)

135-135: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider extracting the seeded password into a class constant.

The literal 1Qaz2wsx! now appears at about 26 call sites in this file. This PR had to edit every one of them. A private constant, as TwoFactorLoginFlowTest::SEED_PASSWORD already does, reduces the next seed change to one edit. Keep the trailing-space form at this line explicit, because that spacing is the subject under test.

♻️ Proposed refactor

Add the constant near the top of the class:

final class OIDCProtocolTestCase extends OpenStackIDBaseTestCase
{
    private const SEED_PASSWORD = '1Qaz2wsx!';

Then replace the literals:

                 'username' => ' sebastian@tipit.net ',
-                'password' => ' 1Qaz2wsx! ',
+                'password' => ' ' . self::SEED_PASSWORD . ' ',
                 'username' => 'sebastian@tipit.net',
-                'password' => '1Qaz2wsx!',
+                'password' => self::SEED_PASSWORD,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/OIDCProtocolTestCase.php` at line 135, Extract the repeated seeded
password into a private OIDCProtocolTestCase::SEED_PASSWORD class constant and
replace the other exact password literals with that constant. Keep the password
value with trailing spaces explicit at the shown password-field call site, since
that test must continue verifying whitespace handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/libs/Auth/MFAConstants.php`:
- Around line 29-31: Add ERROR_CODE_VERIFICATION_FAILED and
ERROR_CODE_INVALID_RECOVERY to the MFA_ERROR_CODE definition, alongside the
existing ERROR_CODE_SESSION_EXPIRED entry, so all three MFA error codes are
exposed to the login SPA.

---

Nitpick comments:
In `@tests/OIDCProtocolTestCase.php`:
- Line 135: Extract the repeated seeded password into a private
OIDCProtocolTestCase::SEED_PASSWORD class constant and replace the other exact
password literals with that constant. Keep the password value with trailing
spaces explicit at the shown password-field call site, since that test must
continue verifying whitespace handling.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 95e6cae3-bc85-47e5-befa-d941108e62e7

📥 Commits

Reviewing files that changed from the base of the PR and between 68a6c8d and 6672516.

📒 Files selected for processing (14)
  • app/Http/Controllers/UserController.php
  • app/Http/Middleware/TwoFactorRateLimitMiddleware.php
  • app/Services/Auth/IRecoveryCodeService.php
  • app/Services/Auth/RecoveryCodeService.php
  • app/Services/Auth/RecoveryCodesStatus.php
  • app/Strategies/MFA/AbstractMFAChallengeStrategy.php
  • app/Strategies/MFA/IMFAChallengeStrategy.php
  • app/Strategies/MFA/MFAPendingState.php
  • app/libs/Auth/AuthService.php
  • app/libs/Auth/MFAConstants.php
  • tests/OIDCProtocolTestCase.php
  • tests/TwoFactorLoginFlowTest.php
  • tests/unit/AuthServiceLogoutTest.php
  • tests/unit/MFA/AbstractMFAChallengeStrategyTest.php

Comment thread app/libs/Auth/MFAConstants.php
…ure breadth

Two changes to phpunit.xml:
- The Application suite's <directory> scan only picks up *Test.php (PHPUnit's
  default suffix), so the four concrete *TestCase.php protocol suites
  (OAuth2Protocol, OIDCProtocol, OIDCPasswordless, OpenIdProtocol - 93 tests)
  were NEVER executed by CI. That is how OIDCProtocolTestCase stayed broken
  for two years with green builds. They are now listed explicitly.
- stopOnFailure=false so a run reports every failure instead of dying on the
  first one.

Also fixes the one test the newly-wired suites surfaced:
testResourceServerIntrospectionNotValidIP expected an unconditional 400, but
the resource-server IP check became opt-in in #98
(oauth2.validate_resource_server_ip, default off) - the test now enables the
flag before asserting the rejection.

Full-suite evidence (523 tests): green except 8 pre-existing
environment-dependent Turnstile tests that need TEST_USER_EMAIL /
TEST_USER_PASSWORD and the Turnstile secrets CI injects (they pass in CI;
locally their markTestSkipped guard is defeated by a typed-property
TypeError when the env vars are absent).
@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-152/

This page is automatically updated on each push to this PR.

MFAConstants now owns all of them:
- error codes: the existing three plus mfa_rate_limit and mfa_required.
  ITwoFactorRateLimitService::RATE_LIMIT_ERROR_CODE and
  ILoginStrategy::MFA_REQUIRED alias it, so consumers keep their names while
  the value is defined once.
- 2fa_* session keys: previously defined TWICE in production
  (AbstractMFAChallengeStrategy's private consts and
  ITwoFactorRateLimitService::PENDING_USER_SESSION_KEY) - both now alias
  MFAConstants.

Also promotes the rate-limit cache-key prefix ('2fa_rate:', previously a
sprintf literal in TwoFactorRateLimitService duplicated by the test flush
helper) to ITwoFactorRateLimitService::RATE_LIMIT_CACHE_KEY_PREFIX.

All ~50 hardcoded literals across TwoFactorLoginFlowTest,
AbstractMFAChallengeStrategyTest and EmailOTPMFAChallengeStrategyTest now
reference the constants.
@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-152/

This page is automatically updated on each push to this PR.

@smarcet smarcet self-assigned this Aug 11, 2026
The literal appeared at 26 call sites; a seed password change is now a
one-line edit, matching TwoFactorLoginFlowTest. The trailing-space login
test keeps its spacing explicit around the constant, since that spacing
is the subject under test. Suite re-run in idp-app: 35/35, 506 assertions.
@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-152/

This page is automatically updated on each push to this PR.

@romanetar

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@romanetar romanetar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@smarcet
smarcet merged commit ec64f2f into feat/mfa-phase1---migrations--and--interfaces Aug 12, 2026
7 of 8 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
tests/TwoFactorLoginFlowTest.php (1)

79-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the rate-limit action constants in test cleanup.

The loop hardcodes 'verify', 'recovery', and 'resend', while ITwoFactorRateLimitService already defines ActionVerify, ActionRecovery, and ActionResend. If an action value changes, teardown can leave stale counters and make tests order-dependent.

Suggested fix
-            foreach (['verify', 'recovery', 'resend'] as $action) {
+            foreach ([
+                ITwoFactorRateLimitService::ActionVerify,
+                ITwoFactorRateLimitService::ActionRecovery,
+                ITwoFactorRateLimitService::ActionResend,
+            ] as $action) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/TwoFactorLoginFlowTest.php` around lines 79 - 80, Update the cleanup
loop in TwoFactorLoginFlowTest to use ITwoFactorRateLimitService::ActionVerify,
ActionRecovery, and ActionResend instead of hardcoded action strings, preserving
the existing cache-key construction and forget behavior.
tests/OAuth2ProtocolTestCase.php (1)

462-467: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Correct the explanation of testValidateToken().

testValidateToken() performs introspection with the regular OAuth client. Resource server 1 is used only by testResourceServerIntrospection().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/OAuth2ProtocolTestCase.php` around lines 462 - 467, Correct the comment
above Config::set in testValidateToken() so it accurately states that
testValidateToken() introspects with the regular OAuth client, while resource
server 1 is used only by testResourceServerIntrospection(). Preserve the
explanation that the IP-validation flag must be enabled for the rejection test
and set after testValidateToken().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/OAuth2ProtocolTestCase.php`:
- Around line 465-466: Update the comment associated with testValidateToken() to
identify the main OAuth2 client defined at the earlier client setup, and state
that its registered IPs include the test-request IP. Remove the incorrect
reference to resource.server.1, which belongs to
testResourceServerIntrospection().

---

Nitpick comments:
In `@tests/OAuth2ProtocolTestCase.php`:
- Around line 462-467: Correct the comment above Config::set in
testValidateToken() so it accurately states that testValidateToken() introspects
with the regular OAuth client, while resource server 1 is used only by
testResourceServerIntrospection(). Preserve the explanation that the
IP-validation flag must be enabled for the rejection test and set after
testValidateToken().

In `@tests/TwoFactorLoginFlowTest.php`:
- Around line 79-80: Update the cleanup loop in TwoFactorLoginFlowTest to use
ITwoFactorRateLimitService::ActionVerify, ActionRecovery, and ActionResend
instead of hardcoded action strings, preserving the existing cache-key
construction and forget behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 19de687d-05c4-4e6f-80f4-efc14eea7fd0

📥 Commits

Reviewing files that changed from the base of the PR and between 6672516 and 305b9bd.

📒 Files selected for processing (11)
  • app/Services/Auth/ITwoFactorRateLimitService.php
  • app/Services/Auth/TwoFactorRateLimitService.php
  • app/Strategies/ILoginStrategy.php
  • app/Strategies/MFA/AbstractMFAChallengeStrategy.php
  • app/libs/Auth/MFAConstants.php
  • phpunit.xml
  • tests/OAuth2ProtocolTestCase.php
  • tests/OIDCProtocolTestCase.php
  • tests/TwoFactorLoginFlowTest.php
  • tests/unit/MFA/AbstractMFAChallengeStrategyTest.php
  • tests/unit/MFA/EmailOTPMFAChallengeStrategyTest.php
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/unit/MFA/AbstractMFAChallengeStrategyTest.php
  • app/Strategies/MFA/AbstractMFAChallengeStrategy.php
  • tests/OIDCProtocolTestCase.php

Comment on lines +465 to +466
// testValidateToken(): that helper introspects from resource server 1,
// whose registered IPs do include the test-request IP.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the resource-server client description.

testValidateToken() uses the main OAuth2 client defined at Lines 343-344. It does not introspect from resource.server.1; that client is used by testResourceServerIntrospection(). Update the comment to describe the actual client setup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/OAuth2ProtocolTestCase.php` around lines 465 - 466, Update the comment
associated with testValidateToken() to identify the main OAuth2 client defined
at the earlier client setup, and state that its registered IPs include the
test-request IP. Remove the incorrect reference to resource.server.1, which
belongs to testResourceServerIntrospection().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants