From 035a220d5555d6d7d5cebce57e22b0e847c7d832 Mon Sep 17 00:00:00 2001 From: Stefan Miklosovic Date: Tue, 16 Sep 2025 15:17:53 +0200 Subject: [PATCH] Implementation of CEP-55 - Generation of role names patch by Stefan Miklosovic; reviewed by Bernardo Botella for CASSANDRA-20897 --- CHANGES.txt | 1 + NEWS.txt | 5 +- conf/cassandra.yaml | 33 ++- conf/cassandra_latest.yaml | 92 ++++++++ doc/cql3/CQL.textile | 14 +- doc/modules/cassandra/nav.adoc | 1 + .../pages/managing/operating/index.adoc | 1 + .../operating/password_validation.adoc | 21 +- .../operating/role_name_generation.adoc | 122 ++++++++++ .../pages/managing/operating/security.adoc | 8 +- doc/scripts/convert_yaml_to_adoc.py | 3 +- pylib/cqlshlib/cql3handling.py | 5 + pylib/cqlshlib/cqlshmain.py | 21 +- pylib/cqlshlib/test/test_cqlsh_completion.py | 4 + src/antlr/Parser.g | 29 ++- .../cassandra/audit/AuditLogManager.java | 6 +- .../cassandra/auth/CassandraRoleManager.java | 80 ++++++- .../apache/cassandra/auth/IRoleManager.java | 41 +++- .../apache/cassandra/auth/RoleOptions.java | 5 + .../apache/cassandra/auth/RoleResource.java | 2 + .../org/apache/cassandra/config/Config.java | 6 +- .../cassandra/config/DatabaseDescriptor.java | 9 +- .../cassandra/config/GuardrailsOptions.java | 23 +- .../cql3/statements/AlterRoleStatement.java | 13 +- .../statements/AuthenticationStatement.java | 32 --- .../cql3/statements/CreateRoleStatement.java | 57 +++-- ...rail.java => AbstractCustomGuardrail.java} | 57 ++--- .../CassandraPasswordConfiguration.java | 7 + .../CassandraPasswordGenerator.java | 14 +- .../db/guardrails/CustomGuardrail.java | 35 ++- .../cassandra/db/guardrails/Guardrails.java | 61 ++++- .../db/guardrails/GuardrailsConfig.java | 9 +- .../db/guardrails/GuardrailsMBean.java | 21 +- .../db/guardrails/NoOpGenerator.java | 13 +- .../db/guardrails/NoOpValidator.java | 5 +- .../guardrails/PasswordPolicyGuardrail.java | 71 ++++++ .../guardrails/RoleNamePolicyGuardrail.java | 71 ++++++ .../db/guardrails/UUIDRoleNameGenerator.java | 192 +++++++++++++++ .../db/guardrails/ValueGenerator.java | 62 +++-- .../db/guardrails/ValueValidator.java | 14 +- .../nodetool/GuardrailsConfigCommand.java | 2 +- .../GuardrailPasswordPolicyTest.java | 165 +++++++++++++ ...java => GuardrailsRoleNamePolicyTest.java} | 40 ++-- .../guardrails/AbstractGenerationalTest.java | 122 ++++++++++ .../CassandraPasswordGeneratorTest.java | 1 - .../CassandraPasswordValidatorTest.java | 12 +- .../GenerationalGuardrailsTest.java | 87 +++++++ ....java => GuardrailPasswordPolicyTest.java} | 220 +++++++----------- .../GuardrailRoleNamePolicyTest.java | 182 +++++++++++++++ .../guardrails/InvalidRoleNameGenerator.java | 58 +++++ .../db/guardrails/RoleNameValidatorTest.java | 50 ++++ .../db/guardrails/TestRoleNameValidator.java | 75 ++++++ .../guardrails/UUIDRoleNameGeneratorTest.java | 206 ++++++++++++++++ .../db/guardrails/ValueGeneratorTest.java | 19 +- .../db/guardrails/ValueValidatorTest.java | 6 +- 55 files changed, 2102 insertions(+), 409 deletions(-) create mode 100644 doc/modules/cassandra/pages/managing/operating/role_name_generation.adoc rename src/java/org/apache/cassandra/db/guardrails/{PasswordGuardrail.java => AbstractCustomGuardrail.java} (60%) create mode 100644 src/java/org/apache/cassandra/db/guardrails/PasswordPolicyGuardrail.java create mode 100644 src/java/org/apache/cassandra/db/guardrails/RoleNamePolicyGuardrail.java create mode 100644 src/java/org/apache/cassandra/db/guardrails/UUIDRoleNameGenerator.java create mode 100644 test/distributed/org/apache/cassandra/distributed/test/guardrails/GuardrailPasswordPolicyTest.java rename test/distributed/org/apache/cassandra/distributed/test/guardrails/{GuardrailPasswordTest.java => GuardrailsRoleNamePolicyTest.java} (61%) create mode 100644 test/unit/org/apache/cassandra/db/guardrails/AbstractGenerationalTest.java create mode 100644 test/unit/org/apache/cassandra/db/guardrails/GenerationalGuardrailsTest.java rename test/unit/org/apache/cassandra/db/guardrails/{GuardrailPasswordTest.java => GuardrailPasswordPolicyTest.java} (63%) create mode 100644 test/unit/org/apache/cassandra/db/guardrails/GuardrailRoleNamePolicyTest.java create mode 100644 test/unit/org/apache/cassandra/db/guardrails/InvalidRoleNameGenerator.java create mode 100644 test/unit/org/apache/cassandra/db/guardrails/RoleNameValidatorTest.java create mode 100644 test/unit/org/apache/cassandra/db/guardrails/TestRoleNameValidator.java create mode 100644 test/unit/org/apache/cassandra/db/guardrails/UUIDRoleNameGeneratorTest.java diff --git a/CHANGES.txt b/CHANGES.txt index fbd9d21d2d..0f5b3fa878 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 5.1 + * Implementation of CEP-55 - Generation of role names (CASSANDRA-20897) * Add cqlsh autocompletion for the identity mapping feature (CASSANDRA-20021) * Add DDL Guardrail enabling administrators to disallow creation/modification of keyspaces with durable_writes = false (CASSANDRA-20913) * Optimize Counter, Meter and Histogram metrics using thread local counters (CASSANDRA-20250) diff --git a/NEWS.txt b/NEWS.txt index f6e04f0223..f2c18f6762 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -102,10 +102,13 @@ New features - Authentication mode is exposed in system_views.clients table, nodetool clientstats and ClientMetrics to help operators identify which authentication modes are being used. nodetool clientstats introduces --verbose flag behind which this information is visible. - - CEP-24 - Password validation / generation. When built-in 'password_validator' guardrail is enabled, it will + - CEP-24 - Password validation / generation. When built-in 'password_policy' guardrail is enabled, it will generate a password of configured password strength policy upon role creation or alteration when 'GENERATED PASSWORD' clause is used. Character sets supported are: English, Cyrillic, modern Cyrillic, German, Polish and Czech. + - CEP-55 - Role name generation and validation. When built-in 'role_name_policy' guardrail is enabled, it will + generate a role name automatically, without operators intervention. It is possible to configure + this policy for both generation and as well as validation of role names. - There is new MBean of name org.apache.cassandra.service.snapshot:type=SnapshotManager which exposes user-facing snapshot operations. Snapshot-related methods on StorageServiceMBean are still present and functional but marked as deprecated. diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml index 0147adc74b..8379ee49e7 100644 --- a/conf/cassandra.yaml +++ b/conf/cassandra.yaml @@ -2507,20 +2507,41 @@ drop_compact_storage_enabled: false # This would also apply to system keyspaces. # maximum_replication_factor_warn_threshold: -1 # maximum_replication_factor_fail_threshold: -1 -# + +#role_name_policy: +# # Implementation class of a validator. When not in form of FQCN, the +# # package name org.apache.cassandra.db.guardrails is prepended. +# # By default, there is no validator. +# #validator_class_name: YourValidatorOfRoleNames +# # 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 is prepended. +# # By default, there is no generator. +# # There is currently only one generator possible to configure - UUIDRoleNameGenerator +# generator_class_name: UUIDRoleNameGenerator +# # Minimum generated size of a name when name_size option is specified in CQL. +# # This can not be less than 10 and more than 32. +# #min_generated_name_size: 10 + +# If this is set to false, then it is not possible to call reconfiguration +# method in GuardrailsMBean. It will effectively forbid the reconfiguration of role_name_policy in runtime. +# You would need to stop the node, change the configuration in cassandra.yaml and start the node again. +# Defaults to true, which means that reconfiguration of role_name_policy via JMX is possible. +#role_name_policy_reconfiguration_enabled: true + # Guardrail to warn or fail when setting / altering a password. # Supported character sets are (both upper and lower-case): English, Cyrillic and modern Cyrillic, Czech, German, Polish. # Password is invalid if all characters are from non-supported character set. If a password is otherwise valid, # but it contains characters from unsupported language, these characters contribute only to password length rule. # All digits and all following special characters are supported too: !"#$%&()*+,-./:;<=>?@[\]^_`{|}~ -#password_validator: +#password_policy: # # Implementation class of a validator. When not in form of FQCN, the -# # package name org.apache.cassandra.db.guardrails.validators is prepended. +# # package name org.apache.cassandra.db.guardrails is prepended. # # By default, there is no validator. -# class_name: CassandraPasswordValidator +# 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. +# # package name org.apache.cassandra.db.guardrails is prepended. # # By default, there is no generator. # generator_class_name: CassandraPasswordGenerator # # There are four characteristics: @@ -2571,7 +2592,7 @@ drop_compact_storage_enabled: false # method in GuardrailsMBean. It will effectively forbid the reconfiguration of password validator in runtime. # You would need to stop the node, change the configuration in cassandra.yaml and start the node again. # Defaults to true, which means that reconfiguration of password validator via JMX is possible. -# password_validator_reconfiguration_enabled: true +#password_policy_reconfiguration_enabled: true # Guardrail to enable a CREATE or ALTER TABLE statement when default_time_to_live is set to 0 # and the table is using TimeWindowCompactionStrategy compaction or a subclass of it. diff --git a/conf/cassandra_latest.yaml b/conf/cassandra_latest.yaml index f426048431..bd2c5577fd 100644 --- a/conf/cassandra_latest.yaml +++ b/conf/cassandra_latest.yaml @@ -2290,6 +2290,98 @@ drop_compact_storage_enabled: false # maximum_replication_factor_warn_threshold: -1 # maximum_replication_factor_fail_threshold: -1 +#role_name_policy: +# # Implementation class of a validator. When not in form of FQCN, the +# # package name org.apache.cassandra.db.guardrails is prepended. +# # By default, there is no validator. +# #validator_class_name: YourValidatorOfRoleNames +# # 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 is prepended. +# # By default, there is no generator. +# # There is currently only one generator possible to configure - UUIDRoleNameGenerator +# generator_class_name: UUIDRoleNameGenerator +# # Minimum generated size of a name when name_size option is specified in CQL. +# # This can not be less than 10 and more than 32. +# #min_generated_name_size: 10 + +# If this is set to false, then it is not possible to call reconfiguration +# method in GuardrailsMBean. It will effectively forbid the reconfiguration of role_name_policy in runtime. +# You would need to stop the node, change the configuration in cassandra.yaml and start the node again. +# Defaults to true, which means that reconfiguration of role_name_policy via JMX is possible. +#role_name_policy_reconfiguration_enabled: true + +# If this is set to false, then it is not possible to call reconfiguration +# method in GuardrailsMBean. It will effectively forbid the reconfiguration of role_name_policy in runtime. +# You would need to stop the node, change the configuration in cassandra.yaml and start the node again. +# Defaults to true, which means that reconfiguration of role_name_policy via JMX is possible. +#rolename_validator_reconfiguration_enabled: true + +# Guardrail to warn or fail when setting / altering a password. +# Supported character sets are (both upper and lower-case): English, Cyrillic and modern Cyrillic, Czech, German, Polish. +# Password is invalid if all characters are from non-supported character set. If a password is otherwise valid, +# but it contains characters from unsupported language, these characters contribute only to password length rule. +# All digits and all following special characters are supported too: !"#$%&()*+,-./:;<=>?@[\]^_`{|}~ +#password_policy: +# # Implementation class of a validator. When not in form of FQCN, the +# # package name org.apache.cassandra.db.guardrails is prepended. +# # By default, there is no validator. +# 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 is prepended. +# # By default, there is no generator. +# generator_class_name: CassandraPasswordGenerator +# # There are four characteristics: +# # 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 number of characteristics found in the password is less than or equal to this number, it will emit warning. +# characteristic_warn: 3 +# # If number of characteristics found in the password is less than or equal to this number, it will emit failure. +# characteristic_fail: 2 +# # Maximum length of a password. Defaults to 1000. +# max_length: 1000 +# # If 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 +# # If a password contain illegal sequences that 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 sequencies from supported character sets. +# # The minimum value for this property is 3, by default it is set to 5. +# illegal_sequence_length: 5 +# # 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 +# # If set to true, a user will be informed what policies a suggested password is missing in order to be valid. +# # Defaults to true. +# detailed_messages: true + +# If this is set to false, then it is not possible to call reconfiguration +# method in GuardrailsMBean. It will effectively forbid the reconfiguration of password validator in runtime. +# You would need to stop the node, change the configuration in cassandra.yaml and start the node again. +# Defaults to true, which means that reconfiguration of password validator via JMX is possible. +#password_policy_reconfiguration_enabled: true + # Guardrail to enable a CREATE or ALTER TABLE statement when default_time_to_live is set to 0 # and the table is using TimeWindowCompactionStrategy compaction or a subclass of it. # It is suspicious to use default_time_to_live set to 0 with such compaction strategy. diff --git a/doc/cql3/CQL.textile b/doc/cql3/CQL.textile index 95cb1ecd96..6efcea6dde 100644 --- a/doc/cql3/CQL.textile +++ b/doc/cql3/CQL.textile @@ -1329,7 +1329,7 @@ h3(#createRoleStmt). CREATE ROLE __Syntax:__ bc(syntax).. - ::= CREATE ROLE ( IF NOT EXISTS )? ( WITH