Bläddra i källkod

Simple group management CLI.

Kestrel 1 år sedan
förälder
incheckning
ef856b990e
6 ändrade filer med 182 tillägg och 22 borttagningar
  1. 2 2
      Cargo.lock
  2. 1 1
      Cargo.toml
  3. 8 3
      simple-setup.sh
  4. 150 16
      src/cli.rs
  5. 0 0
      src/group_management.rs
  6. 21 0
      src/user_management.rs

+ 2 - 2
Cargo.lock

@@ -1127,9 +1127,9 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
 
 [[package]]
 name = "microrm"
-version = "0.3.9"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77e1852d8fdff46f6cc49503db265184449e42e0722cd9ceb9776ffc8894308f"
+checksum = "9f5c3363faceeeffb5d1bf44fc7448e3c3342999dd5f39aa1f27b34b752e4904"
 dependencies = [
  "base64 0.13.1",
  "lazy_static",

+ 1 - 1
Cargo.toml

@@ -21,7 +21,7 @@ base64 = { version = "0.13.0" }
 toml = "0.8.2"
 
 # Data storage dependencies
-microrm = { version = "0.3.9" }
+microrm = { version = "0.3.10" }
 serde_bytes = { version = "0.11.6" }
 
 # Public API/server dependencies

+ 8 - 3
simple-setup.sh

@@ -4,12 +4,17 @@ cargo build
 UAUTH=./target/debug/uauth2
 
 $UAUTH init
+$UAUTH config load /dev/stdin <<EOF
+base_url = "http://localhost:2114/"
+EOF
+
 $UAUTH cert generate
 $UAUTH client create testclient
 $UAUTH user create kestrel
 echo "please enter password for user 'kestrel'"
 $UAUTH user auth -p kestrel
 
-$UAUTH config load /dev/stdin <<EOF
-base_url = "http://localhost:2114/"
-EOF
+$UAUTH group create testgroup
+$UAUTH role create testrole
+$UAUTH group attach-role testgroup testrole
+$UAUTH group attach-user testgroup kestrel

+ 150 - 16
src/cli.rs

@@ -37,6 +37,8 @@ enum Command {
     Server(ServerArgs),
     /// manual token generation and inspection
     Token(TokenArgs),
+    /// role management
+    Role(RoleArgs),
     /// user management
     User(UserArgs),
 }
@@ -63,6 +65,7 @@ impl RootArgs {
             Command::Group(v) => v.run(&self, storage).await,
             Command::Server(v) => v.run(&self, storage).await,
             Command::Token(v) => v.run(&self, storage).await,
+            Command::Role(v) => v.run(&self, storage).await,
             Command::User(v) => v.run(&self, storage).await,
         }
     }
@@ -186,7 +189,14 @@ impl ConfigArgs {
 }
 
 #[derive(Debug, Subcommand)]
-enum GroupCommand {}
+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 {
@@ -195,7 +205,87 @@ struct GroupArgs {
 }
 
 impl GroupArgs {
-    async fn run(&self, root: &RootArgs, db: microrm::DB) {}
+    async fn run(&self, root: &RootArgs, db: microrm::DB) {
+        let qi = db.query_interface();
+        let realm_id = qi.get().by(schema::Realm::Shortname, root.realm.as_str()).one().unwrap().expect("no such realm").id();
+        match &self.command {
+            GroupCommand::Create { group_name } => {
+                match qi.add(&schema::Group {
+                    realm: realm_id,
+                    shortname: group_name.clone(),
+                }) {
+                    Ok(_) => {
+                        println!("Added group {}", group_name);
+                    },
+                    Err(e) => {
+                        println!("Failed to add group: {:?}", e);
+                    },
+                }
+            },
+            GroupCommand::Members { group_name } => {
+                todo!()
+            },
+            GroupCommand::AttachRole { group_name, role_name } => {
+                let group = qi.get().by(schema::Group::Realm, &realm_id).by(schema::Group::Shortname, group_name).one().unwrap();
+                let role = qi.get().by(schema::Role::Realm, &realm_id).by(schema::Role::Shortname, role_name).one().unwrap();
+
+                match (group, role) {
+                    (None, _) => {
+                        println!("No such group!");
+                    },
+                    (_, None) => {
+                        println!("No such role!");
+                    },
+                    (Some(group), Some(role)) => {
+                        match qi.add(&schema::GroupRole {
+                            group: group.id(),
+                            role: role.id(),
+                        }) {
+                            Ok(_) => {
+                                println!("Attached role {} to {}", role_name, group_name);
+                            },
+                            Err(e) => {
+                                println!("Failed to attach role: {:?}", e);
+                            }
+                        }
+                    },
+                }
+
+            },
+            GroupCommand::DetachRole { group_name, role_name } => {
+                
+            },
+            GroupCommand::AttachUser { group_name, username } => {
+                let group = qi.get().by(schema::Group::Realm, &realm_id).by(schema::Group::Shortname, group_name).one().unwrap();
+                let user = qi.get().by(schema::User::Realm, &realm_id).by(schema::User::Username, username).one().unwrap();
+
+                match (group, user) {
+                    (None, _) => {
+                        println!("No such group!");
+                    },
+                    (_, None) => {
+                        println!("No such user!");
+                    },
+                    (Some(group), Some(user)) => {
+                        match qi.add(&schema::GroupMembership {
+                            group: group.id(),
+                            user: user.id(),
+                        }) {
+                            Ok(_) => {
+                                println!("Attached user {} to {}", username, group_name);
+                            },
+                            Err(e) => {
+                                println!("Failed to attach user: {:?}", e);
+                            }
+                        }
+                    },
+                }
+            },
+            GroupCommand::DetachUser { group_name, username } => {
+                
+            }
+        }
+    }
 }
 
 #[derive(Debug, Parser)]
@@ -296,24 +386,67 @@ impl TokenArgs {
     }
 }
 
-#[derive(Debug, Parser)]
-struct CreateUserArgs {
-    username: String,
+#[derive(Debug, Subcommand)]
+enum RoleCommand {
+    List,
+    Create { name: String },
+    Delete { name: String },
 }
 
 #[derive(Debug, Parser)]
-struct AuthUserArgs {
-    username: String,
+struct RoleArgs {
+    #[clap(subcommand)]
+    command: RoleCommand,
+}
 
-    #[clap(short = 'p', long, parse(from_occurrences))]
-    change_password: usize,
+impl RoleArgs {
+    async fn run(&self, root: &RootArgs, db: microrm::DB) {
+        let config = config::Config::build_from(&db.query_interface(), None);
+        match &self.command {
+            RoleCommand::List => {
+                todo!()
+            },
+            RoleCommand::Create { name } => {
+                let qi = db.query_interface();
+                let realm = qi.get().by(schema::Realm::Shortname, &root.realm).one().unwrap().unwrap();
+                let add_result = qi.add(&schema::Role {
+                    realm: 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 } => {
+                let qi = db.query_interface();
+                let realm = qi.get().by(schema::Realm::Shortname, &root.realm).one().unwrap().unwrap();
+                qi.delete().by(schema::Role::Realm, &realm.id()).by(schema::Role::Shortname, name.as_str()).exec().unwrap();
+            },
+        }
+    }
 }
 
 #[derive(Debug, Subcommand)]
 enum UserCommand {
     List,
-    Create(CreateUserArgs),
-    Auth(AuthUserArgs),
+    Create {
+        username: String
+    },
+    Auth {
+        username: String,
+
+        #[clap(short = 'p', long, parse(from_occurrences))]
+        change_password: usize,
+    },
+    Inspect {
+        username: String,
+    }
 }
 
 #[derive(Debug, Parser)]
@@ -326,15 +459,16 @@ impl UserArgs {
     async fn run(&self, root: &RootArgs, db: microrm::DB) {
         match &self.command {
             UserCommand::List => user_management::list(&root.realm, db),
-            UserCommand::Create(args) => {
-                user_management::create(&root.realm, db, args.username.as_str())
+            UserCommand::Create { username } => {
+                user_management::create(&root.realm, db, username.as_str())
             }
-            UserCommand::Auth(args) => user_management::change_auth(
+            UserCommand::Auth { username, change_password } => user_management::change_auth(
                 &root.realm,
                 db,
-                args.username.as_str(),
-                args.change_password > 0,
+                username.as_str(),
+                *change_password > 0,
             ),
+            UserCommand::Inspect { username } => user_management::inspect(&root.realm, db, username.as_str()).expect("database error"),
         }
     }
 }

+ 0 - 0
src/group_management.rs


+ 21 - 0
src/user_management.rs

@@ -100,3 +100,24 @@ pub fn change_auth(realm: &str, db: microrm::DB, username: &str, change_password
         user.set_new_password(&qi, raw_pass.as_bytes());
     }
 }
+
+pub fn inspect(realm: &str, db: microrm::DB, username: &str) -> Result<(), microrm::Error> {
+    let qi = db.query_interface();
+
+    let realm = qi.get().by(schema::Realm::Shortname, realm).one()?.expect("no such realm");
+    let user = qi.get().by(schema::User::Realm, &realm.id()).by(schema::User::Username, username).one()?;
+
+    if let Some(user) = user {
+        println!("User found: {}", username);
+        println!("Groups:");
+        for group_membership in qi.get().by(schema::GroupMembership::User, &user.id()).all()? {
+            let group = qi.get().by_id(&group_membership.group).one()?.expect("reference to nonexistent group?");
+            println!(" - {}", group.shortname);
+        }
+    }
+    else {
+        println!("No such user {} in {} realm", username, realm.shortname);
+    }
+
+    Ok(())
+}