Repository navigation
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |
d79aef8 to
fe2914a
Compare
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |
1 similar comment
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |
There was a problem hiding this comment.
🟡 Changes recommended
Using get_current_user() attributes 2FA resets to the PHP script owner rather than the executing operator, undermining audit-trail accountability.
1 open issue
What changed in this PR
Adds idp:reset-2fa for operators recovering users who have lost their second factor and recovery codes, reusing the shared reset service from #169.
Changes:
- Requires a nonblank reason, resolves the user by email, and delegates the reset to
disableTwoFactor. - Records audit metadata, reports reset counts and audit failures, and warns when group enforcement still applies.
- Adds command registration and tests for validation, reset effects, auditing, and continued group enforcement.
| File | Description |
|---|---|
tests/unit/Console/Reset2FACommandTest.php |
Tests validation, service calls, audit metadata, warnings, and audit failure handling. |
tests/Reset2FACommandIntegrationTest.php |
Checks persisted reset effects and continued group enforcement. |
app/Console/Kernel.php |
Registers the reset command with Artisan. |
app/Console/Commands/Reset2FACommand.php |
Implements reset orchestration, auditing, and operator output. |
Review effort: Balanced
| // the service owns the side effects (flags, codes, devices) in one transaction | ||
| $recovery_code_service->disableTwoFactor($user, null, null); | ||
|
|
||
| $operator = sprintf('%s@%s', get_current_user(), gethostname()); |
There was a problem hiding this comment.
@romanetar Confirmed: get_current_user() returns the owner of the artisan file, not the effective user of the process, so the operator in the settings_changed audit row can name the deploy account instead of whoever ran the command. Suggested fix: posix_getpwuid(posix_geteuid())['name'], falling back to get_current_user() when posix is unavailable. Note that inside a k8s pod (kubectl exec) neither identifies the person, so --reason should name the operator or the ticket, as in the SDS §4.11 example.
There was a problem hiding this comment.
Fixed in b727811. The operator now comes from posix_getpwuid(posix_geteuid()), falling back to get_current_user() when posix is unavailable (see processUser() in Reset2FACommand). Agreed that inside a k8s pod neither identifies the person, so --reason is the accountability anchor and should name the operator or ticket.
fe2914a to
aeeb94f
Compare
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |
1 similar comment
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |
aeeb94f to
967399c
Compare
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |
967399c to
ad297f6
Compare
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |
1 similar comment
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |
0c69b29 to
0231417
Compare
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |
Resets 2FA for one user, for operators with server access: requires
--reason (aborts without it), finds the user by email and calls
IRecoveryCodeService::disableTwoFactor, which clears the enrollment, deletes
the recovery codes and revokes the trusted devices in one transaction.
Emits a settings_changed audit event with {reason, actor: "console",
operator} and prints a summary with the number of codes deleted and devices
revoked. Group-enforced users stay challenged at login because enforcement is
derived from group membership; the output says so explicitly.
get_current_user() returns the owner of the artisan script, not the OS user running the command, so the audit operator was always the checkout owner.
1129da2 to
b727811
Compare
|
📘 OpenAPI / Swagger preview ➡️ https://OpenStackweb.github.io/openstackid/openapi/pr-171/ This page is automatically updated on each push to this PR. |

ref: https://app.clickup.com/t/86ba2zp7r
Stacked on #169 (base:
feat/mfa-disable-two-factor-service), which is stacked on #166 and #125. Merge bottom-up: #125, #166, #169, then this one.Summary
Second half of ClickUp ticket 12 (Admin Enforcement and Reset Commands):
idp:reset-2fa {email} --reason="...", for operators with server access who need to recover a user that lost their second factor and recovery codes.--reasonis required: without it (or blank) the command exits non-zero before touching anything.IRecoveryCodeService::disableTwoFactor($user, null, null)from feat(mfa): add IRecoveryCodeService::disableTwoFactor #169, which clearstwo_factor_enabledandtwo_factor_enforced_at, deletes the recovery codes and revokes the trusted devices in one transaction. The command does not reimplement any of that.settings_changedaudit event with{"reason": "<--reason>", "actor": "console", "operator": "<os user>@<hostname>"}andip_address127.0.0.1.Things to know
User::shouldRequire2FA()on the reloaded user, which is what the login uses, not through an HTTP login.disableTwoFactoras is.Test plan
tests/unit/Console/Reset2FACommandTest.php: 6 tests (missing and blank reason, unknown user, success with audit metadata, enforced-group warning, audit failure).tests/Reset2FACommandIntegrationTest.php: 3 tests against the DB (no reason changes nothing; self-enrolled user fully cleared with 1settings_changedrow; group-enforced admin still requires 2FA).tests/RecoveryCodeRegenerationTest.phpalready fails on the base branch (Class "Strategies\MFA\MFAChallengeStrategyFactory" not found), unrelated to this change.