mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-16 02:45:41 +00:00
feat(web): add OIDC SSO login support (#1943)
This commit is contained in:
@@ -17,6 +17,8 @@ use easytier::{
|
||||
use maxminddb::geoip2;
|
||||
use session::{Location, Session};
|
||||
use storage::{Storage, StorageToken};
|
||||
|
||||
use crate::FeatureFlags;
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
use crate::db::{entity::user_running_network_configs, Db, UserIdInDb};
|
||||
@@ -55,11 +57,13 @@ pub struct ClientManager {
|
||||
client_sessions: Arc<DashMap<url::Url, Arc<Session>>>,
|
||||
storage: Storage,
|
||||
|
||||
feature_flags: Arc<FeatureFlags>,
|
||||
|
||||
geoip_db: Arc<Option<maxminddb::Reader<Vec<u8>>>>,
|
||||
}
|
||||
|
||||
impl ClientManager {
|
||||
pub fn new(db: Db, geoip_db: Option<String>) -> Self {
|
||||
pub fn new(db: Db, geoip_db: Option<String>, feature_flags: Arc<FeatureFlags>) -> Self {
|
||||
let client_sessions = Arc::new(DashMap::new());
|
||||
let sessions: Arc<DashMap<url::Url, Arc<Session>>> = client_sessions.clone();
|
||||
let mut tasks = JoinSet::new();
|
||||
@@ -76,6 +80,8 @@ impl ClientManager {
|
||||
|
||||
client_sessions,
|
||||
storage: Storage::new(db),
|
||||
feature_flags,
|
||||
|
||||
geoip_db: Arc::new(load_geoip_db(geoip_db)),
|
||||
}
|
||||
}
|
||||
@@ -90,6 +96,7 @@ impl ClientManager {
|
||||
let storage = self.storage.weak_ref();
|
||||
let listeners_cnt = self.listeners_cnt.clone();
|
||||
let geoip_db = self.geoip_db.clone();
|
||||
let feature_flags = self.feature_flags.clone();
|
||||
self.tasks.spawn(async move {
|
||||
while let Ok(tunnel) = listener.accept().await {
|
||||
let info = tunnel.info().unwrap();
|
||||
@@ -100,7 +107,12 @@ impl ClientManager {
|
||||
client_url,
|
||||
location
|
||||
);
|
||||
let mut session = Session::new(storage.clone(), client_url.clone(), location);
|
||||
let mut session = Session::new(
|
||||
storage.clone(),
|
||||
client_url.clone(),
|
||||
location,
|
||||
feature_flags.clone(),
|
||||
);
|
||||
session.serve(tunnel).await;
|
||||
sessions.insert(client_url, Arc::new(session));
|
||||
}
|
||||
@@ -291,12 +303,16 @@ mod tests {
|
||||
};
|
||||
use sqlx::Executor;
|
||||
|
||||
use crate::{client_manager::ClientManager, db::Db};
|
||||
use crate::{client_manager::ClientManager, db::Db, FeatureFlags};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_client() {
|
||||
let listener = UdpTunnelListener::new("udp://0.0.0.0:54333".parse().unwrap());
|
||||
let mut mgr = ClientManager::new(Db::memory_db().await, None);
|
||||
let mut mgr = ClientManager::new(
|
||||
Db::memory_db().await,
|
||||
None,
|
||||
Arc::new(FeatureFlags::default()),
|
||||
);
|
||||
mgr.add_listener(Box::new(listener)).await.unwrap();
|
||||
|
||||
mgr.db()
|
||||
|
||||
@@ -18,6 +18,7 @@ use easytier::{
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
use super::storage::{Storage, StorageToken, WeakRefStorage};
|
||||
use crate::FeatureFlags;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Location {
|
||||
@@ -29,6 +30,7 @@ pub struct Location {
|
||||
#[derive(Debug)]
|
||||
pub struct SessionData {
|
||||
storage: WeakRefStorage,
|
||||
feature_flags: Arc<FeatureFlags>,
|
||||
client_url: url::Url,
|
||||
|
||||
storage_token: Option<StorageToken>,
|
||||
@@ -38,11 +40,17 @@ pub struct SessionData {
|
||||
}
|
||||
|
||||
impl SessionData {
|
||||
fn new(storage: WeakRefStorage, client_url: url::Url, location: Option<Location>) -> Self {
|
||||
fn new(
|
||||
storage: WeakRefStorage,
|
||||
client_url: url::Url,
|
||||
location: Option<Location>,
|
||||
feature_flags: Arc<FeatureFlags>,
|
||||
) -> Self {
|
||||
let (tx, _rx1) = broadcast::channel(2);
|
||||
|
||||
SessionData {
|
||||
storage,
|
||||
feature_flags,
|
||||
client_url,
|
||||
storage_token: None,
|
||||
notifier: tx,
|
||||
@@ -98,7 +106,7 @@ impl SessionRpcService {
|
||||
req.machine_id
|
||||
))?;
|
||||
|
||||
let user_id = storage
|
||||
let user_id = match storage
|
||||
.db()
|
||||
.get_user_id_by_token(req.user_token.clone())
|
||||
.await
|
||||
@@ -107,11 +115,18 @@ impl SessionRpcService {
|
||||
"Failed to get user id by token from db: {:?}",
|
||||
req.user_token
|
||||
)
|
||||
})?
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"User not found by token: {:?}",
|
||||
req.user_token
|
||||
))?;
|
||||
})? {
|
||||
Some(id) => id,
|
||||
None if data.feature_flags.allow_auto_create_user => storage
|
||||
.auto_create_user(&req.user_token)
|
||||
.await
|
||||
.with_context(|| format!("Failed to auto-create user: {:?}", req.user_token))?,
|
||||
None => {
|
||||
return Err(
|
||||
anyhow::anyhow!("User not found by token: {:?}", req.user_token).into(),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if data.req.replace(req.clone()).is_none() {
|
||||
assert!(data.storage_token.is_none());
|
||||
@@ -173,8 +188,13 @@ impl Debug for Session {
|
||||
type SessionRpcClient = Box<dyn WebClientService<Controller = BaseController> + Send>;
|
||||
|
||||
impl Session {
|
||||
pub fn new(storage: WeakRefStorage, client_url: url::Url, location: Option<Location>) -> Self {
|
||||
let session_data = SessionData::new(storage, client_url, location);
|
||||
pub fn new(
|
||||
storage: WeakRefStorage,
|
||||
client_url: url::Url,
|
||||
location: Option<Location>,
|
||||
feature_flags: Arc<FeatureFlags>,
|
||||
) -> Self {
|
||||
let session_data = SessionData::new(storage, client_url, location, feature_flags);
|
||||
let data = Arc::new(RwLock::new(session_data));
|
||||
|
||||
let rpc_mgr =
|
||||
|
||||
@@ -21,7 +21,6 @@ struct ClientInfo {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StorageInner {
|
||||
// some map for indexing
|
||||
user_clients_map: DashMap<UserIdInDb, DashMap<uuid::Uuid, ClientInfo>>,
|
||||
pub db: Db,
|
||||
}
|
||||
@@ -123,4 +122,10 @@ impl Storage {
|
||||
pub fn db(&self) -> &Db {
|
||||
&self.0.db
|
||||
}
|
||||
|
||||
pub async fn auto_create_user(&self, username: &str) -> anyhow::Result<UserIdInDb> {
|
||||
let new_user = self.db().auto_create_user(username).await?;
|
||||
tracing::info!("Auto-created user '{}' with id {}", username, new_user.id);
|
||||
Ok(new_user.id)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user