mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-08-06 21:03:13 +00:00
api: correct according to review
This commit is contained in:
@@ -816,6 +816,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/GetCurrentAdminTokenInfo": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Admin API token"
|
||||
],
|
||||
"description": "\nReturn information about the calling admin API token.\n ",
|
||||
"operationId": "GetCurrentAdminTokenInfo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Information about the admin token",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetCurrentAdminTokenInfoResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/GetKeyInfo": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -1108,30 +1132,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/GetCurrentAdminTokenInfo": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Admin API token"
|
||||
],
|
||||
"description": "\nReturn information about the calling admin API token.\n ",
|
||||
"operationId": "GetCurrentAdminTokenInfo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Information about the admin token",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetCurrentAdminTokenInfoResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/LaunchRepairOperation": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@@ -2618,6 +2618,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"GetCurrentAdminTokenInfoResponse": {
|
||||
"$ref": "#/components/schemas/GetAdminTokenInfoResponse"
|
||||
},
|
||||
"GetKeyInfoResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -2832,54 +2835,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"GetCurrentAdminTokenInfoResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"expired",
|
||||
"scope"
|
||||
],
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "date-time",
|
||||
"description": "Creation date"
|
||||
},
|
||||
"expiration": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "date-time",
|
||||
"description": "Expiration time and date, formatted according to RFC 3339"
|
||||
},
|
||||
"expired": {
|
||||
"type": "boolean",
|
||||
"description": "Whether this admin token is expired already"
|
||||
},
|
||||
"id": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "Identifier of the admin token (which is also a prefix of the full bearer token)"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the admin API token"
|
||||
},
|
||||
"scope": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Scope of the admin API token, a list of admin endpoint names (such as\n`GetClusterStatus`, etc), or the special value `*` to allow all\nadmin endpoints"
|
||||
}
|
||||
}
|
||||
},
|
||||
"KeyInfoBucketResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
||||
@@ -192,14 +192,16 @@ impl RequestHandler for GetCurrentAdminTokenInfoRequest {
|
||||
.as_ref()
|
||||
.is_some_and(|s| s == &self.admin_token)
|
||||
{
|
||||
return Ok(GetCurrentAdminTokenInfoResponse {
|
||||
id: None,
|
||||
created: None,
|
||||
name: "metrics_token (from daemon configuration)".into(),
|
||||
expiration: None,
|
||||
expired: false,
|
||||
scope: vec!["Metrics".into()],
|
||||
});
|
||||
return Ok(GetCurrentAdminTokenInfoResponse(
|
||||
GetAdminTokenInfoResponse {
|
||||
id: None,
|
||||
created: None,
|
||||
name: "metrics_token (from daemon configuration)".into(),
|
||||
expiration: None,
|
||||
expired: false,
|
||||
scope: vec!["Metrics".into()],
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
if garage
|
||||
@@ -209,42 +211,24 @@ impl RequestHandler for GetCurrentAdminTokenInfoRequest {
|
||||
.as_ref()
|
||||
.is_some_and(|s| s == &self.admin_token)
|
||||
{
|
||||
return Ok(GetCurrentAdminTokenInfoResponse {
|
||||
id: None,
|
||||
created: None,
|
||||
name: "admin_token (from daemon configuration)".into(),
|
||||
expiration: None,
|
||||
expired: false,
|
||||
scope: vec!["*".into()],
|
||||
});
|
||||
return Ok(GetCurrentAdminTokenInfoResponse(
|
||||
GetAdminTokenInfoResponse {
|
||||
id: None,
|
||||
created: None,
|
||||
name: "admin_token (from daemon configuration)".into(),
|
||||
expiration: None,
|
||||
expired: false,
|
||||
scope: vec!["*".into()],
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let (prefix, _) = self.admin_token.split_once('.').unwrap();
|
||||
let token = get_existing_admin_token(&garage, &prefix.to_string()).await?;
|
||||
|
||||
let candidates = garage
|
||||
.admin_token_table
|
||||
.get_range(
|
||||
&EmptyKey,
|
||||
None,
|
||||
Some(KeyFilter::MatchesAndNotDeleted(
|
||||
prefix.clone().parse().unwrap(),
|
||||
)),
|
||||
10,
|
||||
EnumerationOrder::Forward,
|
||||
)
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();
|
||||
if candidates.len() != 1 {
|
||||
return Err(Error::bad_request(format!(
|
||||
"{} matching admin tokens",
|
||||
candidates.len()
|
||||
)));
|
||||
}
|
||||
Ok(my_admin_token_info_results(
|
||||
&candidates.into_iter().next().unwrap(),
|
||||
now,
|
||||
))
|
||||
Ok(GetCurrentAdminTokenInfoResponse(admin_token_info_results(
|
||||
&token, now,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,21 +290,3 @@ fn apply_token_updates(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn my_admin_token_info_results(token: &AdminApiToken, now: u64) -> GetCurrentAdminTokenInfoResponse {
|
||||
let params = token.params().unwrap();
|
||||
|
||||
GetCurrentAdminTokenInfoResponse {
|
||||
id: Some(token.prefix.clone()),
|
||||
created: Some(
|
||||
DateTime::from_timestamp_millis(params.created as i64)
|
||||
.expect("invalid timestamp stored in db"),
|
||||
),
|
||||
name: params.name.get().to_string(),
|
||||
expiration: params.expiration.get().map(|x| {
|
||||
DateTime::from_timestamp_millis(x as i64).expect("invalid timestamp stored in db")
|
||||
}),
|
||||
expired: params.is_expired(now),
|
||||
scope: params.scope.get().0.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
+2
-16
@@ -399,22 +399,8 @@ pub struct GetCurrentAdminTokenInfoRequest {
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GetCurrentAdminTokenInfoResponse {
|
||||
/// Identifier of the admin token (which is also a prefix of the full bearer token)
|
||||
pub id: Option<String>,
|
||||
/// Creation date
|
||||
pub created: Option<DateTime<Utc>>,
|
||||
/// Name of the admin API token
|
||||
pub name: String,
|
||||
/// Expiration time and date, formatted according to RFC 3339
|
||||
pub expiration: Option<DateTime<Utc>>,
|
||||
/// Whether this admin token is expired already
|
||||
pub expired: bool,
|
||||
/// Scope of the admin API token, a list of admin endpoint names (such as
|
||||
/// `GetClusterStatus`, etc), or the special value `*` to allow all
|
||||
/// admin endpoints
|
||||
pub scope: Vec<String>,
|
||||
}
|
||||
pub struct GetCurrentAdminTokenInfoResponse(pub GetAdminTokenInfoResponse);
|
||||
|
||||
// **********************************************
|
||||
// Layout operations
|
||||
// **********************************************
|
||||
|
||||
@@ -23,8 +23,8 @@ use garage_util::time::now_msec;
|
||||
use garage_api_common::generic_server::*;
|
||||
use garage_api_common::helpers::*;
|
||||
|
||||
use crate::api::*;
|
||||
use crate::api::AdminApiRequest::GetCurrentAdminTokenInfo;
|
||||
use crate::api::*;
|
||||
use crate::error::*;
|
||||
use crate::router_v0;
|
||||
use crate::router_v1;
|
||||
@@ -274,6 +274,7 @@ fn verify_authorization(
|
||||
.get_local(&EmptyKey, &prefix.to_string())?
|
||||
.and_then(|k| k.state.into_option())
|
||||
.filter(|p| !p.is_expired(now_msec()))
|
||||
// GetCurrentAdminTokenInfo endpoint must be accessible even if it is not in the token scopes
|
||||
.filter(|p| p.has_scope(endpoint_name) || endpoint_name == "GetCurrentAdminTokenInfo")
|
||||
.ok_or_else(|| Error::forbidden(invalid_msg))?
|
||||
.token_hash
|
||||
|
||||
Reference in New Issue
Block a user