mirror of
https://github.com/warp-tech/warpgate.git
synced 2024-09-20 06:46:17 +08:00
Credential policies
This commit is contained in:
parent
93a1259c38
commit
890c5d8b5a
|
@ -127,12 +127,20 @@ pub enum UserAuthCredential {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct UserRequireCredentialsPolicy {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub http: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ssh: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct User {
|
||||
pub username: String,
|
||||
pub credentials: Vec<UserAuthCredential>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub require: Option<Vec<String>>,
|
||||
pub require: Option<UserRequireCredentialsPolicy>,
|
||||
pub roles: Vec<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@ use super::ConfigProvider;
|
|||
use crate::helpers::hash::verify_password_hash;
|
||||
use crate::helpers::otp::verify_totp;
|
||||
use crate::{
|
||||
AuthCredential, AuthResult, Target, User, UserAuthCredential, UserSnapshot, WarpgateConfig,
|
||||
AuthCredential, AuthResult, ProtocolName, Target, User, UserAuthCredential, UserSnapshot,
|
||||
WarpgateConfig,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
|
@ -71,6 +72,7 @@ impl ConfigProvider for FileConfigProvider {
|
|||
&mut self,
|
||||
username: &str,
|
||||
credentials: &[AuthCredential],
|
||||
protocol: ProtocolName,
|
||||
) -> Result<AuthResult> {
|
||||
if credentials.is_empty() {
|
||||
return Ok(AuthResult::Rejected);
|
||||
|
@ -159,8 +161,16 @@ impl ConfigProvider for FileConfigProvider {
|
|||
);
|
||||
}
|
||||
|
||||
match user.require {
|
||||
Some(ref required_kinds) => {
|
||||
if let Some(ref policy) = user.require {
|
||||
let required_kinds = match protocol {
|
||||
"SSH" => &policy.ssh,
|
||||
"HTTP" => &policy.http,
|
||||
_ => {
|
||||
error!(%protocol, "Unkown protocol");
|
||||
return Ok(AuthResult::Rejected);
|
||||
}
|
||||
};
|
||||
if let Some(required_kinds) = required_kinds {
|
||||
let mut remaining_required_kinds = HashSet::new();
|
||||
remaining_required_kinds.extend(required_kinds);
|
||||
for kind in required_kinds {
|
||||
|
@ -181,14 +191,15 @@ impl ConfigProvider for FileConfigProvider {
|
|||
return Ok(AuthResult::Rejected);
|
||||
}
|
||||
}
|
||||
None => Ok(if !valid_credentials.is_empty() {
|
||||
AuthResult::Accepted {
|
||||
username: user.username.clone(),
|
||||
}
|
||||
} else {
|
||||
AuthResult::Rejected
|
||||
}),
|
||||
}
|
||||
|
||||
Ok(if !valid_credentials.is_empty() {
|
||||
AuthResult::Accepted {
|
||||
username: user.username.clone(),
|
||||
}
|
||||
} else {
|
||||
AuthResult::Rejected
|
||||
})
|
||||
}
|
||||
|
||||
async fn authorize_target(&mut self, username: &str, target_name: &str) -> Result<bool> {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
mod file;
|
||||
use crate::{Secret, Target, UserSnapshot};
|
||||
use crate::{ProtocolName, Secret, Target, UserSnapshot};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
|
@ -36,6 +36,7 @@ pub trait ConfigProvider {
|
|||
&mut self,
|
||||
username: &str,
|
||||
credentials: &[AuthCredential],
|
||||
protocol: ProtocolName,
|
||||
) -> Result<AuthResult>;
|
||||
|
||||
async fn authorize_target(&mut self, username: &str, target: &str) -> Result<bool>;
|
||||
|
|
|
@ -64,7 +64,7 @@ impl Api {
|
|||
let result = {
|
||||
let mut config_provider = services.config_provider.lock().await;
|
||||
config_provider
|
||||
.authorize(&body.username, &credentials)
|
||||
.authorize(&body.username, &credentials, crate::common::PROTOCOL_NAME)
|
||||
.await
|
||||
.map_err(|e| e.context("Failed to authorize user"))?
|
||||
};
|
||||
|
|
|
@ -952,7 +952,7 @@ impl ServerSession {
|
|||
.config_provider
|
||||
.lock()
|
||||
.await
|
||||
.authorize(username, &self.credentials)
|
||||
.authorize(username, &self.credentials, crate::PROTOCOL_NAME)
|
||||
.await?
|
||||
};
|
||||
|
||||
|
|
|
@ -13,13 +13,18 @@ pub fn load_config(path: &Path, secure: bool) -> Result<WarpgateConfig> {
|
|||
secure_file(path).context("Could not secure config")?;
|
||||
}
|
||||
|
||||
let store: WarpgateConfigStore = Config::builder()
|
||||
let mut store: serde_yaml::Value = Config::builder()
|
||||
.add_source(File::from(path))
|
||||
.add_source(Environment::with_prefix("WARPGATE"))
|
||||
.build()
|
||||
.context("Could not load config")?
|
||||
.try_deserialize()
|
||||
.context("Could not parse config")?;
|
||||
.context("Could not parse YAML")?;
|
||||
|
||||
check_and_migrate_config(&mut store);
|
||||
|
||||
let store: WarpgateConfigStore =
|
||||
serde_yaml::from_value(store).context("Could not load config")?;
|
||||
|
||||
let config = WarpgateConfig {
|
||||
store,
|
||||
|
@ -35,6 +40,42 @@ pub fn load_config(path: &Path, secure: bool) -> Result<WarpgateConfig> {
|
|||
Ok(config)
|
||||
}
|
||||
|
||||
fn check_and_migrate_config(store: &mut serde_yaml::Value) {
|
||||
use serde_yaml::Value;
|
||||
if let Some(map) = store.as_mapping_mut() {
|
||||
if let Some(web_admin) = map.remove(&Value::String("web_admin".into())) {
|
||||
warn!("The `web_admin` config section is deprecated. Rename it to `http`.");
|
||||
map.insert(Value::String("http".into()), web_admin);
|
||||
}
|
||||
|
||||
if let Some(Value::Sequence(ref mut users)) = map.get_mut(&Value::String("users".into())) {
|
||||
for user in users {
|
||||
if let Value::Mapping(ref mut user) = user {
|
||||
if let Some(new_require) = match user.get(&Value::String("require".into())) {
|
||||
Some(Value::Sequence(ref old_requires)) => Some(Value::Mapping(
|
||||
vec![
|
||||
(
|
||||
Value::String("ssh".into()),
|
||||
Value::Sequence(old_requires.clone()),
|
||||
),
|
||||
(
|
||||
Value::String("http".into()),
|
||||
Value::Sequence(old_requires.clone()),
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
)),
|
||||
x => x.cloned(),
|
||||
} {
|
||||
user.insert(Value::String("require".into()), new_require);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn watch_config<P: AsRef<Path>>(
|
||||
path: P,
|
||||
config: Arc<Mutex<WarpgateConfig>>,
|
||||
|
|
Loading…
Reference in a new issue