You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +03:00
Handle password strength verification through OPA
This commit is contained in:
@ -133,7 +133,7 @@ pub(crate) async fn post(
|
|||||||
|
|
||||||
let mut policy = policy_factory.instantiate().await?;
|
let mut policy = policy_factory.instantiate().await?;
|
||||||
let res = policy
|
let res = policy
|
||||||
.evaluate_register(&form.username, &form.email)
|
.evaluate_register(&form.username, &form.password, &form.email)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
for violation in res.violations {
|
for violation in res.violations {
|
||||||
@ -150,6 +150,12 @@ pub(crate) async fn post(
|
|||||||
message: violation.msg,
|
message: violation.msg,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
Some("password") => state.add_error_on_field(
|
||||||
|
RegisterFormField::Password,
|
||||||
|
FieldError::Policy {
|
||||||
|
message: violation.msg,
|
||||||
|
},
|
||||||
|
),
|
||||||
_ => state.add_error_on_form(FormError::Policy {
|
_ => state.add_error_on_form(FormError::Policy {
|
||||||
message: violation.msg,
|
message: violation.msg,
|
||||||
}),
|
}),
|
||||||
|
@ -16,6 +16,26 @@ violation[{"field": "username", "msg": "username too long"}] {
|
|||||||
count(input.user.username) >= 15
|
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
|
# Allow any domains if the data.allowed_domains array is not set
|
||||||
email_domain_allowed {
|
email_domain_allowed {
|
||||||
not data.allowed_domains
|
not data.allowed_domains
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package register
|
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 {
|
test_allow_all_domains {
|
||||||
allow with input.user as mock_user
|
allow with input.user as mock_user
|
||||||
@ -34,3 +34,39 @@ test_short_username {
|
|||||||
test_long_username {
|
test_long_username {
|
||||||
not allow with input.user as {"username": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "email": "hello@element.io"}
|
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
|
||||||
|
}
|
||||||
|
@ -122,13 +122,13 @@ impl PolicyFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct Violation {
|
pub struct Violation {
|
||||||
pub msg: String,
|
pub msg: String,
|
||||||
pub field: Option<String>,
|
pub field: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct EvaluationResult {
|
pub struct EvaluationResult {
|
||||||
#[serde(rename = "result")]
|
#[serde(rename = "result")]
|
||||||
pub violations: Vec<Violation>,
|
pub violations: Vec<Violation>,
|
||||||
@ -153,11 +153,13 @@ impl Policy {
|
|||||||
pub async fn evaluate_register(
|
pub async fn evaluate_register(
|
||||||
&mut self,
|
&mut self,
|
||||||
username: &str,
|
username: &str,
|
||||||
|
password: &str,
|
||||||
email: &str,
|
email: &str,
|
||||||
) -> Result<EvaluationResult, anyhow::Error> {
|
) -> Result<EvaluationResult, anyhow::Error> {
|
||||||
let input = serde_json::json!({
|
let input = serde_json::json!({
|
||||||
"user": {
|
"user": {
|
||||||
"username": username,
|
"username": username,
|
||||||
|
"password": password,
|
||||||
"email": email
|
"email": email
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user