123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- use crate::{
- key, client_management, config, schema::{self, RealmID}, server, token, user_management, UIDCError, group_management, token_management,
- };
- use clap::{Parser, Subcommand};
- use microrm::prelude::*;
- #[derive(Debug, Parser)]
- #[clap(author, version, about, long_about = None)]
- struct RootArgs {
- #[clap(short, long, default_value_t = String::from("uidc.db"))]
- /// Database path
- db: String,
- #[clap(short, long, default_value_t = String::from("primary"))]
- /// Which realm to use, for non-server only
- realm: String,
- #[clap(subcommand)]
- command: Command,
- }
- #[derive(Debug, Subcommand)]
- enum Command {
- /// database initialization
- Init,
- /// OAuth2 client management
- Client(ClientArgs),
- /// general configuration
- Config(ConfigArgs),
- /// permissions grouping management
- Group(GroupArgs),
- /// key management
- Key(KeyArgs),
- /// run the actual OIDC server
- Server(ServerArgs),
- /// manual token generation and inspection
- Token(TokenArgs),
- /// role management
- Role(RoleArgs),
- /// user management
- User(UserArgs),
- }
- struct RunArgs {
- db: microrm::DB,
- realm_id: RealmID,
- }
- impl RootArgs {
- async fn run(&self) -> Result<(), UIDCError> {
- if let Command::Init = self.command {
- return self.init().await;
- }
- let db = microrm::DB::new(schema::schema(), &self.db, microrm::CreateMode::MustExist).map_err(|_| UIDCError::Abort("Error accessing database"))?;
- let realm_id = db.query_interface().get().by(schema::Realm::Shortname, self.realm.as_str()).one()?.ok_or(UIDCError::Abort("no such realm"))?.id();
- let ra = RunArgs { db: db, realm_id };
- match &self.command {
- Command::Init => unreachable!(),
- Command::Config(v) => v.run(ra).await,
- Command::Client(v) => v.run(ra).await,
- Command::Group(v) => v.run(ra).await,
- Command::Key(v) => v.run(ra).await,
- Command::Server(v) => v.run(ra).await,
- Command::Token(v) => v.run(ra).await,
- Command::Role(v) => v.run(ra).await,
- Command::User(v) => v.run(ra).await,
- }
- }
- async fn init(&self) -> Result<(), UIDCError> {
- // first check to see if the database is already vaguely set up
- let maybedb = microrm::DB::new(schema::schema(), &self.db, microrm::CreateMode::MustExist);
- if maybedb.is_ok() {
- return Err(UIDCError::Abort("Database already initialized, not overwriting!"));
- }
- log::info!("Initializing!");
- let db = microrm::DB::new(
- schema::schema(),
- &self.db,
- microrm::CreateMode::AllowNewDatabase,
- )
- .expect("Unable to initialize database!");
- // create primary realm
- db.query_interface()
- .add(&schema::Realm {
- shortname: "primary".to_string(),
- })?;
- Ok(())
- }
- }
- #[derive(Debug, Subcommand)]
- enum KeyCommand {
- Inspect,
- Generate,
- }
- #[derive(Debug, Parser)]
- struct KeyArgs {
- #[clap(subcommand)]
- command: KeyCommand,
- }
- impl KeyArgs {
- async fn run(&self, args: RunArgs) -> Result<(), UIDCError> {
- match &self.command {
- KeyCommand::Inspect => {
- key::inspect(&args.db, args.realm_id)
- }
- KeyCommand::Generate => {
- key::generate(&args.db, args.realm_id)
- }
- }
- }
- }
- #[derive(Debug, Subcommand)]
- enum ClientCommand {
- Create { name: String },
- List,
- Inspect { name: String },
- }
- #[derive(Debug, Parser)]
- struct ClientArgs {
- #[clap(subcommand)]
- command: ClientCommand,
- }
- impl ClientArgs {
- async fn run(&self, args: RunArgs) -> Result<(), UIDCError> {
- match &self.command {
- ClientCommand::Create { name } => {
- client_management::create(&args.db, args.realm_id, name)
- }
- ClientCommand::List => { todo!() }
- ClientCommand::Inspect { name } => {
- client_management::inspect(&args.db, args.realm_id, name)
- }
- }
- }
- }
- #[derive(Debug, Subcommand)]
- enum ConfigCommand {
- Dump,
- Load { toml_path: String },
- Set { key: String, value: String },
- }
- #[derive(Debug, Parser)]
- struct ConfigArgs {
- #[clap(subcommand)]
- command: ConfigCommand,
- }
- impl ConfigArgs {
- async fn run(&self, args: RunArgs) -> Result<(), UIDCError> {
- let qi = args.db.query_interface();
- match &self.command {
- ConfigCommand::Dump => {
- let config = config::Config::build_from(&qi, None);
- println!("config: {:?}", config);
- }
- ConfigCommand::Set { key, value } => {
- todo!()
- }
- ConfigCommand::Load { toml_path } => {
- let config = config::Config::build_from(&qi, Some(toml_path));
- config.save(&qi);
- }
- }
- Ok(())
- }
- }
- #[derive(Debug, Subcommand)]
- enum GroupCommand {
- Create { group_name: String },
- Members { group_name: String },
- AttachRole { group_name: String, role_name: String },
- DetachRole { group_name: String, role_name: String },
- AttachUser { group_name: String, username: String },
- DetachUser { group_name: String, username: String },
- }
- #[derive(Debug, Parser)]
- struct GroupArgs {
- #[clap(subcommand)]
- command: GroupCommand,
- }
- impl GroupArgs {
- async fn run(&self, args: RunArgs) -> Result<(), UIDCError> {
- let qi = args.db.query_interface();
- match &self.command {
- GroupCommand::Create { group_name } => {
- group_management::create_group(&qi, args.realm_id, group_name)?;
- },
- GroupCommand::Members { group_name } => {
- group_management::list_members(&qi, args.realm_id, group_name.as_str())?;
- },
- GroupCommand::AttachRole { group_name, role_name } => {
- group_management::attach_role(&qi, args.realm_id, group_name.as_str(), role_name.as_str())?;
- },
- GroupCommand::DetachRole { group_name, role_name } => {
- group_management::detach_role(&qi, args.realm_id, group_name.as_str(), role_name.as_str())?;
- },
- GroupCommand::AttachUser { group_name, username } => {
- group_management::attach_user(&qi, args.realm_id, group_name.as_str(), username.as_str())?;
- },
- GroupCommand::DetachUser { group_name, username } => {
- group_management::detach_user(&qi, args.realm_id, group_name.as_str(), username.as_str())?;
- }
- }
- Ok(())
- }
- }
- #[derive(Debug, Parser)]
- struct ServerArgs {
- #[clap(short, long)]
- port: Option<u16>,
- }
- impl ServerArgs {
- async fn run(&self, args: RunArgs) -> Result<(), UIDCError> {
- let config = config::Config::build_from(&args.db.query_interface(), None);
- server::run_server(args.db, config, self.port.unwrap_or(2114)).await
- }
- }
- #[derive(Debug, Subcommand)]
- enum TokenCommand {
- GenerateAuth {
- #[clap(short, long)]
- client: String,
- #[clap(short, long)]
- username: String,
- #[clap(short, long)]
- scopes: String,
- },
- GenerateRefresh {
- #[clap(short, long)]
- client: String,
- #[clap(short, long)]
- username: String,
- #[clap(short, long)]
- scopes: String,
- },
- Inspect {
- token: String,
- },
- }
- #[derive(Debug, Parser)]
- struct TokenArgs {
- #[clap(subcommand)]
- command: TokenCommand,
- }
- impl TokenArgs {
- async fn run(&self, args: RunArgs) -> Result<(), UIDCError> {
- let config = config::Config::build_from(&args.db.query_interface(), None);
- let qi = args.db.query_interface();
- match &self.command {
- TokenCommand::GenerateAuth {
- client,
- username,
- scopes,
- } => {
- let token = token_management::create_auth_token(&qi, &config, args.realm_id, client.as_str(), username.as_str(), scopes.as_str())?;
- println!("{}", token);
- Ok(())
- }
- TokenCommand::GenerateRefresh {
- client,
- username,
- scopes,
- } => { todo!() }
- TokenCommand::Inspect { token } => { todo!() }
- }
- }
- }
- #[derive(Debug, Subcommand)]
- enum RoleCommand {
- List,
- Create { name: String },
- Delete { name: String },
- }
- #[derive(Debug, Parser)]
- struct RoleArgs {
- #[clap(subcommand)]
- command: RoleCommand,
- }
- impl RoleArgs {
- async fn run(&self, args: RunArgs) -> Result<(), UIDCError> {
- let qi = args.db.query_interface();
- // let config = config::Config::build_from(&qi, None);
- match &self.command {
- RoleCommand::List => {
- todo!()
- },
- RoleCommand::Create { name } => {
- let add_result = qi.add(&schema::Role {
- realm: args.realm_id,
- shortname: name.clone()
- });
- match add_result {
- Ok(_role_id) => {
- println!("Added role {}", name);
- }
- Err(_) => {
- println!("Failed to add role {}!", name);
- },
- }
- },
- RoleCommand::Delete { name } => {
- qi.delete().by(schema::Role::Realm, &args.realm_id).by(schema::Role::Shortname, name.as_str()).exec().unwrap();
- },
- }
- Ok(())
- }
- }
- #[derive(Debug, Subcommand)]
- enum UserCommand {
- List,
- Create {
- username: String
- },
- Auth {
- username: String,
- #[clap(short = 'p', long, parse(from_occurrences))]
- change_password: usize,
- },
- Inspect {
- username: String,
- }
- }
- #[derive(Debug, Parser)]
- struct UserArgs {
- #[clap(subcommand)]
- command: UserCommand,
- }
- impl UserArgs {
- async fn run(&self, args: RunArgs) -> Result<(), UIDCError> {
- let qi = args.db.query_interface();
- match &self.command {
- UserCommand::List => user_management::list(&qi, args.realm_id),
- UserCommand::Create { username } => {
- user_management::create(&qi, args.realm_id, username.as_str())
- }
- UserCommand::Auth { username, change_password } => user_management::change_auth(
- &qi,
- args.realm_id,
- username.as_str(),
- *change_password > 0,
- ),
- UserCommand::Inspect { username } => user_management::inspect(&qi, args.realm_id, username.as_str()),
- }
- }
- }
- pub fn invoked() {
- let args = RootArgs::parse();
- match smol::block_on(args.run()) {
- Ok(_) => (),
- Err(e) => {
- log::error!("Error occured while running command: {}", e);
- }
- }
- }
|