From 2a226963ee81494ea35f93a67931fd41cc13d73d Mon Sep 17 00:00:00 2001 From: Simon Broeng Jensen Date: Thu, 20 Feb 2025 14:30:32 +0100 Subject: [PATCH] auth: move Permission and ValidationResults to auth crate --- crates/auth/Cargo.toml | 1 + crates/auth/src/access_control.rs | 58 +++++++++++++++++++++++++++ crates/auth/src/lib.rs | 1 + server/Cargo.toml | 4 ++ server/src/infra/access_control.rs | 60 +--------------------------- server/src/infra/auth_service.rs | 6 ++- server/src/infra/graphql/api.rs | 4 +- server/src/infra/graphql/mutation.rs | 7 +--- server/src/infra/graphql/query.rs | 6 +-- server/src/infra/ldap_handler.rs | 3 +- 10 files changed, 78 insertions(+), 72 deletions(-) create mode 100644 crates/auth/src/access_control.rs diff --git a/crates/auth/Cargo.toml b/crates/auth/Cargo.toml index f3297b0..3221300 100644 --- a/crates/auth/Cargo.toml +++ b/crates/auth/Cargo.toml @@ -14,6 +14,7 @@ opaque_server = [] opaque_client = [] js = [] sea_orm = ["dep:sea-orm"] +test = [] [dependencies] rust-argon2 = "0.8" diff --git a/crates/auth/src/access_control.rs b/crates/auth/src/access_control.rs new file mode 100644 index 0000000..279d34e --- /dev/null +++ b/crates/auth/src/access_control.rs @@ -0,0 +1,58 @@ +use crate::types::UserId; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub enum Permission { + Admin, + PasswordManager, + Readonly, + Regular, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct ValidationResults { + pub user: UserId, + pub permission: Permission, +} + +impl ValidationResults { + #[cfg(feature = "test")] + pub fn admin() -> Self { + Self { + user: UserId::new("admin"), + permission: Permission::Admin, + } + } + + #[must_use] + pub fn is_admin(&self) -> bool { + self.permission == Permission::Admin + } + + #[must_use] + pub fn can_read_all(&self) -> bool { + self.permission == Permission::Admin + || self.permission == Permission::Readonly + || self.permission == Permission::PasswordManager + } + + #[must_use] + pub fn can_read(&self, user: &UserId) -> bool { + self.permission == Permission::Admin + || self.permission == Permission::PasswordManager + || self.permission == Permission::Readonly + || &self.user == user + } + + #[must_use] + pub fn can_change_password(&self, user: &UserId, user_is_admin: bool) -> bool { + self.permission == Permission::Admin + || (self.permission == Permission::PasswordManager && !user_is_admin) + || &self.user == user + } + + #[must_use] + pub fn can_write(&self, user: &UserId) -> bool { + self.permission == Permission::Admin || &self.user == user + } +} diff --git a/crates/auth/src/lib.rs b/crates/auth/src/lib.rs index 9e3ab0c..5712234 100644 --- a/crates/auth/src/lib.rs +++ b/crates/auth/src/lib.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::fmt; +pub mod access_control; pub mod opaque; /// The messages for the 3-step OPAQUE and simple login process. diff --git a/server/Cargo.toml b/server/Cargo.toml index 62e6114..280112c 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -171,6 +171,10 @@ version = "*" default-features = false features = ["sync", "tls-rustls"] +[dev-dependencies.lldap_auth] +path = "../crates/auth" +features = ["test"] + [dev-dependencies.reqwest] version = "*" default-features = false diff --git a/server/src/infra/access_control.rs b/server/src/infra/access_control.rs index 55d5979..aa59003 100644 --- a/server/src/infra/access_control.rs +++ b/server/src/infra/access_control.rs @@ -1,13 +1,13 @@ use std::collections::HashSet; use async_trait::async_trait; -use tracing::info; - +use lldap_auth::access_control::{Permission, ValidationResults}; use lldap_domain_handlers::handler::{ BackendHandler, GroupBackendHandler, GroupListerBackendHandler, GroupRequestFilter, ReadSchemaBackendHandler, SchemaBackendHandler, UserBackendHandler, UserListerBackendHandler, UserRequestFilter, }; +use tracing::info; use crate::domain::schema::PublicSchema; use lldap_domain::{ @@ -23,62 +23,6 @@ use lldap_domain::{ }; use lldap_domain_model::error::Result; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum Permission { - Admin, - PasswordManager, - Readonly, - Regular, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ValidationResults { - pub user: UserId, - pub permission: Permission, -} - -impl ValidationResults { - #[cfg(test)] - pub fn admin() -> Self { - Self { - user: UserId::new("admin"), - permission: Permission::Admin, - } - } - - #[must_use] - pub fn is_admin(&self) -> bool { - self.permission == Permission::Admin - } - - #[must_use] - pub fn can_read_all(&self) -> bool { - self.permission == Permission::Admin - || self.permission == Permission::Readonly - || self.permission == Permission::PasswordManager - } - - #[must_use] - pub fn can_read(&self, user: &UserId) -> bool { - self.permission == Permission::Admin - || self.permission == Permission::PasswordManager - || self.permission == Permission::Readonly - || &self.user == user - } - - #[must_use] - pub fn can_change_password(&self, user: &UserId, user_is_admin: bool) -> bool { - self.permission == Permission::Admin - || (self.permission == Permission::PasswordManager && !user_is_admin) - || &self.user == user - } - - #[must_use] - pub fn can_write(&self, user: &UserId) -> bool { - self.permission == Permission::Admin || &self.user == user - } -} - #[async_trait] pub trait UserReadableBackendHandler: ReadSchemaBackendHandler { async fn get_user_details(&self, user_id: &UserId) -> Result; diff --git a/server/src/infra/auth_service.rs b/server/src/infra/auth_service.rs index 08e79cf..4e22a28 100644 --- a/server/src/infra/auth_service.rs +++ b/server/src/infra/auth_service.rs @@ -21,7 +21,9 @@ use std::{ use time::ext::NumericalDuration; use tracing::{debug, info, instrument, warn}; -use lldap_auth::{login, password_reset, registration, JWTClaims}; +use lldap_auth::{ + access_control::ValidationResults, login, password_reset, registration, JWTClaims, +}; use lldap_domain::types::{GroupDetails, GroupName, UserId}; use lldap_domain_handlers::handler::{ BackendHandler, BindRequest, LoginHandler, UserRequestFilter, @@ -31,7 +33,7 @@ use lldap_domain_model::{error::DomainError, model::UserColumn}; use crate::{ domain::opaque_handler::OpaqueHandler, infra::{ - access_control::{ReadonlyBackendHandler, UserReadableBackendHandler, ValidationResults}, + access_control::{ReadonlyBackendHandler, UserReadableBackendHandler}, tcp_backend_handler::*, tcp_server::{error_to_http_response, AppState, TcpError, TcpResult}, }, diff --git a/server/src/infra/graphql/api.rs b/server/src/infra/graphql/api.rs index e16bcb0..098c2ce 100644 --- a/server/src/infra/graphql/api.rs +++ b/server/src/infra/graphql/api.rs @@ -1,7 +1,7 @@ use crate::infra::{ access_control::{ AccessControlledBackendHandler, AdminBackendHandler, ReadonlyBackendHandler, - UserReadableBackendHandler, UserWriteableBackendHandler, ValidationResults, + UserReadableBackendHandler, UserWriteableBackendHandler, }, auth_service::check_if_token_is_valid, cli::ExportGraphQLSchemaOpts, @@ -20,7 +20,7 @@ use juniper::{ }, EmptySubscription, FieldError, RootNode, ScalarValue, }; -use lldap_domain::types::UserId; +use lldap_auth::{access_control::ValidationResults, types::UserId}; use lldap_domain_handlers::handler::BackendHandler; use tracing::debug; diff --git a/server/src/infra/graphql/mutation.rs b/server/src/infra/graphql/mutation.rs index 5dc19bb..23b65b8 100644 --- a/server/src/infra/graphql/mutation.rs +++ b/server/src/infra/graphql/mutation.rs @@ -783,15 +783,12 @@ fn deserialize_attribute( mod tests { use super::*; - use crate::infra::{ - access_control::{Permission, ValidationResults}, - graphql::query::Query, - test_utils::MockTestBackendHandler, - }; + use crate::infra::{graphql::query::Query, test_utils::MockTestBackendHandler}; use juniper::{ execute, graphql_value, DefaultScalarValue, EmptySubscription, GraphQLType, InputValue, RootNode, Variables, }; + use lldap_auth::access_control::{Permission, ValidationResults}; use lldap_domain::types::{AttributeName, AttributeType}; use mockall::predicate::eq; use pretty_assertions::assert_eq; diff --git a/server/src/infra/graphql/query.rs b/server/src/infra/graphql/query.rs index cd30ff3..dc6a5f3 100644 --- a/server/src/infra/graphql/query.rs +++ b/server/src/infra/graphql/query.rs @@ -786,15 +786,13 @@ impl AttributeValue { #[cfg(test)] mod tests { use super::*; - use crate::infra::{ - access_control::{Permission, ValidationResults}, - test_utils::{setup_default_schema, MockTestBackendHandler}, - }; + use crate::infra::test_utils::{setup_default_schema, MockTestBackendHandler}; use chrono::TimeZone; use juniper::{ execute, graphql_value, DefaultScalarValue, EmptyMutation, EmptySubscription, GraphQLType, RootNode, Variables, }; + use lldap_auth::access_control::{Permission, ValidationResults}; use lldap_domain::{ schema::{AttributeList, Schema}, types::{AttributeName, AttributeType, LdapObjectClass}, diff --git a/server/src/infra/ldap_handler.rs b/server/src/infra/ldap_handler.rs index 236282c..f15f978 100644 --- a/server/src/infra/ldap_handler.rs +++ b/server/src/infra/ldap_handler.rs @@ -14,7 +14,7 @@ use crate::{ }, infra::access_control::{ AccessControlledBackendHandler, AdminBackendHandler, UserAndGroupListerBackendHandler, - UserReadableBackendHandler, ValidationResults, + UserReadableBackendHandler, }, }; use anyhow::Result; @@ -25,6 +25,7 @@ use ldap3_proto::proto::{ LdapResult as LdapResultOp, LdapResultCode, LdapSearchRequest, LdapSearchResultEntry, LdapSearchScope, OID_PASSWORD_MODIFY, OID_WHOAMI, }; +use lldap_auth::access_control::ValidationResults; use lldap_domain::{ requests::CreateUserRequest, types::{Attribute, AttributeName, AttributeType, Email, Group, UserAndGroups, UserId},