summaryrefslogtreecommitdiff
path: root/src/domain/queries.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/domain/queries.rs')
-rw-r--r--src/domain/queries.rs307
1 files changed, 307 insertions, 0 deletions
diff --git a/src/domain/queries.rs b/src/domain/queries.rs
new file mode 100644
index 0000000..d4eb19e
--- /dev/null
+++ b/src/domain/queries.rs
@@ -0,0 +1,307 @@
+use crate::domain::models::*;
+use anyhow::Result;
+use chrono::{DateTime, Utc};
+
+/// Query Object pattern for complex database queries
+pub trait Query<T> {
+ fn execute(&self) -> Result<Vec<T>>;
+}
+
+/// Base query criteria
+#[derive(Debug, Clone)]
+pub struct QueryCriteria {
+ pub limit: Option<u32>,
+ pub offset: Option<u32>,
+ pub order_by: Option<String>,
+ pub order_direction: Option<OrderDirection>,
+}
+
+#[derive(Debug, Clone)]
+pub enum OrderDirection {
+ Asc,
+ Desc,
+}
+
+impl Default for QueryCriteria {
+ fn default() -> Self {
+ Self {
+ limit: Some(100),
+ offset: None,
+ order_by: None,
+ order_direction: Some(OrderDirection::Desc),
+ }
+ }
+}
+
+/// Audit Events Query Object
+#[derive(Debug, Clone)]
+pub struct AuditEventsQuery {
+ pub criteria: QueryCriteria,
+ pub client_id: Option<String>,
+ pub user_id: Option<String>,
+ pub event_type: Option<String>,
+ pub success: Option<bool>,
+ pub date_from: Option<DateTime<Utc>>,
+ pub date_to: Option<DateTime<Utc>>,
+ pub ip_address: Option<String>,
+}
+
+impl AuditEventsQuery {
+ pub fn new() -> Self {
+ Self {
+ criteria: QueryCriteria::default(),
+ client_id: None,
+ user_id: None,
+ event_type: None,
+ success: None,
+ date_from: None,
+ date_to: None,
+ ip_address: None,
+ }
+ }
+
+ pub fn for_client(mut self, client_id: &str) -> Self {
+ self.client_id = Some(client_id.to_string());
+ self
+ }
+
+ pub fn for_user(mut self, user_id: &str) -> Self {
+ self.user_id = Some(user_id.to_string());
+ self
+ }
+
+ pub fn event_type(mut self, event_type: &str) -> Self {
+ self.event_type = Some(event_type.to_string());
+ self
+ }
+
+ pub fn successful_only(mut self) -> Self {
+ self.success = Some(true);
+ self
+ }
+
+ pub fn failed_only(mut self) -> Self {
+ self.success = Some(false);
+ self
+ }
+
+ pub fn date_range(mut self, from: DateTime<Utc>, to: DateTime<Utc>) -> Self {
+ self.date_from = Some(from);
+ self.date_to = Some(to);
+ self
+ }
+
+ pub fn from_ip(mut self, ip_address: &str) -> Self {
+ self.ip_address = Some(ip_address.to_string());
+ self
+ }
+
+ pub fn limit(mut self, limit: u32) -> Self {
+ self.criteria.limit = Some(limit);
+ self
+ }
+
+ pub fn offset(mut self, offset: u32) -> Self {
+ self.criteria.offset = Some(offset);
+ self
+ }
+}
+
+/// OAuth Clients Query Object
+#[derive(Debug, Clone)]
+pub struct OAuthClientsQuery {
+ pub criteria: QueryCriteria,
+ pub is_active: Option<bool>,
+ pub client_name_contains: Option<String>,
+ pub has_scope: Option<String>,
+ pub grant_type: Option<String>,
+}
+
+impl OAuthClientsQuery {
+ pub fn new() -> Self {
+ Self {
+ criteria: QueryCriteria::default(),
+ is_active: None,
+ client_name_contains: None,
+ has_scope: None,
+ grant_type: None,
+ }
+ }
+
+ pub fn active_only(mut self) -> Self {
+ self.is_active = Some(true);
+ self
+ }
+
+ pub fn inactive_only(mut self) -> Self {
+ self.is_active = Some(false);
+ self
+ }
+
+ pub fn name_contains(mut self, name_part: &str) -> Self {
+ self.client_name_contains = Some(name_part.to_string());
+ self
+ }
+
+ pub fn with_scope(mut self, scope: &str) -> Self {
+ self.has_scope = Some(scope.to_string());
+ self
+ }
+
+ pub fn with_grant_type(mut self, grant_type: &str) -> Self {
+ self.grant_type = Some(grant_type.to_string());
+ self
+ }
+}
+
+/// Token Usage Analytics Query
+#[derive(Debug, Clone)]
+pub struct TokenUsageQuery {
+ pub criteria: QueryCriteria,
+ pub client_id: Option<String>,
+ pub date_from: Option<DateTime<Utc>>,
+ pub date_to: Option<DateTime<Utc>>,
+ pub group_by: TokenUsageGroupBy,
+}
+
+#[derive(Debug, Clone)]
+pub enum TokenUsageGroupBy {
+ Hour,
+ Day,
+ Week,
+ Month,
+ Client,
+}
+
+impl TokenUsageQuery {
+ pub fn new(group_by: TokenUsageGroupBy) -> Self {
+ Self {
+ criteria: QueryCriteria::default(),
+ client_id: None,
+ date_from: None,
+ date_to: None,
+ group_by,
+ }
+ }
+
+ pub fn for_client(mut self, client_id: &str) -> Self {
+ self.client_id = Some(client_id.to_string());
+ self
+ }
+
+ pub fn date_range(mut self, from: DateTime<Utc>, to: DateTime<Utc>) -> Self {
+ self.date_from = Some(from);
+ self.date_to = Some(to);
+ self
+ }
+}
+
+/// Token Usage Statistics Result
+#[derive(Debug, Clone)]
+pub struct TokenUsageStats {
+ pub period: String,
+ pub client_id: Option<String>,
+ pub token_count: u32,
+ pub unique_users: u32,
+ pub success_rate: f64,
+}
+
+/// Failed Authorization Attempts Query
+#[derive(Debug, Clone)]
+pub struct FailedAuthQuery {
+ pub criteria: QueryCriteria,
+ pub client_id: Option<String>,
+ pub ip_address: Option<String>,
+ pub date_from: Option<DateTime<Utc>>,
+ pub date_to: Option<DateTime<Utc>>,
+ pub min_attempts: u32,
+}
+
+impl FailedAuthQuery {
+ pub fn new() -> Self {
+ Self {
+ criteria: QueryCriteria::default(),
+ client_id: None,
+ ip_address: None,
+ date_from: None,
+ date_to: None,
+ min_attempts: 5, // Minimum failed attempts to be considered suspicious
+ }
+ }
+
+ pub fn for_client(mut self, client_id: &str) -> Self {
+ self.client_id = Some(client_id.to_string());
+ self
+ }
+
+ pub fn from_ip(mut self, ip_address: &str) -> Self {
+ self.ip_address = Some(ip_address.to_string());
+ self
+ }
+
+ pub fn min_attempts(mut self, attempts: u32) -> Self {
+ self.min_attempts = attempts;
+ self
+ }
+
+ pub fn last_24_hours(mut self) -> Self {
+ let now = Utc::now();
+ let yesterday = now - chrono::Duration::hours(24);
+ self.date_from = Some(yesterday);
+ self.date_to = Some(now);
+ self
+ }
+}
+
+/// Failed Authorization Result
+#[derive(Debug, Clone)]
+pub struct FailedAuthResult {
+ pub client_id: Option<String>,
+ pub ip_address: Option<String>,
+ pub attempt_count: u32,
+ pub first_attempt: DateTime<Utc>,
+ pub last_attempt: DateTime<Utc>,
+}
+
+/// Query executor trait
+pub trait QueryExecutor {
+ fn execute_audit_query(&self, query: &AuditEventsQuery) -> Result<Vec<AuditEvent>>;
+ fn execute_client_query(&self, query: &OAuthClientsQuery) -> Result<Vec<OAuthClient>>;
+ fn execute_token_usage_query(&self, query: &TokenUsageQuery) -> Result<Vec<TokenUsageStats>>;
+ fn execute_failed_auth_query(&self, query: &FailedAuthQuery) -> Result<Vec<FailedAuthResult>>;
+}
+
+/// Predefined queries for common use cases
+pub struct CommonQueries;
+
+impl CommonQueries {
+ /// Get recent failed login attempts (security monitoring)
+ pub fn recent_failed_logins() -> FailedAuthQuery {
+ FailedAuthQuery::new()
+ .last_24_hours()
+ .min_attempts(3)
+ }
+
+ /// Get audit trail for a specific client
+ pub fn client_audit_trail(client_id: &str) -> AuditEventsQuery {
+ AuditEventsQuery::new()
+ .for_client(client_id)
+ .limit(1000)
+ }
+
+ /// Get token usage statistics for the last 30 days
+ pub fn monthly_token_usage() -> TokenUsageQuery {
+ let now = Utc::now();
+ let thirty_days_ago = now - chrono::Duration::days(30);
+
+ TokenUsageQuery::new(TokenUsageGroupBy::Day)
+ .date_range(thirty_days_ago, now)
+ }
+
+ /// Get all active clients with OpenID scope
+ pub fn openid_clients() -> OAuthClientsQuery {
+ OAuthClientsQuery::new()
+ .active_only()
+ .with_scope("openid")
+ }
+} \ No newline at end of file