mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-21 11:56:38 +00:00
extract_claims
This commit is contained in:
+14
-4
@@ -1,15 +1,25 @@
|
||||
mod credentials;
|
||||
|
||||
pub use credentials::Credentials;
|
||||
pub use credentials::CredentialsBuilder;
|
||||
pub use credentials::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||
pub struct UserIdentity {
|
||||
pub version: i64,
|
||||
pub credentials: Credentials,
|
||||
pub update_at: OffsetDateTime,
|
||||
pub update_at: Option<OffsetDateTime>,
|
||||
}
|
||||
|
||||
impl UserIdentity {
|
||||
pub fn new(credentials: Credentials) -> Self {
|
||||
UserIdentity {
|
||||
version: 1,
|
||||
credentials,
|
||||
update_at: Some(OffsetDateTime::now_utc()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Credentials> for UserIdentity {
|
||||
@@ -17,7 +27,7 @@ impl From<Credentials> for UserIdentity {
|
||||
UserIdentity {
|
||||
version: 1,
|
||||
credentials: value,
|
||||
update_at: OffsetDateTime::now_utc(),
|
||||
update_at: Some(OffsetDateTime::now_utc()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+49
-41
@@ -1,6 +1,8 @@
|
||||
use crate::policy::{Policy, Validator};
|
||||
use crate::service_type::ServiceType;
|
||||
use crate::utils::extract_claims;
|
||||
use crate::{utils, Error};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
use std::cell::LazyCell;
|
||||
@@ -13,8 +15,8 @@ const ACCESS_KEY_MAX_LEN: usize = 20;
|
||||
const SECRET_KEY_MIN_LEN: usize = 8;
|
||||
const SECRET_KEY_MAX_LEN: usize = 40;
|
||||
|
||||
const ACCOUNT_ON: &str = "on";
|
||||
const ACCOUNT_OFF: &str = "off";
|
||||
pub const ACCOUNT_ON: &str = "on";
|
||||
pub const ACCOUNT_OFF: &str = "off";
|
||||
|
||||
#[cfg_attr(test, derive(PartialEq, Eq, Debug))]
|
||||
struct CredentialHeader {
|
||||
@@ -89,7 +91,7 @@ impl TryFrom<&str> for CredentialHeader {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default, Debug)]
|
||||
pub struct Credentials {
|
||||
pub access_key: String,
|
||||
pub secret_key: String,
|
||||
@@ -109,44 +111,6 @@ impl Credentials {
|
||||
Self::check_key_value(header)
|
||||
}
|
||||
|
||||
pub fn get_new_credentials_with_metadata<T: Serialize>(
|
||||
claims: &T,
|
||||
token_secret: &str,
|
||||
exp: Option<usize>,
|
||||
) -> crate::Result<Self> {
|
||||
let ak = utils::gen_access_key(20).unwrap_or_default();
|
||||
let sk = utils::gen_secret_key(32).unwrap_or_default();
|
||||
|
||||
Self::create_new_credentials_with_metadata(&ak, &sk, claims, token_secret, exp)
|
||||
}
|
||||
|
||||
pub fn create_new_credentials_with_metadata<T: Serialize>(
|
||||
ak: &str,
|
||||
sk: &str,
|
||||
claims: &T,
|
||||
token_secret: &str,
|
||||
exp: Option<usize>,
|
||||
) -> crate::Result<Self> {
|
||||
if ak.len() < ACCESS_KEY_MIN_LEN || ak.len() > ACCESS_KEY_MAX_LEN {
|
||||
return Err(Error::InvalidAccessKeyLength);
|
||||
}
|
||||
|
||||
if sk.len() < SECRET_KEY_MIN_LEN || sk.len() > SECRET_KEY_MAX_LEN {
|
||||
return Err(Error::InvalidAccessKeyLength);
|
||||
}
|
||||
|
||||
let token = utils::generate_jwt(claims, token_secret).map_err(Error::JWTError)?;
|
||||
|
||||
Ok(Self {
|
||||
access_key: ak.to_owned(),
|
||||
secret_key: sk.to_owned(),
|
||||
session_token: token,
|
||||
status: ACCOUNT_ON.to_owned(),
|
||||
expiration: exp.map(|v| OffsetDateTime::now_utc().saturating_add(Duration::seconds(v as i64))),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn check_key_value(_header: CredentialHeader) -> crate::Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
@@ -186,6 +150,50 @@ impl Credentials {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_new_credentials_with_metadata<T: Serialize>(
|
||||
claims: &T,
|
||||
token_secret: &str,
|
||||
exp: Option<usize>,
|
||||
) -> crate::Result<Credentials> {
|
||||
let ak = utils::gen_access_key(20).unwrap_or_default();
|
||||
let sk = utils::gen_secret_key(32).unwrap_or_default();
|
||||
|
||||
create_new_credentials_with_metadata(&ak, &sk, claims, token_secret, exp)
|
||||
}
|
||||
|
||||
pub fn create_new_credentials_with_metadata<T: Serialize>(
|
||||
ak: &str,
|
||||
sk: &str,
|
||||
claims: &T,
|
||||
token_secret: &str,
|
||||
exp: Option<usize>,
|
||||
) -> crate::Result<Credentials> {
|
||||
if ak.len() < ACCESS_KEY_MIN_LEN || ak.len() > ACCESS_KEY_MAX_LEN {
|
||||
return Err(Error::InvalidAccessKeyLength);
|
||||
}
|
||||
|
||||
if sk.len() < SECRET_KEY_MIN_LEN || sk.len() > SECRET_KEY_MAX_LEN {
|
||||
return Err(Error::InvalidAccessKeyLength);
|
||||
}
|
||||
|
||||
let token = utils::generate_jwt(claims, token_secret).map_err(Error::JWTError)?;
|
||||
|
||||
Ok(Credentials {
|
||||
access_key: ak.to_owned(),
|
||||
secret_key: sk.to_owned(),
|
||||
session_token: token,
|
||||
status: ACCOUNT_ON.to_owned(),
|
||||
expiration: exp.map(|v| OffsetDateTime::now_utc().saturating_add(Duration::seconds(v as i64))),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_claims_from_token_with_secret<T: DeserializeOwned>(token: &str, secret: &str) -> crate::Result<T> {
|
||||
let ms = extract_claims::<T>(token, secret).map_err(Error::JWTError)?;
|
||||
// TODO SessionPolicyName
|
||||
Ok(ms.claims)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CredentialsBuilder {
|
||||
session_policy: Option<Policy>,
|
||||
|
||||
@@ -37,6 +37,15 @@ pub enum Error {
|
||||
|
||||
#[error("jwt err {0}")]
|
||||
JWTError(jsonwebtoken::errors::Error),
|
||||
|
||||
#[error("no access key")]
|
||||
NoAccessKey,
|
||||
|
||||
#[error("invalid token")]
|
||||
InvalidToken,
|
||||
|
||||
#[error("invalid access_key")]
|
||||
InvalidAccessKey,
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
+18
-2
@@ -3,7 +3,10 @@ use ecstore::store::ECStore;
|
||||
use log::debug;
|
||||
use manager::IamCache;
|
||||
use policy::{Args, Policy};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
use store::object::ObjectStore;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
@@ -85,6 +88,19 @@ pub async fn add_service_account(cred: Credentials) -> crate::Result<OffsetDateT
|
||||
get()?.add_service_account(cred).await
|
||||
}
|
||||
|
||||
pub async fn check_key(ak: &str) -> crate::Result<Option<UserIdentity>> {
|
||||
pub async fn check_key(ak: &str) -> crate::Result<(Option<UserIdentity>, bool)> {
|
||||
if let Some(sys_cred) = get_global_action_cred() {
|
||||
if sys_cred.access_key == ak {
|
||||
return Ok((Some(UserIdentity::new(sys_cred)), true));
|
||||
}
|
||||
}
|
||||
get()?.check_key(ak).await
|
||||
}
|
||||
|
||||
pub async fn list_users() -> crate::Result<HashMap<String, madmin::UserInfo>> {
|
||||
get()?.get_users().await
|
||||
}
|
||||
|
||||
pub async fn get_user(ak: &str) -> crate::Result<(Option<UserIdentity>, bool)> {
|
||||
get()?.check_key(ak).await
|
||||
}
|
||||
|
||||
+51
-5
@@ -8,7 +8,7 @@ use std::{
|
||||
};
|
||||
|
||||
use ecstore::store_err::is_err_object_not_found;
|
||||
use log::debug;
|
||||
use log::{debug, warn};
|
||||
use time::OffsetDateTime;
|
||||
use tokio::{
|
||||
select,
|
||||
@@ -188,7 +188,7 @@ where
|
||||
OffsetDateTime::now_utc(),
|
||||
);
|
||||
|
||||
Ok(user_entiry.update_at)
|
||||
Ok(user_entiry.update_at.unwrap_or(OffsetDateTime::now_utc()))
|
||||
}
|
||||
|
||||
pub async fn is_allowed<'a>(&self, args: Args<'a>) -> bool {
|
||||
@@ -209,7 +209,7 @@ where
|
||||
Ok((u.clone(), None))
|
||||
}
|
||||
|
||||
pub async fn check_key(&self, ak: &str) -> crate::Result<Option<UserIdentity>> {
|
||||
pub async fn check_key(&self, ak: &str) -> crate::Result<(Option<UserIdentity>, bool)> {
|
||||
let user = self
|
||||
.cache
|
||||
.users
|
||||
@@ -219,8 +219,14 @@ where
|
||||
.or_else(|| self.cache.sts_accounts.load().get(ak).cloned());
|
||||
|
||||
match user {
|
||||
Some(u) if u.credentials.is_valid() => Ok(Some(u)),
|
||||
_ => Ok(None),
|
||||
Some(u) => {
|
||||
if u.credentials.is_valid() {
|
||||
Ok((Some(u), true))
|
||||
} else {
|
||||
Ok((Some(u), false))
|
||||
}
|
||||
}
|
||||
_ => Ok((None, false)),
|
||||
}
|
||||
}
|
||||
pub async fn policy_db_get(&self, name: &str, _groups: Option<Vec<String>>) -> crate::Result<Vec<String>> {
|
||||
@@ -263,4 +269,44 @@ where
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// returns all users (not STS or service accounts)
|
||||
pub async fn get_users(&self) -> crate::Result<HashMap<String, madmin::UserInfo>> {
|
||||
let mut m = HashMap::new();
|
||||
|
||||
let users = self.cache.users.load();
|
||||
let policies = self.cache.user_policies.load();
|
||||
let group_members = self.cache.user_group_memeberships.load();
|
||||
|
||||
for (k, v) in users.iter() {
|
||||
warn!("k: {}, v: {:?}", k, v.credentials);
|
||||
|
||||
if v.credentials.is_temp() || v.credentials.is_service_account() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut u = madmin::UserInfo {
|
||||
status: if v.credentials.is_valid() {
|
||||
madmin::AccountStatus::Enabled
|
||||
} else {
|
||||
madmin::AccountStatus::Disabled
|
||||
},
|
||||
updated_at: v.update_at,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Some(p) = policies.get(k) {
|
||||
u.policy_name = Some(p.policies.clone());
|
||||
u.updated_at = Some(p.update_at);
|
||||
}
|
||||
|
||||
if let Some(members) = group_members.get(k) {
|
||||
u.member_of = Some(members.iter().cloned().collect());
|
||||
}
|
||||
|
||||
m.insert(k.clone(), u);
|
||||
}
|
||||
|
||||
Ok(m)
|
||||
}
|
||||
}
|
||||
|
||||
+13
-2
@@ -1,7 +1,7 @@
|
||||
use crate::Error;
|
||||
use jsonwebtoken::{encode, Algorithm, EncodingKey, Header};
|
||||
use jsonwebtoken::{encode, Algorithm, DecodingKey, EncodingKey, Header};
|
||||
use rand::{Rng, RngCore};
|
||||
use serde::Serialize;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
pub fn gen_access_key(length: usize) -> crate::Result<String> {
|
||||
const ALPHA_NUMERIC_TABLE: [char; 36] = [
|
||||
@@ -45,6 +45,17 @@ pub fn generate_jwt<T: Serialize>(claims: &T, secret: &str) -> Result<String, js
|
||||
encode(&header, &claims, &EncodingKey::from_secret(secret.as_bytes()))
|
||||
}
|
||||
|
||||
pub fn extract_claims<T: DeserializeOwned>(
|
||||
token: &str,
|
||||
secret: &str,
|
||||
) -> Result<jsonwebtoken::TokenData<T>, jsonwebtoken::errors::Error> {
|
||||
jsonwebtoken::decode::<T>(
|
||||
token,
|
||||
&DecodingKey::from_secret(secret.as_bytes()),
|
||||
&jsonwebtoken::Validation::new(Algorithm::HS512),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{gen_access_key, gen_secret_key};
|
||||
|
||||
Reference in New Issue
Block a user