mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-09-01 17:58:24 +00:00
possibility to update access key expiration date
This commit is contained in:
@@ -2162,15 +2162,7 @@
|
|||||||
"$ref": "#/components/schemas/GetBucketInfoResponse"
|
"$ref": "#/components/schemas/GetBucketInfoResponse"
|
||||||
},
|
},
|
||||||
"CreateKeyRequest": {
|
"CreateKeyRequest": {
|
||||||
"type": "object",
|
"$ref": "#/components/schemas/UpdateKeyRequestBody"
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"CreateKeyResponse": {
|
"CreateKeyResponse": {
|
||||||
"$ref": "#/components/schemas/GetKeyInfoResponse"
|
"$ref": "#/components/schemas/GetKeyInfoResponse"
|
||||||
@@ -4115,7 +4107,8 @@
|
|||||||
"type": "null"
|
"type": "null"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/components/schemas/KeyPerm"
|
"$ref": "#/components/schemas/KeyPerm",
|
||||||
|
"description": "Permissions to allow for the key"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -4125,15 +4118,25 @@
|
|||||||
"type": "null"
|
"type": "null"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/components/schemas/KeyPerm"
|
"$ref": "#/components/schemas/KeyPerm",
|
||||||
|
"description": "Permissions to deny for the key"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"expiration": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "Expiration time and date, formatted according to RFC 3339"
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
],
|
||||||
|
"description": "Name of the API key"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -701,9 +701,7 @@ pub struct ApiBucketKeyPerm {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CreateKeyRequest {
|
pub struct CreateKeyRequest(pub UpdateKeyRequestBody);
|
||||||
pub name: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||||
pub struct CreateKeyResponse(pub GetKeyInfoResponse);
|
pub struct CreateKeyResponse(pub GetKeyInfoResponse);
|
||||||
@@ -735,8 +733,13 @@ pub struct UpdateKeyResponse(pub GetKeyInfoResponse);
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UpdateKeyRequestBody {
|
pub struct UpdateKeyRequestBody {
|
||||||
|
/// Name of the API key
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
/// Expiration time and date, formatted according to RFC 3339
|
||||||
|
pub expiration: Option<DateTime<Utc>>,
|
||||||
|
/// Permissions to allow for the key
|
||||||
pub allow: Option<KeyPerm>,
|
pub allow: Option<KeyPerm>,
|
||||||
|
/// Permissions to deny for the key
|
||||||
pub deny: Option<KeyPerm>,
|
pub deny: Option<KeyPerm>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-16
@@ -103,7 +103,10 @@ impl RequestHandler for CreateKeyRequest {
|
|||||||
garage: &Arc<Garage>,
|
garage: &Arc<Garage>,
|
||||||
_admin: &Admin,
|
_admin: &Admin,
|
||||||
) -> Result<CreateKeyResponse, Error> {
|
) -> Result<CreateKeyResponse, Error> {
|
||||||
let key = Key::new(self.name.as_deref().unwrap_or("Unnamed key"));
|
let mut key = Key::new("Unnamed key");
|
||||||
|
|
||||||
|
apply_key_updates(&mut key, self.0);
|
||||||
|
|
||||||
garage.key_table.insert(&key).await?;
|
garage.key_table.insert(&key).await?;
|
||||||
|
|
||||||
Ok(CreateKeyResponse(
|
Ok(CreateKeyResponse(
|
||||||
@@ -149,21 +152,7 @@ impl RequestHandler for UpdateKeyRequest {
|
|||||||
) -> Result<UpdateKeyResponse, Error> {
|
) -> Result<UpdateKeyResponse, Error> {
|
||||||
let mut key = garage.key_helper().get_existing_key(&self.id).await?;
|
let mut key = garage.key_helper().get_existing_key(&self.id).await?;
|
||||||
|
|
||||||
let key_state = key.state.as_option_mut().unwrap();
|
apply_key_updates(&mut key, self.body);
|
||||||
|
|
||||||
if let Some(new_name) = self.body.name {
|
|
||||||
key_state.name.update(new_name);
|
|
||||||
}
|
|
||||||
if let Some(allow) = self.body.allow {
|
|
||||||
if allow.create_bucket {
|
|
||||||
key_state.allow_create_bucket.update(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(deny) = self.body.deny {
|
|
||||||
if deny.create_bucket {
|
|
||||||
key_state.allow_create_bucket.update(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
garage.key_table.insert(&key).await?;
|
garage.key_table.insert(&key).await?;
|
||||||
|
|
||||||
@@ -275,3 +264,26 @@ async fn key_info_results(
|
|||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_key_updates(key: &mut Key, updates: UpdateKeyRequestBody) {
|
||||||
|
let key_state = key.state.as_option_mut().unwrap();
|
||||||
|
|
||||||
|
if let Some(new_name) = updates.name {
|
||||||
|
key_state.name.update(new_name);
|
||||||
|
}
|
||||||
|
if let Some(expiration) = updates.expiration {
|
||||||
|
key_state
|
||||||
|
.expiration
|
||||||
|
.update(Some(expiration.timestamp_millis() as u64));
|
||||||
|
}
|
||||||
|
if let Some(allow) = updates.allow {
|
||||||
|
if allow.create_bucket {
|
||||||
|
key_state.allow_create_bucket.update(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(deny) = updates.deny {
|
||||||
|
if deny.create_bucket {
|
||||||
|
key_state.allow_create_bucket.update(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use format_table::format_table;
|
use format_table::format_table;
|
||||||
|
|
||||||
use chrono::Local;
|
use chrono::{Local, Utc};
|
||||||
|
|
||||||
use garage_util::error::*;
|
use garage_util::error::*;
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ impl Cli {
|
|||||||
KeyOperation::Info(query) => self.cmd_key_info(query).await,
|
KeyOperation::Info(query) => self.cmd_key_info(query).await,
|
||||||
KeyOperation::Create(query) => self.cmd_create_key(query).await,
|
KeyOperation::Create(query) => self.cmd_create_key(query).await,
|
||||||
KeyOperation::Rename(query) => self.cmd_rename_key(query).await,
|
KeyOperation::Rename(query) => self.cmd_rename_key(query).await,
|
||||||
|
KeyOperation::Set(opt) => self.cmd_update_key(opt).await,
|
||||||
KeyOperation::Delete(query) => self.cmd_delete_key(query).await,
|
KeyOperation::Delete(query) => self.cmd_delete_key(query).await,
|
||||||
KeyOperation::Allow(query) => self.cmd_allow_key(query).await,
|
KeyOperation::Allow(query) => self.cmd_allow_key(query).await,
|
||||||
KeyOperation::Deny(query) => self.cmd_deny_key(query).await,
|
KeyOperation::Deny(query) => self.cmd_deny_key(query).await,
|
||||||
@@ -68,9 +69,17 @@ impl Cli {
|
|||||||
|
|
||||||
pub async fn cmd_create_key(&self, opt: KeyNewOpt) -> Result<(), Error> {
|
pub async fn cmd_create_key(&self, opt: KeyNewOpt) -> Result<(), Error> {
|
||||||
let key = self
|
let key = self
|
||||||
.api_request(CreateKeyRequest {
|
.api_request(CreateKeyRequest(UpdateKeyRequestBody {
|
||||||
name: Some(opt.name),
|
name: Some(opt.name),
|
||||||
})
|
expiration: opt
|
||||||
|
.expires_in
|
||||||
|
.map(|x| parse_duration::parse::parse(&x))
|
||||||
|
.transpose()
|
||||||
|
.ok_or_message("Invalid duration passed for --expires-in parameter")?
|
||||||
|
.map(|dur| Utc::now() + dur),
|
||||||
|
allow: None,
|
||||||
|
deny: None,
|
||||||
|
}))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
print_key_info(&key.0);
|
print_key_info(&key.0);
|
||||||
@@ -92,6 +101,38 @@ impl Cli {
|
|||||||
id: key.access_key_id,
|
id: key.access_key_id,
|
||||||
body: UpdateKeyRequestBody {
|
body: UpdateKeyRequestBody {
|
||||||
name: Some(opt.new_name),
|
name: Some(opt.new_name),
|
||||||
|
expiration: None,
|
||||||
|
allow: None,
|
||||||
|
deny: None,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
print_key_info(&new_key.0);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn cmd_update_key(&self, opt: KeySetOpt) -> Result<(), Error> {
|
||||||
|
let key = self
|
||||||
|
.api_request(GetKeyInfoRequest {
|
||||||
|
id: None,
|
||||||
|
search: Some(opt.key_pattern),
|
||||||
|
show_secret_key: false,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let new_key = self
|
||||||
|
.api_request(UpdateKeyRequest {
|
||||||
|
id: key.access_key_id,
|
||||||
|
body: UpdateKeyRequestBody {
|
||||||
|
name: None,
|
||||||
|
expiration: opt
|
||||||
|
.expires_in
|
||||||
|
.map(|x| parse_duration::parse::parse(&x))
|
||||||
|
.transpose()
|
||||||
|
.ok_or_message("Invalid duration passed for --expires-in parameter")?
|
||||||
|
.map(|dur| Utc::now() + dur),
|
||||||
allow: None,
|
allow: None,
|
||||||
deny: None,
|
deny: None,
|
||||||
},
|
},
|
||||||
@@ -143,6 +184,7 @@ impl Cli {
|
|||||||
id: key.access_key_id,
|
id: key.access_key_id,
|
||||||
body: UpdateKeyRequestBody {
|
body: UpdateKeyRequestBody {
|
||||||
name: None,
|
name: None,
|
||||||
|
expiration: None,
|
||||||
allow: Some(KeyPerm {
|
allow: Some(KeyPerm {
|
||||||
create_bucket: opt.create_bucket,
|
create_bucket: opt.create_bucket,
|
||||||
}),
|
}),
|
||||||
@@ -170,6 +212,7 @@ impl Cli {
|
|||||||
id: key.access_key_id,
|
id: key.access_key_id,
|
||||||
body: UpdateKeyRequestBody {
|
body: UpdateKeyRequestBody {
|
||||||
name: None,
|
name: None,
|
||||||
|
expiration: None,
|
||||||
allow: None,
|
allow: None,
|
||||||
deny: Some(KeyPerm {
|
deny: Some(KeyPerm {
|
||||||
create_bucket: opt.create_bucket,
|
create_bucket: opt.create_bucket,
|
||||||
|
|||||||
@@ -426,6 +426,10 @@ pub enum KeyOperation {
|
|||||||
/// Import key
|
/// Import key
|
||||||
#[structopt(name = "import", version = garage_version())]
|
#[structopt(name = "import", version = garage_version())]
|
||||||
Import(KeyImportOpt),
|
Import(KeyImportOpt),
|
||||||
|
|
||||||
|
/// Set parameters for an access key
|
||||||
|
#[structopt(name = "set", version = garage_version())]
|
||||||
|
Set(KeySetOpt),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
@@ -442,6 +446,21 @@ pub struct KeyNewOpt {
|
|||||||
/// Name of the key
|
/// Name of the key
|
||||||
#[structopt(default_value = "Unnamed key")]
|
#[structopt(default_value = "Unnamed key")]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
/// Set an expiration time for the access key
|
||||||
|
/// (see docs.rs/parse_duration for date format)
|
||||||
|
#[structopt(long = "expires-in")]
|
||||||
|
pub expires_in: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(StructOpt, Debug)]
|
||||||
|
pub struct KeySetOpt {
|
||||||
|
/// ID or name of the key
|
||||||
|
pub key_pattern: String,
|
||||||
|
|
||||||
|
/// Set an expiration time for the access key
|
||||||
|
/// (see docs.rs/parse_duration for date format)
|
||||||
|
#[structopt(long = "expires-in")]
|
||||||
|
pub expires_in: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
|
|||||||
Reference in New Issue
Block a user