mirror of
https://github.com/kanidm/kanidm.git
synced 2025-05-22 17:03:55 +02:00
122 password import design (#196)
Implements #122 password import. This adds most of the server core framework to allow password imports from other sources, with new types easily able to be added in credential.rs.
This commit is contained in:
parent
8d8d5d02dd
commit
ceb6048bf0
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -441,6 +441,11 @@ name = "base64"
|
|||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.1"
|
||||
|
@ -1335,6 +1340,7 @@ dependencies = [
|
|||
"actix-files 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"actix-session 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"actix-web 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"concread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cookie 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3146,6 +3152,7 @@ dependencies = [
|
|||
"checksum backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
|
||||
"checksum backtrace-sys 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
|
||||
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
"checksum base64 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5ca2cd0adc3f48f9e9ea5a6bbdf9ccc0bfade884847e484d452414c7ccffb3"
|
||||
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
|
||||
"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
|
||||
"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
|
||||
|
|
89
designs/password-import.rst
Normal file
89
designs/password-import.rst
Normal file
|
@ -0,0 +1,89 @@
|
|||
Password Import
|
||||
---------------
|
||||
|
||||
It's common that an external system may want to synchronise passwords or other
|
||||
security material into a system like Kanidm. Two major examples is a once off
|
||||
import of data from a different identity system, and a setup where an external
|
||||
idm system feeds account, credentials and other data into the system.
|
||||
|
||||
Kanidm is already well placed to handle much of this due to the raw api's stateful
|
||||
nature (though as with anything could always be improved further as further use
|
||||
cases are developed, for example a stateful create-or-assert batch system).
|
||||
|
||||
One area that is lacking however is the ability to provide external password
|
||||
material to an account. This is a case where kanidm never sees the plaintext
|
||||
password, we are only sent a hash of the material.
|
||||
|
||||
Scenarioes
|
||||
----------
|
||||
|
||||
* Once off account import - this is where we are migrating from an existing system to kanidm
|
||||
* Long term password sync - this is where an external system will sync and provide password hashes into kanidm.
|
||||
|
||||
In the situation where the external system has access to the cleartext of the password, the
|
||||
standard password set mechanisms and apis can be used instead.
|
||||
|
||||
Possible Account Configurations
|
||||
-------------------------------
|
||||
|
||||
We have to consider that because kanidm will support various 2FA methods, or in some cases, only
|
||||
webauthn, we must correctly handle this.
|
||||
|
||||
* Password only - synced as expected.
|
||||
* Password + TOTP - the password is updated, TOTP remains.
|
||||
* Password + Webauthn - the password is updated, webauthn remains.
|
||||
* Webauthn only - the password sync is ignored.
|
||||
|
||||
The reason to ignore on webauthn only is that this is not an account recovery mechanism, but
|
||||
a mechanism to allow password material to be supplied. If the account with webauthn only
|
||||
is in need of recovery, other actions must be taken such as a password generate from the
|
||||
idm admin to remove the webauthn devices.
|
||||
|
||||
Similar, if an account has configured 2FA, this must have been performed in kanidm on top of the
|
||||
existing password sync. As a result, we do not fall-back to password only, but only change
|
||||
the password material to match the sync in this case.
|
||||
|
||||
Security Considerations
|
||||
-----------------------
|
||||
|
||||
Since this bypasses all password quality checks that kanidm provides, this is possible to misuse
|
||||
and weaken the security position of accounts.
|
||||
|
||||
Additionally, being able to supply password materials to accounts may allow a compromised password
|
||||
provided to be able to take over high privilege kanidm accounts.
|
||||
|
||||
For this reason, the ability to import passwords must be limited to:
|
||||
|
||||
* A service account with strong credentials
|
||||
* high_privilige accounts may NOT have their passwords set in this manner
|
||||
|
||||
Once kanidm implements password badlist checks in the auth path, passwords that have been synced
|
||||
into kanidm via this route may not function as they are found in the badlist, causing the account
|
||||
to be locked - this sounds like a good thing :)
|
||||
|
||||
Design
|
||||
------
|
||||
|
||||
The current design would be that passwords are provided on a create or modification statement
|
||||
with a unique attribute name such as "password_import". Note this is not a credential type per schema
|
||||
but a UTF-8 string. As many systems keep there passwords as utf-8 strings, this is a reasonable
|
||||
choice for import.
|
||||
|
||||
As password_import is an attribute, it can be limited by access controls in the normal manner for
|
||||
create and modify operations. A default password_import capable permission group should be supplied
|
||||
for service accounts to be added to if this functionality is required.
|
||||
|
||||
Pre-create-transform and pre-modify both run before schema - a plugin would be at this step
|
||||
that takes the content of password_import, and applies it to the account primary credential
|
||||
as mentioned above. The password_import attribute would then be removed from the entry/modification.
|
||||
|
||||
At this step the content of password_import could be sanity checked as a format. We would need to
|
||||
be capable of attempting to parse multiple formats in this step.
|
||||
|
||||
Risks
|
||||
-----
|
||||
|
||||
Due to the addition of the password_import in the modify, we need to be sure in replication that
|
||||
we don't commit the password_import value into the changelog when it will be removed after.
|
||||
|
||||
|
|
@ -607,6 +607,17 @@ impl KanidmClient {
|
|||
res.map(|_| ())
|
||||
}
|
||||
|
||||
pub fn idm_account_primary_credential_import_password(
|
||||
&self,
|
||||
id: &str,
|
||||
pw: &str,
|
||||
) -> Result<(), ClientError> {
|
||||
self.perform_put_request(
|
||||
format!("/v1/account/{}/_attr/password_import", id).as_str(),
|
||||
vec![pw.to_string()],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn idm_account_primary_credential_set_generated(
|
||||
&self,
|
||||
id: &str,
|
||||
|
@ -700,6 +711,10 @@ impl KanidmClient {
|
|||
self.perform_post_request(format!("/v1/account/{}/_ssh_pubkeys", id).as_str(), sk)
|
||||
}
|
||||
|
||||
pub fn idm_account_person_extend(&self, id: &str) -> Result<(), ClientError> {
|
||||
self.perform_post_request(format!("/v1/account/{}/_person/_extend", id).as_str(), ())
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn idm_account_rename_ssh_pubkey(&self, id: &str, oldtag: &str, newtag: &str) -> Result<(), ClientError> {
|
||||
self.perform_put_request(format!("/v1/account/{}/_ssh_pubkeys/{}", id, oldtag).as_str(), newtag.to_string())
|
||||
|
|
|
@ -715,6 +715,50 @@ fn test_server_rest_recycle_lifecycle() {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_server_rest_account_import_password() {
|
||||
run_test(|mut rsclient: KanidmClient| {
|
||||
let res = rsclient.auth_simple_password("admin", ADMIN_TEST_PASSWORD);
|
||||
assert!(res.is_ok());
|
||||
// To enable the admin to actually make some of these changes, we have
|
||||
// to make them a password import admin. NOT recommended in production!
|
||||
rsclient
|
||||
.idm_group_add_members("idm_people_account_password_import_priv", vec!["admin"])
|
||||
.unwrap();
|
||||
rsclient
|
||||
.idm_group_add_members("idm_people_extend_priv", vec!["admin"])
|
||||
.unwrap();
|
||||
|
||||
// Create a new account
|
||||
rsclient
|
||||
.idm_account_create("demo_account", "Deeeeemo")
|
||||
.unwrap();
|
||||
|
||||
// Make them a person, so we can import the password
|
||||
rsclient.idm_account_person_extend("demo_account").unwrap();
|
||||
|
||||
// Attempt to import a bad password
|
||||
let r = rsclient.idm_account_primary_credential_import_password("demo_account", "password");
|
||||
assert!(r.is_err());
|
||||
|
||||
// Import a good password
|
||||
// eicieY7ahchaoCh0eeTa
|
||||
// pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w=
|
||||
rsclient
|
||||
.idm_account_primary_credential_import_password(
|
||||
"demo_account",
|
||||
"pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w=",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Now show we can auth with it
|
||||
// "reset" the client.
|
||||
let _ = rsclient.logout();
|
||||
let res = rsclient.auth_simple_password("demo_account", "eicieY7ahchaoCh0eeTa");
|
||||
assert!(res.is_ok());
|
||||
});
|
||||
}
|
||||
|
||||
// Test the self version of the radius path.
|
||||
|
||||
// Test hitting all auth-required endpoints and assert they give unauthorized.
|
||||
|
|
|
@ -16,6 +16,7 @@ pub enum SchemaError {
|
|||
InvalidAttributeSyntax,
|
||||
EmptyFilter,
|
||||
Corrupted,
|
||||
PhantomAttribute,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
|
@ -23,6 +24,7 @@ pub enum PluginError {
|
|||
AttrUnique(String),
|
||||
Base(String),
|
||||
ReferentialIntegrity(String),
|
||||
PasswordImport(String),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
|
@ -30,6 +32,7 @@ pub enum ConsistencyError {
|
|||
Unknown,
|
||||
// Class, Attribute
|
||||
SchemaClassMissingAttribute(String, String),
|
||||
SchemaClassPhantomAttribute(String, String),
|
||||
QueryServerSearchFailure,
|
||||
EntryUuidCorrupt(u64),
|
||||
UuidIndexCorrupt(String),
|
||||
|
|
|
@ -70,6 +70,7 @@ idlset = { version = "0.1" , features = ["use_smallvec"] }
|
|||
# idlset = { version = "0.1" }
|
||||
|
||||
zxcvbn = "2.0"
|
||||
base64 = "0.12"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
|
|
|
@ -813,23 +813,23 @@ pub trait AccessControlsTransaction {
|
|||
|
||||
// Now check all the subsets are true. Remember, purge class
|
||||
// is already checked above.
|
||||
|
||||
let mut result = true;
|
||||
if !requested_pres.is_subset(&allowed_pres) {
|
||||
audit_log!(audit, "requested_pres is not a subset of allowed");
|
||||
audit_log!(audit, "{:?} !⊆ {:?}", requested_pres, allowed_pres);
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
if !requested_rem.is_subset(&allowed_rem) {
|
||||
audit_log!(audit, "requested_rem is not a subset of allowed");
|
||||
audit_log!(audit, "{:?} !⊆ {:?}", requested_rem, allowed_rem);
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
if !requested_classes.is_subset(&allowed_classes) {
|
||||
audit_log!(audit, "requested_classes is not a subset of allowed");
|
||||
audit_log!(audit, "{:?} !⊆ {:?}", requested_classes, allowed_classes);
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
true
|
||||
result
|
||||
} // if acc == false
|
||||
});
|
||||
Ok(r)
|
||||
|
|
|
@ -118,6 +118,15 @@ impl Message for IdmAccountSetPasswordMessage {
|
|||
type Result = Result<OperationResponse, OperationError>;
|
||||
}
|
||||
|
||||
pub struct IdmAccountPersonExtendMessage {
|
||||
pub uat: Option<UserAuthToken>,
|
||||
pub uuid_or_name: String,
|
||||
}
|
||||
|
||||
impl Message for IdmAccountPersonExtendMessage {
|
||||
type Result = Result<(), OperationError>;
|
||||
}
|
||||
|
||||
pub struct IdmAccountUnixExtendMessage {
|
||||
pub uat: Option<UserAuthToken>,
|
||||
pub uuid_or_name: String,
|
||||
|
@ -847,6 +856,39 @@ impl Handler<InternalSshKeyCreateMessage> for QueryServerWriteV1 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Handler<IdmAccountPersonExtendMessage> for QueryServerWriteV1 {
|
||||
type Result = Result<(), OperationError>;
|
||||
|
||||
fn handle(
|
||||
&mut self,
|
||||
msg: IdmAccountPersonExtendMessage,
|
||||
_: &mut Self::Context,
|
||||
) -> Self::Result {
|
||||
let mut audit = AuditScope::new("idm_account_person_extend");
|
||||
let res = audit_segment!(&mut audit, || {
|
||||
let IdmAccountPersonExtendMessage { uat, uuid_or_name } = msg;
|
||||
|
||||
// The filter_map here means we only create the mods if the gidnumber or shell are set
|
||||
// in the actual request.
|
||||
let mods: Vec<_> = vec![Some(Modify::Present(
|
||||
"class".to_string(),
|
||||
Value::new_class("person"),
|
||||
))]
|
||||
.into_iter()
|
||||
.filter_map(|v| v)
|
||||
.collect();
|
||||
|
||||
let ml = ModifyList::new_list(mods);
|
||||
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
|
||||
self.modify_from_internal_parts(&mut audit, uat, uuid_or_name, ml, filter)
|
||||
});
|
||||
self.log.do_send(audit);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<IdmAccountUnixExtendMessage> for QueryServerWriteV1 {
|
||||
type Result = Result<(), OperationError>;
|
||||
|
||||
|
|
922
kanidmd/src/lib/constants/acp.rs
Normal file
922
kanidmd/src/lib/constants/acp.rs
Normal file
|
@ -0,0 +1,922 @@
|
|||
/*
|
||||
// Template acp
|
||||
pub static _UUID_IDM_ACP_XX_V1: &str = "00000000-0000-0000-0000-ffffff0000XX";
|
||||
pub static JSON_IDM_ACP_XX_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify",
|
||||
"access_control_create",
|
||||
"access_control_delete"
|
||||
],
|
||||
"name": ["idm_acp_xx"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff0000XX"],
|
||||
"description": ["Builtin IDM Control for xx"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-0000000000XX\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"attr\",\"value\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
|
||||
],
|
||||
"acp_modify_class": [
|
||||
|
||||
],
|
||||
"acp_create_attr": [
|
||||
|
||||
],
|
||||
"acp_create_class": [
|
||||
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
*/
|
||||
|
||||
pub static JSON_IDM_ADMINS_ACP_RECYCLE_SEARCH_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["object", "access_control_profile", "access_control_search"],
|
||||
"name": ["idm_admins_acp_recycle_search"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000002"],
|
||||
"description": ["Builtin IDM admin recycle bin search permission."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000019\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"Eq\": [\"class\", \"recycled\"]}"
|
||||
],
|
||||
"acp_search_attr": ["name", "class", "uuid", "last_modified_cid"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_ADMINS_ACP_REVIVE_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["object", "access_control_profile", "access_control_modify"],
|
||||
"name": ["idm_admins_acp_revive"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000003"],
|
||||
"description": ["Builtin IDM Administrators Access Controls."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000019\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"Eq\":[\"class\",\"recycled\"]}"
|
||||
],
|
||||
"acp_modify_removedattr": ["class"],
|
||||
"acp_modify_class": ["recycled"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_SELF_ACP_READ_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["object", "access_control_profile", "access_control_search"],
|
||||
"name": ["idm_self_acp_read"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000004"],
|
||||
"description": ["Builtin IDM Control for self read - required for whoami and many other functions."],
|
||||
"acp_receiver": [
|
||||
"{\"And\": [\"Self\", {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"\"Self\""
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"name",
|
||||
"spn",
|
||||
"displayname",
|
||||
"legalname",
|
||||
"class",
|
||||
"memberof",
|
||||
"radius_secret",
|
||||
"gidnumber",
|
||||
"loginshell",
|
||||
"uuid"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_SELF_ACP_WRITE_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["object", "access_control_profile", "access_control_modify"],
|
||||
"name": ["idm_self_acp_write"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000021"],
|
||||
"description": ["Builtin IDM Control for self write - required for people to update their own identities and credentials in line with best practices."],
|
||||
"acp_receiver": [
|
||||
"{\"And\": [\"Self\", {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}, {\"Eq\": [\"uuid\", \"00000000-0000-0000-0000-ffffffffffff\"]}]}}]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"\"Self\""
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"name", "displayname", "legalname", "radius_secret", "primary_credential", "ssh_publickey", "unix_password"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"name", "displayname", "legalname", "radius_secret", "primary_credential", "ssh_publickey", "unix_password"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_ALL_ACP_READ_V1: &str = r#"{
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["object", "access_control_profile", "access_control_search"],
|
||||
"name": ["idm_all_acp_read"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000006"],
|
||||
"description": ["Builtin IDM Control for all read - IE anonymous and all authenticated accounts."],
|
||||
"acp_receiver": [
|
||||
"{\"Pres\":\"class\"}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Pres\": \"class\"}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"name",
|
||||
"spn",
|
||||
"displayname",
|
||||
"class",
|
||||
"memberof",
|
||||
"member",
|
||||
"uuid",
|
||||
"gidnumber",
|
||||
"loginshell",
|
||||
"ssh_publickey"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 7 people read acp JSON_IDM_PEOPLE_READ_PRIV_V1
|
||||
pub static JSON_IDM_ACP_PEOPLE_READ_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search"
|
||||
],
|
||||
"name": ["idm_acp_people_read_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000007"],
|
||||
"description": ["Builtin IDM Control for reading personal sensitive data."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000002\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"name", "displayname", "legalname", "mail"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// 8 people write acp JSON_IDM_PEOPLE_WRITE_PRIV_V1
|
||||
pub static JSON_IDM_ACP_PEOPLE_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_people_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000008"],
|
||||
"description": ["Builtin IDM Control for managing personal and sensitive data."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000003\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"person\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"name", "displayname", "legalname", "mail"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"name", "displayname", "legalname", "mail"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// 13 user (person) account create acp JSON_IDM_PERSON_ACCOUNT_CREATE_PRIV_V1
|
||||
pub static JSON_IDM_ACP_PEOPLE_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_delete",
|
||||
"access_control_create"
|
||||
],
|
||||
"name": ["idm_acp_people_manage"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000013"],
|
||||
"description": ["Builtin IDM Control for creating person (user) accounts"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000013\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"Eq\": [\"class\",\"person\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_create_attr": [
|
||||
"class",
|
||||
"name",
|
||||
"displayname",
|
||||
"legalname",
|
||||
"primary_credential",
|
||||
"ssh_publickey",
|
||||
"mail"
|
||||
],
|
||||
"acp_create_class": [
|
||||
"object", "person", "account"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// 31 - password import modification priv
|
||||
// right now, create requires you to have access to every attribute in a single snapshot,
|
||||
// so people will need to two step (create then import pw). Later we could add another
|
||||
// acp that allows the create here too? Should it be seperate?
|
||||
pub static JSON_IDM_ACP_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_people_account_password_import_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000031"],
|
||||
"description": ["Builtin IDM Control for allowing imports of passwords to people+account types."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000023\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"person\"]}, {\"Eq\": [\"class\",\"account\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"password_import"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"password_import"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
//
|
||||
pub static JSON_IDM_ACP_PEOPLE_EXTEND_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_people_extend_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000032"],
|
||||
"description": ["Builtin IDM Control for allowing person class extension"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000024\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"class"
|
||||
],
|
||||
"acp_modify_class": ["person"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// -- end people
|
||||
|
||||
// 9 group write acp JSON_IDM_GROUP_WRITE_PRIV_V1
|
||||
pub static JSON_IDM_ACP_GROUP_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_group_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000009"],
|
||||
"description": ["Builtin IDM Control for managing groups"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000004\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"group\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"class", "name", "spn", "uuid", "description", "member"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"name", "description", "member"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"name", "description", "member"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// 10 account read acp JSON_IDM_ACCOUNT_READ_PRIV_V1
|
||||
pub static JSON_IDM_ACP_ACCOUNT_READ_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search"
|
||||
],
|
||||
"name": ["idm_acp_account_read_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000010"],
|
||||
"description": ["Builtin IDM Control for accounts."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000005\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"class", "name", "spn", "uuid", "displayname", "ssh_publickey", "primary_credential", "memberof", "mail", "gidnumber"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// 11 account write acp JSON_IDM_ACCOUNT_WRITE_PRIV_V1
|
||||
pub static JSON_IDM_ACP_ACCOUNT_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_account_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000011"],
|
||||
"description": ["Builtin IDM Control for managing accounts."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000006\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"name", "displayname", "ssh_publickey", "primary_credential", "mail"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"name", "displayname", "ssh_publickey", "primary_credential", "mail"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// 12 service account create acp (only admins?) JSON_IDM_SERVICE_ACCOUNT_CREATE_PRIV_V1
|
||||
pub static JSON_IDM_ACP_ACCOUNT_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_delete",
|
||||
"access_control_create"
|
||||
],
|
||||
"name": ["idm_acp_account_manage"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000012"],
|
||||
"description": ["Builtin IDM Control for creating and deleting (service) accounts"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000014\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_create_attr": [
|
||||
"class",
|
||||
"name",
|
||||
"displayname",
|
||||
"description",
|
||||
"primary_credential",
|
||||
"ssh_publickey"
|
||||
],
|
||||
"acp_create_class": [
|
||||
"object", "account"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// 14 radius read acp JSON_IDM_RADIUS_SERVERS_V1
|
||||
// The targetscope of this could change later to a "radius access" group or similar so we can add/remove
|
||||
// users from having radius access easier.
|
||||
pub static JSON_IDM_ACP_RADIUS_SERVERS_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search"
|
||||
],
|
||||
"name": ["idm_acp_radius_servers"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000014"],
|
||||
"description": ["Builtin IDM Control for RADIUS servers to read credentials and other needed details."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000007\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Pres\": \"class\"}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"name", "spn", "uuid", "radius_secret"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// 15 high priv account read JSON_IDM_HP_ACCOUNT_READ_PRIV_V1
|
||||
pub static JSON_IDM_ACP_HP_ACCOUNT_READ_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search"
|
||||
],
|
||||
"name": ["idm_acp_hp_account_read_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000015"],
|
||||
"description": ["Builtin IDM Control for reading high privilege accounts."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000009\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"class", "name", "spn", "uuid", "displayname", "ssh_publickey", "primary_credential", "memberof"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// 16 high priv account write JSON_IDM_HP_ACCOUNT_WRITE_PRIV_V1
|
||||
pub static JSON_IDM_ACP_HP_ACCOUNT_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_hp_account_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000016"],
|
||||
"description": ["Builtin IDM Control for managing high privilege accounts."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000009\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"name", "displayname", "ssh_publickey", "primary_credential"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"name", "displayname", "ssh_publickey", "primary_credential"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 17 high priv group write --> JSON_IDM_HP_GROUP_WRITE_PRIV_V1 (12)
|
||||
pub static JSON_IDM_ACP_HP_GROUP_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_hp_group_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000017"],
|
||||
"description": ["Builtin IDM Control for managing high privilege groups"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000012\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"group\"]}, {\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"class", "name", "uuid", "description", "member"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"name", "description", "member"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"name", "description", "member"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 18 schema write JSON_IDM_SCHEMA_WRITE_PRIV_V1
|
||||
pub static JSON_IDM_ACP_SCHEMA_WRITE_ATTRS_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify",
|
||||
"access_control_create"
|
||||
],
|
||||
"name": ["idm_acp_schema_write_attrs_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000018"],
|
||||
"description": ["Builtin IDM Control for management of schema attributes."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000010\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"attributetype\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"class",
|
||||
"description",
|
||||
"index",
|
||||
"unique",
|
||||
"multivalue",
|
||||
"attributename",
|
||||
"syntax",
|
||||
"uuid"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"description",
|
||||
"index",
|
||||
"unique",
|
||||
"multivalue",
|
||||
"syntax"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"description",
|
||||
"index",
|
||||
"unique",
|
||||
"multivalue",
|
||||
"syntax"
|
||||
],
|
||||
"acp_modify_class": [],
|
||||
"acp_create_attr": [
|
||||
"class",
|
||||
"description",
|
||||
"index",
|
||||
"unique",
|
||||
"multivalue",
|
||||
"attributename",
|
||||
"syntax",
|
||||
"uuid"
|
||||
],
|
||||
"acp_create_class": [
|
||||
"object", "attributetype"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 19 acp read/write
|
||||
pub static JSON_IDM_ACP_ACP_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify",
|
||||
"access_control_create",
|
||||
"access_control_delete"
|
||||
],
|
||||
"name": ["idm_acp_acp_manage_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000019"],
|
||||
"description": ["Builtin IDM Control for access profiles management."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000011\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"access_control_profile\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"name",
|
||||
"class",
|
||||
"description",
|
||||
"acp_enable",
|
||||
"acp_receiver",
|
||||
"acp_targetscope",
|
||||
"acp_search_attr",
|
||||
"acp_modify_removedattr",
|
||||
"acp_modify_presentattr",
|
||||
"acp_modify_class",
|
||||
"acp_create_class",
|
||||
"acp_create_attr"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"name",
|
||||
"class",
|
||||
"description",
|
||||
"acp_enable",
|
||||
"acp_receiver",
|
||||
"acp_targetscope",
|
||||
"acp_search_attr",
|
||||
"acp_modify_removedattr",
|
||||
"acp_modify_presentattr",
|
||||
"acp_modify_class",
|
||||
"acp_create_class",
|
||||
"acp_create_attr"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"name",
|
||||
"class",
|
||||
"description",
|
||||
"acp_enable",
|
||||
"acp_receiver",
|
||||
"acp_targetscope",
|
||||
"acp_search_attr",
|
||||
"acp_modify_removedattr",
|
||||
"acp_modify_presentattr",
|
||||
"acp_modify_class",
|
||||
"acp_create_class",
|
||||
"acp_create_attr"
|
||||
],
|
||||
"acp_modify_class": [
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify",
|
||||
"access_control_create",
|
||||
"access_control_delete"
|
||||
],
|
||||
"acp_create_attr": [
|
||||
"name",
|
||||
"class",
|
||||
"description",
|
||||
"acp_enable",
|
||||
"acp_receiver",
|
||||
"acp_targetscope",
|
||||
"acp_search_attr",
|
||||
"acp_modify_removedattr",
|
||||
"acp_modify_presentattr",
|
||||
"acp_modify_class",
|
||||
"acp_create_class",
|
||||
"acp_create_attr"
|
||||
],
|
||||
"acp_create_class": [
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify",
|
||||
"access_control_create",
|
||||
"access_control_delete"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_ACP_SCHEMA_WRITE_CLASSES_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify",
|
||||
"access_control_create"
|
||||
],
|
||||
"name": ["idm_acp_schema_write_classes_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000020"],
|
||||
"description": ["Builtin IDM Control for management of schema classes."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000010\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"classtype\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"class",
|
||||
"description",
|
||||
"classname",
|
||||
"systemmay",
|
||||
"may",
|
||||
"systemmust",
|
||||
"must",
|
||||
"uuid"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"class",
|
||||
"description",
|
||||
"may",
|
||||
"must"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"class",
|
||||
"description",
|
||||
"may",
|
||||
"must"
|
||||
],
|
||||
"acp_modify_class": [],
|
||||
"acp_create_attr": [
|
||||
"class",
|
||||
"description",
|
||||
"classname",
|
||||
"may",
|
||||
"must",
|
||||
"uuid"
|
||||
],
|
||||
"acp_create_class": [
|
||||
"object", "classtype"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 21 - anonymous / everyone schema read.
|
||||
|
||||
// 22 - group create right
|
||||
pub static JSON_IDM_ACP_GROUP_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_delete",
|
||||
"access_control_create"
|
||||
],
|
||||
"name": ["idm_acp_group_manage"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000022"],
|
||||
"description": ["Builtin IDM Control for creating and deleting groups in the directory"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000015\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"group\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_create_attr": [
|
||||
"class",
|
||||
"name",
|
||||
"description",
|
||||
"member"
|
||||
],
|
||||
"acp_create_class": [
|
||||
"object", "group"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 23 - HP account manage
|
||||
pub static JSON_IDM_ACP_HP_ACCOUNT_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_delete",
|
||||
"access_control_create"
|
||||
],
|
||||
"name": ["idm_acp_hp_account_manage"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000023"],
|
||||
"description": ["Builtin IDM Control for creating and deleting hp and regular (service) accounts"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000016\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_create_attr": [
|
||||
"class",
|
||||
"name",
|
||||
"displayname",
|
||||
"description",
|
||||
"primary_credential",
|
||||
"ssh_publickey"
|
||||
],
|
||||
"acp_create_class": [
|
||||
"object", "account"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 24 - hp group manage
|
||||
pub static JSON_IDM_ACP_HP_GROUP_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_delete",
|
||||
"access_control_create"
|
||||
],
|
||||
"name": ["idm_acp_hp_group_manage"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000024"],
|
||||
"description": ["Builtin IDM Control for creating and deleting hp and regular groups in the directory"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000017\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"group\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_create_attr": [
|
||||
"class",
|
||||
"name",
|
||||
"description",
|
||||
"member"
|
||||
],
|
||||
"acp_create_class": [
|
||||
"object", "group"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 28 - domain admins acp
|
||||
pub static JSON_IDM_ACP_DOMAIN_ADMIN_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_domain_admin_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000026"],
|
||||
"description": ["Builtin IDM Control for granting domain info administration locally"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000020\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"uuid\",\"00000000-0000-0000-0000-ffffff000025\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"name",
|
||||
"uuid",
|
||||
"domain_name",
|
||||
"domain_ssid",
|
||||
"domain_uuid"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"domain_ssid"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"domain_ssid"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 28 - system config
|
||||
pub static JSON_IDM_ACP_SYSTEM_CONFIG_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_system_config_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000028"],
|
||||
"description": ["Builtin IDM Control for granting system configuration rights"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000019\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"uuid\",\"00000000-0000-0000-0000-ffffff000027\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"name",
|
||||
"uuid",
|
||||
"description",
|
||||
"badlist_password"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"badlist_password"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// 29 account unix extend
|
||||
pub static JSON_IDM_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_search",
|
||||
"access_control_profile",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_account_unix_extend_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000029"],
|
||||
"description": ["Builtin IDM Control for managing accounts."],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000021\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"account\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"class", "name", "spn", "uuid", "description", "gidnumber", "loginshell", "unix_password"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"class", "loginshell", "gidnumber", "unix_password"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"class", "loginshell", "gidnumber", "unix_password"
|
||||
],
|
||||
"acp_modify_class": ["posixaccount"]
|
||||
}
|
||||
}"#;
|
||||
// 30 group unix extend
|
||||
pub static JSON_IDM_ACP_GROUP_UNIX_EXTEND_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"access_control_profile",
|
||||
"access_control_search",
|
||||
"access_control_modify"
|
||||
],
|
||||
"name": ["idm_acp_group_unix_extend_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000030"],
|
||||
"description": ["Builtin IDM Control for managing and extending unix groups"],
|
||||
"acp_receiver": [
|
||||
"{\"Eq\":[\"memberof\",\"00000000-0000-0000-0000-000000000022\"]}"
|
||||
],
|
||||
"acp_targetscope": [
|
||||
"{\"And\": [{\"Eq\": [\"class\",\"group\"]}, {\"AndNot\": {\"Or\": [{\"Eq\": [\"memberof\",\"00000000-0000-0000-0000-000000001000\"]}, {\"Eq\": [\"class\", \"tombstone\"]}, {\"Eq\": [\"class\", \"recycled\"]}]}}]}"
|
||||
],
|
||||
"acp_search_attr": [
|
||||
"class", "name", "spn", "uuid", "description", "member", "gidnumber"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"class", "gidnumber"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"class", "gidnumber"
|
||||
],
|
||||
"acp_modify_class": ["posixgroup"]
|
||||
}
|
||||
}"#;
|
378
kanidmd/src/lib/constants/entries.rs
Normal file
378
kanidmd/src/lib/constants/entries.rs
Normal file
|
@ -0,0 +1,378 @@
|
|||
pub static JSON_ADMIN_V1: &str = r#"{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["account", "memberof", "object"],
|
||||
"name": ["admin"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000000"],
|
||||
"description": ["Builtin System Admin account."],
|
||||
"displayname": ["System Administrator"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_ADMIN_V1: &str = r#"{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-000000000018"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["account", "memberof", "object"],
|
||||
"name": ["idm_admin"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000018"],
|
||||
"description": ["Builtin IDM Admin account."],
|
||||
"displayname": ["IDM Administrator"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_ADMINS_V1: &str = r#"{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-000000000001"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_admins"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000001"],
|
||||
"description": ["Builtin IDM Administrators Group."],
|
||||
"member": ["00000000-0000-0000-0000-000000000018"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_SYSTEM_ADMINS_V1: &str = r#"{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-000000000019"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["system_admins"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000019"],
|
||||
"description": ["Builtin System Administrators Group."],
|
||||
"member": ["00000000-0000-0000-0000-000000000000"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// groups
|
||||
// * People read managers
|
||||
pub static JSON_IDM_PEOPLE_READ_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_people_read_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000002"],
|
||||
"description": ["Builtin IDM Group for granting elevated people (personal data) read permissions."],
|
||||
"member": ["00000000-0000-0000-0000-000000000003"]
|
||||
}
|
||||
}"#;
|
||||
// * People write managers
|
||||
pub static JSON_IDM_PEOPLE_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_people_manage_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000013"],
|
||||
"description": ["Builtin IDM Group for granting elevated people (personal data) write and lifecycle management permissions."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000001"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_IDM_PEOPLE_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_people_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000003"],
|
||||
"description": ["Builtin IDM Group for granting elevated people (personal data) write permissions."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000013",
|
||||
"00000000-0000-0000-0000-000000000024"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_people_account_password_import_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000023"],
|
||||
"description": ["Builtin IDM Group for importing passwords to person accounts - intended for service account membership only."]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_PEOPLE_EXTEND_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_people_extend_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000024"],
|
||||
"description": ["Builtin IDM Group for extending accounts to be people."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000001"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// * group write manager (no read, everyone has read via the anon, etc)
|
||||
// IDM_GROUP_CREATE_PRIV
|
||||
pub static JSON_IDM_GROUP_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_group_manage_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000015"],
|
||||
"description": ["Builtin IDM Group for granting elevated group write and lifecycle permissions."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000001",
|
||||
"00000000-0000-0000-0000-000000000019"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_IDM_GROUP_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_group_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000004"],
|
||||
"description": ["Builtin IDM Group for granting elevated group write permissions."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000015"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_IDM_GROUP_UNIX_EXTEND_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_group_unix_extend_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000022"],
|
||||
"description": ["Builtin IDM Group for granting unix group extension permissions."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000001"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// * account read manager
|
||||
pub static JSON_IDM_ACCOUNT_READ_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_account_read_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000005"],
|
||||
"description": ["Builtin IDM Group for granting elevated account read permissions."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000006"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// * account write manager
|
||||
pub static JSON_IDM_ACCOUNT_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_account_manage_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000014"],
|
||||
"description": ["Builtin IDM Group for granting elevated account write and lifecycle permissions."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000001"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_IDM_ACCOUNT_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_account_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000006"],
|
||||
"description": ["Builtin IDM Group for granting elevated account write permissions."],
|
||||
"member": ["00000000-0000-0000-0000-000000000014"]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_IDM_ACCOUNT_UNIX_EXTEND_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_account_unix_extend_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000021"],
|
||||
"description": ["Builtin IDM Group for granting account unix extend permissions."],
|
||||
"member": ["00000000-0000-0000-0000-000000000001"]
|
||||
}
|
||||
}"#;
|
||||
// * RADIUS servers
|
||||
pub static JSON_IDM_RADIUS_SERVERS_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_radius_servers"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000007"],
|
||||
"description": ["Builtin IDM Group for RADIUS server access delegation."]
|
||||
}
|
||||
}"#;
|
||||
// * high priv account read manager
|
||||
pub static JSON_IDM_HP_ACCOUNT_READ_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_hp_account_read_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000008"],
|
||||
"description": ["Builtin IDM Group for granting elevated account read permissions over high privilege accounts."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000009"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// * high priv account write manager
|
||||
pub static JSON_IDM_HP_ACCOUNT_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_hp_account_manage_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000016"],
|
||||
"description": ["Builtin IDM Group for granting elevated account write and lifecycle permissions over high privilege accounts."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000019"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_IDM_HP_ACCOUNT_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_hp_account_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000009"],
|
||||
"description": ["Builtin IDM Group for granting elevated account write permissions over high privilege accounts."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000016"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// * Schema write manager
|
||||
pub static JSON_IDM_SCHEMA_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_schema_manage_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000010"],
|
||||
"description": ["Builtin IDM Group for granting elevated schema write and management permissions."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000019"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
// * ACP read/write manager
|
||||
pub static JSON_IDM_ACP_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_acp_manage_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000011"],
|
||||
"description": ["Builtin IDM Group for granting control over all access control profile modifications."],
|
||||
"member": ["00000000-0000-0000-0000-000000000019"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_IDM_HP_GROUP_MANAGE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_hp_group_manage_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000017"],
|
||||
"description": ["Builtin IDM Group for granting elevated group write and lifecycle privileges for high privilege groups."],
|
||||
"member": ["00000000-0000-0000-0000-000000000019"]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_IDM_HP_GROUP_WRITE_PRIV_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_hp_group_write_priv"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000012"],
|
||||
"description": ["Builtin IDM Group for granting elevated group write privileges for high privilege groups."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000017"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_DOMAIN_ADMINS: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["domain_admins"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000000020"],
|
||||
"description": ["Builtin IDM Group for granting local domain administration rights and trust administration rights."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000000"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// This must be the last group to init to include the UUID of the other high priv groups.
|
||||
pub static JSON_IDM_HIGH_PRIVILEGE_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["group", "object"],
|
||||
"name": ["idm_high_privilege"],
|
||||
"uuid": ["00000000-0000-0000-0000-000000001000"],
|
||||
"description": ["Builtin IDM provided groups with high levels of access that should be audited and limited in modification."],
|
||||
"member": [
|
||||
"00000000-0000-0000-0000-000000000001",
|
||||
"00000000-0000-0000-0000-000000000002",
|
||||
"00000000-0000-0000-0000-000000000003",
|
||||
"00000000-0000-0000-0000-000000000004",
|
||||
"00000000-0000-0000-0000-000000000005",
|
||||
"00000000-0000-0000-0000-000000000006",
|
||||
"00000000-0000-0000-0000-000000000007",
|
||||
"00000000-0000-0000-0000-000000000008",
|
||||
"00000000-0000-0000-0000-000000000009",
|
||||
"00000000-0000-0000-0000-000000000010",
|
||||
"00000000-0000-0000-0000-000000000011",
|
||||
"00000000-0000-0000-0000-000000000012",
|
||||
"00000000-0000-0000-0000-000000000013",
|
||||
"00000000-0000-0000-0000-000000000014",
|
||||
"00000000-0000-0000-0000-000000000015",
|
||||
"00000000-0000-0000-0000-000000000016",
|
||||
"00000000-0000-0000-0000-000000000017",
|
||||
"00000000-0000-0000-0000-000000000019",
|
||||
"00000000-0000-0000-0000-000000000020",
|
||||
"00000000-0000-0000-0000-000000000023",
|
||||
"00000000-0000-0000-0000-000000000024",
|
||||
"00000000-0000-0000-0000-000000001000"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_SYSTEM_INFO_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["object", "system_info", "system"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000001"],
|
||||
"description": ["System info and metadata object."],
|
||||
"version": ["2"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_DOMAIN_INFO_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["object", "domain_info", "system"],
|
||||
"name": ["domain_local"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffff000025"],
|
||||
"description": ["This local domain's info and metadata object."]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// Anonymous should be the last opbject in the range here.
|
||||
pub static JSON_ANONYMOUS_V1: &str = r#"{
|
||||
"attrs": {
|
||||
"class": ["account", "object"],
|
||||
"name": ["anonymous"],
|
||||
"uuid": ["00000000-0000-0000-0000-ffffffffffff"],
|
||||
"description": ["Anonymous access account."],
|
||||
"displayname": ["Anonymous"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// need a domain_trust_info as well.
|
||||
// TODO
|
||||
|
||||
// ============ TEST DATA ============
|
||||
#[cfg(test)]
|
||||
pub static JSON_TESTPERSON1: &str = r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["object"],
|
||||
"name": ["testperson1"],
|
||||
"uuid": ["cc8e95b4-c24f-4d68-ba54-8bed76f63930"]
|
||||
}
|
||||
}"#;
|
||||
|
||||
#[cfg(test)]
|
||||
pub static JSON_TESTPERSON2: &str = r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["object"],
|
||||
"name": ["testperson2"],
|
||||
"uuid": ["538faac7-4d29-473b-a59d-23023ac19955"]
|
||||
}
|
||||
}"#;
|
File diff suppressed because it is too large
Load diff
613
kanidmd/src/lib/constants/schema.rs
Normal file
613
kanidmd/src/lib/constants/schema.rs
Normal file
|
@ -0,0 +1,613 @@
|
|||
// Core
|
||||
// Schema uuids start at 00000000-0000-0000-0000-ffff00000000
|
||||
|
||||
// system supplementary
|
||||
pub static JSON_SCHEMA_ATTR_DISPLAYNAME: &str = r#"{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-ffff00000040"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"The publicly visible display name of this person"
|
||||
],
|
||||
"index": [
|
||||
"EQUALITY"
|
||||
],
|
||||
"unique": [
|
||||
"false"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"displayname"
|
||||
],
|
||||
"syntax": [
|
||||
"UTF8STRING"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000040"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_SCHEMA_ATTR_MAIL: &str = r#"
|
||||
{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-ffff00000041"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"mail addresses of the object"
|
||||
],
|
||||
"index": [
|
||||
"EQUALITY"
|
||||
],
|
||||
"unique": [
|
||||
"true"
|
||||
],
|
||||
"multivalue": [
|
||||
"true"
|
||||
],
|
||||
"attributename": [
|
||||
"mail"
|
||||
],
|
||||
"syntax": [
|
||||
"UTF8STRING"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000041"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
pub static JSON_SCHEMA_ATTR_SSH_PUBLICKEY: &str = r#"
|
||||
{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-ffff00000042"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"SSH public keys of the object"
|
||||
],
|
||||
"index": [],
|
||||
"unique": [
|
||||
"false"
|
||||
],
|
||||
"multivalue": [
|
||||
"true"
|
||||
],
|
||||
"attributename": [
|
||||
"ssh_publickey"
|
||||
],
|
||||
"syntax": [
|
||||
"SSHKEY"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000042"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
pub static JSON_SCHEMA_ATTR_PRIMARY_CREDENTIAL: &str = r#"
|
||||
{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-ffff00000043"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"Primary credential material of the account for authentication interactively."
|
||||
],
|
||||
"index": [],
|
||||
"unique": [
|
||||
"false"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"primary_credential"
|
||||
],
|
||||
"syntax": [
|
||||
"CREDENTIAL"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000043"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
pub static JSON_SCHEMA_ATTR_LEGALNAME: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"The private and sensitive legal name of this person"
|
||||
],
|
||||
"index": [
|
||||
"EQUALITY"
|
||||
],
|
||||
"unique": [
|
||||
"false"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"legalname"
|
||||
],
|
||||
"syntax": [
|
||||
"UTF8STRING"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000050"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_SCHEMA_ATTR_RADIUS_SECRET: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"The accounts generated radius secret for device network authentication"
|
||||
],
|
||||
"index": [],
|
||||
"unique": [
|
||||
"false"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"radius_secret"
|
||||
],
|
||||
"syntax": [
|
||||
"RADIUS_UTF8STRING"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000051"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_SCHEMA_ATTR_DOMAIN_NAME: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"The domain's DNS name for webauthn and SPN generation purposes."
|
||||
],
|
||||
"index": [
|
||||
"EQUALITY"
|
||||
],
|
||||
"unique": [
|
||||
"true"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"domain_name"
|
||||
],
|
||||
"syntax": [
|
||||
"UTF8STRING_INSENSITIVE"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000053"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_SCHEMA_ATTR_DOMAIN_UUID: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"The domain's uuid, used in CSN and trust relationships."
|
||||
],
|
||||
"index": [
|
||||
"EQUALITY"
|
||||
],
|
||||
"unique": [
|
||||
"true"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"domain_uuid"
|
||||
],
|
||||
"syntax": [
|
||||
"UUID"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000054"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
pub static JSON_SCHEMA_ATTR_DOMAIN_SSID: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"The domains site-wide SSID for device autoconfiguration of wireless"
|
||||
],
|
||||
"index": [],
|
||||
"unique": [
|
||||
"true"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"domain_ssid"
|
||||
],
|
||||
"syntax": [
|
||||
"UTF8STRING"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000055"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_SCHEMA_ATTR_GIDNUMBER: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"The groupid (uid) number of a group or account. This is the same value as the UID number on posix accounts for security reasons."
|
||||
],
|
||||
"index": [
|
||||
"EQUALITY"
|
||||
],
|
||||
"unique": [
|
||||
"true"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"gidnumber"
|
||||
],
|
||||
"syntax": [
|
||||
"UINT32"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000056"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_SCHEMA_ATTR_BADLIST_PASSWORD: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"A password that is badlisted meaning that it can not be set as a valid password by any user account."
|
||||
],
|
||||
"index": [],
|
||||
"unique": [
|
||||
"true"
|
||||
],
|
||||
"multivalue": [
|
||||
"true"
|
||||
],
|
||||
"attributename": [
|
||||
"badlist_password"
|
||||
],
|
||||
"syntax": [
|
||||
"UTF8STRING_INSENSITIVE"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000059"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_SCHEMA_ATTR_LOGINSHELL: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"A posix users unix login shell"
|
||||
],
|
||||
"index": [],
|
||||
"unique": [
|
||||
"false"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"loginshell"
|
||||
],
|
||||
"syntax": [
|
||||
"UTF8STRING_INSENSITIVE"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000061"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_SCHEMA_ATTR_UNIX_PASSWORD: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"A posix users unix login password."
|
||||
],
|
||||
"index": [],
|
||||
"unique": [
|
||||
"false"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"unix_password"
|
||||
],
|
||||
"syntax": [
|
||||
"CREDENTIAL"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000062"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub static JSON_SCHEMA_CLASS_PERSON: &str = r#"
|
||||
{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-ffff00000044"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"classtype"
|
||||
],
|
||||
"description": [
|
||||
"Object representation of a person"
|
||||
],
|
||||
"classname": [
|
||||
"person"
|
||||
],
|
||||
"systemmay": [
|
||||
"mail",
|
||||
"legalname"
|
||||
],
|
||||
"systemmust": [
|
||||
"displayname",
|
||||
"name"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000044"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
pub static JSON_SCHEMA_CLASS_GROUP: &str = r#"
|
||||
{
|
||||
"valid": {
|
||||
"uuid": "00000000-0000-0000-0000-ffff00000045"
|
||||
},
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"classtype"
|
||||
],
|
||||
"description": [
|
||||
"Object representation of a group"
|
||||
],
|
||||
"classname": [
|
||||
"group"
|
||||
],
|
||||
"systemmay": [
|
||||
"member"
|
||||
],
|
||||
"systemmust": [
|
||||
"name",
|
||||
"spn"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000045"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
pub static JSON_SCHEMA_CLASS_ACCOUNT: &str = r#"
|
||||
{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"classtype"
|
||||
],
|
||||
"description": [
|
||||
"Object representation of a account"
|
||||
],
|
||||
"classname": [
|
||||
"account"
|
||||
],
|
||||
"systemmay": [
|
||||
"primary_credential",
|
||||
"ssh_publickey",
|
||||
"radius_secret"
|
||||
],
|
||||
"systemmust": [
|
||||
"displayname",
|
||||
"name",
|
||||
"spn"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000046"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
// domain_info type
|
||||
// domain_uuid
|
||||
// domain_name <- should be the dns name?
|
||||
// domain_ssid <- for radius
|
||||
//
|
||||
pub static JSON_SCHEMA_CLASS_DOMAIN_INFO: &str = r#"
|
||||
{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"classtype"
|
||||
],
|
||||
"description": [
|
||||
"Local domain information and partial configuration."
|
||||
],
|
||||
"classname": [
|
||||
"domain_info"
|
||||
],
|
||||
"systemmay": [
|
||||
"domain_ssid"
|
||||
],
|
||||
"systemmust": [
|
||||
"name",
|
||||
"domain_uuid",
|
||||
"domain_name"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000052"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
pub static JSON_SCHEMA_CLASS_POSIXGROUP: &str = r#"
|
||||
{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"classtype"
|
||||
],
|
||||
"description": [
|
||||
"Object representation of a posix group, requires group"
|
||||
],
|
||||
"classname": [
|
||||
"posixgroup"
|
||||
],
|
||||
"systemmust": [
|
||||
"gidnumber"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000058"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
pub static JSON_SCHEMA_CLASS_POSIXACCOUNT: &str = r#"
|
||||
{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"classtype"
|
||||
],
|
||||
"description": [
|
||||
"Object representation of a posix account, requires account"
|
||||
],
|
||||
"classname": [
|
||||
"posixaccount"
|
||||
],
|
||||
"systemmay": [
|
||||
"loginshell",
|
||||
"unix_password"
|
||||
],
|
||||
"systemmust": [
|
||||
"gidnumber"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000057"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
pub static JSON_SCHEMA_CLASS_SYSTEM_CONFIG: &str = r#"
|
||||
{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"classtype"
|
||||
],
|
||||
"description": [
|
||||
"The class representing a system (topologies) configuration options."
|
||||
],
|
||||
"classname": [
|
||||
"system_config"
|
||||
],
|
||||
"systemmay": [
|
||||
"description",
|
||||
"badlist_password"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000060"
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
155
kanidmd/src/lib/constants/uuids.rs
Normal file
155
kanidmd/src/lib/constants/uuids.rs
Normal file
|
@ -0,0 +1,155 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
// Built in group and account ranges.
|
||||
pub static STR_UUID_ADMIN: &str = "00000000-0000-0000-0000-000000000000";
|
||||
pub static _UUID_IDM_ADMINS: &str = "00000000-0000-0000-0000-000000000001";
|
||||
pub static _UUID_IDM_PEOPLE_READ_PRIV: &str = "00000000-0000-0000-0000-000000000002";
|
||||
pub static _UUID_IDM_PEOPLE_WRITE_PRIV: &str = "00000000-0000-0000-0000-000000000003";
|
||||
pub static _UUID_IDM_GROUP_WRITE_PRIV: &str = "00000000-0000-0000-0000-000000000004";
|
||||
pub static _UUID_IDM_ACCOUNT_READ_PRIV: &str = "00000000-0000-0000-0000-000000000005";
|
||||
pub static _UUID_IDM_ACCOUNT_WRITE_PRIV: &str = "00000000-0000-0000-0000-000000000006";
|
||||
pub static _UUID_IDM_RADIUS_SERVERS: &str = "00000000-0000-0000-0000-000000000007";
|
||||
pub static _UUID_IDM_HP_ACCOUNT_READ_PRIV: &str = "00000000-0000-0000-0000-000000000008";
|
||||
pub static _UUID_IDM_HP_ACCOUNT_WRITE_PRIV: &str = "00000000-0000-0000-0000-000000000009";
|
||||
pub static _UUID_IDM_SCHEMA_MANAGE_PRIV: &str = "00000000-0000-0000-0000-000000000010";
|
||||
pub static _UUID_IDM_ACP_MANAGE_PRIV: &str = "00000000-0000-0000-0000-000000000011";
|
||||
pub static _UUID_IDM_HP_GROUP_WRITE_PRIV: &str = "00000000-0000-0000-0000-000000000012";
|
||||
pub static _UUID_IDM_PEOPLE_MANAGE_PRIV: &str = "00000000-0000-0000-0000-000000000013";
|
||||
pub static _UUID_IDM_ACCOUNT_MANAGE_PRIV: &str = "00000000-0000-0000-0000-000000000014";
|
||||
pub static _UUID_IDM_GROUP_MANAGE_PRIV: &str = "00000000-0000-0000-0000-000000000015";
|
||||
pub static _UUID_IDM_HP_ACCOUNT_MANAGE_PRIV: &str = "00000000-0000-0000-0000-000000000016";
|
||||
pub static _UUID_IDM_HP_GROUP_MANAGE_PRIV: &str = "00000000-0000-0000-0000-000000000017";
|
||||
pub static _UUID_IDM_ADMIN_V1: &str = "00000000-0000-0000-0000-000000000018";
|
||||
pub static _UUID_SYSTEM_ADMINS: &str = "00000000-0000-0000-0000-000000000019";
|
||||
// TODO
|
||||
pub static UUID_DOMAIN_ADMINS: &str = "00000000-0000-0000-0000-000000000020";
|
||||
pub static _UUID_IDM_ACCOUNT_UNIX_EXTEND_PRIV: &str = "00000000-0000-0000-0000-000000000021";
|
||||
pub static _UUID_IDM_GROUP_UNIX_EXTEND_PRIV: &str = "00000000-0000-0000-0000-000000000022";
|
||||
pub static _UUID_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV: &str =
|
||||
"00000000-0000-0000-0000-000000000023";
|
||||
pub static _UUID_IDM_PEOPLE_EXTEND_PRIV: &str = "00000000-0000-0000-0000-000000000024";
|
||||
//
|
||||
pub static _UUID_IDM_HIGH_PRIVILEGE: &str = "00000000-0000-0000-0000-000000001000";
|
||||
|
||||
// Builtin schema
|
||||
pub static UUID_SCHEMA_ATTR_CLASS: &str = "00000000-0000-0000-0000-ffff00000000";
|
||||
pub static UUID_SCHEMA_ATTR_UUID: &str = "00000000-0000-0000-0000-ffff00000001";
|
||||
pub static UUID_SCHEMA_ATTR_NAME: &str = "00000000-0000-0000-0000-ffff00000002";
|
||||
pub static UUID_SCHEMA_ATTR_SPN: &str = "00000000-0000-0000-0000-ffff00000003";
|
||||
pub static UUID_SCHEMA_ATTR_DESCRIPTION: &str = "00000000-0000-0000-0000-ffff00000004";
|
||||
pub static UUID_SCHEMA_ATTR_MULTIVALUE: &str = "00000000-0000-0000-0000-ffff00000005";
|
||||
pub static UUID_SCHEMA_ATTR_UNIQUE: &str = "00000000-0000-0000-0000-ffff00000047";
|
||||
pub static UUID_SCHEMA_ATTR_INDEX: &str = "00000000-0000-0000-0000-ffff00000006";
|
||||
pub static UUID_SCHEMA_ATTR_SYNTAX: &str = "00000000-0000-0000-0000-ffff00000007";
|
||||
pub static UUID_SCHEMA_ATTR_SYSTEMMAY: &str = "00000000-0000-0000-0000-ffff00000008";
|
||||
pub static UUID_SCHEMA_ATTR_MAY: &str = "00000000-0000-0000-0000-ffff00000009";
|
||||
pub static UUID_SCHEMA_ATTR_SYSTEMMUST: &str = "00000000-0000-0000-0000-ffff00000010";
|
||||
pub static UUID_SCHEMA_ATTR_MUST: &str = "00000000-0000-0000-0000-ffff00000011";
|
||||
pub static UUID_SCHEMA_ATTR_MEMBEROF: &str = "00000000-0000-0000-0000-ffff00000012";
|
||||
pub static UUID_SCHEMA_ATTR_MEMBER: &str = "00000000-0000-0000-0000-ffff00000013";
|
||||
pub static UUID_SCHEMA_ATTR_DIRECTMEMBEROF: &str = "00000000-0000-0000-0000-ffff00000014";
|
||||
pub static UUID_SCHEMA_ATTR_VERSION: &str = "00000000-0000-0000-0000-ffff00000015";
|
||||
pub static UUID_SCHEMA_ATTR_DOMAIN: &str = "00000000-0000-0000-0000-ffff00000016";
|
||||
pub static UUID_SCHEMA_ATTR_ACP_ENABLE: &str = "00000000-0000-0000-0000-ffff00000017";
|
||||
pub static UUID_SCHEMA_ATTR_ACP_RECEIVER: &str = "00000000-0000-0000-0000-ffff00000018";
|
||||
pub static UUID_SCHEMA_ATTR_ACP_TARGETSCOPE: &str = "00000000-0000-0000-0000-ffff00000019";
|
||||
pub static UUID_SCHEMA_ATTR_ACP_SEARCH_ATTR: &str = "00000000-0000-0000-0000-ffff00000020";
|
||||
pub static UUID_SCHEMA_ATTR_ACP_CREATE_CLASS: &str = "00000000-0000-0000-0000-ffff00000021";
|
||||
pub static UUID_SCHEMA_ATTR_ACP_CREATE_ATTR: &str = "00000000-0000-0000-0000-ffff00000022";
|
||||
pub static UUID_SCHEMA_ATTR_ACP_MODIFY_REMOVEDATTR: &str = "00000000-0000-0000-0000-ffff00000023";
|
||||
pub static UUID_SCHEMA_ATTR_ACP_MODIFY_PRESENTATTR: &str = "00000000-0000-0000-0000-ffff00000024";
|
||||
pub static UUID_SCHEMA_ATTR_ACP_MODIFY_CLASS: &str = "00000000-0000-0000-0000-ffff00000025";
|
||||
pub static UUID_SCHEMA_CLASS_ATTRIBUTETYPE: &str = "00000000-0000-0000-0000-ffff00000026";
|
||||
pub static UUID_SCHEMA_CLASS_CLASSTYPE: &str = "00000000-0000-0000-0000-ffff00000027";
|
||||
pub static UUID_SCHEMA_CLASS_OBJECT: &str = "00000000-0000-0000-0000-ffff00000028";
|
||||
pub static UUID_SCHEMA_CLASS_EXTENSIBLEOBJECT: &str = "00000000-0000-0000-0000-ffff00000029";
|
||||
pub static UUID_SCHEMA_CLASS_MEMBEROF: &str = "00000000-0000-0000-0000-ffff00000030";
|
||||
pub static UUID_SCHEMA_CLASS_RECYCLED: &str = "00000000-0000-0000-0000-ffff00000031";
|
||||
pub static UUID_SCHEMA_CLASS_TOMBSTONE: &str = "00000000-0000-0000-0000-ffff00000032";
|
||||
pub static UUID_SCHEMA_CLASS_SYSTEM_INFO: &str = "00000000-0000-0000-0000-ffff00000033";
|
||||
pub static UUID_SCHEMA_CLASS_ACCESS_CONTROL_PROFILE: &str = "00000000-0000-0000-0000-ffff00000034";
|
||||
pub static UUID_SCHEMA_CLASS_ACCESS_CONTROL_SEARCH: &str = "00000000-0000-0000-0000-ffff00000035";
|
||||
pub static UUID_SCHEMA_CLASS_ACCESS_CONTROL_DELETE: &str = "00000000-0000-0000-0000-ffff00000036";
|
||||
pub static UUID_SCHEMA_CLASS_ACCESS_CONTROL_MODIFY: &str = "00000000-0000-0000-0000-ffff00000037";
|
||||
pub static UUID_SCHEMA_CLASS_ACCESS_CONTROL_CREATE: &str = "00000000-0000-0000-0000-ffff00000038";
|
||||
pub static UUID_SCHEMA_CLASS_SYSTEM: &str = "00000000-0000-0000-0000-ffff00000039";
|
||||
pub static UUID_SCHEMA_ATTR_DISPLAYNAME: &str = "00000000-0000-0000-0000-ffff00000040";
|
||||
pub static UUID_SCHEMA_ATTR_MAIL: &str = "00000000-0000-0000-0000-ffff00000041";
|
||||
pub static UUID_SCHEMA_ATTR_SSH_PUBLICKEY: &str = "00000000-0000-0000-0000-ffff00000042";
|
||||
pub static UUID_SCHEMA_ATTR_PRIMARY_CREDENTIAL: &str = "00000000-0000-0000-0000-ffff00000043";
|
||||
pub static UUID_SCHEMA_CLASS_PERSON: &str = "00000000-0000-0000-0000-ffff00000044";
|
||||
pub static UUID_SCHEMA_CLASS_GROUP: &str = "00000000-0000-0000-0000-ffff00000045";
|
||||
pub static UUID_SCHEMA_CLASS_ACCOUNT: &str = "00000000-0000-0000-0000-ffff00000046";
|
||||
// GAP - 47
|
||||
pub static UUID_SCHEMA_ATTR_ATTRIBUTENAME: &str = "00000000-0000-0000-0000-ffff00000048";
|
||||
pub static UUID_SCHEMA_ATTR_CLASSNAME: &str = "00000000-0000-0000-0000-ffff00000049";
|
||||
pub static UUID_SCHEMA_ATTR_LEGALNAME: &str = "00000000-0000-0000-0000-ffff00000050";
|
||||
pub static UUID_SCHEMA_ATTR_RADIUS_SECRET: &str = "00000000-0000-0000-0000-ffff00000051";
|
||||
pub static UUID_SCHEMA_CLASS_DOMAIN_INFO: &str = "00000000-0000-0000-0000-ffff00000052";
|
||||
pub static UUID_SCHEMA_ATTR_DOMAIN_NAME: &str = "00000000-0000-0000-0000-ffff00000053";
|
||||
pub static UUID_SCHEMA_ATTR_DOMAIN_UUID: &str = "00000000-0000-0000-0000-ffff00000054";
|
||||
pub static UUID_SCHEMA_ATTR_DOMAIN_SSID: &str = "00000000-0000-0000-0000-ffff00000055";
|
||||
|
||||
pub static UUID_SCHEMA_ATTR_GIDNUMBER: &str = "00000000-0000-0000-0000-ffff00000056";
|
||||
pub static UUID_SCHEMA_CLASS_POSIXACCOUNT: &str = "00000000-0000-0000-0000-ffff00000057";
|
||||
pub static UUID_SCHEMA_CLASS_POSIXGROUP: &str = "00000000-0000-0000-0000-ffff00000058";
|
||||
pub static UUID_SCHEMA_ATTR_BADLIST_PASSWORD: &str = "00000000-0000-0000-0000-ffff00000059";
|
||||
pub static UUID_SCHEMA_CLASS_SYSTEM_CONFIG: &str = "00000000-0000-0000-0000-ffff00000060";
|
||||
pub static UUID_SCHEMA_ATTR_LOGINSHELL: &str = "00000000-0000-0000-0000-ffff00000061";
|
||||
pub static UUID_SCHEMA_ATTR_UNIX_PASSWORD: &str = "00000000-0000-0000-0000-ffff00000062";
|
||||
pub static UUID_SCHEMA_ATTR_LAST_MOD_CID: &str = "00000000-0000-0000-0000-ffff00000063";
|
||||
pub static UUID_SCHEMA_ATTR_PHANTOM: &str = "00000000-0000-0000-0000-ffff00000064";
|
||||
pub static UUID_SCHEMA_ATTR_CLAIM: &str = "00000000-0000-0000-0000-ffff00000065";
|
||||
pub static UUID_SCHEMA_ATTR_PASSWORD_IMPORT: &str = "00000000-0000-0000-0000-ffff00000066";
|
||||
|
||||
// System and domain infos
|
||||
// I'd like to strongly criticise william of the past for fucking up these allocations.
|
||||
pub static _UUID_SYSTEM_INFO: &str = "00000000-0000-0000-0000-ffffff000001";
|
||||
pub static UUID_DOMAIN_INFO: &str = "00000000-0000-0000-0000-ffffff000025";
|
||||
// DO NOT allocate here, allocate below.
|
||||
|
||||
// Access controls
|
||||
// skip 00 / 01 - see system info
|
||||
pub static _UUID_IDM_ADMINS_ACP_RECYCLE_SEARCH_V1: &str = "00000000-0000-0000-0000-ffffff000002";
|
||||
pub static _UUID_IDM_ADMINS_ACP_REVIVE_V1: &str = "00000000-0000-0000-0000-ffffff000003";
|
||||
pub static _UUID_IDM_SELF_ACP_READ_V1: &str = "00000000-0000-0000-0000-ffffff000004";
|
||||
pub static _UUID_IDM_ALL_ACP_READ_V1: &str = "00000000-0000-0000-0000-ffffff000006";
|
||||
pub static _UUID_IDM_ACP_PEOPLE_READ_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000007";
|
||||
pub static _UUID_IDM_ACP_PEOPLE_WRITE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000008";
|
||||
pub static _UUID_IDM_ACP_GROUP_WRITE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000009";
|
||||
pub static _UUID_IDM_ACP_ACCOUNT_READ_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000010";
|
||||
pub static _UUID_IDM_ACP_ACCOUNT_WRITE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000011";
|
||||
pub static _UUID_IDM_ACP_ACCOUNT_MANAGE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000012";
|
||||
pub static _UUID_IDM_ACP_PEOPLE_MANAGE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000013";
|
||||
pub static _UUID_IDM_ACP_RADIUS_SERVERS_V1: &str = "00000000-0000-0000-0000-ffffff000014";
|
||||
pub static _UUID_IDM_ACP_HP_ACCOUNT_READ_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000015";
|
||||
pub static _UUID_IDM_ACP_HP_ACCOUNT_WRITE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000016";
|
||||
pub static _UUID_IDM_ACP_HP_GROUP_WRITE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000017";
|
||||
pub static _UUID_IDM_ACP_SCHEMA_WRITE_ATTRS_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000018";
|
||||
pub static _UUID_IDM_ACP_ACP_MANAGE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000019";
|
||||
pub static _UUID_IDM_ACP_SCHEMA_WRITE_CLASSES_PRIV_V1: &str =
|
||||
"00000000-0000-0000-0000-ffffff000020";
|
||||
pub static _UUID_IDM_SELF_ACP_WRITE_V1: &str = "00000000-0000-0000-0000-ffffff000021";
|
||||
pub static _UUID_IDM_ACP_GROUP_MANAGE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000022";
|
||||
pub static _UUID_IDM_ACP_HP_ACCOUNT_MANAGE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000023";
|
||||
pub static _UUID_IDM_ACP_HP_GROUP_MANAGE_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000024";
|
||||
// Skip 25 - see domain info.
|
||||
pub static UUID_IDM_ACP_DOMAIN_ADMIN_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000026";
|
||||
pub static STR_UUID_SYSTEM_CONFIG: &str = "00000000-0000-0000-0000-ffffff000027";
|
||||
pub static UUID_IDM_ACP_SYSTEM_CONFIG_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000028";
|
||||
pub static _UUID_IDM_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000029";
|
||||
pub static _UUID_IDM_ACP_GROUP_UNIX_EXTEND_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000030";
|
||||
pub static _UUID_IDM_ACP_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1: &str =
|
||||
"00000000-0000-0000-0000-ffffff000031";
|
||||
pub static _UUID_IDM_ACP_PEOPLE_EXTEND_PRIV_V1: &str = "00000000-0000-0000-0000-ffffff000032";
|
||||
|
||||
// End of system ranges
|
||||
pub static STR_UUID_DOES_NOT_EXIST: &str = "00000000-0000-0000-0000-fffffffffffe";
|
||||
pub static STR_UUID_ANONYMOUS: &str = "00000000-0000-0000-0000-ffffffffffff";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref UUID_ADMIN: Uuid = Uuid::parse_str(STR_UUID_ADMIN).unwrap();
|
||||
pub static ref UUID_DOES_NOT_EXIST: Uuid = Uuid::parse_str(STR_UUID_DOES_NOT_EXIST).unwrap();
|
||||
pub static ref UUID_ANONYMOUS: Uuid = Uuid::parse_str(STR_UUID_ANONYMOUS).unwrap();
|
||||
pub static ref UUID_SYSTEM_CONFIG: Uuid = Uuid::parse_str(STR_UUID_SYSTEM_CONFIG).unwrap();
|
||||
}
|
|
@ -19,11 +19,11 @@ use crate::actors::v1_read::{
|
|||
};
|
||||
use crate::actors::v1_write::QueryServerWriteV1;
|
||||
use crate::actors::v1_write::{
|
||||
AppendAttributeMessage, CreateMessage, DeleteMessage, IdmAccountSetPasswordMessage,
|
||||
IdmAccountUnixExtendMessage, IdmAccountUnixSetCredMessage, IdmGroupUnixExtendMessage,
|
||||
InternalCredentialSetMessage, InternalDeleteMessage, InternalRegenerateRadiusMessage,
|
||||
InternalSshKeyCreateMessage, ModifyMessage, PurgeAttributeMessage, RemoveAttributeValueMessage,
|
||||
ReviveRecycledMessage, SetAttributeMessage,
|
||||
AppendAttributeMessage, CreateMessage, DeleteMessage, IdmAccountPersonExtendMessage,
|
||||
IdmAccountSetPasswordMessage, IdmAccountUnixExtendMessage, IdmAccountUnixSetCredMessage,
|
||||
IdmGroupUnixExtendMessage, InternalCredentialSetMessage, InternalDeleteMessage,
|
||||
InternalRegenerateRadiusMessage, InternalSshKeyCreateMessage, ModifyMessage,
|
||||
PurgeAttributeMessage, RemoveAttributeValueMessage, ReviveRecycledMessage, SetAttributeMessage,
|
||||
};
|
||||
use crate::async_log;
|
||||
use crate::audit::AuditScope;
|
||||
|
@ -416,6 +416,29 @@ async fn schema_classtype_get_id(
|
|||
}
|
||||
}
|
||||
|
||||
// == person ==
|
||||
|
||||
async fn person_get((session, state): (Session, Data<AppState>)) -> HttpResponse {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("person")));
|
||||
json_rest_event_get(session, state, filter, None).await
|
||||
}
|
||||
|
||||
async fn person_post(
|
||||
(obj, session, state): (Json<ProtoEntry>, Session, Data<AppState>),
|
||||
) -> HttpResponse {
|
||||
let classes = vec!["account".to_string(), "object".to_string()];
|
||||
json_rest_event_post(obj.into_inner(), session, state, classes).await
|
||||
}
|
||||
|
||||
async fn person_id_get(
|
||||
(path, session, state): (Path<String>, Session, Data<AppState>),
|
||||
) -> HttpResponse {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("person")));
|
||||
json_rest_event_get_id(path, session, state, filter, None).await
|
||||
}
|
||||
|
||||
// == account ==
|
||||
|
||||
async fn account_get((session, state): (Session, Data<AppState>)) -> HttpResponse {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
json_rest_event_get(session, state, filter, None).await
|
||||
|
@ -640,6 +663,19 @@ async fn account_get_id_radius_token(
|
|||
}
|
||||
}
|
||||
|
||||
async fn account_post_id_person_extend(
|
||||
(path, session, state): (Path<String>, Session, Data<AppState>),
|
||||
) -> HttpResponse {
|
||||
let uat = get_current_user(&session);
|
||||
let uuid_or_name = path.into_inner();
|
||||
let m_obj = IdmAccountPersonExtendMessage { uat, uuid_or_name };
|
||||
match state.qe_w.send(m_obj).await {
|
||||
Ok(Ok(r)) => HttpResponse::Ok().json(r),
|
||||
Ok(Err(e)) => operation_error_to_response(e),
|
||||
Err(_) => HttpResponse::InternalServerError().json("mailbox failure"),
|
||||
}
|
||||
}
|
||||
|
||||
async fn account_post_id_unix(
|
||||
(obj, path, session, state): (
|
||||
Json<AccountUnixExtend>,
|
||||
|
@ -1493,6 +1529,21 @@ pub fn create_server_core(config: Configuration) {
|
|||
web::get().to(do_nothing),
|
||||
),
|
||||
)
|
||||
.service(
|
||||
web::scope("/v1/person")
|
||||
.route("", web::get().to(person_get))
|
||||
.route("", web::post().to(person_post))
|
||||
.route("/{id}", web::get().to(person_id_get)), /*
|
||||
.route("/{id}", web::delete().to(account_id_delete))
|
||||
.route("/{id}/_attr/{attr}", web::get().to(account_id_get_attr))
|
||||
.route("/{id}/_attr/{attr}", web::post().to(account_id_post_attr))
|
||||
.route("/{id}/_attr/{attr}", web::put().to(account_id_put_attr))
|
||||
.route(
|
||||
"/{id}/_attr/{attr}",
|
||||
web::delete().to(account_id_delete_attr),
|
||||
)
|
||||
*/
|
||||
)
|
||||
.service(
|
||||
web::scope("/v1/account")
|
||||
.route("", web::get().to(account_get))
|
||||
|
@ -1506,6 +1557,10 @@ pub fn create_server_core(config: Configuration) {
|
|||
"/{id}/_attr/{attr}",
|
||||
web::delete().to(account_id_delete_attr),
|
||||
)
|
||||
.route(
|
||||
"/{id}/_person/_extend",
|
||||
web::post().to(account_post_id_person_extend),
|
||||
)
|
||||
.route("/{id}/_lock", web::get().to(do_nothing))
|
||||
.route("/{id}/_credential", web::get().to(do_nothing))
|
||||
.route(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::be::dbvalue::{DbCredV1, DbPasswordV1};
|
||||
use base64;
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::pkcs5::pbkdf2_hmac;
|
||||
use rand::prelude::*;
|
||||
|
@ -24,6 +25,8 @@ const PBKDF2_SALT_LEN: usize = 24;
|
|||
// 64 * u8 -> 512 bits of out.
|
||||
const PBKDF2_KEY_LEN: usize = 64;
|
||||
|
||||
const PBKDF2_IMPORT_MIN_LEN: usize = 32;
|
||||
|
||||
// Why PBKDF2? Rust's bcrypt has a number of hardcodings like max pw len of 72
|
||||
// I don't really feel like adding in so many restrictions, so I'll use
|
||||
// pbkdf2 in openssl because it doesn't have the same limits.
|
||||
|
@ -50,6 +53,40 @@ impl TryFrom<DbPasswordV1> for Password {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Password {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
// There is probably a more efficent way to try this given different types?
|
||||
|
||||
// test django - algo$salt$hash
|
||||
let django_pbkdf: Vec<&str> = value.split('$').collect();
|
||||
if django_pbkdf.len() == 4 {
|
||||
let algo = django_pbkdf[0];
|
||||
let cost = django_pbkdf[1];
|
||||
let salt = django_pbkdf[2];
|
||||
let hash = django_pbkdf[3];
|
||||
match algo {
|
||||
"pbkdf2_sha256" => {
|
||||
let c = usize::from_str_radix(cost, 10).map_err(|_| ())?;
|
||||
let s: Vec<_> = salt.as_bytes().iter().map(|b| *b).collect();
|
||||
let h = base64::decode(hash).map_err(|_| ())?;
|
||||
if h.len() < PBKDF2_IMPORT_MIN_LEN {
|
||||
return Err(());
|
||||
}
|
||||
return Ok(Password {
|
||||
material: KDF::PBKDF2(c, s, h),
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing matched to this point.
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Password {
|
||||
fn new_pbkdf2(cleartext: &str) -> KDF {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
@ -78,7 +115,11 @@ impl Password {
|
|||
pub fn verify(&self, cleartext: &str) -> bool {
|
||||
match &self.material {
|
||||
KDF::PBKDF2(cost, salt, key) => {
|
||||
let mut chal_key: Vec<u8> = (0..PBKDF2_KEY_LEN).map(|_| 0).collect();
|
||||
// We have to get the number of bits to derive from our stored hash
|
||||
// as some imported hash types may have variable lengths
|
||||
let key_len = key.len();
|
||||
debug_assert!(key_len >= PBKDF2_IMPORT_MIN_LEN);
|
||||
let mut chal_key: Vec<u8> = (0..key_len).map(|_| 0).collect();
|
||||
pbkdf2_hmac(
|
||||
cleartext.as_bytes(),
|
||||
salt.as_slice(),
|
||||
|
@ -189,6 +230,22 @@ impl Credential {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_password(&self, pw: Password) -> Self {
|
||||
Credential {
|
||||
password: Some(pw),
|
||||
claims: self.claims.clone(),
|
||||
uuid: self.uuid.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_from_password(pw: Password) -> Self {
|
||||
Credential {
|
||||
password: Some(pw),
|
||||
claims: Vec::new(),
|
||||
uuid: Uuid::new_v4(),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn add_claim(&mut self) {
|
||||
}
|
||||
|
@ -213,6 +270,7 @@ impl Credential {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::credential::*;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
fn test_credential_simple() {
|
||||
|
@ -223,4 +281,17 @@ mod tests {
|
|||
assert!(!c.verify_password("It Works!"));
|
||||
assert!(!c.verify_password("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_password_from_invalid() {
|
||||
assert!(Password::try_from("password").is_err())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_password_from_django_pbkdf2_sha256() {
|
||||
let im_pw = "pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w=";
|
||||
let password = "eicieY7ahchaoCh0eeTa";
|
||||
let r = Password::try_from(im_pw).expect("Failed to parse");
|
||||
assert!(r.verify(password));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -641,6 +641,14 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
|||
Some(a_schema) => {
|
||||
// Now, for each type we do a *full* check of the syntax
|
||||
// and validity of the ava.
|
||||
if a_schema.phantom {
|
||||
debug!(
|
||||
"Attempt to add phantom attribute to extensible: {}",
|
||||
attr_name
|
||||
);
|
||||
return Err(SchemaError::PhantomAttribute);
|
||||
}
|
||||
|
||||
let r = a_schema.validate_ava(avas);
|
||||
match r {
|
||||
Ok(_) => {}
|
||||
|
@ -657,6 +665,10 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// Note - we do NOT need to check phantom attributes here because they are
|
||||
// not allowed to exist in the class, which means a phantom attribute can't
|
||||
// be in the may/must set, and would FAIL our normal checks anyway.
|
||||
|
||||
// We clone string here, but it's so we can check all
|
||||
// the values in "may" ar here - so we can't avoid this look up. What we
|
||||
// could do though, is have &String based on the schemaattribute though?;
|
||||
|
@ -1730,6 +1742,10 @@ where
|
|||
self.attrs.remove(attr);
|
||||
}
|
||||
|
||||
pub fn pop_ava(&mut self, attr: &str) -> Option<BTreeSet<Value>> {
|
||||
self.attrs.remove(attr)
|
||||
}
|
||||
|
||||
/// Overwrite the existing avas.
|
||||
pub fn set_avas(&mut self, attr: &str, values: Vec<Value>) {
|
||||
// Overwrite the existing value, build a tree from the list.
|
||||
|
|
|
@ -313,8 +313,6 @@ mod tests {
|
|||
|
||||
let e: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"name": ["testperson"],
|
||||
|
@ -351,8 +349,6 @@ mod tests {
|
|||
|
||||
let e: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"name": ["testperson"],
|
||||
|
@ -381,8 +377,6 @@ mod tests {
|
|||
|
||||
let e: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"name": ["testperson"],
|
||||
|
@ -413,8 +407,6 @@ mod tests {
|
|||
|
||||
let e: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"name": ["testperson"],
|
||||
|
|
|
@ -13,6 +13,7 @@ mod domain;
|
|||
mod failure;
|
||||
mod gidnumber;
|
||||
mod memberof;
|
||||
mod password_import;
|
||||
mod protected;
|
||||
mod recycle;
|
||||
mod refint;
|
||||
|
@ -282,6 +283,15 @@ impl Plugins {
|
|||
) -> Result<(), OperationError> {
|
||||
audit_segment!(au, || {
|
||||
run_pre_create_transform_plugin!(au, qs, cand, ce, base::Base)
|
||||
.and_then(|_| {
|
||||
run_pre_create_transform_plugin!(
|
||||
au,
|
||||
qs,
|
||||
cand,
|
||||
ce,
|
||||
password_import::PasswordImport
|
||||
)
|
||||
})
|
||||
.and_then(|_| {
|
||||
run_pre_create_transform_plugin!(au, qs, cand, ce, gidnumber::GidNumber)
|
||||
})
|
||||
|
@ -340,6 +350,9 @@ impl Plugins {
|
|||
audit_segment!(au, || {
|
||||
run_pre_modify_plugin!(au, qs, cand, me, protected::Protected)
|
||||
.and_then(|_| run_pre_modify_plugin!(au, qs, cand, me, base::Base))
|
||||
.and_then(|_| {
|
||||
run_pre_modify_plugin!(au, qs, cand, me, password_import::PasswordImport)
|
||||
})
|
||||
.and_then(|_| run_pre_modify_plugin!(au, qs, cand, me, gidnumber::GidNumber))
|
||||
.and_then(|_| run_pre_modify_plugin!(au, qs, cand, me, spn::Spn))
|
||||
// attr unique should always be last
|
||||
|
|
225
kanidmd/src/lib/plugins/password_import.rs
Normal file
225
kanidmd/src/lib/plugins/password_import.rs
Normal file
|
@ -0,0 +1,225 @@
|
|||
// Transform password import requests into proper kanidm credentials.
|
||||
use crate::audit::AuditScope;
|
||||
use crate::credential::{Credential, Password};
|
||||
use crate::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew};
|
||||
use crate::event::{CreateEvent, ModifyEvent};
|
||||
use crate::plugins::Plugin;
|
||||
use crate::server::QueryServerWriteTransaction;
|
||||
use crate::value::Value;
|
||||
use kanidm_proto::v1::{OperationError, PluginError};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
pub struct PasswordImport {}
|
||||
|
||||
impl Plugin for PasswordImport {
|
||||
fn id() -> &'static str {
|
||||
"plugin_password_import"
|
||||
}
|
||||
|
||||
fn pre_create_transform(
|
||||
_au: &mut AuditScope,
|
||||
_qs: &mut QueryServerWriteTransaction,
|
||||
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
|
||||
_ce: &CreateEvent,
|
||||
) -> Result<(), OperationError> {
|
||||
cand.iter_mut()
|
||||
.try_for_each(|e| {
|
||||
// is there a password we are trying to import?
|
||||
let vs = match e.pop_ava("password_import") {
|
||||
Some(vs) => vs,
|
||||
None => return Ok(()),
|
||||
};
|
||||
// if there are multiple, fail.
|
||||
if vs.len() > 1 {
|
||||
return Err(OperationError::Plugin(PluginError::PasswordImport("multiple password_imports specified".to_string())))
|
||||
}
|
||||
// Until upstream btreeset supports first(), we need to convert to a vec.
|
||||
let vs: Vec<_> = vs.into_iter().collect();
|
||||
|
||||
debug_assert!(vs.len() >= 1);
|
||||
let im_pw = vs.first()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.ok_or(OperationError::Plugin(PluginError::PasswordImport("password_import has incorrect value type".to_string())))?;
|
||||
|
||||
// convert the import_password to a cred
|
||||
let pw = Password::try_from(im_pw)
|
||||
.map_err(|_| OperationError::Plugin(PluginError::PasswordImport("password_import was unable to convert hash format".to_string())))?;
|
||||
|
||||
// does the entry have a primary cred?
|
||||
match e.get_ava_single_credential("primary_credential") {
|
||||
Some(_c) => {
|
||||
Err(
|
||||
OperationError::Plugin(PluginError::PasswordImport(
|
||||
"password_import - impossible state, how did you get a credential into a create!?".to_string()))
|
||||
)
|
||||
}
|
||||
None => {
|
||||
// just set it then!
|
||||
let c = Credential::new_from_password(pw);
|
||||
e.set_avas("primary_credential",
|
||||
vec![Value::new_credential("primary", c)]);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn pre_modify(
|
||||
_au: &mut AuditScope,
|
||||
_qs: &mut QueryServerWriteTransaction,
|
||||
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
|
||||
_me: &ModifyEvent,
|
||||
) -> Result<(), OperationError> {
|
||||
cand.iter_mut().try_for_each(|e| {
|
||||
// is there a password we are trying to import?
|
||||
let vs = match e.pop_ava("password_import") {
|
||||
Some(vs) => vs,
|
||||
None => return Ok(()),
|
||||
};
|
||||
// if there are multiple, fail.
|
||||
if vs.len() > 1 {
|
||||
return Err(OperationError::Plugin(PluginError::PasswordImport(
|
||||
"multiple password_imports specified".to_string(),
|
||||
)));
|
||||
}
|
||||
// Until upstream btreeset supports first(), we need to convert to a vec.
|
||||
let vs: Vec<_> = vs.into_iter().collect();
|
||||
|
||||
debug_assert!(vs.len() >= 1);
|
||||
let im_pw = vs.first().unwrap().to_str().ok_or(OperationError::Plugin(
|
||||
PluginError::PasswordImport("password_import has incorrect value type".to_string()),
|
||||
))?;
|
||||
|
||||
// convert the import_password to a cred
|
||||
let pw = Password::try_from(im_pw).map_err(|_| {
|
||||
OperationError::Plugin(PluginError::PasswordImport(
|
||||
"password_import was unable to convert hash format".to_string(),
|
||||
))
|
||||
})?;
|
||||
|
||||
// does the entry have a primary cred?
|
||||
match e.get_ava_single_credential("primary_credential") {
|
||||
Some(c) => {
|
||||
// This is the major diff to create, we can update in place!
|
||||
let c = c.update_password(pw);
|
||||
e.set_avas(
|
||||
"primary_credential",
|
||||
vec![Value::new_credential("primary", c)],
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
// just set it then!
|
||||
let c = Credential::new_from_password(pw);
|
||||
e.set_avas(
|
||||
"primary_credential",
|
||||
vec![Value::new_credential("primary", c)],
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::credential::Credential;
|
||||
use crate::entry::{Entry, EntryInit, EntryNew};
|
||||
use crate::modify::{Modify, ModifyList};
|
||||
use crate::value::{PartialValue, Value};
|
||||
|
||||
static IMPORT_HASH: &'static str =
|
||||
"pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w=";
|
||||
// static IMPORT_PASSWORD: &'static str = "eicieY7ahchaoCh0eeTa";
|
||||
|
||||
#[test]
|
||||
fn test_pre_create_password_import_1() {
|
||||
let preload: Vec<Entry<EntryInit, EntryNew>> = Vec::new();
|
||||
|
||||
let e: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["person", "account"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["d2b496bd-8493-47b7-8142-f568b5cf47ee"],
|
||||
"password_import": ["pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w="]
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
||||
let create = vec![e.clone()];
|
||||
|
||||
run_create_test!(Ok(()), preload, create, None, |_, _| {});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modify_password_import_1() {
|
||||
// Add another uuid to a type
|
||||
let ea: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["account", "person"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["d2b496bd-8493-47b7-8142-f568b5cf47ee"]
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
||||
let preload = vec![ea];
|
||||
|
||||
run_modify_test!(
|
||||
Ok(()),
|
||||
preload,
|
||||
filter!(f_eq("name", PartialValue::new_iutf8s("testperson"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
"password_import".to_string(),
|
||||
Value::from(IMPORT_HASH)
|
||||
)]),
|
||||
None,
|
||||
|_, _| {}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modify_password_import_2() {
|
||||
// Add another uuid to a type
|
||||
let mut ea: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["account", "person"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["d2b496bd-8493-47b7-8142-f568b5cf47ee"]
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
||||
let c = Credential::new_password_only("password");
|
||||
ea.add_ava("primary_credential", &Value::new_credential("primary", c));
|
||||
|
||||
let preload = vec![ea];
|
||||
|
||||
run_modify_test!(
|
||||
Ok(()),
|
||||
preload,
|
||||
filter!(f_eq("name", PartialValue::new_iutf8s("testperson"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
"password_import".to_string(),
|
||||
Value::from(IMPORT_HASH)
|
||||
)]),
|
||||
None,
|
||||
|_, _| {}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -94,6 +94,7 @@ pub struct SchemaAttribute {
|
|||
pub description: String,
|
||||
pub multivalue: bool,
|
||||
pub unique: bool,
|
||||
pub phantom: bool,
|
||||
pub index: Vec<IndexType>,
|
||||
pub syntax: SyntaxType,
|
||||
}
|
||||
|
@ -144,6 +145,7 @@ impl SchemaAttribute {
|
|||
.get_ava_single_bool("unique")
|
||||
.ok_or_else(|| OperationError::InvalidSchemaState("missing unique".to_string()))
|
||||
);
|
||||
let phantom = value.get_ava_single_bool("phantom").unwrap_or(false);
|
||||
// index vec
|
||||
// even if empty, it SHOULD be present ... (is that value to put an empty set?)
|
||||
// The get_ava_opt_index handles the optional case for us :)
|
||||
|
@ -169,6 +171,7 @@ impl SchemaAttribute {
|
|||
description,
|
||||
multivalue,
|
||||
unique,
|
||||
phantom,
|
||||
index,
|
||||
syntax,
|
||||
})
|
||||
|
@ -466,68 +469,35 @@ pub trait SchemaTransaction {
|
|||
// Does this need to validate anything further at all? The UUID
|
||||
// will be checked as part of the schema migration on startup, so I think
|
||||
// just that all the content is sane is fine.
|
||||
for class in class_snapshot.values() {
|
||||
class_snapshot.values().for_each(|class| {
|
||||
// report the class we are checking
|
||||
for a in &class.systemmay {
|
||||
// report the attribute.
|
||||
/*
|
||||
audit_log!(
|
||||
audit,
|
||||
"validate systemmay class:attr -> {}:{}",
|
||||
class.name,
|
||||
a
|
||||
);
|
||||
*/
|
||||
if !attribute_snapshot.contains_key(a) {
|
||||
res.push(Err(ConsistencyError::SchemaClassMissingAttribute(
|
||||
class.name.clone(),
|
||||
a.clone(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
for a in &class.may {
|
||||
// report the attribute.
|
||||
/*
|
||||
audit_log!(audit, "validate may class:attr -> {}:{}", class.name, a);
|
||||
*/
|
||||
if !attribute_snapshot.contains_key(a) {
|
||||
res.push(Err(ConsistencyError::SchemaClassMissingAttribute(
|
||||
class.name.clone(),
|
||||
a.clone(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
for a in &class.systemmust {
|
||||
// report the attribute.
|
||||
/*
|
||||
audit_log!(
|
||||
audit,
|
||||
"validate systemmust class:attr -> {}:{}",
|
||||
class.name,
|
||||
a
|
||||
);
|
||||
*/
|
||||
if !attribute_snapshot.contains_key(a) {
|
||||
res.push(Err(ConsistencyError::SchemaClassMissingAttribute(
|
||||
class.name.clone(),
|
||||
a.clone(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
for a in &class.must {
|
||||
// report the attribute.
|
||||
/*
|
||||
audit_log!(audit, "validate must class:attr -> {}:{}", class.name, a);
|
||||
*/
|
||||
if !attribute_snapshot.contains_key(a) {
|
||||
res.push(Err(ConsistencyError::SchemaClassMissingAttribute(
|
||||
class.name.clone(),
|
||||
a.clone(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class
|
||||
.systemmay
|
||||
.iter()
|
||||
.chain(class.may.iter())
|
||||
.chain(class.systemmust.iter())
|
||||
.chain(class.must.iter())
|
||||
.for_each(|a| {
|
||||
match attribute_snapshot.get(a) {
|
||||
Some(attr) => {
|
||||
// We have the attribute, ensure it's not a phantom.
|
||||
if attr.phantom {
|
||||
res.push(Err(ConsistencyError::SchemaClassPhantomAttribute(
|
||||
class.name.clone(),
|
||||
a.clone(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// No such attr, something is missing!
|
||||
res.push(Err(ConsistencyError::SchemaClassMissingAttribute(
|
||||
class.name.clone(),
|
||||
a.clone(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
})
|
||||
}); // end for
|
||||
res
|
||||
}
|
||||
|
||||
|
@ -621,16 +591,13 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_classes(
|
||||
&mut self,
|
||||
attributetypes: Vec<SchemaClass>,
|
||||
) -> Result<(), OperationError> {
|
||||
pub fn update_classes(&mut self, classtypes: Vec<SchemaClass>) -> Result<(), OperationError> {
|
||||
// purge all old attributes.
|
||||
self.classes.clear();
|
||||
// Update with new ones.
|
||||
// Do we need to check for dups?
|
||||
// No, they'll over-write each other ... but we do need name uniqueness.
|
||||
attributetypes.into_iter().for_each(|a| {
|
||||
classtypes.into_iter().for_each(|a| {
|
||||
self.classes.insert(a.name.clone(), a);
|
||||
});
|
||||
Ok(())
|
||||
|
@ -677,6 +644,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("The set of classes defining an object"),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -692,6 +660,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
// Uniqueness is handled by base.rs, not attrunique here due to
|
||||
// needing to check recycled objects too.
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UUID,
|
||||
},
|
||||
|
@ -707,6 +676,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
// Uniqueness is handled by base.rs, not attrunique here due to
|
||||
// needing to check recycled objects too.
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::CID,
|
||||
},
|
||||
|
@ -720,6 +690,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("The shortform name of an object"),
|
||||
multivalue: false,
|
||||
unique: true,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -735,6 +706,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: false,
|
||||
unique: true,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::SERVICE_PRINCIPLE_NAME,
|
||||
},
|
||||
|
@ -748,6 +720,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("The name of a schema attribute"),
|
||||
multivalue: false,
|
||||
unique: true,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -761,6 +734,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("The name of a schema class"),
|
||||
multivalue: false,
|
||||
unique: true,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -774,6 +748,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("A description of an attribute, object or class"),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::UTF8STRING,
|
||||
},
|
||||
|
@ -784,6 +759,17 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("If true, this attribute is able to store multiple values rather than just a single value."),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::BOOLEAN,
|
||||
});
|
||||
self.attributes.insert(String::from("phantom"), SchemaAttribute {
|
||||
name: String::from("phantom"),
|
||||
uuid: Uuid::parse_str(UUID_SCHEMA_ATTR_PHANTOM).expect("unable to parse static uuid"),
|
||||
description: String::from("If true, this attribute must NOT be present in any may/must sets of a class as. This represents generated attributes."),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::BOOLEAN,
|
||||
});
|
||||
|
@ -793,6 +779,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("If true, this attribute must store a unique value through out the database."),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::BOOLEAN,
|
||||
});
|
||||
|
@ -807,6 +794,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::INDEX_ID,
|
||||
},
|
||||
|
@ -822,6 +810,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::SYNTAX_ID,
|
||||
},
|
||||
|
@ -837,6 +826,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -852,6 +842,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -867,6 +858,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -882,6 +874,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -896,7 +889,8 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
.expect("unable to parse static uuid"),
|
||||
description: String::from("A flag to determine if this ACP is active for application. True is enabled, and enforce. False is checked but not enforced."),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::BOOLEAN,
|
||||
},
|
||||
|
@ -913,6 +907,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY, IndexType::SUBSTRING],
|
||||
syntax: SyntaxType::JSON_FILTER,
|
||||
},
|
||||
|
@ -928,6 +923,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY, IndexType::SUBSTRING],
|
||||
syntax: SyntaxType::JSON_FILTER,
|
||||
},
|
||||
|
@ -940,7 +936,8 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
.expect("unable to parse static uuid"),
|
||||
description: String::from("The attributes that may be viewed or searched by the reciever on targetscope."),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -956,6 +953,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -971,6 +969,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -984,7 +983,8 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
.expect("unable to parse static uuid"),
|
||||
description: String::from("The set of attribute types that could be removed or purged in a modification."),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -997,7 +997,8 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
.expect("unable to parse static uuid"),
|
||||
description: String::from("The set of attribute types that could be added or asserted in a modification."),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -1010,7 +1011,8 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
.expect("unable to parse static uuid"),
|
||||
description: String::from("The set of class values that could be asserted or added to an entry. Only applies to modify::present operations on class."),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -1025,6 +1027,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("reverse group membership of the object"),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::REFERENCE_UUID,
|
||||
},
|
||||
|
@ -1038,6 +1041,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("reverse direct group membership of the object"),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::REFERENCE_UUID,
|
||||
},
|
||||
|
@ -1051,6 +1055,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("List of members of the group"),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::REFERENCE_UUID,
|
||||
},
|
||||
|
@ -1067,6 +1072,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
|
@ -1081,10 +1087,39 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
description: String::from("A DNS Domain name entry."),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
},
|
||||
);
|
||||
self.attributes.insert(
|
||||
String::from("claim"),
|
||||
SchemaAttribute {
|
||||
name: String::from("claim"),
|
||||
uuid: Uuid::parse_str(UUID_SCHEMA_ATTR_CLAIM)
|
||||
.expect("unable to parse static uuid"),
|
||||
description: String::from("The spn of a claim this entry holds"),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: true,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::SERVICE_PRINCIPLE_NAME,
|
||||
},
|
||||
);
|
||||
self.attributes.insert(
|
||||
String::from("password_import"),
|
||||
SchemaAttribute {
|
||||
name: String::from("password_import"),
|
||||
uuid: Uuid::parse_str(UUID_SCHEMA_ATTR_PASSWORD_IMPORT)
|
||||
.expect("unable to parse static uuid"),
|
||||
description: String::from("An imported password hash from an external system."),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: true,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::UTF8STRING,
|
||||
},
|
||||
);
|
||||
|
||||
self.classes.insert(
|
||||
String::from("attributetype"),
|
||||
|
@ -1093,7 +1128,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
uuid: Uuid::parse_str(UUID_SCHEMA_CLASS_ATTRIBUTETYPE)
|
||||
.expect("unable to parse static uuid"),
|
||||
description: String::from("Definition of a schema attribute"),
|
||||
systemmay: vec![String::from("index")],
|
||||
systemmay: vec![String::from("phantom"), String::from("index")],
|
||||
may: vec![],
|
||||
systemmust: vec![
|
||||
String::from("class"),
|
||||
|
@ -1317,6 +1352,7 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
);
|
||||
|
||||
let r = self.validate(&mut au);
|
||||
audit_log!(au, "{:?}", r);
|
||||
if r.is_empty() {
|
||||
self.reload_idxmeta();
|
||||
Ok(())
|
||||
|
@ -1706,6 +1742,7 @@ mod tests {
|
|||
description: String::from(""),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||
};
|
||||
|
@ -1728,6 +1765,7 @@ mod tests {
|
|||
description: String::from(""),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::UTF8STRING,
|
||||
};
|
||||
|
@ -1745,6 +1783,7 @@ mod tests {
|
|||
description: String::from(""),
|
||||
multivalue: true,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::BOOLEAN,
|
||||
};
|
||||
|
@ -1768,6 +1807,7 @@ mod tests {
|
|||
description: String::from(""),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::SYNTAX_ID,
|
||||
};
|
||||
|
@ -1786,6 +1826,7 @@ mod tests {
|
|||
description: String::from(""),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: false,
|
||||
index: vec![IndexType::EQUALITY],
|
||||
syntax: SyntaxType::INDEX_ID,
|
||||
};
|
||||
|
@ -1920,6 +1961,26 @@ mod tests {
|
|||
Err(SchemaError::InvalidAttributeSyntax)
|
||||
);
|
||||
|
||||
// You may not have the phantom.
|
||||
let e_phantom: Entry<EntryInvalid, EntryNew> = unsafe {
|
||||
Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["object", "attributetype"],
|
||||
"attributename": ["testattr"],
|
||||
"description": ["testattr"],
|
||||
"multivalue": ["true"],
|
||||
"unique": ["false"],
|
||||
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||
"syntax": ["UTF8STRING"],
|
||||
"password_import": ["password"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
assert!(e_phantom.validate(&schema).is_err());
|
||||
|
||||
let e_ok: Entry<EntryInvalid, EntryNew> = unsafe {
|
||||
Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
|
@ -1987,55 +2048,6 @@ mod tests {
|
|||
println!("{}", audit);
|
||||
}
|
||||
|
||||
/*
|
||||
#[test]
|
||||
fn test_schema_entry_normalise() {
|
||||
// Check that entries can be normalised sanely
|
||||
let mut audit = AuditScope::new("test_schema_entry_normalise");
|
||||
let schema_outer = Schema::new(&mut audit).expect("failed to create schema");
|
||||
let schema = schema_outer.write();
|
||||
|
||||
// Check that an entry normalises, despite being inconsistent to
|
||||
// schema.
|
||||
let e_test: Entry<EntryInit, EntryNew> = serde_json::from_str(
|
||||
r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["extensibleobject"],
|
||||
"name": ["TestPerson"],
|
||||
"syntax": ["utf8string"],
|
||||
"NotAllowed": ["Some Value"],
|
||||
"UUID": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||
"index": ["equality"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
;
|
||||
|
||||
let e_expect: Entry<EntryNormalised, EntryNew> = serde_json::from_str(
|
||||
r#"{
|
||||
"valid": null,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["extensibleobject"],
|
||||
"name": ["testperson"],
|
||||
"syntax": ["UTF8STRING"],
|
||||
"notallowed": ["Some Value"],
|
||||
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||
"index": ["EQUALITY"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
;
|
||||
|
||||
let e_normal = e_test.normalise(&schema).expect("validation failure");
|
||||
|
||||
assert_eq!(e_expect, e_normal);
|
||||
println!("{}", audit);
|
||||
}
|
||||
*/
|
||||
|
||||
#[test]
|
||||
fn test_schema_extensible() {
|
||||
let mut audit = AuditScope::new("test_schema_extensible");
|
||||
|
@ -2061,6 +2073,25 @@ mod tests {
|
|||
Err(SchemaError::InvalidAttributeSyntax)
|
||||
);
|
||||
|
||||
// Extensible doesn't mean you can have the phantoms
|
||||
let e_extensible_phantom: Entry<EntryInvalid, EntryNew> = unsafe {
|
||||
Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["extensibleobject"],
|
||||
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||
"password_import": ["zzzz"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
e_extensible_phantom.validate(&schema),
|
||||
Err(SchemaError::PhantomAttribute)
|
||||
);
|
||||
|
||||
let e_extensible: Entry<EntryInvalid, EntryNew> = unsafe {
|
||||
Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
|
@ -2142,9 +2173,29 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_schema_filter_normalisation() {
|
||||
// Test mixed case attr name
|
||||
// test syntax of bool
|
||||
// test normalise of insensitive strings
|
||||
fn test_schema_class_phantom_reject() {
|
||||
// Check that entries can be normalised and validated sanely
|
||||
let mut audit = AuditScope::new("test_schema_class_phantom_reject");
|
||||
let schema_outer = Schema::new(&mut audit).expect("failed to create schema");
|
||||
let mut schema = schema_outer.write();
|
||||
|
||||
assert!(schema.validate(&mut audit).len() == 0);
|
||||
|
||||
// Attempt to create a class with a phantom attribute, should be refused.
|
||||
let class = SchemaClass {
|
||||
name: String::from("testobject"),
|
||||
uuid: Uuid::new_v4(),
|
||||
description: String::from("test object"),
|
||||
systemmay: vec!["claim".to_string()],
|
||||
may: vec![],
|
||||
systemmust: vec![],
|
||||
must: vec![],
|
||||
};
|
||||
|
||||
assert!(schema.update_classes(vec![class]).is_ok());
|
||||
|
||||
assert!(schema.validate(&mut audit).len() == 1);
|
||||
|
||||
println!("{}", audit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1836,6 +1836,8 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
let idm_entries = [
|
||||
// Builtin groups
|
||||
JSON_IDM_PEOPLE_MANAGE_PRIV_V1,
|
||||
JSON_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1,
|
||||
JSON_IDM_PEOPLE_EXTEND_PRIV_V1,
|
||||
JSON_IDM_PEOPLE_WRITE_PRIV_V1,
|
||||
JSON_IDM_PEOPLE_READ_PRIV_V1,
|
||||
JSON_IDM_GROUP_MANAGE_PRIV_V1,
|
||||
|
@ -1884,6 +1886,8 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
JSON_IDM_ACP_SYSTEM_CONFIG_PRIV_V1,
|
||||
JSON_IDM_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1,
|
||||
JSON_IDM_ACP_GROUP_UNIX_EXTEND_PRIV_V1,
|
||||
JSON_IDM_ACP_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1,
|
||||
JSON_IDM_ACP_PEOPLE_EXTEND_PRIV_V1,
|
||||
];
|
||||
|
||||
let res: Result<(), _> = idm_entries
|
||||
|
|
Loading…
Reference in a new issue