Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/defguard_core/src/db/models/audit_log/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,8 @@ pub struct VpnClientMfaMetadata {
pub device: Device<Id>,
pub method: MFAMethod,
}

#[derive(Serialize)]
pub struct EnrollmentDeviceAddedMetadata {
pub device: Device<Id>,
}
7 changes: 7 additions & 0 deletions crates/defguard_core/src/db/models/audit_log/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ pub enum EventType {
VpnClientConnectedMfa,
VpnClientDisconnectedMfa,
VpnClientMfaFailed,
// Enrollment events
EnrollmentStarted,
EnrollmentDeviceAdded,
EnrollmentCompleted,
PasswordResetRequested,
PasswordResetStarted,
PasswordResetCompleted,
}

#[derive(Model, FromRow, Serialize)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ pub struct ServiceAccountConfig {
client_email: String,
}

#[allow(dead_code)]
pub(crate) struct GoogleDirectorySync {
service_account_config: ServiceAccountConfig,
access_token: Option<String>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use super::{
};
use crate::enterprise::directory_sync::REQUEST_TIMEOUT;

#[allow(dead_code)]
pub(crate) struct MicrosoftDirectorySync {
access_token: Option<String>,
token_expiry: Option<chrono::DateTime<Utc>>,
Expand Down
1 change: 0 additions & 1 deletion crates/defguard_core/src/enterprise/directory_sync/okta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ impl Claims {
}
}

#[allow(dead_code)]
pub struct OktaDirectorySync {
access_token: Option<String>,
token_expiry: Option<DateTime<Utc>>,
Expand Down
39 changes: 21 additions & 18 deletions crates/defguard_core/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,26 +177,18 @@ pub struct BidiRequestContext {
pub user_id: Id,
pub username: String,
pub ip: IpAddr,
pub device: Device<Id>,
pub location: WireguardNetwork<Id>,
pub user_agent: String,
}

impl BidiRequestContext {
pub fn new(
user_id: Id,
username: String,
ip: IpAddr,
device: Device<Id>,
location: WireguardNetwork<Id>,
) -> Self {
pub fn new(user_id: Id, username: String, ip: IpAddr, user_agent: String) -> Self {
let timestamp = Utc::now().naive_utc();
Self {
timestamp,
user_id,
username,
ip,
device,
location,
user_agent,
}
}
}
Expand All @@ -211,31 +203,42 @@ pub struct BidiStreamEvent {
/// Wrapper enum for different types of events emitted by the bidi stream.
///
/// Each variant represents a separate gRPC service that's part of the bi-directional communications server.
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
pub enum BidiStreamEventType {
Enrollment(EnrollmentEvent),
PasswordReset(PasswordResetEvent),
DesktopClientMfa(DesktopClientMfaEvent),
ConfigPolling(ConfigPollingEvent),
}

#[derive(Debug)]
pub enum EnrollmentEvent {
EnrollmentStarted,
EnrollmentDeviceAdded { device: Device<Id> },
EnrollmentCompleted,
}

#[derive(Debug)]
pub enum PasswordResetEvent {}
pub enum PasswordResetEvent {
PasswordResetRequested,
PasswordResetStarted,
PasswordResetCompleted,
}

#[derive(Debug)]
pub enum DesktopClientMfaEvent {
Connected { method: MFAMethod },
Failed { method: MFAMethod },
Connected {
device: Device<Id>,
location: WireguardNetwork<Id>,
method: MFAMethod,
},
Failed {
device: Device<Id>,
location: WireguardNetwork<Id>,
method: MFAMethod,
},
}

#[derive(Debug)]
pub enum ConfigPollingEvent {}

/// Shared context for every internally-triggered event.
///
/// Similarly to `ApiRequestContexts` at the moment it's mostly meant to populate the audit log.
Expand Down
23 changes: 13 additions & 10 deletions crates/defguard_core/src/grpc/desktop_client_mfa.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, net::Ipv4Addr};
use std::collections::HashMap;

use chrono::Utc;
use sqlx::PgPool;
Expand All @@ -10,8 +10,8 @@ use tokio::sync::{
use tonic::{Code, Status};

use super::proto::proxy::{
ClientMfaFinishRequest, ClientMfaFinishResponse, ClientMfaStartRequest, ClientMfaStartResponse,
MfaMethod,
self, ClientMfaFinishRequest, ClientMfaFinishResponse, ClientMfaStartRequest,
ClientMfaStartResponse, MfaMethod,
};
use crate::{
auth::{Claims, ClaimsType},
Expand All @@ -20,6 +20,7 @@ use crate::{
Device, GatewayEvent, Id, User, UserInfo, WireguardNetwork,
},
events::{BidiRequestContext, BidiStreamEvent, BidiStreamEventType, DesktopClientMfaEvent},
grpc::utils::parse_client_info,
handlers::mail::send_email_mfa_code_email,
mail::Mail,
};
Expand Down Expand Up @@ -221,6 +222,7 @@ impl ClientMfaServer {
pub async fn finish_client_mfa_login(
&mut self,
request: ClientMfaFinishRequest,
info: Option<proxy::DeviceInfo>,
) -> Result<ClientMfaFinishResponse, Status> {
debug!("Finishing desktop client login: {request:?}");
// get pubkey from token
Expand All @@ -239,13 +241,8 @@ impl ClientMfaServer {
} = session;

// Prepare event context
let context = BidiRequestContext::new(
user.id,
user.username.clone(),
std::net::IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
device.clone(),
location.clone(),
);
let (ip, user_agent) = parse_client_info(&info).map_err(Status::internal)?;
let context = BidiRequestContext::new(user.id, user.username.clone(), ip, user_agent);

// validate code
match method {
Expand All @@ -256,6 +253,8 @@ impl ClientMfaServer {
context,
event: BidiStreamEventType::DesktopClientMfa(
DesktopClientMfaEvent::Failed {
location: location.clone(),
device: device.clone(),
method: (*method).into(),
},
),
Expand All @@ -270,6 +269,8 @@ impl ClientMfaServer {
context,
event: BidiStreamEventType::DesktopClientMfa(
DesktopClientMfaEvent::Failed {
location: location.clone(),
device: device.clone(),
method: (*method).into(),
},
),
Expand Down Expand Up @@ -334,6 +335,8 @@ impl ClientMfaServer {
self.emit_event(BidiStreamEvent {
context,
event: BidiStreamEventType::DesktopClientMfa(DesktopClientMfaEvent::Connected {
location: location.clone(),
device: device.clone(),
method: (*method).into(),
}),
})?;
Expand Down
46 changes: 37 additions & 9 deletions crates/defguard_core/src/grpc/enrollment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use super::{
},
InstanceInfo,
};
use crate::grpc::utils::parse_client_info;
use crate::{
db::{
models::{
Expand Down Expand Up @@ -40,7 +41,6 @@ pub(super) struct EnrollmentServer {
pool: PgPool,
wireguard_tx: Sender<GatewayEvent>,
mail_tx: UnboundedSender<Mail>,
#[allow(dead_code)]
bidi_event_tx: UnboundedSender<BidiStreamEvent>,
}

Expand Down Expand Up @@ -97,7 +97,6 @@ impl EnrollmentServer {
}

// Send event to the dedicated bidi stream event channel
#[allow(dead_code)]
fn emit_event(
&self,
context: BidiRequestContext,
Expand All @@ -115,6 +114,7 @@ impl EnrollmentServer {
pub async fn start_enrollment(
&self,
request: EnrollmentStartRequest,
info: Option<super::proto::proxy::DeviceInfo>,
) -> Result<EnrollmentStartResponse, Status> {
debug!("Starting enrollment session, request: {request:?}");
// fetch enrollment token
Expand Down Expand Up @@ -248,6 +248,15 @@ impl EnrollmentServer {
Status::internal("unexpected error")
})?;

// Prepare event context and push the event
let (ip, user_agent) = parse_client_info(&info).map_err(Status::internal)?;
let context = BidiRequestContext::new(user_id, username, ip, user_agent);
self.emit_event(context, EnrollmentEvent::EnrollmentStarted)
.map_err(|err| {
error!("Failed to send event. Reason: {err}",);
Status::internal("unexpected error")
})?;

Ok(response)
} else {
debug!("Invalid enrollment token, the token does not have specified type.");
Expand All @@ -266,9 +275,9 @@ impl EnrollmentServer {

let ip_address;
let device_info;
if let Some(info) = req_device_info {
ip_address = info.ip_address.unwrap_or_default();
let user_agent = info.user_agent.unwrap_or_default();
if let Some(ref info) = req_device_info {
ip_address = info.ip_address.clone();
let user_agent = info.user_agent.clone().unwrap_or_default();
device_info = Some(get_device_info(&user_agent));
} else {
ip_address = String::new();
Expand Down Expand Up @@ -364,6 +373,16 @@ impl EnrollmentServer {
ldap_add_user(&mut user, Some(&request.password), &self.pool).await;

info!("User {} activated", user.username);

// Prepare event context and push the event
let (ip, user_agent) = parse_client_info(&req_device_info).map_err(Status::internal)?;
let context = BidiRequestContext::new(user.id, user.username.clone(), ip, user_agent);
self.emit_event(context, EnrollmentEvent::EnrollmentCompleted)
.map_err(|err| {
error!("Failed to send event. Reason: {err}",);
Status::internal("unexpected error")
})?;

Ok(())
}

Expand Down Expand Up @@ -400,9 +419,9 @@ impl EnrollmentServer {

let ip_address;
let device_info;
if let Some(info) = req_device_info {
ip_address = info.ip_address.unwrap_or_default();
let user_agent = info.user_agent.unwrap_or_default();
if let Some(ref info) = req_device_info {
ip_address = info.ip_address.clone();
let user_agent = info.user_agent.clone().unwrap_or_default();
device_info = Some(get_device_info(&user_agent));
} else {
ip_address = String::new();
Expand Down Expand Up @@ -679,7 +698,7 @@ impl EnrollmentServer {
info!("Device {} remote configuration done.", device.name);

let response = DeviceConfigResponse {
device: Some(device.into()),
device: Some(device.clone().into()),
configs: configs.into_iter().map(Into::into).collect(),
instance: Some(
InstanceInfo::new(settings, &user.username, &enterprise_settings).into(),
Expand All @@ -688,6 +707,15 @@ impl EnrollmentServer {
};
debug!("{response:?}.");

// Prepare event context and push the event
let (ip, user_agent) = parse_client_info(&req_device_info).map_err(Status::internal)?;
let context = BidiRequestContext::new(user.id, user.username.clone(), ip, user_agent);
self.emit_event(context, EnrollmentEvent::EnrollmentDeviceAdded { device })
.map_err(|err| {
error!("Failed to send event. Reason: {err}",);
Status::internal("unexpected error")
})?;

Ok(response)
}

Expand Down
15 changes: 12 additions & 3 deletions crates/defguard_core/src/grpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,10 @@ pub async fn run_grpc_bidi_stream(
let payload = match received.payload {
// rpc StartEnrollment (EnrollmentStartRequest) returns (EnrollmentStartResponse)
Some(core_request::Payload::EnrollmentStart(request)) => {
match enrollment_server.start_enrollment(request).await {
match enrollment_server
.start_enrollment(request, received.device_info)
.await
{
Ok(response_payload) => {
Some(core_response::Payload::EnrollmentStart(response_payload))
}
Expand Down Expand Up @@ -595,7 +598,10 @@ pub async fn run_grpc_bidi_stream(
}
// rpc StartPasswordReset (PasswordResetStartRequest) returns (PasswordResetStartResponse)
Some(core_request::Payload::PasswordResetStart(request)) => {
match password_reset_server.start_password_reset(request).await {
match password_reset_server
.start_password_reset(request, received.device_info)
.await
{
Ok(response_payload) => Some(
core_response::Payload::PasswordResetStart(response_payload),
),
Expand Down Expand Up @@ -632,7 +638,10 @@ pub async fn run_grpc_bidi_stream(
}
// rpc ClientMfaFinish (ClientMfaFinishRequest) returns (ClientMfaFinishResponse)
Some(core_request::Payload::ClientMfaFinish(request)) => {
match client_mfa_server.finish_client_mfa_login(request).await {
match client_mfa_server
.finish_client_mfa_login(request, received.device_info)
.await
{
Ok(response_payload) => {
Some(core_response::Payload::ClientMfaFinish(response_payload))
}
Expand Down
Loading