admin api: add openapi spec for admin token management functions
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful

This commit is contained in:
Alex 2025-03-11 15:38:38 +01:00
parent d067a40b3f
commit 9511b20153
3 changed files with 363 additions and 11 deletions

View file

@ -225,6 +225,40 @@
} }
} }
}, },
"/v2/CreateAdminToken": {
"post": {
"tags": [
"Admin API token"
],
"description": "Creates a new admin API token",
"operationId": "CreateAdminToken",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAdminTokenRequestBody"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Admin token has been created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateAdminTokenResponse"
}
}
}
},
"500": {
"description": "Internal server error"
}
}
}
},
"/v2/CreateBucket": { "/v2/CreateBucket": {
"post": { "post": {
"tags": [ "tags": [
@ -325,6 +359,31 @@
} }
} }
}, },
"/v2/DeleteAdminToken": {
"post": {
"tags": [
"Admin API token"
],
"description": "Delete an admin API token from the cluster, revoking all its permissions.",
"operationId": "DeleteAdminToken",
"parameters": [
{
"name": "id",
"in": "path",
"description": "Admin API token ID",
"required": true
}
],
"responses": {
"200": {
"description": "Admin token has been deleted"
},
"500": {
"description": "Internal server error"
}
}
}
},
"/v2/DeleteBucket": { "/v2/DeleteBucket": {
"post": { "post": {
"tags": [ "tags": [
@ -415,6 +474,44 @@
} }
} }
}, },
"/v2/GetAdminTokenInfo": {
"get": {
"tags": [
"Admin API token"
],
"description": "\nReturn information about a specific admin API token.\nYou can search by specifying the exact token identifier (`id`) or by specifying a pattern (`search`).\n ",
"operationId": "GetAdminTokenInfo",
"parameters": [
{
"name": "id",
"in": "path",
"description": "Admin API token ID",
"required": true
},
{
"name": "search",
"in": "path",
"description": "Partial token ID or name to search for",
"required": true
}
],
"responses": {
"200": {
"description": "Information about the admin token",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetAdminTokenInfoResponse"
}
}
}
},
"500": {
"description": "Internal server error"
}
}
}
},
"/v2/GetBlockInfo": { "/v2/GetBlockInfo": {
"post": { "post": {
"tags": [ "tags": [
@ -886,6 +983,30 @@
} }
} }
}, },
"/v2/ListAdminTokens": {
"get": {
"tags": [
"Admin API token"
],
"description": "Returns all admin API tokens in the cluster.",
"operationId": "ListAdminTokens",
"responses": {
"200": {
"description": "Returns info about all admin API tokens",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ListAdminTokensResponse"
}
}
}
},
"500": {
"description": "Internal server error"
}
}
}
},
"/v2/ListBlockErrors": { "/v2/ListBlockErrors": {
"get": { "get": {
"tags": [ "tags": [
@ -1216,6 +1337,48 @@
} }
} }
}, },
"/v2/UpdateAdminToken": {
"post": {
"tags": [
"Admin API token"
],
"description": "\nUpdates information about the specified admin API token.\n ",
"operationId": "UpdateAdminToken",
"parameters": [
{
"name": "id",
"in": "path",
"description": "Admin API token ID",
"required": true
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAdminTokenRequestBody"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Admin token has been updated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAdminTokenResponse"
}
}
}
},
"500": {
"description": "Internal server error"
}
}
}
},
"/v2/UpdateBucket": { "/v2/UpdateBucket": {
"post": { "post": {
"tags": [ "tags": [
@ -1775,6 +1938,25 @@
} }
} }
}, },
"CreateAdminTokenResponse": {
"allOf": [
{
"$ref": "#/components/schemas/GetAdminTokenInfoResponse"
},
{
"type": "object",
"required": [
"secretToken"
],
"properties": {
"secretToken": {
"type": "string",
"description": "The secret bearer token. **CAUTION:** This token will be shown only\nONCE, so this value MUST be remembered somewhere, or the token\nwill be unusable."
}
}
}
]
},
"CreateBucketLocalAlias": { "CreateBucketLocalAlias": {
"type": "object", "type": "object",
"required": [ "required": [
@ -1858,6 +2040,43 @@
} }
} }
}, },
"GetAdminTokenInfoResponse": {
"type": "object",
"required": [
"id",
"name",
"expired",
"scope"
],
"properties": {
"expiration": {
"type": [
"string",
"null"
],
"description": "Expiration time and date, formatted according to RFC 3339"
},
"expired": {
"type": "boolean",
"description": "Whether this admin token is expired already"
},
"id": {
"type": "string",
"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"
}
}
},
"GetBucketInfoKey": { "GetBucketInfoKey": {
"type": "object", "type": "object",
"required": [ "required": [
@ -2325,6 +2544,12 @@
} }
} }
}, },
"ListAdminTokensResponse": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GetAdminTokenInfoResponse"
}
},
"ListBucketsResponse": { "ListBucketsResponse": {
"type": "array", "type": "array",
"items": { "items": {
@ -3404,6 +3629,38 @@
"cancel" "cancel"
] ]
}, },
"UpdateAdminTokenRequestBody": {
"type": "object",
"properties": {
"expiration": {
"type": [
"string",
"null"
],
"description": "Expiration time and date, formatted according to RFC 3339"
},
"name": {
"type": [
"string",
"null"
],
"description": "Name of the admin API token"
},
"scope": {
"type": [
"array",
"null"
],
"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. **WARNING:** Granting a scope of `CreateAdminToken` or\n`UpdateAdminToken` trivially allows for privilege escalation, and is thus\nfunctionnally equivalent to granting a scope of `*`."
}
}
},
"UpdateAdminTokenResponse": {
"$ref": "#/components/schemas/GetAdminTokenInfoResponse"
},
"UpdateBucketRequestBody": { "UpdateBucketRequestBody": {
"type": "object", "type": "object",
"properties": { "properties": {

View file

@ -298,15 +298,9 @@ pub struct ConnectNodeResponse {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListAdminTokensRequest; pub struct ListAdminTokensRequest;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ListAdminTokensResponse(pub Vec<GetAdminTokenInfoResponse>); pub struct ListAdminTokensResponse(pub Vec<GetAdminTokenInfoResponse>);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListAdminTokensResponseItem {
pub id: String,
pub name: String,
}
// ---- GetAdminTokenInfo ---- // ---- GetAdminTokenInfo ----
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -315,13 +309,21 @@ pub struct GetAdminTokenInfoRequest {
pub search: Option<String>, pub search: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GetAdminTokenInfoResponse { pub struct GetAdminTokenInfoResponse {
/// Identifier of the admin token (which is also a prefix of the full bearer token)
pub id: String, pub id: String,
/// Name of the admin API token
pub name: String, pub name: String,
/// Expiration time and date, formatted according to RFC 3339
#[schema(value_type = Option<String>)]
pub expiration: Option<chrono::DateTime<chrono::Utc>>, pub expiration: Option<chrono::DateTime<chrono::Utc>>,
/// Whether this admin token is expired already
pub expired: bool, 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 scope: Vec<String>,
} }
@ -330,9 +332,12 @@ pub struct GetAdminTokenInfoResponse {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateAdminTokenRequest(pub UpdateAdminTokenRequestBody); pub struct CreateAdminTokenRequest(pub UpdateAdminTokenRequestBody);
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CreateAdminTokenResponse { pub struct CreateAdminTokenResponse {
/// The secret bearer token. **CAUTION:** This token will be shown only
/// ONCE, so this value MUST be remembered somewhere, or the token
/// will be unusable.
pub secret_token: String, pub secret_token: String,
#[serde(flatten)] #[serde(flatten)]
pub info: GetAdminTokenInfoResponse, pub info: GetAdminTokenInfoResponse,
@ -346,15 +351,23 @@ pub struct UpdateAdminTokenRequest {
pub body: UpdateAdminTokenRequestBody, pub body: UpdateAdminTokenRequestBody,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UpdateAdminTokenRequestBody { pub struct UpdateAdminTokenRequestBody {
/// Name of the admin API token
pub name: Option<String>, pub name: Option<String>,
/// Expiration time and date, formatted according to RFC 3339
#[schema(value_type = Option<String>)]
pub expiration: Option<chrono::DateTime<chrono::Utc>>, pub expiration: Option<chrono::DateTime<chrono::Utc>>,
/// 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. **WARNING:** Granting a scope of `CreateAdminToken` or
/// `UpdateAdminToken` trivially allows for privilege escalation, and is thus
/// functionnally equivalent to granting a scope of `*`.
pub scope: Option<Vec<String>>, pub scope: Option<Vec<String>>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdateAdminTokenResponse(pub GetAdminTokenInfoResponse); pub struct UpdateAdminTokenResponse(pub GetAdminTokenInfoResponse);
// ---- DeleteAdminToken ---- // ---- DeleteAdminToken ----

View file

@ -66,6 +66,82 @@ fn GetClusterStatistics() -> () {}
)] )]
fn ConnectClusterNodes() -> () {} fn ConnectClusterNodes() -> () {}
// **********************************************
// Admin API token operations
// **********************************************
#[utoipa::path(get,
path = "/v2/ListAdminTokens",
tag = "Admin API token",
description = "Returns all admin API tokens in the cluster.",
responses(
(status = 200, description = "Returns info about all admin API tokens", body = ListAdminTokensResponse),
(status = 500, description = "Internal server error")
),
)]
fn ListAdminTokens() -> () {}
#[utoipa::path(get,
path = "/v2/GetAdminTokenInfo",
tag = "Admin API token",
description = "
Return information about a specific admin API token.
You can search by specifying the exact token identifier (`id`) or by specifying a pattern (`search`).
",
params(
("id", description = "Admin API token ID"),
("search", description = "Partial token ID or name to search for"),
),
responses(
(status = 200, description = "Information about the admin token", body = GetAdminTokenInfoResponse),
(status = 500, description = "Internal server error")
),
)]
fn GetAdminTokenInfo() -> () {}
#[utoipa::path(post,
path = "/v2/CreateAdminToken",
tag = "Admin API token",
description = "Creates a new admin API token",
request_body = UpdateAdminTokenRequestBody,
responses(
(status = 200, description = "Admin token has been created", body = CreateAdminTokenResponse),
(status = 500, description = "Internal server error")
),
)]
fn CreateAdminToken() -> () {}
#[utoipa::path(post,
path = "/v2/UpdateAdminToken",
tag = "Admin API token",
description = "
Updates information about the specified admin API token.
",
request_body = UpdateAdminTokenRequestBody,
params(
("id", description = "Admin API token ID"),
),
responses(
(status = 200, description = "Admin token has been updated", body = UpdateAdminTokenResponse),
(status = 500, description = "Internal server error")
),
)]
fn UpdateAdminToken() -> () {}
#[utoipa::path(post,
path = "/v2/DeleteAdminToken",
tag = "Admin API token",
description = "Delete an admin API token from the cluster, revoking all its permissions.",
params(
("id", description = "Admin API token ID"),
),
responses(
(status = 200, description = "Admin token has been deleted"),
(status = 500, description = "Internal server error")
),
)]
fn DeleteAdminToken() -> () {}
// ********************************************** // **********************************************
// Layout operations // Layout operations
// ********************************************** // **********************************************
@ -723,6 +799,12 @@ impl Modify for SecurityAddon {
GetClusterStatus, GetClusterStatus,
GetClusterStatistics, GetClusterStatistics,
ConnectClusterNodes, ConnectClusterNodes,
// Admin token operations
ListAdminTokens,
GetAdminTokenInfo,
CreateAdminToken,
UpdateAdminToken,
DeleteAdminToken,
// Layout operations // Layout operations
GetClusterLayout, GetClusterLayout,
GetClusterLayoutHistory, GetClusterLayoutHistory,