1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-29 22:01:14 +03:00

Handle password strength verification through OPA

This commit is contained in:
Quentin Gliech
2022-06-03 16:04:14 +02:00
parent eb22c33a7d
commit e694932daf
4 changed files with 68 additions and 4 deletions

View File

@ -133,7 +133,7 @@ pub(crate) async fn post(
let mut policy = policy_factory.instantiate().await?;
let res = policy
.evaluate_register(&form.username, &form.email)
.evaluate_register(&form.username, &form.password, &form.email)
.await?;
for violation in res.violations {
@ -150,6 +150,12 @@ pub(crate) async fn post(
message: violation.msg,
},
),
Some("password") => state.add_error_on_field(
RegisterFormField::Password,
FieldError::Policy {
message: violation.msg,
},
),
_ => state.add_error_on_form(FormError::Policy {
message: violation.msg,
}),

View File

@ -16,6 +16,26 @@ violation[{"field": "username", "msg": "username too long"}] {
count(input.user.username) >= 15
}
violation[{"field": "password", "msg": msg}] {
count(input.user.password) < data.passwords.min_length
msg := sprintf("needs to be at least %d characters", [data.passwords.min_length])
}
violation[{"field": "password", "msg": "requires at least one number"}] {
data.passwords.require_number
not regex.match("[0-9]", input.user.password)
}
violation[{"field": "password", "msg": "requires at least one lowercase letter"}] {
data.passwords.require_lowercase
not regex.match("[a-z]", input.user.password)
}
violation[{"field": "password", "msg": "requires at least one uppercase letter"}] {
data.passwords.require_uppercase
not regex.match("[A-Z]", input.user.password)
}
# Allow any domains if the data.allowed_domains array is not set
email_domain_allowed {
not data.allowed_domains

View File

@ -1,6 +1,6 @@
package register
mock_user := {"username": "hello", "email": "hello@staging.element.io"}
mock_user := {"username": "hello", "password": "Hunter2", "email": "hello@staging.element.io"}
test_allow_all_domains {
allow with input.user as mock_user
@ -34,3 +34,39 @@ test_short_username {
test_long_username {
not allow with input.user as {"username": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "email": "hello@element.io"}
}
test_password_require_number {
allow with input.user as mock_user
with data.passwords.require_number as true
not allow with input.user as mock_user
with input.user.password as "hunter"
with data.passwords.require_number as true
}
test_password_require_lowercase {
allow with input.user as mock_user
with data.passwords.require_lowercase as true
not allow with input.user as mock_user
with input.user.password as "HUNTER2"
with data.passwords.require_lowercase as true
}
test_password_require_uppercase {
allow with input.user as mock_user
with data.passwords.require_uppercase as true
not allow with input.user as mock_user
with input.user.password as "hunter2"
with data.passwords.require_uppercase as true
}
test_password_min_length {
allow with input.user as mock_user
with data.passwords.min_length as 6
not allow with input.user as mock_user
with input.user.password as "short"
with data.passwords.min_length as 6
}

View File

@ -122,13 +122,13 @@ impl PolicyFactory {
}
}
#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
pub struct Violation {
pub msg: String,
pub field: Option<String>,
}
#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
pub struct EvaluationResult {
#[serde(rename = "result")]
pub violations: Vec<Violation>,
@ -153,11 +153,13 @@ impl Policy {
pub async fn evaluate_register(
&mut self,
username: &str,
password: &str,
email: &str,
) -> Result<EvaluationResult, anyhow::Error> {
let input = serde_json::json!({
"user": {
"username": username,
"password": password,
"email": email
}
});