Enforce network IP restriction
This commit is contained in:
parent
501520a9df
commit
af1dd4d122
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -68,6 +68,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix-remote-ip"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7629b357d4705cf3f1e31f989f48ecd56027112f7d52dcf06dd96ee197065f8e"
|
||||||
|
dependencies = [
|
||||||
|
"actix-web",
|
||||||
|
"futures-util",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-router"
|
name = "actix-router"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@ -1887,6 +1898,7 @@ checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
|||||||
name = "matrix_gateway"
|
name = "matrix_gateway"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"actix-remote-ip",
|
||||||
"actix-session",
|
"actix-session",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
@ -25,4 +25,5 @@ uuid = { version = "1.12.1", features = ["v4", "serde"] }
|
|||||||
ipnet = { version = "2.11.0", features = ["serde"] }
|
ipnet = { version = "2.11.0", features = ["serde"] }
|
||||||
chrono = "0.4.39"
|
chrono = "0.4.39"
|
||||||
futures-util = "0.3.31"
|
futures-util = "0.3.31"
|
||||||
jwt-simple = { version = "0.12.11", default-features=false, features=["pure-rust"] }
|
jwt-simple = { version = "0.12.11", default-features=false, features=["pure-rust"] }
|
||||||
|
actix-remote-ip = "0.1.0"
|
@ -1,9 +1,11 @@
|
|||||||
use crate::user::{APIClient, APIClientID, UserConfig, UserID};
|
use crate::user::{APIClient, APIClientID, UserConfig, UserID};
|
||||||
use crate::utils::curr_time;
|
use crate::utils::curr_time;
|
||||||
|
use actix_remote_ip::RemoteIP;
|
||||||
use actix_web::dev::Payload;
|
use actix_web::dev::Payload;
|
||||||
use actix_web::{FromRequest, HttpRequest};
|
use actix_web::{FromRequest, HttpRequest};
|
||||||
use jwt_simple::common::VerificationOptions;
|
use jwt_simple::common::VerificationOptions;
|
||||||
use jwt_simple::prelude::{Duration, HS256Key, MACLike};
|
use jwt_simple::prelude::{Duration, HS256Key, MACLike};
|
||||||
|
use std::net::IpAddr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub struct APIClientAuth {
|
pub struct APIClientAuth {
|
||||||
@ -19,7 +21,7 @@ pub struct TokenClaims {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl APIClientAuth {
|
impl APIClientAuth {
|
||||||
async fn extract_auth(req: &HttpRequest) -> Result<Self, actix_web::Error> {
|
async fn extract_auth(req: &HttpRequest, remote_ip: IpAddr) -> Result<Self, actix_web::Error> {
|
||||||
let Some(token) = req.headers().get("x-client-auth") else {
|
let Some(token) = req.headers().get("x-client-auth") else {
|
||||||
return Err(actix_web::error::ErrorBadRequest(
|
return Err(actix_web::error::ErrorBadRequest(
|
||||||
"Missing authentication header!",
|
"Missing authentication header!",
|
||||||
@ -99,6 +101,19 @@ impl APIClientAuth {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check IP restriction
|
||||||
|
if let Some(net) = client.network {
|
||||||
|
if !net.contains(&remote_ip) {
|
||||||
|
log::error!(
|
||||||
|
"Trying to use client {} from unauthorized IP address: {remote_ip}",
|
||||||
|
client.id.0
|
||||||
|
);
|
||||||
|
return Err(actix_web::error::ErrorForbidden(
|
||||||
|
"This client cannot be used from this IP address!",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check URI & verb
|
// Check URI & verb
|
||||||
if claims.custom.uri != req.uri().to_string() {
|
if claims.custom.uri != req.uri().to_string() {
|
||||||
return Err(actix_web::error::ErrorBadRequest("URI mismatch!"));
|
return Err(actix_web::error::ErrorBadRequest("URI mismatch!"));
|
||||||
@ -115,7 +130,6 @@ impl APIClientAuth {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO : handle payload
|
// TODO : handle payload
|
||||||
// TODO : check for IP restriction
|
|
||||||
|
|
||||||
// Update last use (if needed)
|
// Update last use (if needed)
|
||||||
if client.need_update_last_used() {
|
if client.need_update_last_used() {
|
||||||
@ -143,6 +157,12 @@ impl FromRequest for APIClientAuth {
|
|||||||
|
|
||||||
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
let req = req.clone();
|
let req = req.clone();
|
||||||
Box::pin(async move { Self::extract_auth(&req).await })
|
|
||||||
|
let remote_ip = match RemoteIP::from_request(&req, &mut Payload::None).into_inner() {
|
||||||
|
Ok(ip) => ip,
|
||||||
|
Err(e) => return Box::pin(async { Err(e) }),
|
||||||
|
};
|
||||||
|
|
||||||
|
Box::pin(async move { Self::extract_auth(&req, remote_ip.0).await })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use actix_remote_ip::RemoteIPConfig;
|
||||||
use actix_session::config::SessionLifecycle;
|
use actix_session::config::SessionLifecycle;
|
||||||
use actix_session::{storage::RedisSessionStore, SessionMiddleware};
|
use actix_session::{storage::RedisSessionStore, SessionMiddleware};
|
||||||
use actix_web::cookie::Key;
|
use actix_web::cookie::Key;
|
||||||
@ -35,6 +36,9 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.session_lifecycle(SessionLifecycle::BrowserSession(Default::default()))
|
.session_lifecycle(SessionLifecycle::BrowserSession(Default::default()))
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
|
.app_data(web::Data::new(RemoteIPConfig {
|
||||||
|
proxy: AppConfig::get().proxy_ip.clone(),
|
||||||
|
}))
|
||||||
// Web configuration routes
|
// Web configuration routes
|
||||||
.route("/assets/{tail:.*}", web::get().to(web_ui::static_file))
|
.route("/assets/{tail:.*}", web::get().to(web_ui::static_file))
|
||||||
.route("/", web::get().to(web_ui::home))
|
.route("/", web::get().to(web_ui::home))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user