= Password validation and generation
:navtitle: Password validation and generation
:description: Password validation and generation  - How it works, how to configure it, and more.
:keywords: CEP-24, Password, Generation, Validation, Security

Here’s the problem: while users have always had the ability to create whatever password they wanted in Cassandra -
from straightforward to incredibly complex and everything in between–this ultimately created a noticeable security vulnerability.

While organizations might have internal processes for generating secure passwords that adhere to their own security policies,
Cassandra itself did not have the means to enforce these standards. To make the security vulnerability worse,
if a password initially met internal security guidelines, users could later downgrade their password to
a less secure option simply by using `ALTER ROLE` statements.

When internal password requirements are enforced for an individual, users face the additional
burden of creating compliant passwords. This inevitably involved lots of trial-and-error in attempting
to create a compliant password that satisfied complex security roles.

But what if there was a way to have Cassandra automatically create passwords that meet all
bespoke security requirements–but without requiring manual effort from users or system operators?

That’s why we developed https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=228494146[CEP-24: Password validation/generation].
We recognized that the complexity of secure password management could be significantly reduced (or eliminated entirely)
with the right approach  –and improving both security and user experience at the same time.

== The Goals of CEP-24

A Cassandra Enhancement Proposal (or CEP) is a structured process for proposing, creating, and ultimately implementing
new features for the Cassandra project. All CEPs are thoroughly vetted among the Cassandra community before
they are officially integrated into the project.

These were the key goals we established for CEP-24:

* Introduce a way to enforce password strength upon role creation or role alteration.
* Implement a reference implementation of a password validator which adheres to a recommended password strength policy,
to be used for Cassandra users out of the box.
* Emit a warning (and proceed) or just reject `CREATE ROLE` and `ALTER ROLE` statements when the provided
password does not meet a certain security level, based on user configuration of Cassandra.
* To be able to implement a custom password validator with its own policy, whatever it might be,
and provide a modular/pluggable mechanism to do so.
* Provide a way for Cassandra to generate a password which would pass the subsequent validation for use by the user.

The Cassandra Password Validator and Generator builds upon an established framework in Cassandra called Guardrails,
which was originally implemented under CEP-3 (more details https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-3%3A+Guardrails[here]).

== Implementation and configuration

The password validator implements a custom guardrail introduced as part of CEP-24. A custom guardrail can validate and
generate values of arbitrary types when properly implemented. In the CEP-24 context,
the password guardrail provides `CassandraPasswordValidator` by extending `ValueValidator`,
while passwords are generated by `CassandraPasswordGenerator` by extending `ValueGenerator`.
Both components work with passwords as `String` type values.

Password validation and generation are configured in `cassandra.yaml` file under the `password_policy` section.
Let’s explore the key configuration properties available.

First, the `class_name` and `generator_class_name` parameters
specify which validator and generator classes will be used to validate and generate passwords respectively.

Cassandra ships `CassandraPasswordValidator` and `CassandraPasswordGenerator` out of the box.
However, if a particular enterprise decides that they need something very custom, they are free to implement their own validators,
put it on Cassandra’s class path and reference it in the configuration behind `class_name` parameter. Same for the validator.

CEP-24 provides implementations of the validator and generator that the Cassandra team believes will satisfy
the requirements of most users. These default implementations address common password security needs.
However, the framework is designed with flexibility in mind, allowing organizations to implement custom validation
and generation rules that align with their specific security policies and business requirements.

----
password_policy:
# Implementation class of a validator. When not in form of FQCN, the
# package name org.apache.cassandra.db.guardrails.validators is prepended.
# By default, there is no validator.
  class_name: CassandraPasswordValidator
# Implementation class of related generator which generates values
# which are valid when tested against this validator.
# When not in form of FQCN, the package name
# org.apache.cassandra.db.guardrails.generators is prepended.
# By default, there is no generator.
  generator_class_name: CassandraPasswordGenerator
----

Password quality might be looked at as the number of _characteristics_ a password satisfies.
There are two levels for any password to be evaluated – warning level and failure level.
Warning and failure levels nicely fit into how Guardrails act. Every guardrail has warning and failure thresholds.
Based on what value a specific guardrail evaluates, it will either emit a warning to a user that its usage
is discouraged (but ultimately allowed), or it will fail to be set altogether.

This same principle applies to password evaluation – each password is assessed against both warning and failure thresholds.
These thresholds are determined by counting the characteristics present in the password.

The system evaluates five key characteristics:

* the password’s overall length
* the number of uppercase characters
* the number of lowercase characters
* the number of special characters
* and the number of digits.

A comprehensive password security policy can be enforced by configuring minimum requirements for each of these characteristics.

----
 # There are four characteristics (excluding password's length):
 # upper-case, lower-case, special character and digit.
 # If this value is set e.g. to 3, a password has to
 # consist of 3 out of 4 characteristics.
 # For example, it has to contain at least 2 upper-case characters,
 # 2 lower-case, and 2 digits to pass,
 # but it does not have to contain any special characters.
 # If the number of characteristics found in the password is
 # less than or equal to this number, it will emit a warning.
 characteristic_warn: 3
 # If the number of characteristics found in the password is
 #less than or equal to this number, it will emit a failure.
 characteristic_fail: 2
----

Next, there are configuration parameters for each characteristic which count towards warning or failure:
----

# If the password is shorter than this value,
# the validator will emit a warning.
length_warn: 12
# If a password is shorter than this value,
# the validator will emit a failure.
length_fail: 8
# If a password does not contain at least n
# upper-case characters, the validator will emit a warning.
upper_case_warn: 2
# If a password does not contain at least
# n upper-case characters, the validator will emit a failure.
upper_case_fail: 1
# If a password does not contain at least
# n lower-case characters, the validator will emit a warning.
lower_case_warn: 2
# If a password does not contain at least
# n lower-case characters, the validator will emit a failure.
lower_case_fail: 1
# If a password does not contain at least
# n digits, the validator will emit a warning.
digit_warn: 2
# If a password does not contain at least
# n digits, the validator will emit a failure.
digit_fail: 1
# If a password does not contain at least
# n special characters, the validator will emit a warning.
special_warn: 2
# If a password does not contain at least
# n special characters, the validator will emit a failure.
special_fail: 1
----

It is also possible to say that illegal sequences of certain length found in a password will be forbidden:

----
# If a password contains illegal sequences that are at least this long, it is invalid.
# Illegal sequences might be either alphabetical (form 'abcde'),
# numerical (form '34567'), or US qwerty (form 'asdfg') as well
# as sequences from supported character sets.
# The minimum value for this property is 3,
# by default it is set to 5.
illegal_sequence_length: 5
----

Lastly, it is also possible to configure a dictionary of passwords to check against.
That way, we will be checking against password dictionary attacks.
It is up to the operator of a cluster to configure the password dictionary:

----
# Dictionary to check the passwords against. Defaults to no dictionary.
# Whole dictionary is cached into memory. Use with caution with relatively big dictionaries.
# Entries in a dictionary, one per line, have to be sorted per String's compareTo contract.
dictionary: /path/to/dictionary/file
----

Now that we have gone over all the configuration parameters, let’s take a look at an example of how password
validation and generation look in practice.

=== Validation and generation of a password

Consider a scenario where a Cassandra super-user (such as the default ‘cassandra’ role) attempts
to create a new role named ‘alice’.

----
cassandra@cqlsh> CREATE ROLE alice WITH PASSWORD = 'cassandraisadatabase' AND LOGIN = true;
InvalidRequest: Error from server: code=2200 [Invalid query]
message="Password was not set as it violated configured password
strength policy. To fix this error, the following has to be resolved:
Password contains the dictionary word 'cassandraisadatabase'. You may also use
'GENERATED PASSWORD' upon role creation or alteration."
----

The password is in the dictionary. When an operator sees this,
they will try to fix it by creating some random password not in dictionary:

----
cassandra@cqlsh> CREATE ROLE alice WITH PASSWORD = 'T8aum3?' AND LOGIN = true;
InvalidRequest: Error from server: code=2200 [Invalid query]
message="Password was not set as it violated configured password strength
policy. To fix this error, the following has to be resolved: Password
must be 8 or more characters in length. You may also use
'GENERATED PASSWORD' upon role creation or alteration."
----

Password is not in the dictionary, but it is not long enough. In the following example,
the password is finally set, but it is not considered to be secure enough.
It satisfies the minimum requirements but our validator identified that not all characteristics were met.

----
cassandra@cqlsh> CREATE ROLE alice WITH PASSWORD = 'mYAtt3mp' AND LOGIN = true;

Warnings:

Guardrail password violated: Password was set, however it might not be
strong enough according to the configured password strength policy.
To fix this warning, the following has to be resolved: Password must be 12 or more
characters in length. Passwords must contain 2 or more digit characters. Password
must contain 2 or more special characters. Password matches 2 of 4 character rules,
but 4 are required. You may also use 'GENERATED PASSWORD' upon role creation or alteration.
----

When an operator saw this, they noticed the note about the `GENERATED PASSWORD` clause which will
generate a password automatically without an operator needing to invent it on their own.
This is a lot of times, as shown, a cumbersome process better to be left on a machine.

----
cassandra@cqlsh> ALTER ROLE alice WITH GENERATED PASSWORD;

generated_password
------------------
   R7tb33?.mcAX
----

The generated password shown above will satisfy all the rules we have configured in `cassandra.yaml` automatically.
Every generated password will satisfy all the rules. This is clearly an advantage over manual password generation.

When the CQL statement is executed, it will be visible in the CQLSH history (`HISTORY` command or in `cqlsh_history` file)
but the password will not be logged, hence it cannot leak. It will also not appear in any auditing logs.
Previously, Cassandra had to obfuscate such statements. This is not necessary anymore.

We can create a role with generated password like this:

----
cassandra@cqlsh> CREATE ROLE alice WITH GENERATED PASSWORD AND LOGIN = true;
----

When a password is generated for `alice` she can log in:

----
$ cqlsh -u alice -p R7tb33?.mcAX
...
alice@cqlsh>
----

NOTE: It is recommended to save password to ~/.cassandra/credentials, for example:

----
[PlainTextAuthProvider]
username = cassandra
password = R7tb33?.mcAX
----

and by setting auth_provider in `~/.cassandra/cqlshrc`

----
[auth_provider]
module = cassandra.auth
classname = PlainTextAuthProvider
----

It is also possible to configure password validators in such a way that a user does not see why a password failed.
This is driven by configuration property for `password_policy` called `detailed_messages`. When set to `false`,
the violations will be very brief:

----
alice@cqlsh> ALTER ROLE alice WITH PASSWORD = 'myattempt';

InvalidRequest: Error from server: code=2200 [Invalid query]
message="Password was not set as it violated configured password strength policy.
You may also use 'GENERATED PASSWORD' upon role creation or alteration."
----

Several potential enhancements to password generation and validation could be implemented in future releases.
One promising extension would be validating new passwords against previous values.
This would prevent users from reusing passwords until after they’ve created a specified number of different passwords.
A related enhancement could include restricting how frequently users can change their passwords,
preventing rapid cycling through passwords to circumvent history-based restrictions.

These features, while valuable for comprehensive password security, were considered beyond the scope of the initial
implementation and may be addressed in future updates.

=== Runtime configuration

Since this solution is based on guardrails which are configurable via JMX in runtime, same hold for
password validator, also configured via `GuardrailsMBean` as any other guardrails. There are two methods exposed:

* `Map<String, Object> getPasswordPolicy()` - gets password validator configuration as JSON string,
* `void setPasswordPolicy(String value)` - reconfigures the password validator by reading
and parsing the configuration from the provided String, being JSON representation of configuration map.
Reconfiguration of password validator in runtime is considered
to be very sensitive operation. If an operator evaluates the reconfiguration in runtime is not allowed, they
might set `password_policy_reconfiguration_enabled` to `false` in `cassandra.yaml` to disable it.

=== Diagnostic events

If diagnostic event's framework is enabled and consumers are subscribed to them, diagnostic events about
warning and failures to generate a password will be published.

=== Final thoughts and next steps

The Cassandra Password Validator and Generator implemented under CEP-24
represents a significant improvement in Cassandra’s security posture.

By providing robust, configurable password policies with built-in enforcement mechanisms and
convenient password generation capabilities, organizations can now ensure compliance with their
security standards directly at the database level. This not only strengthens overall system security
but also improves the user experience by eliminating guesswork around password requirements.

As Cassandra continues to evolve as an enterprise-ready database solution,
these security enhancements demonstrate a commitment to meeting the demanding
security requirements of modern applications while maintaining the flexibility that makes Cassandra so powerful.