diff --git a/crates/defguard_core/src/db/models/device.rs b/crates/defguard_core/src/db/models/device.rs index f359eb638..38f2bd01f 100644 --- a/crates/defguard_core/src/db/models/device.rs +++ b/crates/defguard_core/src/db/models/device.rs @@ -28,10 +28,14 @@ use super::wireguard::{ }; use crate::{ KEY_LENGTH, - db::{User, models::wireguard::ServiceLocationMode}, + db::{ + User, + models::wireguard::{ServiceLocationMode, get_allowed_ips_for_device}, + }, + enterprise::db::models::enterprise_settings::EnterpriseSettings, }; -#[derive(Serialize, ToSchema)] +#[derive(Deserialize, Serialize, ToSchema)] pub struct DeviceConfig { pub(crate) network_id: Id, pub(crate) network_name: String, @@ -40,7 +44,7 @@ pub struct DeviceConfig { pub(crate) address: Vec, pub(crate) endpoint: String, #[schema(value_type = String)] - pub(crate) allowed_ips: Vec, + pub allowed_ips: Vec, pub(crate) pubkey: String, pub(crate) dns: Option, pub(crate) keepalive_interval: i32, @@ -568,10 +572,11 @@ impl Device { /// Create WireGuard config for device. #[must_use] pub(crate) fn create_config( - network: &WireguardNetwork, + location: &WireguardNetwork, wireguard_network_device: &WireguardNetworkDevice, + enterprise_settings: &EnterpriseSettings, ) -> String { - let dns = match &network.dns { + let dns = match &location.dns { Some(dns) => { if dns.is_empty() { String::new() @@ -582,10 +587,11 @@ impl Device { None => String::new(), }; - let allowed_ips = if network.allowed_ips.is_empty() { + let location_allowed_ips = get_allowed_ips_for_device(enterprise_settings, location); + let allowed_ips = if location_allowed_ips.is_empty() { String::new() } else { - format!("AllowedIPs = {}\n", network.allowed_ips.as_csv()) + format!("AllowedIPs = {}\n", location_allowed_ips.as_csv()) }; format!( @@ -600,9 +606,9 @@ impl Device { Endpoint = {}:{}\n\ PersistentKeepalive = 300", wireguard_network_device.wireguard_ips.as_csv(), - network.pubkey, - network.endpoint, - network.port, + location.pubkey, + location.endpoint, + location.port, ) } @@ -682,33 +688,35 @@ impl Device { pub(crate) async fn get_network_configs( &self, - network: &WireguardNetwork, transaction: &mut PgConnection, + location: &WireguardNetwork, + enterprise_settings: &EnterpriseSettings, ) -> Result<(DeviceNetworkInfo, DeviceConfig), DeviceError> { let wireguard_network_device = - WireguardNetworkDevice::find(&mut *transaction, self.id, network.id) + WireguardNetworkDevice::find(&mut *transaction, self.id, location.id) .await? .ok_or_else(|| DeviceError::Unexpected("Device not found in network".into()))?; let device_network_info = DeviceNetworkInfo { - network_id: network.id, + network_id: location.id, device_wireguard_ips: wireguard_network_device.wireguard_ips.clone(), preshared_key: wireguard_network_device.preshared_key.clone(), is_authorized: wireguard_network_device.is_authorized, }; - let config = Self::create_config(network, &wireguard_network_device); + let config = Self::create_config(location, &wireguard_network_device, enterprise_settings); + let allowed_ips = get_allowed_ips_for_device(enterprise_settings, location); let device_config = DeviceConfig { - network_id: network.id, - network_name: network.name.clone(), + network_id: location.id, + network_name: location.name.clone(), config, - endpoint: format!("{}:{}", network.endpoint, network.port), + endpoint: format!("{}:{}", location.endpoint, location.port), address: wireguard_network_device.wireguard_ips, - allowed_ips: network.allowed_ips.clone(), - pubkey: network.pubkey.clone(), - dns: network.dns.clone(), - keepalive_interval: network.keepalive_interval, - location_mfa_mode: network.location_mfa_mode.clone(), - service_location_mode: network.service_location_mode.clone(), + allowed_ips, + pubkey: location.pubkey.clone(), + dns: location.dns.clone(), + keepalive_interval: location.keepalive_interval, + location_mfa_mode: location.location_mfa_mode.clone(), + service_location_mode: location.service_location_mode.clone(), }; Ok((device_network_info, device_config)) @@ -716,33 +724,35 @@ impl Device { pub(crate) async fn add_to_network( &self, - network: &WireguardNetwork, - ip: &[IpAddr], transaction: &mut PgConnection, + location: &WireguardNetwork, + ip: &[IpAddr], + enterprise_settings: &EnterpriseSettings, ) -> Result<(DeviceNetworkInfo, DeviceConfig), DeviceError> { let wireguard_network_device = self - .assign_network_ips(&mut *transaction, network, ip) + .assign_network_ips(&mut *transaction, location, ip) .await?; let device_network_info = DeviceNetworkInfo { - network_id: network.id, + network_id: location.id, device_wireguard_ips: wireguard_network_device.wireguard_ips.clone(), preshared_key: wireguard_network_device.preshared_key.clone(), is_authorized: wireguard_network_device.is_authorized, }; - let config = Self::create_config(network, &wireguard_network_device); + let config = Self::create_config(location, &wireguard_network_device, enterprise_settings); + let allowed_ips = get_allowed_ips_for_device(enterprise_settings, location); let device_config = DeviceConfig { - network_id: network.id, - network_name: network.name.clone(), + network_id: location.id, + network_name: location.name.clone(), config, - endpoint: format!("{}:{}", network.endpoint, network.port), + endpoint: format!("{}:{}", location.endpoint, location.port), address: wireguard_network_device.wireguard_ips, - allowed_ips: network.allowed_ips.clone(), - pubkey: network.pubkey.clone(), - dns: network.dns.clone(), - keepalive_interval: network.keepalive_interval, - location_mfa_mode: network.location_mfa_mode.clone(), - service_location_mode: network.service_location_mode.clone(), + allowed_ips, + pubkey: location.pubkey.clone(), + dns: location.dns.clone(), + keepalive_interval: location.keepalive_interval, + location_mfa_mode: location.location_mfa_mode.clone(), + service_location_mode: location.service_location_mode.clone(), }; Ok((device_network_info, device_config)) @@ -754,58 +764,62 @@ impl Device { transaction: &mut PgConnection, ) -> Result<(Vec, Vec), DeviceError> { info!("Adding device {} to all existing networks", self.name); - let networks = WireguardNetwork::all(&mut *transaction).await?; + let locations = WireguardNetwork::all(&mut *transaction).await?; + + let enterprise_settings = EnterpriseSettings::get(&mut *transaction).await?; let mut configs = Vec::new(); let mut network_info = Vec::new(); - for network in networks { + for location in locations { debug!( - "Assigning IP for device {} (user {}) in network {network}", + "Assigning IP for device {} (user {}) in location {location}", self.name, self.user_id ); // check for pubkey conflicts with networks - if network.pubkey == self.wireguard_pubkey { - return Err(DeviceError::PubkeyConflict(self.clone(), network.name)); + if location.pubkey == self.wireguard_pubkey { + return Err(DeviceError::PubkeyConflict(self.clone(), location.name)); } - if WireguardNetworkDevice::find(&mut *transaction, self.id, network.id) + if WireguardNetworkDevice::find(&mut *transaction, self.id, location.id) .await? .is_some() { - debug!("Device {self} already has an IP within network {network}. Skipping...",); + debug!("Device {self} already has an IP within location {location}. Skipping...",); continue; } - if let Ok(wireguard_network_device) = network + if let Ok(wireguard_network_device) = location .add_device_to_network(&mut *transaction, self, None) .await { debug!( - "Assigned IPs {} for device {} (user {}) in network {network}", + "Assigned IPs {} for device {} (user {}) in location {location}", wireguard_network_device.wireguard_ips.as_csv(), self.name, self.user_id ); let device_network_info = DeviceNetworkInfo { - network_id: network.id, + network_id: location.id, device_wireguard_ips: wireguard_network_device.wireguard_ips.clone(), preshared_key: wireguard_network_device.preshared_key.clone(), is_authorized: wireguard_network_device.is_authorized, }; network_info.push(device_network_info); - let config = Self::create_config(&network, &wireguard_network_device); + let config = + Self::create_config(&location, &wireguard_network_device, &enterprise_settings); + let allowed_ips = get_allowed_ips_for_device(&enterprise_settings, &location); configs.push(DeviceConfig { - network_id: network.id, - network_name: network.name, + network_id: location.id, + network_name: location.name, config, - endpoint: format!("{}:{}", network.endpoint, network.port), + endpoint: format!("{}:{}", location.endpoint, location.port), address: wireguard_network_device.wireguard_ips, - allowed_ips: network.allowed_ips, - pubkey: network.pubkey, - dns: network.dns, - keepalive_interval: network.keepalive_interval, - location_mfa_mode: network.location_mfa_mode.clone(), - service_location_mode: network.service_location_mode.clone(), + allowed_ips, + pubkey: location.pubkey, + dns: location.dns, + keepalive_interval: location.keepalive_interval, + location_mfa_mode: location.location_mfa_mode.clone(), + service_location_mode: location.service_location_mode.clone(), }); } } @@ -940,7 +954,7 @@ impl Device { } /// Gets the first network of the network device - /// FIXME: Return only one network, not a Vec + // FIXME: Return only one network, not a Vec pub async fn find_network_device_networks<'e, E>( &self, executor: E, diff --git a/crates/defguard_core/src/db/models/wireguard.rs b/crates/defguard_core/src/db/models/wireguard.rs index 91966330f..ed828123c 100644 --- a/crates/defguard_core/src/db/models/wireguard.rs +++ b/crates/defguard_core/src/db/models/wireguard.rs @@ -2,7 +2,7 @@ use std::{ collections::HashMap, fmt::{self, Display}, iter::zip, - net::{IpAddr, Ipv4Addr}, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, }; use base64::prelude::{BASE64_STANDARD, Engine}; @@ -40,7 +40,11 @@ use super::{ wireguard_peer_stats::WireguardPeerStats, }; use crate::{ - enterprise::{firewall::FirewallError, is_enterprise_license_active}, + enterprise::{ + db::models::enterprise_settings::{ClientTrafficPolicy, EnterpriseSettings}, + firewall::FirewallError, + is_enterprise_license_active, + }, grpc::gateway::{send_multiple_wireguard_events, state::GatewayState}, wg_config::ImportedDevice, }; @@ -1492,6 +1496,24 @@ pub(crate) async fn networks_stats( }) } +// If `force_all_traffic` setting is enabled we override the allowed_ips +// to also enforce this on legacy clients. +pub fn get_allowed_ips_for_device( + enterprise_settings: &EnterpriseSettings, + location: &WireguardNetwork, +) -> Vec { + if enterprise_settings.client_traffic_policy == ClientTrafficPolicy::ForceAllTraffic { + vec![ + IpNetwork::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0) + .expect("Failed to parse UNSPECIFIED IPv4 constant"), + IpNetwork::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0) + .expect("Failed to parse UNSPECIFIED IPv6 constant"), + ] + } else { + location.allowed_ips.clone() + } +} + #[cfg(test)] mod test { use std::str::FromStr; diff --git a/crates/defguard_core/src/grpc/enrollment.rs b/crates/defguard_core/src/grpc/enrollment.rs index 13b0733ea..037144032 100644 --- a/crates/defguard_core/src/grpc/enrollment.rs +++ b/crates/defguard_core/src/grpc/enrollment.rs @@ -671,7 +671,7 @@ impl EnrollmentServer { } let (network_info, configs) = device - .get_network_configs(&network, &mut transaction) + .get_network_configs(&mut transaction, &network, &enterprise_settings) .await .map_err(|err| { error!( diff --git a/crates/defguard_core/src/grpc/utils.rs b/crates/defguard_core/src/grpc/utils.rs index b82e91fa1..617850b49 100644 --- a/crates/defguard_core/src/grpc/utils.rs +++ b/crates/defguard_core/src/grpc/utils.rs @@ -18,7 +18,9 @@ use crate::{ models::{ device::{DeviceType, WireguardNetworkDevice}, polling_token::PollingToken, - wireguard::{LocationMfaMode, ServiceLocationMode, WireguardNetwork}, + wireguard::{ + LocationMfaMode, ServiceLocationMode, WireguardNetwork, get_allowed_ips_for_device, + }, }, }, enterprise::db::models::{ @@ -82,8 +84,8 @@ pub(crate) async fn build_device_config_response( Status::internal(format!("unexpected error: {err}")) })?; - let networks = WireguardNetwork::all(pool).await.map_err(|err| { - error!("Failed to fetch all networks: {err}"); + let locations = WireguardNetwork::all(pool).await.map_err(|err| { + error!("Failed to fetch all locations: {err}"); Status::internal(format!("unexpected error: {err}")) })?; @@ -114,21 +116,21 @@ pub(crate) async fn build_device_config_response( Status::internal(format!("unexpected error: {err}")) })?; if let Some(wireguard_network_device) = wireguard_network_device { - let network = wireguard_network_device + let location = wireguard_network_device .network(pool) .await .map_err(|err| { error!( - "Failed to fetch network for WireGuard network device {}: {err}", + "Failed to fetch location for WireGuard network device {}: {err}", device.name ); Status::internal(format!("unexpected error: {err}")) })?; - if network.service_location_mode != ServiceLocationMode::Disabled { + if location.service_location_mode != ServiceLocationMode::Disabled { error!( "Network device {} tried to fetch config for service location {}, which is unsupported.", - device.name, network.name + device.name, location.name ); return Err(Status::permission_denied( "service location mode is not available for network devices", @@ -136,23 +138,28 @@ pub(crate) async fn build_device_config_response( } // DEPRECATED(1.5): superseeded by location_mfa_mode - let mfa_enabled = network.location_mfa_mode == LocationMfaMode::Internal; + let mfa_enabled = location.location_mfa_mode == LocationMfaMode::Internal; + let allowed_ips = get_allowed_ips_for_device(&enterprise_settings, &location).as_csv(); let config = ProtoDeviceConfig { - config: Device::create_config(&network, &wireguard_network_device), - network_id: network.id, - network_name: network.name, + config: Device::create_config( + &location, + &wireguard_network_device, + &enterprise_settings, + ), + network_id: location.id, + network_name: location.name, assigned_ip: wireguard_network_device.wireguard_ips.as_csv(), - endpoint: format!("{}:{}", network.endpoint, network.port), - pubkey: network.pubkey, - allowed_ips: network.allowed_ips.as_csv(), - dns: network.dns, - keepalive_interval: network.keepalive_interval, + endpoint: format!("{}:{}", location.endpoint, location.port), + pubkey: location.pubkey, + allowed_ips, + dns: location.dns, + keepalive_interval: location.keepalive_interval, #[allow(deprecated)] mfa_enabled, location_mfa_mode: Some( >::into( - network.location_mfa_mode, + location.location_mfa_mode, ) .into(), ), @@ -160,59 +167,66 @@ pub(crate) async fn build_device_config_response( Some( >::into(network.service_location_mode) + >>::into(location.service_location_mode) .into(), ), }; configs.push(config); } } else { - for network in networks { + for location in locations { let wireguard_network_device = WireguardNetworkDevice::find( - pool, device.id, network.id, + pool, + device.id, + location.id, ) .await .map_err(|err| { error!( "Failed to fetch WireGuard network device for device {} and network {}: {err}", - device.id, network.id + device.id, location.id ); Status::internal(format!("unexpected error: {err}")) })?; - if network.should_prevent_service_location_usage() { + if location.should_prevent_service_location_usage() { warn!( "Tried to use service location {} with disabled enterprise features.", - network.name + location.name ); continue; } - if network.service_location_mode != ServiceLocationMode::Disabled + if location.service_location_mode != ServiceLocationMode::Disabled && !ClientFeature::ServiceLocations.is_supported_by_device(device_info.as_ref()) { info!( "Device {} does not support service locations feature, skipping sending network {} configuration to device {}.", - device.name, network.name, device.name + device.name, location.name, device.name ); continue; } // DEPRECATED(1.5): superseeded by location_mfa_mode - let mfa_enabled = network.location_mfa_mode == LocationMfaMode::Internal; + let mfa_enabled = location.location_mfa_mode == LocationMfaMode::Internal; + let allowed_ips = get_allowed_ips_for_device(&enterprise_settings, &location).as_csv(); if let Some(wireguard_network_device) = wireguard_network_device { let config = ProtoDeviceConfig { - config: Device::create_config(&network, &wireguard_network_device), - network_id: network.id, - network_name: network.name, + config: Device::create_config( + &location, + &wireguard_network_device, + &enterprise_settings, + ), + network_id: location.id, + network_name: location.name, assigned_ip: wireguard_network_device.wireguard_ips.as_csv(), - endpoint: format!("{}:{}", network.endpoint, network.port), - pubkey: network.pubkey, - allowed_ips: network.allowed_ips.as_csv(), - dns: network.dns, - keepalive_interval: network.keepalive_interval, + endpoint: format!("{}:{}", location.endpoint, location.port), + pubkey: location.pubkey, + allowed_ips, + dns: location.dns, + keepalive_interval: location.keepalive_interval, #[allow(deprecated)] mfa_enabled, location_mfa_mode: Some( >::into( - network.location_mfa_mode, + location.location_mfa_mode, ) .into(), ), @@ -220,7 +234,7 @@ pub(crate) async fn build_device_config_response( Some( >::into(network.service_location_mode) + >>::into(location.service_location_mode) .into(), ), }; diff --git a/crates/defguard_core/src/handlers/network_devices.rs b/crates/defguard_core/src/handlers/network_devices.rs index b0b1863fd..622b73d7b 100644 --- a/crates/defguard_core/src/handlers/network_devices.rs +++ b/crates/defguard_core/src/handlers/network_devices.rs @@ -25,7 +25,7 @@ use crate::{ wireguard::NetworkAddressError, }, }, - enterprise::limits::update_counts, + enterprise::{db::models::enterprise_settings::EnterpriseSettings, limits::update_counts}, events::{ApiEvent, ApiEventType, ApiRequestContext}, handlers::mail::send_new_device_added_email, server_config, @@ -112,31 +112,36 @@ pub async fn download_network_device_config( Path(device_id): Path, ) -> Result { debug!("Creating a WireGuard config for network device {device_id}."); + let enterprise_settings = EnterpriseSettings::get(&appstate.pool).await?; let device = Device::find_by_id(&appstate.pool, device_id) .await? .ok_or(WebError::ObjectNotFound(format!( "Network device with ID {device_id} not found" )))?; - let network = device + let location = device .find_network_device_networks(&appstate.pool) .await? .pop() .ok_or(WebError::ObjectNotFound(format!( - "No network found for network device: {}({})", + "No location found for network device: {}({})", device.name, device.id )))?; - let network_device = WireguardNetworkDevice::find(&appstate.pool, device_id, network.id) + let network_device = WireguardNetworkDevice::find(&appstate.pool, device_id, location.id) .await? .ok_or(WebError::ObjectNotFound(format!( "No IP address found for device: {}({})", device.name, device.id )))?; debug!( - "Created a WireGuard config for network device {device_id} in network {}.", - network.name + "Created a WireGuard config for network device {device_id} in location {}.", + location.name ); - Ok(Device::create_config(&network, &network_device)) + Ok(Device::create_config( + &location, + &network_device, + &enterprise_settings, + )) } pub async fn get_network_device( @@ -399,6 +404,8 @@ pub(crate) async fn start_network_device_setup( session.user.username, setup_start.location_id ); + let enterprise_settings = EnterpriseSettings::get(&appstate.pool).await?; + let user = session.user; let network = WireguardNetwork::find_by_id(&appstate.pool, setup_start.location_id) .await? @@ -447,7 +454,7 @@ pub(crate) async fn start_network_device_setup( network.can_assign_ips(&mut transaction, &ips, None).await?; let (_, config) = device - .add_to_network(&network, &ips, &mut transaction) + .add_to_network(&mut transaction, &network, &ips, &enterprise_settings) .await?; info!( @@ -566,16 +573,17 @@ pub(crate) async fn add_network_device( "User {} adding network device {device_name} in location {}.", session.user.username, add_network_device.location_id ); + let enterprise_settings = EnterpriseSettings::get(&appstate.pool).await?; let user = session.user; - let network = WireguardNetwork::find_by_id(&appstate.pool, add_network_device.location_id) + let location = WireguardNetwork::find_by_id(&appstate.pool, add_network_device.location_id) .await? .ok_or_else(|| { error!( - "Failed to add device {device_name}, network with ID {} not found", + "Failed to add device {device_name}, location with ID {} not found", add_network_device.location_id ); - WebError::BadRequest("Failed to add device, network not found".to_string()) + WebError::BadRequest("Failed to add device, location not found".to_string()) })?; Device::validate_pubkey(&add_network_device.wireguard_pubkey) @@ -615,10 +623,12 @@ pub(crate) async fn add_network_device( error!(msg); WebError::BadRequest(msg) })?; - network.can_assign_ips(&mut transaction, &ips, None).await?; + location + .can_assign_ips(&mut transaction, &ips, None) + .await?; let (network_info, config) = device - .add_to_network(&network, &ips, &mut transaction) + .add_to_network(&mut transaction, &location, &ips, &enterprise_settings) .await?; appstate.send_wireguard_event(GatewayEvent::DeviceCreated(DeviceInfo { @@ -629,9 +639,9 @@ pub(crate) async fn add_network_device( update_counts(&mut *transaction).await?; // send firewall update event if ACLs & enterprise features are enabled - if let Some(firewall_config) = network.try_get_firewall_config(&mut transaction).await? { + if let Some(firewall_config) = location.try_get_firewall_config(&mut transaction).await? { appstate.send_wireguard_event(GatewayEvent::FirewallConfigChanged( - network.id, + location.id, firewall_config, )); } @@ -664,10 +674,7 @@ pub(crate) async fn add_network_device( ); appstate.emit_event(ApiEvent { context, - event: Box::new(ApiEventType::NetworkDeviceAdded { - device, - location: network, - }), + event: Box::new(ApiEventType::NetworkDeviceAdded { device, location }), })?; Ok(ApiResponse { diff --git a/crates/defguard_core/src/handlers/openid_flow.rs b/crates/defguard_core/src/handlers/openid_flow.rs index cad6c47f7..27c97006a 100644 --- a/crates/defguard_core/src/handlers/openid_flow.rs +++ b/crates/defguard_core/src/handlers/openid_flow.rs @@ -398,9 +398,16 @@ pub async fn authorization( "Redirecting user to consent form - client id {}", data.client_id ); - // FIXME: do not panic return Ok(redirect_to( - format!("/consent?{}", serde_urlencoded::to_string(data).unwrap()), + format!( + "/consent?{}", + serde_urlencoded::to_string(data).map_err(|err| { + error!( + "Failed to URL-encode OID authorization request data: {err}" + ); + WebError::Http(StatusCode::INTERNAL_SERVER_ERROR) + })? + ), private_cookies, )); } diff --git a/crates/defguard_core/src/handlers/wireguard.rs b/crates/defguard_core/src/handlers/wireguard.rs index 34a2af7ea..134839092 100644 --- a/crates/defguard_core/src/handlers/wireguard.rs +++ b/crates/defguard_core/src/handlers/wireguard.rs @@ -710,10 +710,10 @@ pub(crate) async fn add_user_devices( } // assign IPs and generate configs for each network -#[derive(Serialize, ToSchema)] +#[derive(Deserialize, Serialize, ToSchema)] pub struct AddDeviceResult { - configs: Vec, - device: Device, + pub configs: Vec, + pub device: Device, } /// Add device @@ -734,9 +734,9 @@ pub struct AddDeviceResult { /// - `WebError` if error occurs #[utoipa::path( post, - path = "/api/v1/device/{device_id}", + path = "/api/v1/device/{username}", params( - ("device_id" = String, description = "ID of device.") + ("username" = String, description = "Username of the device owner.") ), request_body = AddDevice, responses( @@ -1338,10 +1338,10 @@ pub(crate) async fn download_config( ) -> Result { debug!("Creating config for device {device_id} in network {network_id}"); - let settings = EnterpriseSettings::get(&appstate.pool).await?; - if settings.only_client_activation && !session.is_admin { + let enterprise_settings = EnterpriseSettings::get(&appstate.pool).await?; + if enterprise_settings.only_client_activation && !session.is_admin { warn!( - "User {} tried to download device config, but manual device management is disaled", + "User {} tried to download device config, but manual device management is disabled", session.user.username ); return Err(WebError::Forbidden( @@ -1355,7 +1355,11 @@ pub(crate) async fn download_config( WireguardNetworkDevice::find(&appstate.pool, device_id, network_id).await?; if let Some(wireguard_network_device) = wireguard_network_device { info!("Created config for device {}({device_id})", device.name); - Ok(Device::create_config(&network, &wireguard_network_device)) + Ok(Device::create_config( + &network, + &wireguard_network_device, + &enterprise_settings, + )) } else { error!( "Failed to create config, no IP address found for device: {}({})", diff --git a/crates/defguard_core/tests/integration/api/enterprise_settings.rs b/crates/defguard_core/tests/integration/api/enterprise_settings.rs index c065dde6c..b7dc2d4ab 100644 --- a/crates/defguard_core/tests/integration/api/enterprise_settings.rs +++ b/crates/defguard_core/tests/integration/api/enterprise_settings.rs @@ -1,10 +1,13 @@ +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + use defguard_core::{ enterprise::{ db::models::enterprise_settings::{ClientTrafficPolicy, EnterpriseSettings}, license::{get_cached_license, set_cached_license}, }, - handlers::Auth, + handlers::{Auth, wireguard::AddDeviceResult}, }; +use ipnetwork::IpNetwork; use reqwest::StatusCode; use serde_json::json; use sqlx::postgres::{PgConnectOptions, PgPoolOptions}; @@ -380,3 +383,61 @@ async fn dg25_13_test_disable_device_config(_: PgPoolOptions, options: PgConnect let response = client.get("/api/v1/network/1/device/1/config").send().await; assert_eq!(response.status(), StatusCode::FORBIDDEN); } + +#[sqlx::test] +async fn test_override_allowed_ips(_: PgPoolOptions, options: PgConnectOptions) { + let pool = setup_pool(options).await; + + // admin login + let (client, _) = make_test_client(pool).await; + let auth = Auth::new("admin", "pass123"); + let response = client.post("/api/v1/auth").json(&auth).send().await; + assert_eq!(response.status(), StatusCode::OK); + + // create network + let response = client + .post("/api/v1/network") + .json(&make_network()) + .send() + .await; + assert_eq!(response.status(), StatusCode::CREATED); + + // force all traffic setting for clients + let settings = EnterpriseSettings { + admin_device_management: false, + client_traffic_policy: ClientTrafficPolicy::ForceAllTraffic, + only_client_activation: false, + }; + let response = client + .patch("/api/v1/settings_enterprise") + .json(&settings) + .send() + .await; + assert_eq!(response.status(), StatusCode::OK); + + // add device for normal user + let device = json!({ + "name": "device", + "wireguard_pubkey": "LQKsT6/3HWKuJmMulH63R8iK+5sI8FyYEL6WDIi6lQU=", + }); + let response = client + .post("/api/v1/device/hpotter") + .json(&device) + .send() + .await; + assert_eq!(response.status(), StatusCode::CREATED); + + let response: AddDeviceResult = response.json().await; + + for config in response.configs { + assert_eq!( + config.allowed_ips, + vec![ + IpNetwork::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0) + .expect("Failed to parse UNSPECIFIED IPv4 constant"), + IpNetwork::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0) + .expect("Failed to parse UNSPECIFIED IPv6 constant"), + ] + ) + } +} diff --git a/web/package.json b/web/package.json index 1bae33f33..471524356 100644 --- a/web/package.json +++ b/web/package.json @@ -81,7 +81,7 @@ "ipaddr.js": "^2.3.0", "itertools": "^2.5.0", "js-base64": "^3.7.8", - "lodash-es": "^4.17.22", + "lodash-es": "^4.17.23", "merge-refs": "^2.0.0", "millify": "^6.1.0", "motion": "^12.24.12", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index abd76b667..ae819222d 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -108,8 +108,8 @@ importers: specifier: ^3.7.8 version: 3.7.8 lodash-es: - specifier: ^4.17.22 - version: 4.17.22 + specifier: ^4.17.23 + version: 4.17.23 merge-refs: specifier: ^2.0.0 version: 2.0.0(@types/react@19.2.7) @@ -2249,8 +2249,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.22: - resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} + lodash-es@4.17.23: + resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} lodash.ismatch@4.4.0: resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==} @@ -5234,7 +5234,7 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.22: {} + lodash-es@4.17.23: {} lodash.ismatch@4.4.0: {}