Windows build fixes and test coverage (#2220)

* adding testing for users functions
* turning KanidmClient build error into a ClientError
* removing a redundant closure
This commit is contained in:
James Hodgkinson 2023-10-17 18:18:07 +11:00 committed by GitHub
parent fced4c485c
commit 6850a17e8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 914 additions and 688 deletions

20
Cargo.lock generated
View file

@ -1565,6 +1565,12 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.27" version = "1.0.27"
@ -2979,6 +2985,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"shellexpand", "shellexpand",
"sketching",
"time", "time",
"tokio", "tokio",
"tracing", "tracing",
@ -3173,6 +3180,8 @@ dependencies = [
"lazy_static", "lazy_static",
"oauth2", "oauth2",
"openssl", "openssl",
"petgraph",
"regex",
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_json",
@ -4071,6 +4080,17 @@ dependencies = [
"ucd-trie", "ucd-trie",
] ]
[[package]]
name = "petgraph"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
dependencies = [
"fixedbitset",
"indexmap 2.0.2",
"serde",
]
[[package]] [[package]]
name = "picky-asn1" name = "picky-asn1"
version = "0.8.0" version = "0.8.0"

View file

@ -108,10 +108,10 @@ impl Display for KanidmClientBuilder {
#[test] #[test]
fn test_kanidmclientbuilder_display() { fn test_kanidmclientbuilder_display() {
let foo = KanidmClientBuilder::default(); let foo = KanidmClientBuilder::default();
println!("{}", foo.to_string()); println!("{}", foo);
assert!(foo.to_string().contains("verify_ca")); assert!(foo.to_string().contains("verify_ca"));
let foo = KanidmClientBuilder { let testclient = KanidmClientBuilder {
address: Some("https://example.com".to_string()), address: Some("https://example.com".to_string()),
verify_ca: true, verify_ca: true,
verify_hostnames: true, verify_hostnames: true,
@ -119,13 +119,13 @@ fn test_kanidmclientbuilder_display() {
connect_timeout: Some(420), connect_timeout: Some(420),
use_system_proxies: true, use_system_proxies: true,
}; };
println!("foo {}", foo.to_string()); println!("foo {}", testclient);
assert!(foo.to_string().contains("verify_ca: true")); assert!(testclient.to_string().contains("verify_ca: true"));
assert!(foo.to_string().contains("verify_hostnames: true")); assert!(testclient.to_string().contains("verify_hostnames: true"));
let badness = foo.danger_accept_invalid_hostnames(true); let badness = testclient.danger_accept_invalid_hostnames(true);
let badness = badness.danger_accept_invalid_certs(true); let badness = badness.danger_accept_invalid_certs(true);
println!("badness: {}", badness.to_string()); println!("badness: {}", badness);
assert!(badness.to_string().contains("verify_ca: false")); assert!(badness.to_string().contains("verify_ca: false"));
assert!(badness.to_string().contains("verify_hostnames: false")); assert!(badness.to_string().contains("verify_hostnames: false"));
} }
@ -415,13 +415,15 @@ impl KanidmClientBuilder {
*/ */
/// Build the client ready for usage. /// Build the client ready for usage.
pub fn build(self) -> Result<KanidmClient, reqwest::Error> { pub fn build(self) -> Result<KanidmClient, ClientError> {
// Errghh, how to handle this cleaner. // Errghh, how to handle this cleaner.
let address = match &self.address { let address = match &self.address {
Some(a) => a.clone(), Some(a) => a.clone(),
None => { None => {
error!("Configuration option 'uri' missing from client configuration, cannot continue client startup without specifying a server to connect to. 🤔"); error!("Configuration option 'uri' missing from client configuration, cannot continue client startup without specifying a server to connect to. 🤔");
std::process::exit(1); return Err(ClientError::ConfigParseIssue(
"Configuration option 'uri' missing from client configuration, cannot continue client startup without specifying a server to connect to. 🤔".to_string(),
));
} }
}; };
@ -449,7 +451,7 @@ impl KanidmClientBuilder {
None => client_builder, None => client_builder,
}; };
let client = client_builder.build()?; let client = client_builder.build().map_err(ClientError::Transport)?;
// Now get the origin. // Now get the origin.
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]
@ -544,7 +546,7 @@ impl KanidmClient {
(*tguard).as_ref().cloned() (*tguard).as_ref().cloned()
} }
pub fn new_session(&self) -> Result<Self, reqwest::Error> { pub fn new_session(&self) -> Result<Self, ClientError> {
// Copy our builder, and then just process it. // Copy our builder, and then just process it.
let builder = self.builder.clone(); let builder = self.builder.clone();
builder.build() builder.build()

View file

@ -84,7 +84,14 @@ impl From<OpenSSLErrorStack> for CryptoError {
fn from(ossl_err: OpenSSLErrorStack) -> Self { fn from(ossl_err: OpenSSLErrorStack) -> Self {
error!(?ossl_err); error!(?ossl_err);
let code = ossl_err.errors().get(0).map(|e| e.code()).unwrap_or(0); let code = ossl_err.errors().get(0).map(|e| e.code()).unwrap_or(0);
CryptoError::OpenSSL(code) #[cfg(not(target_family="windows"))]
let result = CryptoError::OpenSSL(code);
// this is an .into() because on windows it's a u32 not a u64
#[cfg(target_family="windows")]
let result = CryptoError::OpenSSL(code.into());
result
} }
} }

View file

@ -1,6 +1,5 @@
// #[cfg(target_os = "windows")] use core::fmt;
// use std::os::windows::fs::MetadataExt; use std::{path::Path, fs::Metadata};
/// Check a given file's metadata is read-only for the current user (true = read-only) Stub function if you're building for windows! /// Check a given file's metadata is read-only for the current user (true = read-only) Stub function if you're building for windows!
pub fn readonly(meta: &Metadata) -> bool { pub fn readonly(meta: &Metadata) -> bool {
eprintln!( eprintln!(

View file

@ -1,59 +1,4 @@
use libc::passwd as c_passwd; #[cfg(target_family = "unix")]
use libc::{gid_t, uid_t}; pub mod unix;
use std::ffi::{CStr, OsStr, OsString}; #[cfg(target_family = "unix")]
use std::os::unix::ffi::OsStrExt; pub use unix::*;
use std::{mem, ptr};
pub fn get_current_uid() -> uid_t {
unsafe { libc::getuid() }
}
pub fn get_effective_uid() -> uid_t {
unsafe { libc::geteuid() }
}
pub fn get_current_gid() -> gid_t {
unsafe { libc::getgid() }
}
pub fn get_effective_gid() -> gid_t {
unsafe { libc::getegid() }
}
pub fn get_user_name_by_uid(uid: uid_t) -> Option<OsString> {
let mut passwd = unsafe { mem::zeroed::<c_passwd>() };
let mut buf = vec![0; 2048];
let mut result = ptr::null_mut::<c_passwd>();
#[cfg(feature = "logging")]
trace!("Running getpwuid_r for user #{}", uid);
loop {
let r =
unsafe { libc::getpwuid_r(uid, &mut passwd, buf.as_mut_ptr(), buf.len(), &mut result) };
if r != libc::ERANGE {
break;
}
let newsize = buf.len().checked_mul(2)?;
buf.resize(newsize, 0);
}
if result.is_null() {
// There is no such user, or an error has occurred.
// errno gets set if theres an error.
return None;
}
if result != &mut passwd {
// The result of getpwuid_r should be its input passwd.
return None;
}
let name = unsafe {
OsStr::from_bytes(CStr::from_ptr(result.read().pw_name).to_bytes()).to_os_string()
};
Some(name)
}

72
libs/users/src/unix.rs Normal file
View file

@ -0,0 +1,72 @@
use libc::passwd as c_passwd;
use libc::{gid_t, uid_t};
use std::ffi::{CStr, OsStr, OsString};
use std::os::unix::ffi::OsStrExt;
use std::{mem, ptr};
pub fn get_current_uid() -> uid_t {
unsafe { libc::getuid() }
}
pub fn get_effective_uid() -> uid_t {
unsafe { libc::geteuid() }
}
pub fn get_current_gid() -> gid_t {
unsafe { libc::getgid() }
}
pub fn get_effective_gid() -> gid_t {
unsafe { libc::getegid() }
}
pub fn get_user_name_by_uid(uid: uid_t) -> Option<OsString> {
let mut passwd = unsafe { mem::zeroed::<c_passwd>() };
let mut buf = vec![0; 2048];
let mut result = ptr::null_mut::<c_passwd>();
#[cfg(feature = "logging")]
trace!("Running getpwuid_r for user #{}", uid);
loop {
let r =
unsafe { libc::getpwuid_r(uid, &mut passwd, buf.as_mut_ptr(), buf.len(), &mut result) };
if r != libc::ERANGE {
break;
}
let newsize = buf.len().checked_mul(2)?;
buf.resize(newsize, 0);
}
if result.is_null() {
// There is no such user, or an error has occurred.
// errno gets set if theres an error.
return None;
}
if result != &mut passwd {
// The result of getpwuid_r should be its input passwd.
return None;
}
let name = unsafe {
OsStr::from_bytes(CStr::from_ptr(result.read().pw_name).to_bytes()).to_os_string()
};
Some(name)
}
#[test]
/// just testing these literally don't panic
fn test_get_effective_uid() {
let euid = get_effective_uid();
assert!(euid > 0);
let egid = get_effective_gid();
assert!(egid > 0);
let username = get_user_name_by_uid(get_current_uid());
assert!(username.is_some());
}

View file

@ -1,3 +1,5 @@
# Release checklist
## Pre-Reqs ## Pre-Reqs
```bash ```bash
@ -65,7 +67,7 @@ cargo install cargo-udeps
- [ ] docker buildx use cluster - [ ] docker buildx use cluster
- [ ] `make buildx/kanidmd/x86_64_v3 buildx/kanidmd buildx/kanidm_tools buildx/radiusd` - [ ] `make buildx/kanidmd/x86_64_v3 buildx/kanidmd buildx/kanidm_tools buildx/radiusd`
- [ ] `IMAGE_VERSION=latest make buildx/kanidmd/x86_64_v3 buildx/kanidmd buildx/kanidm_tools buildx/radiusd` - [ ] `IMAGE_VERSION=latest make buildx/kanidmd/x86_64_v3 buildx/kanidmd buildx/kanidm_tools buildx/radiusd`
- [ ] Update the readme on docker https://hub.docker.com/repository/docker/kanidm/server - [ ] Update the readme on docker <https://hub.docker.com/repository/docker/kanidm/server>
### Distro ### Distro

View file

@ -405,6 +405,7 @@ pub enum DbValueAccessScopeV1 {
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[allow(clippy::enum_variant_names)]
pub enum DbValueIdentityId { pub enum DbValueIdentityId {
#[serde(rename = "v1i")] #[serde(rename = "v1i")]
V1Internal, V1Internal,

View file

@ -1,5 +1,5 @@
//! Constant Entries for the IDM //! Constant Entries for the IDM
use crate::prelude::AttrString; use crate::prelude::{idm_builtin_admin_groups, AttrString};
use enum_iterator::Sequence; use enum_iterator::Sequence;
use std::fmt::Display; use std::fmt::Display;
@ -9,7 +9,7 @@ use crate::idm::account::Account;
use crate::value::PartialValue; use crate::value::PartialValue;
use crate::value::Value; use crate::value::Value;
use kanidm_proto::constants::*; use kanidm_proto::constants::*;
use kanidm_proto::v1::{AccountType, Filter, OperationError, UiHint}; use kanidm_proto::v1::{AccountType, OperationError};
#[cfg(test)] #[cfg(test)]
use uuid::uuid; use uuid::uuid;
@ -685,67 +685,6 @@ impl EntryClass {
} }
} }
#[derive(Clone, Debug, Default)]
/// Built-in group definitions
pub struct BuiltinGroup {
pub name: &'static str,
description: &'static str,
uuid: uuid::Uuid,
members: Vec<uuid::Uuid>,
dyngroup: bool,
dyngroup_filter: Option<Filter>,
extra_attributes: Vec<(Attribute, Value)>,
}
impl TryFrom<BuiltinGroup> for EntryInitNew {
type Error = OperationError;
fn try_from(val: BuiltinGroup) -> Result<Self, OperationError> {
let mut entry = EntryInitNew::new();
entry.add_ava(Attribute::Name, Value::new_iname(val.name));
entry.add_ava(Attribute::Description, Value::new_utf8s(val.description));
// classes for groups
entry.set_ava(
Attribute::Class,
vec![EntryClass::Group.into(), EntryClass::Object.into()],
);
if val.dyngroup {
if !val.members.is_empty() {
return Err(OperationError::InvalidSchemaState(format!(
"Builtin dyngroup {} has members specified, this is not allowed",
val.name
)));
}
entry.add_ava(Attribute::Class, EntryClass::DynGroup.to_value());
match val.dyngroup_filter {
Some(filter) => entry.add_ava(Attribute::DynGroupFilter, Value::JsonFilt(filter)),
None => {
error!(
"No filter specified for dyngroup '{}' this is going to break things!",
val.name
);
return Err(OperationError::FilterGeneration);
}
};
}
entry.add_ava(Attribute::Uuid, Value::Uuid(val.uuid));
entry.set_ava(
Attribute::Member,
val.members
.into_iter()
.map(Value::Refer)
.collect::<Vec<Value>>(),
);
// add any extra attributes
val.extra_attributes
.into_iter()
.for_each(|(attr, val)| entry.add_ava(attr, val));
// all done!
Ok(entry)
}
}
lazy_static! { lazy_static! {
/// Builtin System Admin account. /// Builtin System Admin account.
pub static ref BUILTIN_ACCOUNT_IDM_ADMIN: BuiltinAccount = BuiltinAccount { pub static ref BUILTIN_ACCOUNT_IDM_ADMIN: BuiltinAccount = BuiltinAccount {
@ -756,449 +695,6 @@ lazy_static! {
displayname: "IDM Administrator", displayname: "IDM Administrator",
}; };
/// Builtin IDM Administrators Group.
pub static ref BUILTIN_GROUP_IDM_ADMINS_V1: BuiltinGroup = BuiltinGroup {
name: "idm_admins",
description: "Builtin IDM Administrators Group.",
uuid: UUID_IDM_ADMINS,
members: vec![UUID_IDM_ADMIN],
..Default::default()
};
pub static ref BUILTIN_GROUP_SYSTEM_ADMINS_V1: BuiltinGroup = BuiltinGroup {
name: "system_admins",
description: "Builtin System Administrators Group.",
uuid: UUID_SYSTEM_ADMINS,
members: vec![BUILTIN_ACCOUNT_ADMIN.uuid],
..Default::default()
};
// * People read managers
/// Builtin IDM Group for granting elevated people (personal data) read permissions.
pub static ref IDM_PEOPLE_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_read_priv",
description: "Builtin IDM Group for granting elevated people (personal data) read permissions.",
uuid: UUID_IDM_PEOPLE_READ_PRIV,
members: vec![UUID_IDM_PEOPLE_WRITE_PRIV],
..Default::default()
};
pub static ref IDM_PEOPLE_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_write_priv",
description: "Builtin IDM Group for granting elevated people (personal data) write permissions.",
uuid: UUID_IDM_PEOPLE_WRITE_PRIV,
members: vec![UUID_IDM_PEOPLE_MANAGE_PRIV,UUID_IDM_PEOPLE_EXTEND_PRIV],
..Default::default()
};
// * People write managers
/// Builtin IDM Group for granting elevated people (personal data) write and lifecycle management permissions.
pub static ref IDM_PEOPLE_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_manage_priv",
description: "Builtin IDM Group for granting elevated people (personal data) write and lifecycle management permissions.",
uuid: UUID_IDM_PEOPLE_MANAGE_PRIV,
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
/// Builtin IDM Group for importing passwords to person accounts - intended for service account membership only.
pub static ref IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_account_password_import_priv",
description: "Builtin IDM Group for importing passwords to person accounts - intended for service account membership only.",
uuid: UUID_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV,
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
/// Builtin IDM Group for allowing the ability to extend accounts to have the "person" flag set.
pub static ref IDM_PEOPLE_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_extend_priv",
description: "Builtin System Administrators Group.",
uuid: UUID_IDM_PEOPLE_EXTEND_PRIV,
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
/// Self-write of mail
pub static ref IDM_PEOPLE_SELF_WRITE_MAIL_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_self_write_mail_priv",
description: "Builtin IDM Group for people accounts to update their own mail.",
uuid: UUID_IDM_PEOPLE_SELF_WRITE_MAIL_PRIV,
members: Vec::new(),
..Default::default()
};
/// Builtin IDM Group for granting elevated high privilege people (personal data) read permissions.
pub static ref IDM_HP_PEOPLE_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_people_read_priv",
description: "Builtin IDM Group for granting elevated high privilege people (personal data) read permissions.",
uuid: UUID_IDM_HP_PEOPLE_READ_PRIV,
members: vec![UUID_IDM_HP_PEOPLE_WRITE_PRIV],
..Default::default()
};
/// Builtin IDM Group for granting elevated high privilege people (personal data) write permissions.
pub static ref IDM_HP_PEOPLE_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_people_write_priv",
description: "Builtin IDM Group for granting elevated high privilege people (personal data) write permissions.",
uuid: UUID_IDM_HP_PEOPLE_WRITE_PRIV,
members: vec![UUID_IDM_HP_PEOPLE_EXTEND_PRIV],
..Default::default()
};
/// Builtin IDM Group for extending high privilege accounts to be people.
pub static ref IDM_HP_PEOPLE_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_people_extend_priv",
description: "Builtin IDM Group for extending high privilege accounts to be people.",
uuid: UUID_IDM_HP_PEOPLE_EXTEND_PRIV,
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
// * group write manager (no read, everyone has read via the anon, etc)
/// Builtin IDM Group for granting elevated group write and lifecycle permissions.
pub static ref IDM_GROUP_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_manage_priv",
description: "Builtin IDM Group for granting elevated group write and lifecycle permissions.",
uuid: UUID_IDM_GROUP_MANAGE_PRIV,
members: vec![
BUILTIN_GROUP_IDM_ADMINS_V1.uuid,
BUILTIN_GROUP_SYSTEM_ADMINS_V1.uuid,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated group write and lifecycle permissions.
pub static ref IDM_GROUP_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_write_priv",
description: "Builtin IDM Group for granting elevated group write permissions.",
uuid: UUID_IDM_GROUP_WRITE_PRIV,
members: vec![
UUID_IDM_GROUP_MANAGE_PRIV
],
..Default::default()
};
/// Builtin IDM Group for granting unix group extension permissions.
pub static ref IDM_GROUP_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_unix_extend_priv",
description: "Builtin IDM Group for granting UNIX group extension permissions.",
uuid: UUID_IDM_GROUP_UNIX_EXTEND_PRIV,
members: vec![
UUID_IDM_ADMINS
],
..Default::default()
};
/// Account read manager
pub static ref IDM_ACCOUNT_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_read_priv",
description: "Builtin IDM Group for granting elevated account read permissions.",
uuid: UUID_IDM_ACCOUNT_READ_PRIV,
members: vec![
UUID_IDM_ACCOUNT_WRITE_PRIV,
],
..Default::default()
};
pub static ref IDM_ACCOUNT_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_manage_priv",
description: "Builtin IDM Group for granting elevated account write and lifecycle permissions.",
uuid: UUID_IDM_ACCOUNT_MANAGE_PRIV,
members: vec![
UUID_IDM_ADMINS,
],
..Default::default()
};
pub static ref IDM_ACCOUNT_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_write_priv",
description: "Builtin IDM Group for granting elevated account write permissions.",
uuid: UUID_IDM_ACCOUNT_WRITE_PRIV,
members: vec![
UUID_IDM_ACCOUNT_MANAGE_PRIV,
],
..Default::default()
};
pub static ref IDM_ACCOUNT_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_unix_extend_priv",
description: "Builtin IDM Group for granting account unix extend permissions.",
uuid: UUID_IDM_ACCOUNT_UNIX_EXTEND_PRIV,
members: vec![
UUID_IDM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for RADIUS secret write for all non-hp accounts.
pub static ref IDM_RADIUS_SECRET_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_radius_secret_write_priv",
description: "Builtin IDM Group for RADIUS secret write for all non-hp accounts.",
uuid: UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
members: vec![
UUID_IDM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for RADIUS secret reading for all non-hp accounts.
pub static ref IDM_RADIUS_SECRET_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_radius_secret_read_priv",
description: "Builtin IDM Group for RADIUS secret reading for all non-hp accounts.",
uuid: UUID_IDM_RADIUS_SECRET_READ_PRIV_V1,
members: vec![
UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
],
..Default::default()
};
/// Builtin IDM Group for RADIUS server access delegation.
pub static ref IDM_RADIUS_SERVERS_V1: BuiltinGroup = BuiltinGroup {
name: "idm_radius_servers",
description: "Builtin IDM Group for RADIUS server access delegation.",
uuid: UUID_IDM_RADIUS_SERVERS,
members: vec![
],
..Default::default()
};
/// High privilege account read manager
pub static ref IDM_HP_ACCOUNT_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_read_priv",
description: "Builtin IDM Group for granting elevated account read permissions over high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_READ_PRIV,
members: vec![
UUID_IDM_HP_ACCOUNT_WRITE_PRIV
],
..Default::default()
};
/// Builtin IDM Group for granting elevated account write permissions over high privilege accounts.
pub static ref IDM_HP_ACCOUNT_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_manage_priv",
description: "Builtin IDM Group for granting elevated account write and lifecycle permissions over high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated account write permissions over high privilege accounts.
pub static ref IDM_HP_ACCOUNT_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_write_priv",
description: "Builtin IDM Group for granting elevated account write permissions over high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_WRITE_PRIV,
members: vec![
UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
],
..Default::default()
};
/// Builtin IDM Group for granting account unix extend permissions for high privilege accounts.
pub static ref IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_unix_extend_priv",
description: "Builtin IDM Group for granting account UNIX extend permissions for high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// * Schema write manager
pub static ref IDM_SCHEMA_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_schema_manage_priv",
description: "Builtin IDM Group for granting elevated schema write and management permissions.",
uuid: UUID_IDM_SCHEMA_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// ACP read/write manager
pub static ref IDM_ACP_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_acp_manage_priv",
description: "Builtin IDM Group for granting control over all access control profile modifications.",
uuid: UUID_IDM_ACP_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated group write and lifecycle privileges for high privilege groups.
pub static ref IDM_HP_GROUP_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_group_manage_priv",
description: "Builtin IDM Group for granting elevated group write and lifecycle privileges for high privilege groups.",
uuid: UUID_IDM_HP_GROUP_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated group write privileges for high privilege groups.
pub static ref IDM_HP_GROUP_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_group_write_priv",
description: "Builtin IDM Group for granting elevated group write privileges for high privilege groups.",
uuid: UUID_IDM_HP_GROUP_WRITE_PRIV,
members: vec![
UUID_IDM_HP_GROUP_MANAGE_PRIV,
],
..Default::default()
};
}
// at some point vs code just gives up on syntax highlighting inside lazy_static...
lazy_static! {
/// Builtin IDM Group for granting unix group extension permissions for high privilege groups.
pub static ref IDM_HP_GROUP_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_group_unix_extend_priv",
description: "Builtin IDM Group for granting unix group extension permissions for high privilege groups.",
uuid: UUID_IDM_HP_GROUP_UNIX_EXTEND_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting local domain administration rights and trust administration rights
pub static ref DOMAIN_ADMINS: BuiltinGroup = BuiltinGroup {
name: "domain_admins",
description: "Builtin IDM Group for granting local domain administration rights and trust administration rights.",
uuid: UUID_DOMAIN_ADMINS,
members: vec![
UUID_ADMIN,
],
..Default::default()
};
/// Builtin IDM Group for managing oauth2 resource server integrations to this authentication domain.
pub static ref IDM_HP_OAUTH2_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_oauth2_manage_priv",
description: "Builtin IDM Group for managing oauth2 resource server integrations to this authentication domain.",
uuid: UUID_IDM_HP_OAUTH2_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for allowing migrations of service accounts into persons
pub static ref IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV: BuiltinGroup = BuiltinGroup {
name: "idm_hp_service_account_into_person_migrate_priv",
description:"Builtin IDM Group for allowing migrations of service accounts into persons",
uuid: UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for allowing migrations of service accounts into persons
pub static ref IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV: BuiltinGroup = BuiltinGroup {
name: "idm_hp_sync_account_manage_priv",
description: "Builtin IDM Group for managing synchronisation from external identity sources",
uuid: UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for extending high privilege accounts to be people.
pub static ref IDM_ALL_PERSONS: BuiltinGroup = BuiltinGroup {
name: "idm_all_persons",
description: "Builtin IDM Group for extending high privilege accounts to be people.",
uuid: UUID_IDM_ALL_PERSONS,
members: Vec::new(),
dyngroup: true,
dyngroup_filter: Some(
Filter::And(vec![
Filter::Eq(Attribute::Class.to_string(), EntryClass::Person.to_string()),
Filter::Eq(Attribute::Class.to_string(), EntryClass::Account.to_string()),
])
),
..Default::default()
};
/// Builtin IDM Group for extending high privilege accounts to be people.
pub static ref IDM_ALL_ACCOUNTS: BuiltinGroup = BuiltinGroup {
name: "idm_all_accounts",
description: "Builtin IDM dynamic group containing all entries that can authenticate.",
uuid: UUID_IDM_ALL_ACCOUNTS,
members: Vec::new(),
dyngroup: true,
dyngroup_filter: Some(
Filter::Eq(Attribute::Class.to_string(), EntryClass::Account.to_string()),
),
..Default::default()
};
pub static ref IDM_UI_ENABLE_EXPERIMENTAL_FEATURES: BuiltinGroup = BuiltinGroup {
name: "idm_ui_enable_experimental_features",
description: "Members of this group will have access to experimental web UI features.",
uuid: UUID_IDM_UI_ENABLE_EXPERIMENTAL_FEATURES,
extra_attributes: vec![
(Attribute::GrantUiHint, Value::UiHint(UiHint::ExperimentalFeatures))
],
..Default::default()
};
/// Members of this group will have access to read the mail attribute of all persons and service accounts.
pub static ref IDM_ACCOUNT_MAIL_READ_PRIV: BuiltinGroup = BuiltinGroup {
name: "idm_account_mail_read_priv",
description: "Members of this group will have access to read the mail attribute of all persons and service accounts.",
uuid: UUID_IDM_ACCOUNT_MAIL_READ_PRIV,
..Default::default()
};
/// This must be the last group to init to include the UUID of the other high priv groups.
pub static ref IDM_HIGH_PRIVILEGE_V1: BuiltinGroup = BuiltinGroup {
name: "idm_high_privilege",
uuid: UUID_IDM_HIGH_PRIVILEGE,
description: "Builtin IDM provided groups with high levels of access that should be audited and limited in modification.",
members: vec![
UUID_IDM_ADMINS,
UUID_IDM_PEOPLE_READ_PRIV,
UUID_IDM_PEOPLE_WRITE_PRIV,
UUID_IDM_GROUP_WRITE_PRIV,
UUID_IDM_ACCOUNT_READ_PRIV,
UUID_IDM_ACCOUNT_WRITE_PRIV,
UUID_IDM_RADIUS_SERVERS,
UUID_IDM_HP_ACCOUNT_READ_PRIV,
UUID_IDM_HP_ACCOUNT_WRITE_PRIV,
UUID_IDM_SCHEMA_MANAGE_PRIV,
UUID_IDM_ACP_MANAGE_PRIV,
UUID_IDM_HP_GROUP_WRITE_PRIV,
UUID_IDM_PEOPLE_MANAGE_PRIV,
UUID_IDM_ACCOUNT_MANAGE_PRIV,
UUID_IDM_GROUP_MANAGE_PRIV,
UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
UUID_IDM_HP_GROUP_MANAGE_PRIV,
UUID_SYSTEM_ADMINS,
UUID_DOMAIN_ADMINS,
UUID_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV,
UUID_IDM_PEOPLE_EXTEND_PRIV,
UUID_IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV,
UUID_IDM_HP_GROUP_UNIX_EXTEND_PRIV,
UUID_IDM_HP_OAUTH2_MANAGE_PRIV,
UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
UUID_IDM_RADIUS_SECRET_READ_PRIV_V1,
UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
UUID_IDM_HIGH_PRIVILEGE,
],
dyngroup: false,
dyngroup_filter: None,
extra_attributes: Vec::new(),
};
pub static ref E_SYSTEM_INFO_V1: EntryInitNew = entry_init!( pub static ref E_SYSTEM_INFO_V1: EntryInitNew = entry_init!(
(Attribute::Class, EntryClass::Object.to_value()), (Attribute::Class, EntryClass::Object.to_value()),
(Attribute::Class, EntryClass::SystemInfo.to_value()), (Attribute::Class, EntryClass::SystemInfo.to_value()),
@ -1305,31 +801,21 @@ lazy_static! {
}; };
} }
pub fn builtin_accounts() -> Vec<&'static BuiltinAccount> {
vec![
&BUILTIN_ACCOUNT_ANONYMOUS_V1,
&BUILTIN_ACCOUNT_ADMIN,
&BUILTIN_ACCOUNT_IDM_ADMIN,
]
}
// ============ TEST DATA ============ // ============ TEST DATA ============
#[cfg(test)] #[cfg(test)]
pub const UUID_TESTPERSON_1: Uuid = uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930"); pub const UUID_TESTPERSON_1: Uuid = uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930");
#[cfg(test)]
pub const JSON_TESTPERSON1: &str = r#"{
"attrs": {
"class": ["object"],
"name": ["testperson1"],
"uuid": ["cc8e95b4-c24f-4d68-ba54-8bed76f63930"]
}
}"#;
#[cfg(test)] #[cfg(test)]
pub const UUID_TESTPERSON_2: Uuid = uuid!("538faac7-4d29-473b-a59d-23023ac19955"); pub const UUID_TESTPERSON_2: Uuid = uuid!("538faac7-4d29-473b-a59d-23023ac19955");
#[cfg(test)]
pub const JSON_TESTPERSON2: &str = r#"{
"attrs": {
"class": ["object"],
"name": ["testperson2"],
"uuid": ["538faac7-4d29-473b-a59d-23023ac19955"]
}
}"#;
#[cfg(test)] #[cfg(test)]
lazy_static! { lazy_static! {
pub static ref E_TESTPERSON_1: EntryInitNew = entry_init!( pub static ref E_TESTPERSON_1: EntryInitNew = entry_init!(
@ -1343,3 +829,17 @@ lazy_static! {
(Attribute::Uuid, Value::Uuid(UUID_TESTPERSON_2)) (Attribute::Uuid, Value::Uuid(UUID_TESTPERSON_2))
); );
} }
/// Build a list of internal admin entries
pub fn idm_builtin_admin_entries() -> Result<Vec<EntryInitNew>, OperationError> {
let mut res: Vec<EntryInitNew> = vec![
BUILTIN_ACCOUNT_ANONYMOUS_V1.clone().into(),
BUILTIN_ACCOUNT_ADMIN.clone().into(),
BUILTIN_ACCOUNT_IDM_ADMIN.clone().into(),
];
for group in idm_builtin_admin_groups() {
let g: EntryInitNew = group.clone().try_into()?;
res.push(g);
}
Ok(res)
}

View file

@ -0,0 +1,566 @@
use crate::entry::EntryInitNew;
use crate::prelude::*;
use kanidm_proto::v1::{Filter, OperationError, UiHint};
#[derive(Clone, Debug, Default)]
/// Built-in group definitions
pub struct BuiltinGroup {
pub name: &'static str,
pub description: &'static str,
pub uuid: uuid::Uuid,
pub members: Vec<uuid::Uuid>,
pub dyngroup: bool,
pub dyngroup_filter: Option<Filter>,
pub extra_attributes: Vec<(Attribute, Value)>,
}
impl TryFrom<BuiltinGroup> for EntryInitNew {
type Error = OperationError;
fn try_from(val: BuiltinGroup) -> Result<Self, OperationError> {
let mut entry = EntryInitNew::new();
entry.add_ava(Attribute::Name, Value::new_iname(val.name));
entry.add_ava(Attribute::Description, Value::new_utf8s(val.description));
// classes for groups
entry.set_ava(
Attribute::Class,
vec![EntryClass::Group.into(), EntryClass::Object.into()],
);
if val.dyngroup {
if !val.members.is_empty() {
return Err(OperationError::InvalidSchemaState(format!(
"Builtin dyngroup {} has members specified, this is not allowed",
val.name
)));
}
entry.add_ava(Attribute::Class, EntryClass::DynGroup.to_value());
match val.dyngroup_filter {
Some(filter) => entry.add_ava(Attribute::DynGroupFilter, Value::JsonFilt(filter)),
None => {
error!(
"No filter specified for dyngroup '{}' this is going to break things!",
val.name
);
return Err(OperationError::FilterGeneration);
}
};
}
entry.add_ava(Attribute::Uuid, Value::Uuid(val.uuid));
entry.set_ava(
Attribute::Member,
val.members
.into_iter()
.map(Value::Refer)
.collect::<Vec<Value>>(),
);
// add any extra attributes
val.extra_attributes
.into_iter()
.for_each(|(attr, val)| entry.add_ava(attr, val));
// all done!
Ok(entry)
}
}
lazy_static! {
/// Builtin IDM Administrators Group.
pub static ref BUILTIN_GROUP_IDM_ADMINS_V1: BuiltinGroup = BuiltinGroup {
name: "idm_admins",
description: "Builtin IDM Administrators Group.",
uuid: UUID_IDM_ADMINS,
members: vec![UUID_IDM_ADMIN],
..Default::default()
};
pub static ref BUILTIN_GROUP_SYSTEM_ADMINS_V1: BuiltinGroup = BuiltinGroup {
name: "system_admins",
description: "Builtin System Administrators Group.",
uuid: UUID_SYSTEM_ADMINS,
members: vec![BUILTIN_ACCOUNT_ADMIN.uuid],
..Default::default()
};
// * People read managers
/// Builtin IDM Group for granting elevated people (personal data) read permissions.
pub static ref IDM_PEOPLE_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_read_priv",
description: "Builtin IDM Group for granting elevated people (personal data) read permissions.",
uuid: UUID_IDM_PEOPLE_READ_PRIV,
members: vec![UUID_IDM_PEOPLE_WRITE_PRIV],
..Default::default()
};
pub static ref IDM_PEOPLE_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_write_priv",
description: "Builtin IDM Group for granting elevated people (personal data) write permissions.",
uuid: UUID_IDM_PEOPLE_WRITE_PRIV,
members: vec![UUID_IDM_PEOPLE_MANAGE_PRIV,UUID_IDM_PEOPLE_EXTEND_PRIV],
..Default::default()
};
// * People write managers
/// Builtin IDM Group for granting elevated people (personal data) write and lifecycle management permissions.
pub static ref IDM_PEOPLE_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_manage_priv",
description: "Builtin IDM Group for granting elevated people (personal data) write and lifecycle management permissions.",
uuid: UUID_IDM_PEOPLE_MANAGE_PRIV,
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
/// Builtin IDM Group for importing passwords to person accounts - intended for service account membership only.
pub static ref IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_account_password_import_priv",
description: "Builtin IDM Group for importing passwords to person accounts - intended for service account membership only.",
uuid: UUID_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV,
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
/// Builtin IDM Group for allowing the ability to extend accounts to have the "person" flag set.
pub static ref IDM_PEOPLE_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_extend_priv",
description: "Builtin System Administrators Group.",
uuid: UUID_IDM_PEOPLE_EXTEND_PRIV,
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
/// Self-write of mail
pub static ref IDM_PEOPLE_SELF_WRITE_MAIL_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_self_write_mail_priv",
description: "Builtin IDM Group for people accounts to update their own mail.",
uuid: UUID_IDM_PEOPLE_SELF_WRITE_MAIL_PRIV,
members: Vec::new(),
..Default::default()
};
/// Builtin IDM Group for granting elevated high privilege people (personal data) read permissions.
pub static ref IDM_HP_PEOPLE_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_people_read_priv",
description: "Builtin IDM Group for granting elevated high privilege people (personal data) read permissions.",
uuid: UUID_IDM_HP_PEOPLE_READ_PRIV,
members: vec![UUID_IDM_HP_PEOPLE_WRITE_PRIV],
..Default::default()
};
/// Builtin IDM Group for granting elevated high privilege people (personal data) write permissions.
pub static ref IDM_HP_PEOPLE_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_people_write_priv",
description: "Builtin IDM Group for granting elevated high privilege people (personal data) write permissions.",
uuid: UUID_IDM_HP_PEOPLE_WRITE_PRIV,
members: vec![UUID_IDM_HP_PEOPLE_EXTEND_PRIV],
..Default::default()
};
/// Builtin IDM Group for extending high privilege accounts to be people.
pub static ref IDM_HP_PEOPLE_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_people_extend_priv",
description: "Builtin IDM Group for extending high privilege accounts to be people.",
uuid: UUID_IDM_HP_PEOPLE_EXTEND_PRIV,
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
// * group write manager (no read, everyone has read via the anon, etc)
/// Builtin IDM Group for granting elevated group write and lifecycle permissions.
pub static ref IDM_GROUP_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_manage_priv",
description: "Builtin IDM Group for granting elevated group write and lifecycle permissions.",
uuid: UUID_IDM_GROUP_MANAGE_PRIV,
members: vec![
BUILTIN_GROUP_IDM_ADMINS_V1.uuid,
BUILTIN_GROUP_SYSTEM_ADMINS_V1.uuid,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated group write and lifecycle permissions.
pub static ref IDM_GROUP_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_write_priv",
description: "Builtin IDM Group for granting elevated group write permissions.",
uuid: UUID_IDM_GROUP_WRITE_PRIV,
members: vec![
UUID_IDM_GROUP_MANAGE_PRIV
],
..Default::default()
};
/// Builtin IDM Group for granting unix group extension permissions.
pub static ref IDM_GROUP_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_unix_extend_priv",
description: "Builtin IDM Group for granting UNIX group extension permissions.",
uuid: UUID_IDM_GROUP_UNIX_EXTEND_PRIV,
members: vec![
UUID_IDM_ADMINS
],
..Default::default()
};
/// Account read manager
pub static ref IDM_ACCOUNT_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_read_priv",
description: "Builtin IDM Group for granting elevated account read permissions.",
uuid: UUID_IDM_ACCOUNT_READ_PRIV,
members: vec![
UUID_IDM_ACCOUNT_WRITE_PRIV,
],
..Default::default()
};
pub static ref IDM_ACCOUNT_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_manage_priv",
description: "Builtin IDM Group for granting elevated account write and lifecycle permissions.",
uuid: UUID_IDM_ACCOUNT_MANAGE_PRIV,
members: vec![
UUID_IDM_ADMINS,
],
..Default::default()
};
pub static ref IDM_ACCOUNT_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_write_priv",
description: "Builtin IDM Group for granting elevated account write permissions.",
uuid: UUID_IDM_ACCOUNT_WRITE_PRIV,
members: vec![
UUID_IDM_ACCOUNT_MANAGE_PRIV,
],
..Default::default()
};
pub static ref IDM_ACCOUNT_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_unix_extend_priv",
description: "Builtin IDM Group for granting account unix extend permissions.",
uuid: UUID_IDM_ACCOUNT_UNIX_EXTEND_PRIV,
members: vec![
UUID_IDM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for RADIUS secret write for all non-hp accounts.
pub static ref IDM_RADIUS_SECRET_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_radius_secret_write_priv",
description: "Builtin IDM Group for RADIUS secret write for all non-hp accounts.",
uuid: UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
members: vec![
UUID_IDM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for RADIUS secret reading for all non-hp accounts.
pub static ref IDM_RADIUS_SECRET_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_radius_secret_read_priv",
description: "Builtin IDM Group for RADIUS secret reading for all non-hp accounts.",
uuid: UUID_IDM_RADIUS_SECRET_READ_PRIV_V1,
members: vec![
UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
],
..Default::default()
};
/// Builtin IDM Group for RADIUS server access delegation.
pub static ref IDM_RADIUS_SERVERS_V1: BuiltinGroup = BuiltinGroup {
name: "idm_radius_servers",
description: "Builtin IDM Group for RADIUS server access delegation.",
uuid: UUID_IDM_RADIUS_SERVERS,
members: vec![
],
..Default::default()
};
/// High privilege account read manager
pub static ref IDM_HP_ACCOUNT_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_read_priv",
description: "Builtin IDM Group for granting elevated account read permissions over high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_READ_PRIV,
members: vec![
UUID_IDM_HP_ACCOUNT_WRITE_PRIV
],
..Default::default()
};
/// Builtin IDM Group for granting elevated account write permissions over high privilege accounts.
pub static ref IDM_HP_ACCOUNT_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_manage_priv",
description: "Builtin IDM Group for granting elevated account write and lifecycle permissions over high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated account write permissions over high privilege accounts.
pub static ref IDM_HP_ACCOUNT_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_write_priv",
description: "Builtin IDM Group for granting elevated account write permissions over high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_WRITE_PRIV,
members: vec![
UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
],
..Default::default()
};
/// Builtin IDM Group for granting account unix extend permissions for high privilege accounts.
pub static ref IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_unix_extend_priv",
description: "Builtin IDM Group for granting account UNIX extend permissions for high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// * Schema write manager
pub static ref IDM_SCHEMA_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_schema_manage_priv",
description: "Builtin IDM Group for granting elevated schema write and management permissions.",
uuid: UUID_IDM_SCHEMA_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// ACP read/write manager
pub static ref IDM_ACP_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_acp_manage_priv",
description: "Builtin IDM Group for granting control over all access control profile modifications.",
uuid: UUID_IDM_ACP_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated group write and lifecycle privileges for high privilege groups.
pub static ref IDM_HP_GROUP_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_group_manage_priv",
description: "Builtin IDM Group for granting elevated group write and lifecycle privileges for high privilege groups.",
uuid: UUID_IDM_HP_GROUP_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated group write privileges for high privilege groups.
pub static ref IDM_HP_GROUP_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_group_write_priv",
description: "Builtin IDM Group for granting elevated group write privileges for high privilege groups.",
uuid: UUID_IDM_HP_GROUP_WRITE_PRIV,
members: vec![
UUID_IDM_HP_GROUP_MANAGE_PRIV,
],
..Default::default()
};
}
// at some point vs code just gives up on syntax highlighting inside lazy_static...
lazy_static! {
/// Builtin IDM Group for granting unix group extension permissions for high privilege groups.
pub static ref IDM_HP_GROUP_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_group_unix_extend_priv",
description: "Builtin IDM Group for granting unix group extension permissions for high privilege groups.",
uuid: UUID_IDM_HP_GROUP_UNIX_EXTEND_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting local domain administration rights and trust administration rights
pub static ref DOMAIN_ADMINS: BuiltinGroup = BuiltinGroup {
name: "domain_admins",
description: "Builtin IDM Group for granting local domain administration rights and trust administration rights.",
uuid: UUID_DOMAIN_ADMINS,
members: vec![
UUID_ADMIN,
],
..Default::default()
};
/// Builtin IDM Group for managing oauth2 resource server integrations to this authentication domain.
pub static ref IDM_HP_OAUTH2_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_oauth2_manage_priv",
description: "Builtin IDM Group for managing oauth2 resource server integrations to this authentication domain.",
uuid: UUID_IDM_HP_OAUTH2_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for allowing migrations of service accounts into persons
pub static ref IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV: BuiltinGroup = BuiltinGroup {
name: "idm_hp_service_account_into_person_migrate_priv",
description:"Builtin IDM Group for allowing migrations of service accounts into persons",
uuid: UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for allowing migrations of service accounts into persons
pub static ref IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV: BuiltinGroup = BuiltinGroup {
name: "idm_hp_sync_account_manage_priv",
description: "Builtin IDM Group for managing synchronisation from external identity sources",
uuid: UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for extending high privilege accounts to be people.
pub static ref IDM_ALL_PERSONS: BuiltinGroup = BuiltinGroup {
name: "idm_all_persons",
description: "Builtin IDM Group for extending high privilege accounts to be people.",
uuid: UUID_IDM_ALL_PERSONS,
members: Vec::new(),
dyngroup: true,
dyngroup_filter: Some(
Filter::And(vec![
Filter::Eq(Attribute::Class.to_string(), EntryClass::Person.to_string()),
Filter::Eq(Attribute::Class.to_string(), EntryClass::Account.to_string()),
])
),
..Default::default()
};
/// Builtin IDM Group for extending high privilege accounts to be people.
pub static ref IDM_ALL_ACCOUNTS: BuiltinGroup = BuiltinGroup {
name: "idm_all_accounts",
description: "Builtin IDM dynamic group containing all entries that can authenticate.",
uuid: UUID_IDM_ALL_ACCOUNTS,
members: Vec::new(),
dyngroup: true,
dyngroup_filter: Some(
Filter::Eq(Attribute::Class.to_string(), EntryClass::Account.to_string()),
),
..Default::default()
};
pub static ref IDM_UI_ENABLE_EXPERIMENTAL_FEATURES: BuiltinGroup = BuiltinGroup {
name: "idm_ui_enable_experimental_features",
description: "Members of this group will have access to experimental web UI features.",
uuid: UUID_IDM_UI_ENABLE_EXPERIMENTAL_FEATURES,
extra_attributes: vec![
(Attribute::GrantUiHint, Value::UiHint(UiHint::ExperimentalFeatures))
],
..Default::default()
};
/// Members of this group will have access to read the mail attribute of all persons and service accounts.
pub static ref IDM_ACCOUNT_MAIL_READ_PRIV: BuiltinGroup = BuiltinGroup {
name: "idm_account_mail_read_priv",
description: "Members of this group will have access to read the mail attribute of all persons and service accounts.",
uuid: UUID_IDM_ACCOUNT_MAIL_READ_PRIV,
..Default::default()
};
/// This must be the last group to init to include the UUID of the other high priv groups.
pub static ref IDM_HIGH_PRIVILEGE_V1: BuiltinGroup = BuiltinGroup {
name: "idm_high_privilege",
uuid: UUID_IDM_HIGH_PRIVILEGE,
description: "Builtin IDM provided groups with high levels of access that should be audited and limited in modification.",
members: vec![
UUID_IDM_ADMINS,
UUID_IDM_PEOPLE_READ_PRIV,
UUID_IDM_PEOPLE_WRITE_PRIV,
UUID_IDM_GROUP_WRITE_PRIV,
UUID_IDM_ACCOUNT_READ_PRIV,
UUID_IDM_ACCOUNT_WRITE_PRIV,
UUID_IDM_RADIUS_SERVERS,
UUID_IDM_HP_ACCOUNT_READ_PRIV,
UUID_IDM_HP_ACCOUNT_WRITE_PRIV,
UUID_IDM_SCHEMA_MANAGE_PRIV,
UUID_IDM_ACP_MANAGE_PRIV,
UUID_IDM_HP_GROUP_WRITE_PRIV,
UUID_IDM_PEOPLE_MANAGE_PRIV,
UUID_IDM_ACCOUNT_MANAGE_PRIV,
UUID_IDM_GROUP_MANAGE_PRIV,
UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
UUID_IDM_HP_GROUP_MANAGE_PRIV,
UUID_SYSTEM_ADMINS,
UUID_DOMAIN_ADMINS,
UUID_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV,
UUID_IDM_PEOPLE_EXTEND_PRIV,
UUID_IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV,
UUID_IDM_HP_GROUP_UNIX_EXTEND_PRIV,
UUID_IDM_HP_OAUTH2_MANAGE_PRIV,
UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
UUID_IDM_RADIUS_SECRET_READ_PRIV_V1,
UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
UUID_IDM_HIGH_PRIVILEGE,
],
dyngroup: false,
dyngroup_filter: None,
extra_attributes: Vec::new(),
};
}
/// Make a list of all the non-admin BuiltinGroup's that are created by default, doing it in a standard-ish way so we can use it for testing and stuff
pub fn idm_builtin_non_admin_groups() -> Vec<&'static BuiltinGroup> {
// Create any system default schema entries.
vec![
&IDM_ALL_PERSONS,
&IDM_ALL_ACCOUNTS,
&IDM_PEOPLE_MANAGE_PRIV_V1,
&IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1,
&IDM_PEOPLE_EXTEND_PRIV_V1,
&IDM_PEOPLE_SELF_WRITE_MAIL_PRIV_V1,
&IDM_PEOPLE_WRITE_PRIV_V1,
&IDM_PEOPLE_READ_PRIV_V1,
&IDM_HP_PEOPLE_EXTEND_PRIV_V1,
&IDM_HP_PEOPLE_WRITE_PRIV_V1,
&IDM_HP_PEOPLE_READ_PRIV_V1,
&IDM_GROUP_MANAGE_PRIV_V1,
&IDM_GROUP_WRITE_PRIV_V1,
&IDM_GROUP_UNIX_EXTEND_PRIV_V1,
&IDM_ACCOUNT_MANAGE_PRIV_V1,
&IDM_ACCOUNT_WRITE_PRIV_V1,
&IDM_ACCOUNT_UNIX_EXTEND_PRIV_V1,
&IDM_ACCOUNT_READ_PRIV_V1,
&IDM_RADIUS_SECRET_WRITE_PRIV_V1,
&IDM_RADIUS_SECRET_READ_PRIV_V1,
&IDM_RADIUS_SERVERS_V1,
// Write deps on read, so write must be added first.
&IDM_HP_ACCOUNT_MANAGE_PRIV_V1,
&IDM_HP_ACCOUNT_WRITE_PRIV_V1,
&IDM_HP_ACCOUNT_READ_PRIV_V1,
&IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV_V1,
&IDM_SCHEMA_MANAGE_PRIV_V1,
&IDM_HP_GROUP_MANAGE_PRIV_V1,
&IDM_HP_GROUP_WRITE_PRIV_V1,
&IDM_HP_GROUP_UNIX_EXTEND_PRIV_V1,
&IDM_ACP_MANAGE_PRIV_V1,
&DOMAIN_ADMINS,
&IDM_HP_OAUTH2_MANAGE_PRIV_V1,
&IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
&IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
// All members must exist before we write HP
&IDM_HIGH_PRIVILEGE_V1,
// other things
&IDM_UI_ENABLE_EXPERIMENTAL_FEATURES,
&IDM_ACCOUNT_MAIL_READ_PRIV,
]
}
pub fn idm_builtin_admin_groups() -> Vec<&'static BuiltinGroup> {
vec![
&BUILTIN_GROUP_SYSTEM_ADMINS_V1,
&BUILTIN_GROUP_IDM_ADMINS_V1,
]
}

View file

@ -2,6 +2,7 @@
pub mod acp; pub mod acp;
pub mod entries; pub mod entries;
pub mod groups;
pub mod schema; pub mod schema;
pub mod system_config; pub mod system_config;
pub mod uuids; pub mod uuids;
@ -9,6 +10,7 @@ pub mod values;
pub use crate::constants::acp::*; pub use crate::constants::acp::*;
pub use crate::constants::entries::*; pub use crate::constants::entries::*;
pub use crate::constants::groups::*;
pub use crate::constants::schema::*; pub use crate::constants::schema::*;
pub use crate::constants::system_config::*; pub use crate::constants::system_config::*;
pub use crate::constants::uuids::*; pub use crate::constants::uuids::*;

View file

@ -351,6 +351,7 @@ impl Entry<EntryInit, EntryNew> {
} }
#[cfg(test)] #[cfg(test)]
// TODO: #[deprecated(note = "Use entry_init! macro instead or like... anything else")]
pub(crate) fn unsafe_from_entry_str(es: &str) -> Self { pub(crate) fn unsafe_from_entry_str(es: &str) -> Self {
// Just use log directly here, it's testing // Just use log directly here, it's testing
// str -> proto entry // str -> proto entry

View file

@ -2358,8 +2358,7 @@ mod tests {
let admin = Identity::from_impersonate_entry_readwrite(E_TEST_ACCOUNT_1.clone()); let admin = Identity::from_impersonate_entry_readwrite(E_TEST_ACCOUNT_1.clone());
let e1: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(JSON_TESTPERSON1); let ev1 = E_TESTPERSON_1.clone().into_sealed_committed();
let ev1 = e1.into_sealed_committed();
let r_set = vec![Arc::new(ev1)]; let r_set = vec![Arc::new(ev1)];
@ -2398,8 +2397,7 @@ mod tests {
let admin = Identity::from_impersonate_entry_readwrite(E_TEST_ACCOUNT_1.clone()); let admin = Identity::from_impersonate_entry_readwrite(E_TEST_ACCOUNT_1.clone());
let e1: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(JSON_TESTPERSON1); let ev1 = E_TESTPERSON_1.clone().into_sealed_committed();
let ev1 = e1.into_sealed_committed();
let r_set = vec![Arc::new(ev1)]; let r_set = vec![Arc::new(ev1)];

View file

@ -615,13 +615,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
// Check the admin object exists (migrations). // Check the admin object exists (migrations).
// Create the default idm_admin group. // Create the default idm_admin group.
let admin_entries: Vec<EntryInitNew> = vec![ let admin_entries: Vec<EntryInitNew> = idm_builtin_admin_entries()?;
BUILTIN_ACCOUNT_ANONYMOUS_V1.clone().into(),
BUILTIN_ACCOUNT_ADMIN.clone().into(),
BUILTIN_ACCOUNT_IDM_ADMIN.clone().into(),
BUILTIN_GROUP_IDM_ADMINS_V1.clone().try_into()?,
BUILTIN_GROUP_SYSTEM_ADMINS_V1.clone().try_into()?,
];
let res: Result<(), _> = admin_entries let res: Result<(), _> = admin_entries
.into_iter() .into_iter()
// Each item individually logs it's result // Each item individually logs it's result
@ -632,49 +626,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
debug_assert!(res.is_ok()); debug_assert!(res.is_ok());
res?; res?;
// Create any system default schema entries. let idm_entries = idm_builtin_non_admin_groups();
let idm_entries: Vec<&BuiltinGroup> = vec![
&IDM_ALL_PERSONS,
&IDM_ALL_ACCOUNTS,
&IDM_PEOPLE_MANAGE_PRIV_V1,
&IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1,
&IDM_PEOPLE_EXTEND_PRIV_V1,
&IDM_PEOPLE_SELF_WRITE_MAIL_PRIV_V1,
&IDM_PEOPLE_WRITE_PRIV_V1,
&IDM_PEOPLE_READ_PRIV_V1,
&IDM_HP_PEOPLE_EXTEND_PRIV_V1,
&IDM_HP_PEOPLE_WRITE_PRIV_V1,
&IDM_HP_PEOPLE_READ_PRIV_V1,
&IDM_GROUP_MANAGE_PRIV_V1,
&IDM_GROUP_WRITE_PRIV_V1,
&IDM_GROUP_UNIX_EXTEND_PRIV_V1,
&IDM_ACCOUNT_MANAGE_PRIV_V1,
&IDM_ACCOUNT_WRITE_PRIV_V1,
&IDM_ACCOUNT_UNIX_EXTEND_PRIV_V1,
&IDM_ACCOUNT_READ_PRIV_V1,
&IDM_RADIUS_SECRET_WRITE_PRIV_V1,
&IDM_RADIUS_SECRET_READ_PRIV_V1,
&IDM_RADIUS_SERVERS_V1,
// Write deps on read, so write must be added first.
&IDM_HP_ACCOUNT_MANAGE_PRIV_V1,
&IDM_HP_ACCOUNT_WRITE_PRIV_V1,
&IDM_HP_ACCOUNT_READ_PRIV_V1,
&IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV_V1,
&IDM_SCHEMA_MANAGE_PRIV_V1,
&IDM_HP_GROUP_MANAGE_PRIV_V1,
&IDM_HP_GROUP_WRITE_PRIV_V1,
&IDM_HP_GROUP_UNIX_EXTEND_PRIV_V1,
&IDM_ACP_MANAGE_PRIV_V1,
&DOMAIN_ADMINS,
&IDM_HP_OAUTH2_MANAGE_PRIV_V1,
&IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
&IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
// All members must exist before we write HP
&IDM_HIGH_PRIVILEGE_V1,
// other things
&IDM_UI_ENABLE_EXPERIMENTAL_FEATURES,
&IDM_ACCOUNT_MAIL_READ_PRIV,
];
let res: Result<(), _> = idm_entries let res: Result<(), _> = idm_entries
.into_iter() .into_iter()

View file

@ -1138,9 +1138,9 @@ impl<'a> QueryServerTransaction<'a> for QueryServerWriteTransaction<'a> {
impl QueryServer { impl QueryServer {
pub fn new(be: Backend, schema: Schema, domain_name: String) -> Result<Self, OperationError> { pub fn new(be: Backend, schema: Schema, domain_name: String) -> Result<Self, OperationError> {
let (s_uuid, d_uuid) = { let (s_uuid, d_uuid) = {
let mut wr = be.write().unwrap(); let mut wr = be.write()?;
let s_uuid = wr.get_db_s_uuid().unwrap(); let s_uuid = wr.get_db_s_uuid()?;
let d_uuid = wr.get_db_d_uuid().unwrap(); let d_uuid = wr.get_db_d_uuid()?;
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]
wr.commit() wr.commit()
.expect("Critical - unable to commit db_s_uuid or db_d_uuid"); .expect("Critical - unable to commit db_s_uuid or db_d_uuid");

View file

@ -39,6 +39,8 @@ tracing = { workspace = true, features = ["attributes"] }
tokio = { workspace = true, features = ["net", "sync", "io-util", "macros"] } tokio = { workspace = true, features = ["net", "sync", "io-util", "macros"] }
openssl = { workspace = true } openssl = { workspace = true }
lazy_static = { workspace = true } lazy_static = { workspace = true }
petgraph = { version = "0.6.4", features = ["serde"] }
regex.workspace = true
[build-dependencies] [build-dependencies]

View file

@ -0,0 +1,119 @@
//! I'm working towards making this a proper enumeration/discovery toolkit for access things in Kanidm.
//!
//! - @yaleman
//!
use std::collections::{BTreeSet, HashMap};
// use kanidm_client::KanidmClient;
use kanidmd_lib::constants::entries::Attribute;
use kanidmd_lib::constants::groups::{idm_builtin_admin_groups, idm_builtin_non_admin_groups};
use kanidmd_lib::prelude::{builtin_accounts, EntryInitNew};
use petgraph::graphmap::GraphMap;
use uuid::Uuid;
async fn enumerate_default_groups(/*_client: KanidmClient*/) {
let mut uuidmap: HashMap<Uuid, EntryInitNew> = HashMap::new();
let mut graph = GraphMap::<Uuid, (), petgraph::Undirected>::new();
builtin_accounts().into_iter().for_each(|account| {
// println!("adding builtin {}", account.uuid);
uuidmap.insert(account.uuid, account.clone().try_into().unwrap());
graph.add_node(account.uuid);
});
idm_builtin_non_admin_groups()
.into_iter()
.for_each(|group| {
uuidmap.insert(group.uuid, group.clone().try_into().unwrap());
graph.add_node(group.uuid);
group.members.iter().for_each(|member| {
graph.add_edge(*member, group.uuid, ());
});
});
idm_builtin_admin_groups().into_iter().for_each(|group| {
uuidmap.insert(group.uuid, group.clone().try_into().unwrap());
graph.add_node(group.uuid);
group.members.iter().for_each(|member| {
graph.add_edge(*member, group.uuid, ());
});
});
// // println!("{}", mermaidchart);
// let mut dotgraph = format!("{:?}", Dot::with_config(&graph, &[Config::EdgeNoLabel]));
// // regex to extract uuids
// // let re = regex::Regex::new(r"(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})").unwrap();
// for (uuid, uuid_value) in uuidmap.clone() {
// let uuid_str = uuid.to_string();
// if dotgraph.contains(&uuid_str) {
// // println!("uuid {} not found in graph", uuid_str);
// let name = uuid_value.get_ava_single(Attribute::Name).unwrap();
// dotgraph = dotgraph.replace(&uuid_str, name.as_string().unwrap());
// }
// }
// // println!("{}", dotgraph);
#[derive(Debug)]
enum EntryType {
Person(String),
ServiceAccount(String),
Group(String),
UnknownType(String),
}
impl EntryType {
fn as_mermaid_tag(&self) -> String {
match self {
EntryType::Person(name) => format!("{}(\"Person:{}\")", name, name),
EntryType::ServiceAccount(name) => format!("{}{{\"SA: {}\"}}", name, name),
EntryType::Group(name) => format!("{}[\"Group: {}\"]", name, name),
EntryType::UnknownType(name) => format!("{}[\"Unknown Type {}\"]", name, name),
}
}
}
impl From<EntryInitNew> for EntryType {
fn from(entry: EntryInitNew) -> Self {
let name = entry.get_ava_single(Attribute::Name).unwrap();
let name = name.as_string().unwrap();
let classes = entry
.get_ava_set(Attribute::Class)
.unwrap()
.as_iutf8_set()
.cloned()
.unwrap_or(BTreeSet::<String>::new());
if classes.contains("group") {
EntryType::Group(name.clone())
} else if classes.contains("service_account") {
EntryType::ServiceAccount(name.clone())
} else if classes.contains("person") {
EntryType::Person(name.clone())
} else {
EntryType::UnknownType(name.clone())
}
}
}
println!("graph RL;");
for (left, right, _weight) in graph.all_edges() {
let left = uuidmap.get(&left).unwrap();
// let left_name = left.get_ava_single(Attribute::Name).unwrap();
let right = uuidmap.get(&right).unwrap();
// let right_name = right.get_ava_single(Attribute::Name).unwrap();
println!(
" {} --> {}",
EntryType::from(left.clone()).as_mermaid_tag(),
EntryType::from(right.clone()).as_mermaid_tag(),
);
}
}
#[tokio::main]
async fn main() {
enumerate_default_groups().await;
}

View file

@ -3,7 +3,6 @@ name = "kanidm_tools"
default-run = "kanidm" default-run = "kanidm"
description = "Kanidm Client Tools" description = "Kanidm Client Tools"
documentation = "https://kanidm.github.io/kanidm/stable/" documentation = "https://kanidm.github.io/kanidm/stable/"
version = { workspace = true } version = { workspace = true }
authors = { workspace = true } authors = { workspace = true }
rust-version = { workspace = true } rust-version = { workspace = true }
@ -52,7 +51,8 @@ url = { workspace = true, features = ["serde"] }
uuid = { workspace = true } uuid = { workspace = true }
zxcvbn = { workspace = true } zxcvbn = { workspace = true }
lazy_static.workspace = true lazy_static.workspace = true
regex.workspace = true regex = { workspace = true }
sketching = { workspace = true }
[dependencies.cursive] [dependencies.cursive]
version = "0.20.0" version = "0.20.0"

View file

@ -1,6 +1,6 @@
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[command(version)] #[command(version)]
struct SshAuthorizedOpt { pub(crate) struct SshAuthorizedOpt {
#[clap(short, long = "debug")] #[clap(short, long = "debug")]
debug: bool, debug: bool,
#[clap(short = 'H', long = "url")] #[clap(short = 'H', long = "url")]

View file

@ -11,23 +11,20 @@
use std::path::PathBuf; use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use kanidm_client::{ClientError, KanidmClientBuilder}; use kanidm_client::{ClientError, KanidmClient, KanidmClientBuilder};
use kanidm_proto::constants::{DEFAULT_CLIENT_CONFIG_PATH, DEFAULT_CLIENT_CONFIG_PATH_HOME}; use kanidm_proto::constants::{DEFAULT_CLIENT_CONFIG_PATH, DEFAULT_CLIENT_CONFIG_PATH_HOME};
use tracing::{debug, error}; use tracing::{debug, error};
include!("opt/ssh_authorizedkeys.rs"); include!("opt/ssh_authorizedkeys.rs");
// For now we lift a few things from the main.rs to use. pub(crate) fn build_configured_client(opt: &SshAuthorizedOpt) -> Result<KanidmClient, ()> {
//
// usage: AuthorizedKeysCommand /usr/sbin/kanidm_ssh_authorizedkeys %u -H URL -D anonymous -C /etc/kanidm/ca.pem
//
#[tokio::main(flavor = "current_thread")]
async fn main() {
let opt = SshAuthorizedOpt::parse();
if opt.debug { if opt.debug {
::std::env::set_var("RUST_LOG", "kanidm=debug,kanidm_client=debug"); ::std::env::set_var("RUST_LOG", "kanidm=debug,kanidm_client=debug");
} }
#[cfg(not(test))]
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
#[cfg(test)]
sketching::test_init();
let config_path: String = shellexpand::tilde(DEFAULT_CLIENT_CONFIG_PATH_HOME).into_owned(); let config_path: String = shellexpand::tilde(DEFAULT_CLIENT_CONFIG_PATH_HOME).into_owned();
debug!("Attempting to use config {}", DEFAULT_CLIENT_CONFIG_PATH); debug!("Attempting to use config {}", DEFAULT_CLIENT_CONFIG_PATH);
@ -37,10 +34,9 @@ async fn main() {
debug!("Attempting to use config {}", config_path); debug!("Attempting to use config {}", config_path);
cb.read_options_from_optional_config(config_path) cb.read_options_from_optional_config(config_path)
}) })
.unwrap_or_else(|e| { .map_err(|e| {
error!("Failed to parse config (if present) -- {:?}", e); error!("Failed to parse config (if present) -- {:?}", e);
std::process::exit(1); })?;
});
let client_builder = match &opt.addr { let client_builder = match &opt.addr {
Some(a) => client_builder.address(a.to_string()), Some(a) => client_builder.address(a.to_string()),
@ -51,25 +47,31 @@ async fn main() {
let client_builder = match ca_path { let client_builder = match ca_path {
Some(p) => client_builder Some(p) => client_builder
.add_root_certificate_filepath(p) .add_root_certificate_filepath(p)
.unwrap_or_else(|e| { .map_err(|e| {
error!("Failed to add ca certificate -- {:?}", e); error!("Failed to add ca certificate -- {:?}", e);
std::process::exit(1); })?,
}),
None => client_builder, None => client_builder,
}; };
let client = client_builder.build().unwrap_or_else(|e| { client_builder
error!("Failed to build client instance -- {:?}", e); .build()
std::process::exit(1); .map_err(|e| error!("Failed to build client instance -- {:?}", e))
}); }
// For now we lift a few things from the main.rs to use.
//
// usage: AuthorizedKeysCommand /usr/sbin/kanidm_ssh_authorizedkeys %u -H URL -D anonymous -C /etc/kanidm/ca.pem
//
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), ()> {
let opt: SshAuthorizedOpt = SshAuthorizedOpt::parse();
let client = build_configured_client(&opt)?;
let r = if opt.username == "anonymous" { let r = if opt.username == "anonymous" {
client.auth_anonymous().await client.auth_anonymous().await
} else { } else {
let password = rpassword::prompt_password("Enter password: ").unwrap_or_else(|e| { let password = rpassword::prompt_password("Enter password: ")
error!("Failed to retrieve password - {:?}", e); .map_err(|e| error!("Failed to retrieve password - {:?}", e))?;
std::process::exit(1);
});
client client
.auth_simple_password(opt.username.as_str(), password.as_str()) .auth_simple_password(opt.username.as_str(), password.as_str())
.await .await
@ -81,16 +83,52 @@ async fn main() {
} }
_ => error!("Error during authentication phase: {:?}", r), _ => error!("Error during authentication phase: {:?}", r),
} }
std::process::exit(1); return Err(());
} }
match client client
.idm_account_get_ssh_pubkeys(opt.account_id.as_str()) .idm_account_get_ssh_pubkeys(opt.account_id.as_str())
.await .await
{ .map(|pkeys| pkeys.iter().for_each(|pkey| println!("{}", pkey)))
Ok(pkeys) => pkeys.iter().for_each(|pkey| println!("{}", pkey)), .map_err(|e| {
Err(e) => { error!(
error!("Failed to retrieve pubkeys - {:?}", e); "Failed to retrieve SSH keys for {} - {:?}",
} opt.account_id.to_string(),
e
)
})
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use crate::build_configured_client;
use crate::SshAuthorizedOpt;
#[test]
fn test_build_configured_client() {
let opt = SshAuthorizedOpt {
debug: false,
addr: Some("https://example.com:8443".to_string()),
ca_path: None,
username: "anonymous".to_string(),
account_id: "anonymous".to_string(),
};
let client = build_configured_client(&opt);
assert!(client.is_ok());
}
#[test]
fn test_build_configured_client_err() {
let opt = SshAuthorizedOpt {
debug: false,
addr: None,
ca_path: Some(PathBuf::from("/etc/kanidm/ca.pem")),
username: "anonymous".to_string(),
account_id: "anonymous".to_string(),
};
let client = build_configured_client(&opt);
assert!(client.is_err())
} }
} }