252 lines
8.7 KiB
Rust
252 lines
8.7 KiB
Rust
|
extern crate chrono;
|
||
|
extern crate clap;
|
||
|
extern crate orizentic;
|
||
|
|
||
|
use chrono::Duration;
|
||
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||
|
use std::env;
|
||
|
|
||
|
use orizentic::*;
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
enum OrizenticErr {
|
||
|
ParseError(std::num::ParseIntError),
|
||
|
}
|
||
|
|
||
|
// ORIZENTIC_DB
|
||
|
// ORIZENTIC_SECRET
|
||
|
//
|
||
|
// list
|
||
|
// create
|
||
|
// revoke
|
||
|
// encode
|
||
|
pub fn main() {
|
||
|
let db_path = env::var_os("ORIZENTIC_DB").map(|str| {
|
||
|
str.into_string()
|
||
|
.expect("ORIZENTIC_DB contains invalid Unicode sequences")
|
||
|
});
|
||
|
let secret = env::var_os("ORIZENTIC_SECRET").map(|str| {
|
||
|
Secret(
|
||
|
str.into_string()
|
||
|
.map(|s| s.into_bytes())
|
||
|
.expect("ORIZENTIC_SECRET contains invalid Unicode sequences"),
|
||
|
)
|
||
|
});
|
||
|
|
||
|
let matches = App::new("orizentic cli")
|
||
|
.subcommand(SubCommand::with_name("list"))
|
||
|
.subcommand(
|
||
|
SubCommand::with_name("create")
|
||
|
.arg(
|
||
|
Arg::with_name("issuer")
|
||
|
.long("issuer")
|
||
|
.takes_value(true)
|
||
|
.required(true),
|
||
|
)
|
||
|
.arg(
|
||
|
Arg::with_name("ttl")
|
||
|
.long("ttl")
|
||
|
.takes_value(true)
|
||
|
.required(true),
|
||
|
)
|
||
|
.arg(
|
||
|
Arg::with_name("resource")
|
||
|
.long("resource")
|
||
|
.takes_value(true)
|
||
|
.required(true),
|
||
|
)
|
||
|
.arg(
|
||
|
Arg::with_name("username")
|
||
|
.long("username")
|
||
|
.takes_value(true)
|
||
|
.required(true),
|
||
|
)
|
||
|
.arg(
|
||
|
Arg::with_name("perms")
|
||
|
.long("perms")
|
||
|
.takes_value(true)
|
||
|
.required(true),
|
||
|
),
|
||
|
)
|
||
|
.subcommand(
|
||
|
SubCommand::with_name("revoke").arg(
|
||
|
Arg::with_name("id")
|
||
|
.long("id")
|
||
|
.takes_value(true)
|
||
|
.required(true),
|
||
|
),
|
||
|
)
|
||
|
.subcommand(
|
||
|
SubCommand::with_name("encode").arg(
|
||
|
Arg::with_name("id")
|
||
|
.long("id")
|
||
|
.takes_value(true)
|
||
|
.required(true),
|
||
|
),
|
||
|
)
|
||
|
.get_matches();
|
||
|
|
||
|
match matches.subcommand() {
|
||
|
("list", _) => list_tokens(db_path),
|
||
|
("create", Some(args)) => create_token(db_path, secret, args),
|
||
|
("revoke", Some(args)) => revoke_token(db_path, args),
|
||
|
("encode", Some(args)) => encode_token(db_path, secret, args),
|
||
|
(cmd, _) => {
|
||
|
println!("unknown subcommand: {}", cmd);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn list_tokens(db_path: Option<String>) {
|
||
|
let db_path_ = db_path.expect("ORIZENTIC_DB is required for this operation");
|
||
|
let claimsets = orizentic::filedb::load_claims_from_file(&db_path_);
|
||
|
match claimsets {
|
||
|
Ok(claimsets_) => {
|
||
|
for claimset in claimsets_ {
|
||
|
println!("[{}]", claimset.id);
|
||
|
println!("Audience: {}", String::from(claimset.audience));
|
||
|
match claimset.expiration {
|
||
|
Some(expiration) => println!(
|
||
|
"Expiration: {}",
|
||
|
expiration.format("%Y-%m-%d %H:%M:%S")
|
||
|
),
|
||
|
None => println!("Expiration: None"),
|
||
|
}
|
||
|
println!("Issuer: {}", claimset.issuer.0);
|
||
|
println!(
|
||
|
"Issued At: {}",
|
||
|
claimset.issued_at.format("%Y-%m-%d %H:%M:%S")
|
||
|
);
|
||
|
println!("Resource Name: {}", claimset.resource.0);
|
||
|
|
||
|
let perm_val: String = itertools::Itertools::intersperse(
|
||
|
claimset.permissions.0.clone().into_iter(),
|
||
|
String::from(", "),
|
||
|
)
|
||
|
.collect();
|
||
|
println!("Permissions: {}", perm_val);
|
||
|
println!("")
|
||
|
}
|
||
|
}
|
||
|
Err(err) => {
|
||
|
println!("claimset failed to load: {}", err);
|
||
|
std::process::exit(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn create_token(db_path: Option<String>, secret: Option<Secret>, args: &ArgMatches) {
|
||
|
let db_path_ = db_path.expect("ORIZENTIC_DB is required for this operation");
|
||
|
let secret_ = secret.expect("ORIZENTIC_SECRET is required for this operation");
|
||
|
let issuer = args
|
||
|
.value_of("issuer")
|
||
|
.map(|x| Issuer(String::from(x)))
|
||
|
.expect("--issuer is a required parameter");
|
||
|
let ttl: Option<TTL> = args.value_of("ttl").map(|x| {
|
||
|
x.parse()
|
||
|
.and_then(|d| Ok(TTL(Duration::seconds(d))))
|
||
|
.map_err(|err| OrizenticErr::ParseError(err))
|
||
|
.expect("Failed to parse TTL")
|
||
|
});
|
||
|
let resource_name = args
|
||
|
.value_of("resource")
|
||
|
.map(|x| ResourceName(String::from(x)))
|
||
|
.expect("--resource is a required parameter");
|
||
|
let username = args
|
||
|
.value_of("username")
|
||
|
.map(|x| Username::from(x))
|
||
|
.expect("--username is a required parameter");
|
||
|
let perms: Permissions = args
|
||
|
.value_of("perms")
|
||
|
.map(|str| Permissions(str.split(',').map(|s| String::from(s)).collect()))
|
||
|
.expect("--permissions is a required parameter");
|
||
|
|
||
|
let claimsets = orizentic::filedb::load_claims_from_file(&db_path_);
|
||
|
match claimsets {
|
||
|
Err(err) => {
|
||
|
println!("claimset failed to load: {}", err);
|
||
|
std::process::exit(1);
|
||
|
}
|
||
|
Ok(claimsets_) => {
|
||
|
let new_claimset = ClaimSet::new(issuer, ttl, resource_name, username, perms);
|
||
|
let mut ctx = orizentic::OrizenticCtx::new(secret_, claimsets_);
|
||
|
ctx.add_claimset(new_claimset.clone());
|
||
|
match orizentic::filedb::save_claims_to_file(&ctx.list_claimsets(), &db_path_) {
|
||
|
Err(err) => {
|
||
|
println!("Failed to write claimset to file: {:?}", err);
|
||
|
std::process::exit(1);
|
||
|
}
|
||
|
Ok(_) => match ctx.encode_claimset(&new_claimset) {
|
||
|
Ok(token) => println!("{}", token.text),
|
||
|
Err(err) => {
|
||
|
println!("token could not be encoded: {:?}", err);
|
||
|
std::process::exit(1);
|
||
|
}
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn revoke_token(db_path: Option<String>, args: &ArgMatches) {
|
||
|
let db_path_ = db_path.expect("ORIZENTIC_DB is required for this operation");
|
||
|
let claimsets = orizentic::filedb::load_claims_from_file(&db_path_);
|
||
|
|
||
|
match claimsets {
|
||
|
Err(err) => {
|
||
|
println!("claimset failed to load: {}", err);
|
||
|
std::process::exit(1);
|
||
|
}
|
||
|
Ok(claimsets_) => {
|
||
|
let id = args
|
||
|
.value_of("id")
|
||
|
.map(String::from)
|
||
|
.expect("--id is a required parameter");
|
||
|
let mut ctx =
|
||
|
orizentic::OrizenticCtx::new(Secret(String::from("").into_bytes()), claimsets_);
|
||
|
ctx.revoke_by_uuid(&id);
|
||
|
match orizentic::filedb::save_claims_to_file(&ctx.list_claimsets(), &db_path_) {
|
||
|
Err(err) => {
|
||
|
println!("Failed to write claimset to file: {:?}", err);
|
||
|
std::process::exit(1);
|
||
|
}
|
||
|
Ok(_) => {}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn encode_token(db_path: Option<String>, secret: Option<Secret>, args: &ArgMatches) {
|
||
|
let db_path_ = db_path.expect("ORIZENTIC_DB is required for this operation");
|
||
|
let secret_ = secret.expect("ORIZENTIC_SECRET is required for this operation");
|
||
|
let id = args
|
||
|
.value_of("id")
|
||
|
.map(String::from)
|
||
|
.expect("--id is a required parameter");
|
||
|
|
||
|
let claimsets = orizentic::filedb::load_claims_from_file(&db_path_);
|
||
|
match claimsets {
|
||
|
Err(err) => {
|
||
|
println!("claimset failed to load: {}", err);
|
||
|
std::process::exit(1);
|
||
|
}
|
||
|
Ok(claimsets_) => {
|
||
|
let ctx = orizentic::OrizenticCtx::new(secret_, claimsets_);
|
||
|
let claimset = ctx.find_claimset(&id);
|
||
|
match claimset {
|
||
|
Some(claimset_) => match ctx.encode_claimset(&claimset_) {
|
||
|
Ok(token) => println!("{}", token.text),
|
||
|
Err(err) => {
|
||
|
println!("token could not be encoded: {:?}", err);
|
||
|
std::process::exit(1);
|
||
|
}
|
||
|
},
|
||
|
None => {
|
||
|
println!("No claimset found");
|
||
|
std::process::exit(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|