add creation date to admin api tokens
This commit is contained in:
parent
325f79012c
commit
88b4623bf1
5 changed files with 37 additions and 8 deletions
|
@ -2048,6 +2048,14 @@
|
||||||
"scope"
|
"scope"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"created": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "Creation date"
|
||||||
|
},
|
||||||
"expiration": {
|
"expiration": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl RequestHandler for ListAdminTokensRequest {
|
||||||
0,
|
0,
|
||||||
GetAdminTokenInfoResponse {
|
GetAdminTokenInfoResponse {
|
||||||
id: None,
|
id: None,
|
||||||
|
created: None,
|
||||||
name: "admin_token (from daemon configuration)".into(),
|
name: "admin_token (from daemon configuration)".into(),
|
||||||
expiration: None,
|
expiration: None,
|
||||||
expired: false,
|
expired: false,
|
||||||
|
@ -54,6 +55,7 @@ impl RequestHandler for ListAdminTokensRequest {
|
||||||
1,
|
1,
|
||||||
GetAdminTokenInfoResponse {
|
GetAdminTokenInfoResponse {
|
||||||
id: None,
|
id: None,
|
||||||
|
created: None,
|
||||||
name: "metrics_token (from daemon configuration)".into(),
|
name: "metrics_token (from daemon configuration)".into(),
|
||||||
expiration: None,
|
expiration: None,
|
||||||
expired: false,
|
expired: false,
|
||||||
|
@ -180,6 +182,10 @@ fn admin_token_info_results(token: &AdminApiToken, now: u64) -> GetAdminTokenInf
|
||||||
|
|
||||||
GetAdminTokenInfoResponse {
|
GetAdminTokenInfoResponse {
|
||||||
id: Some(token.prefix.clone()),
|
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(),
|
name: params.name.get().to_string(),
|
||||||
expiration: params.expiration.get().map(|x| {
|
expiration: params.expiration.get().map(|x| {
|
||||||
DateTime::from_timestamp_millis(x as i64).expect("invalid timestamp stored in db")
|
DateTime::from_timestamp_millis(x as i64).expect("invalid timestamp stored in db")
|
||||||
|
|
|
@ -314,6 +314,8 @@ pub struct GetAdminTokenInfoRequest {
|
||||||
pub struct GetAdminTokenInfoResponse {
|
pub struct GetAdminTokenInfoResponse {
|
||||||
/// Identifier of the admin token (which is also a prefix of the full bearer token)
|
/// Identifier of the admin token (which is also a prefix of the full bearer token)
|
||||||
pub id: Option<String>,
|
pub id: Option<String>,
|
||||||
|
/// Creation date
|
||||||
|
pub created: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
/// Name of the admin API token
|
/// Name of the admin API token
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// Expiration time and date, formatted according to RFC 3339
|
/// Expiration time and date, formatted according to RFC 3339
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use format_table::format_table;
|
use format_table::format_table;
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::{Local, Utc};
|
||||||
|
|
||||||
use garage_util::error::*;
|
use garage_util::error::*;
|
||||||
|
|
||||||
|
@ -30,11 +30,15 @@ impl Cli {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn cmd_list_admin_tokens(&self) -> Result<(), Error> {
|
pub async fn cmd_list_admin_tokens(&self) -> Result<(), Error> {
|
||||||
let list = self.api_request(ListAdminTokensRequest).await?;
|
let mut list = self.api_request(ListAdminTokensRequest).await?;
|
||||||
|
|
||||||
let mut table = vec!["ID\tNAME\tEXPIRATION\tSCOPE".to_string()];
|
list.0.sort_by_key(|x| x.created);
|
||||||
|
|
||||||
|
let mut table = vec!["ID\tCREATED\tNAME\tEXPIRATION\tSCOPE".to_string()];
|
||||||
for tok in list.0.iter() {
|
for tok in list.0.iter() {
|
||||||
let scope = if tok.scope.len() > 1 {
|
let scope = if tok.expired {
|
||||||
|
String::new()
|
||||||
|
} else if tok.scope.len() > 1 {
|
||||||
format!("[{}]", tok.scope.len())
|
format!("[{}]", tok.scope.len())
|
||||||
} else {
|
} else {
|
||||||
tok.scope.get(0).cloned().unwrap_or_default()
|
tok.scope.get(0).cloned().unwrap_or_default()
|
||||||
|
@ -43,12 +47,15 @@ impl Cli {
|
||||||
"expired".to_string()
|
"expired".to_string()
|
||||||
} else {
|
} else {
|
||||||
tok.expiration
|
tok.expiration
|
||||||
.map(|x| x.to_string())
|
.map(|x| x.with_timezone(&Local).to_string())
|
||||||
.unwrap_or("never".into())
|
.unwrap_or("never".into())
|
||||||
};
|
};
|
||||||
table.push(format!(
|
table.push(format!(
|
||||||
"{}\t{}\t{}\t{}\t",
|
"{}\t{}\t{}\t{}\t{}",
|
||||||
tok.id.as_deref().unwrap_or("-"),
|
tok.id.as_deref().unwrap_or("-"),
|
||||||
|
tok.created
|
||||||
|
.map(|x| x.with_timezone(&Local).date_naive().to_string())
|
||||||
|
.unwrap_or("-".into()),
|
||||||
tok.name,
|
tok.name,
|
||||||
exp,
|
exp,
|
||||||
scope,
|
scope,
|
||||||
|
@ -209,8 +216,9 @@ impl Cli {
|
||||||
|
|
||||||
fn print_token_info(token: &GetAdminTokenInfoResponse) {
|
fn print_token_info(token: &GetAdminTokenInfoResponse) {
|
||||||
format_table(vec![
|
format_table(vec![
|
||||||
format!("ID:\t{}", token.id.as_deref().unwrap_or("-")),
|
format!("ID:\t{}", token.id.as_ref().unwrap()),
|
||||||
format!("Name:\t{}", token.name),
|
format!("Name:\t{}", token.name),
|
||||||
|
format!("Created:\t{}", token.created.unwrap().with_timezone(&Local)),
|
||||||
format!(
|
format!(
|
||||||
"Validity:\t{}",
|
"Validity:\t{}",
|
||||||
token.expired.then_some("EXPIRED").unwrap_or("valid")
|
token.expired.then_some("EXPIRED").unwrap_or("valid")
|
||||||
|
@ -219,7 +227,7 @@ fn print_token_info(token: &GetAdminTokenInfoResponse) {
|
||||||
"Expiration:\t{}",
|
"Expiration:\t{}",
|
||||||
token
|
token
|
||||||
.expiration
|
.expiration
|
||||||
.map(|x| x.to_string())
|
.map(|x| x.with_timezone(&Local).to_string())
|
||||||
.unwrap_or("never".into())
|
.unwrap_or("never".into())
|
||||||
),
|
),
|
||||||
format!("Scope:\t{}", token.scope.to_vec().join(", ")),
|
format!("Scope:\t{}", token.scope.to_vec().join(", ")),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use base64::prelude::*;
|
use base64::prelude::*;
|
||||||
|
|
||||||
use garage_util::crdt::{self, Crdt};
|
use garage_util::crdt::{self, Crdt};
|
||||||
|
use garage_util::time::now_msec;
|
||||||
|
|
||||||
use garage_table::{EmptyKey, Entry, TableSchema};
|
use garage_table::{EmptyKey, Entry, TableSchema};
|
||||||
|
|
||||||
|
@ -24,6 +25,9 @@ mod v2 {
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct AdminApiTokenParams {
|
pub struct AdminApiTokenParams {
|
||||||
|
/// Creation date
|
||||||
|
pub created: u64,
|
||||||
|
|
||||||
/// The entire API token hashed as a password
|
/// The entire API token hashed as a password
|
||||||
pub token_hash: String,
|
pub token_hash: String,
|
||||||
|
|
||||||
|
@ -91,6 +95,7 @@ impl AdminApiToken {
|
||||||
let ret = AdminApiToken {
|
let ret = AdminApiToken {
|
||||||
prefix,
|
prefix,
|
||||||
state: crdt::Deletable::present(AdminApiTokenParams {
|
state: crdt::Deletable::present(AdminApiTokenParams {
|
||||||
|
created: now_msec(),
|
||||||
token_hash: hashed_token,
|
token_hash: hashed_token,
|
||||||
name: crdt::Lww::new(name.to_string()),
|
name: crdt::Lww::new(name.to_string()),
|
||||||
expiration: crdt::Lww::new(None),
|
expiration: crdt::Lww::new(None),
|
||||||
|
|
Loading…
Add table
Reference in a new issue