-
Notifications
You must be signed in to change notification settings - Fork 138
Feat: Force password reset #601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
kenjis
merged 25 commits into
codeigniter4:develop
from
sammyskills:force-password-reset
Feb 3, 2023
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
6c76cc4
added resettable trait
sammyskills 9a07e9d
updated user entity, use resettable trait
sammyskills 4ba4ce9
updated user identity model, created new methods
sammyskills 320e4d4
updated auth config, added force_reset redirect
sammyskills 415edf8
added ForcePasswordResetFilter
sammyskills f36a46b
updated registrar config, added the force-reset filter
sammyskills 8812d40
created Tests: ForcePasswordResetTest
sammyskills 947705d
updated Tests: UserIdentityModelTest
sammyskills 0d2f89a
updated docs:install.md, added force password reset explanation
sammyskills 066126e
apply suggestions from code review: removed testForceGlobalPasswordRe…
sammyskills 268018f
fixed Postgres test failure
sammyskills 7f68d02
fixed Rector Analysis failure
sammyskills 8159ea6
rebased docs:install.md
sammyskills 8b45094
fixed checks
sammyskills 7c044fa
fixed postgres test failure - b2
sammyskills 7c94a67
updated docs:install.md
sammyskills 7e77fd4
forceGlobalPasswordReset() no longer excludes the logged in user
sammyskills 0621000
reduced test users to 50
sammyskills 2a4d1c3
added the unique() faker modifier to prevent duplicates
sammyskills 482c715
applied code review suggestions on code files
sammyskills 03351e0
applied code review suggestions on docs
sammyskills 491b0d2
fixed phpstan error
sammyskills f61a5b3
fixed phpstan error - 2
sammyskills 1b406e4
fixed phpstan error -3
sammyskills 83baaa8
applied code review suggestion on tests and auth config file
sammyskills File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Forcing Password Reset | ||
|
||
Depending on the scope of your application, there may be times when you'll decide that it is absolutely necessary to force user(s) to reset their password. This practice is common when you find out that users of your application do not use strong passwords OR there is a reasonable suspicion that their passwords have been compromised. This guide provides you with ways to achieve this. | ||
|
||
- [Forcing Password Reset](#forcing-password-reset) | ||
- [Available Methods](#available-methods) | ||
- [Check if a User Requires Password Reset](#check-if-a-user-requires-password-reset) | ||
- [Force Password Reset On a User](#force-password-reset-on-a-user) | ||
- [Removing Password Reset Flag On a User](#removing-password-reset-flag-on-a-user) | ||
- [Force Password Reset On Multiple Users](#force-password-reset-on-multiple-users) | ||
- [Force Password Reset On All Users](#force-password-reset-on-all-users) | ||
|
||
## Available Methods | ||
|
||
Shield provides a way to enforce password resets throughout your application. The `Resettable` trait on the `User` entity and the `UserIdentityModel` provides the following methods to do so. | ||
|
||
### Check if a User Requires Password Reset | ||
|
||
When you need to check if a user requires password reset, you can do so using the `requiresPasswordReset()` method on the `User` entity. Returns boolean `true`/`false`. | ||
|
||
```php | ||
if ($user->requiresPasswordReset()) { | ||
//... | ||
} | ||
``` | ||
|
||
### Force Password Reset On a User | ||
|
||
To force password reset on a user, you can do so using the `forcePasswordReset()` method on the `User` entity. | ||
|
||
```php | ||
$user->forcePasswordReset(); | ||
``` | ||
|
||
### Remove Force Password Reset Flag On a User | ||
|
||
Undoing or removing the force password reset flag on a user can be done using the `undoForcePasswordReset()` method on the `User` entity. | ||
|
||
```php | ||
$user->undoForcePasswordReset(); | ||
``` | ||
|
||
### Force Password Reset On Multiple Users | ||
|
||
If you see the need to force password reset for more than one user, the `forceMultiplePasswordReset()` method of the `UserIdentityModel` allows you to do this easily. It accepts an `Array` of user IDs. | ||
|
||
```php | ||
use CodeIgniter\Shield\Models\UserIdentityModel; | ||
... | ||
... | ||
... | ||
$identities = new UserIdentityModel(); | ||
$identities->forceMultiplePasswordReset([1,2,3,4]); | ||
``` | ||
|
||
### Force Password Reset On All Users | ||
|
||
If you suspect a security breach or compromise in the passwords of your users, you can easily force password reset on all the users of your application using the `forceGlobalPasswordReset()` method of the `UserIdentityModel`. | ||
|
||
```php | ||
use CodeIgniter\Shield\Models\UserIdentityModel; | ||
... | ||
... | ||
... | ||
$identities = new UserIdentityModel(); | ||
$identities->forceGlobalPasswordReset(); | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace CodeIgniter\Shield\Filters; | ||
|
||
use CodeIgniter\Filters\FilterInterface; | ||
use CodeIgniter\HTTP\IncomingRequest; | ||
use CodeIgniter\HTTP\RedirectResponse; | ||
use CodeIgniter\HTTP\RequestInterface; | ||
use CodeIgniter\HTTP\Response; | ||
use CodeIgniter\HTTP\ResponseInterface; | ||
use CodeIgniter\Shield\Authentication\Authenticators\Session; | ||
|
||
/** | ||
* Force Password Reset Filter. | ||
*/ | ||
class ForcePasswordResetFilter implements FilterInterface | ||
{ | ||
/** | ||
* Checks if a logged in user should reset their | ||
* password, and then redirect to the appropriate | ||
* page. | ||
* | ||
* @param array|null $arguments | ||
* | ||
* @return RedirectResponse|void | ||
*/ | ||
public function before(RequestInterface $request, $arguments = null) | ||
{ | ||
if (! $request instanceof IncomingRequest) { | ||
return; | ||
} | ||
|
||
helper('setting'); | ||
|
||
/** @var Session $authenticator */ | ||
$authenticator = auth('session')->getAuthenticator(); | ||
|
||
if ($authenticator->loggedIn() && $authenticator->getUser()->requiresPasswordReset()) { | ||
return redirect()->to(config('Auth')->forcePasswordResetRedirect()); | ||
} | ||
} | ||
|
||
/** | ||
* We don't have anything to do here. | ||
* | ||
* @param Response|ResponseInterface $response | ||
* @param array|null $arguments | ||
*/ | ||
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null): void | ||
{ | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace CodeIgniter\Shield\Traits; | ||
|
||
use CodeIgniter\Shield\Authentication\Authenticators\Session; | ||
use CodeIgniter\Shield\Models\UserIdentityModel; | ||
|
||
/** | ||
* Reusable methods to help the | ||
* enforcing of password resets | ||
*/ | ||
trait Resettable | ||
{ | ||
/** | ||
* Returns true|false based on the value of the | ||
* force reset column of the user's identity. | ||
*/ | ||
public function requiresPasswordReset(): bool | ||
{ | ||
$identity_model = model(UserIdentityModel::class); | ||
$identity = $identity_model->getIdentityByType($this, Session::ID_TYPE_EMAIL_PASSWORD); | ||
|
||
return $identity->force_reset; | ||
} | ||
|
||
/** | ||
* Force password reset | ||
*/ | ||
public function forcePasswordReset(): void | ||
{ | ||
// Do nothing if user already requires reset | ||
if ($this->requiresPasswordReset()) { | ||
return; | ||
} | ||
|
||
// Set force_reset to true | ||
$identity_model = model(UserIdentityModel::class); | ||
$identity_model->set('force_reset', 1); | ||
$identity_model->where(['user_id' => $this->id, 'type' => Session::ID_TYPE_EMAIL_PASSWORD]); | ||
$identity_model->update(); | ||
sammyskills marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/** | ||
* Undo Force password reset | ||
*/ | ||
public function undoForcePasswordReset(): void | ||
{ | ||
// If user doesn't require password reset, do nothing | ||
if ($this->requiresPasswordReset() === false) { | ||
return; | ||
} | ||
|
||
// Set force_reset to false | ||
$identity_model = model(UserIdentityModel::class); | ||
$identity_model->set('force_reset', 0); | ||
$identity_model->where(['user_id' => $this->id, 'type' => Session::ID_TYPE_EMAIL_PASSWORD]); | ||
$identity_model->update(); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.