Download the PHP package choks/password-policy-bundle without Composer
On this page you can find all versions of the php package choks/password-policy-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package password-policy-bundle
What is this?
Password Policy is a Symfony Bundle where you can validate user passwords against policy.
Pre-Requirements
- PHP: >=8.1
- Openssl PHP Extension
- Symfony 6 or 7
Installation
Install via composer:
Add to your bundles:
If you are using doctrine and DBAL storage, when generating schema, a table for storing Password History will be installed automatically. If don't, you will need to create it manually.
Usage
Before we dig, let's explain how it works. First, you can use validation against policy on any object as long
as that object implements Choks\PasswordPolicy\Contract\PasswordPolicySubjectInterface
, which will require
to implement getIdentifier()
so we can distinguish owner of password when saving into Password History and
getPlainPassword()
so we can compare (why plain password?)
Basically there are two ways of validating:
- Manually, by calling service methods
- Automatically, by putting
#[Choks\PasswordPolicy\Atrribute\Listen]
on Doctrine Entity
And two ways of specifying the policy in your application:
- Via bundle configuration (or)
- Via your own Policy Provider
Defining policy
Via Configuration
That's it, your configuration is set
Via your own Policy Provider
Here is an example of your custom Policy Provider.
Next step is to register this as service and then, put it to bundle config:
Whenever you try to validate manually or automatically, this provider will be called to get Policy to use.
Checking Policy and manipulating Password History
Manually
Checking against policy
You can get or inject Checker Service via ID password_policy.checker
or Choks\PasswordPolicy\Contract\PolicyCheckerInterface
.
Let's say you are validating $user
(Remember, $user has to implement PasswordPolicySubjectInterface
)
Adding to password history (if you use it)
You can get or inject Password History service via ID password_policy.history
or Choks\PasswordPolicy\Contract\PasswordHistoryInterface
Automatic checking
Although, I would encourage to manually control flow of checking, it's much easier to let bundle do that for you.
By adding #[Listen]
attribute, you are expecting bundle to automatically:
- When User is being inserted or update (when flushed):
- Validate password retrieved by
getPlainPassword()
against current policy, - Add password to history (using crypt, see complete config reference below) if history policy is used.
- Validate password retrieved by
- When User is being removed (when flushed):
- Remove passwords for user in history.
At the momnent of saving entity, if validation fails, the Choks\PasswordPolicy\Exception\PolicyCheckException
will be
thrown. If you catch it, you can examine violations via getViolations()
,
Clearing all password history
In some cases, you want to clear all passwords from history. Probably after update of this bundle, or when you change policy or so. You can do that by executing a command:
Expiration
You can set also set expiration policy. If you want to get expired password, or passwords, you can use:
If you want to use it in your services, inject with autowire Choks\PasswordPolicy\Contract\PasswordExpirationInterface
For more customization, you can also call method processExpired and
Choks\PasswordPolicy\Event\ExpiredPasswordEvent
will be dispatched, so you can listen and catch it,
if last password is found to be expired:
Why plain password? Is it safe?
When using Symfony's password_hashers
algo, could be and it is usually non-deterministic.
What it means is that every hash for same plain password is different. Also, and usually, those hashing algorithms are
one direction only, means that it cannot be decrypted/un-hashed.
Hahser also does not give us ability to compare Users plain password with some hashed one, it can only verify
hashed user password using UserPasswordHasherInterface
on User, against plain one.
We need to store encrypted password in history, and in order to do that, bundle is using its own crypt algo (That's
why you have cipher_method
in configuration. You can always choose different one.). When we compare user plain password
with password in history, we are decrypting those and compare.
How you will deliver plain password via getPlainPassword()
it's up to you, but I encourage you not to persist it, and
if can use eraseCredentials()
to unset it.
Note: If getPlainPassword()
return NULL, every password policy operation will be skipped.
Configuration Reference
Note: not_used_in_past_n_passwords
and period
could be used combined or independent (one set, other not). But in o
order to use period, both unit and value must be set.
Table for storing History
If you are not using doctrine generate schema and in some case your table didn't get created, you can create it manually by this DDL:
What is planned to be done in future (not promised)?
- Custom Policy provider per entity, defined via #[Listen]
Contribute
Feel free to contribute, at any time. Please provide new tests or tests changed. Also, if you find some bug, open an issue and will try to fix it as soon as possible.
Todo
- [ ] Garbage collection for passwords in history (FILO, per User)
- [ ] Support schema update without Doctrine ORM, without PostSchema listener
All versions of password-policy-bundle with dependencies
ext-openssl Version *
doctrine/orm Version ^2.0|^3.0
symfony/console Version ^6.0|^7.0
symfony/dependency-injection Version ^6.0|^7.0
symfony/framework-bundle Version ^6.0|^7.0
symfony/security-bundle Version ^6.0|^7.0
symfony/translation Version ^6.0|^7.0
symfony/yaml Version ^6.0|^7.0