mirror of
https://github.com/kanidm/kanidm.git
synced 2025-05-28 20:03:54 +02:00
1496 ldap basedn config (#1500)
This commit is contained in:
parent
87d9f74d83
commit
c1f62674f5
|
@ -39,24 +39,24 @@ tree. Kanidm is a flat model, so we have to emulate some tree-like elements, and
|
|||
|
||||
For this reason, when you search the LDAP interface, Kanidm will make some mapping decisions.
|
||||
|
||||
- The Kanidm domain name is used to generate the DN of the suffix.
|
||||
- The Kanidm domain name is used to generate the DN of the suffix by default.
|
||||
- The domain\_info object becomes the suffix root.
|
||||
- All other entries are direct subordinates of the domain\_info for DN purposes.
|
||||
- Distinguished Names (DNs) are generated from the spn, name, or uuid attribute.
|
||||
- Bind DNs can be remapped and rewritten, and may not even be a DN during bind.
|
||||
- The '\*' and '+' operators can not be used in conjunction with attribute lists in searches.
|
||||
|
||||
These decisions were made to make the path as simple and effective as possible, relying more on the
|
||||
Kanidm query and filter system than attempting to generate a tree-like representation of data. As
|
||||
almost all clients can use filters for entry selection we don't believe this is a limitation for the
|
||||
consuming applications.
|
||||
Kanidm query and filter system rather than attempting to generate a tree-like representation of
|
||||
data. As almost all clients can use filters for entry selection we don't believe this is a
|
||||
limitation for the consuming applications.
|
||||
|
||||
## Security
|
||||
|
||||
### TLS
|
||||
|
||||
StartTLS is not supported due to security risks. LDAPS is the only secure method of communicating to
|
||||
any LDAP server. Kanidm will use it's certificates for both HTTPS and LDAPS.
|
||||
StartTLS is not supported due to security risks such as credential leakage and MITM attacks that are
|
||||
fundamental in how StartTLS works and can not be repaired. LDAPS is the only secure method of
|
||||
communicating to any LDAP server. Kanidm will use it's certificates for both HTTPS and LDAPS.
|
||||
|
||||
### Writes
|
||||
|
||||
|
@ -70,11 +70,16 @@ bind for any DN will use its configured posix password.
|
|||
|
||||
As the POSIX password is not equivalent in strength to the primary credentials of Kanidm (which in
|
||||
most cases is multi-factor authentication), the LDAP bind does not grant rights to elevated read
|
||||
permissions. All binds have the permissions of "Anonymous" even if the anonymous account is locked.
|
||||
permissions. All binds have the permissions of "anonymous" even if the anonymous account is locked.
|
||||
|
||||
The exception is service accounts which can use api-tokens during an LDAP bind for elevated read
|
||||
permissions.
|
||||
|
||||
### Filtering Objects
|
||||
|
||||
It is recommended that client applications filter accounts that can authenticate with
|
||||
`(class=account)` and groups with `(class=group)`.
|
||||
|
||||
## Server Configuration
|
||||
|
||||
To configure Kanidm to provide LDAP, add the argument to the `server.toml` configuration:
|
||||
|
@ -102,6 +107,7 @@ To show what attribute maps exists for an entry you can use the attribute search
|
|||
```bash
|
||||
# To show Kanidm attributes
|
||||
ldapsearch ... -x '(name=admin)' '*'
|
||||
|
||||
# To show all attribute maps
|
||||
ldapsearch ... -x '(name=admin)' '+'
|
||||
```
|
||||
|
@ -113,6 +119,11 @@ Kanidm native attributes.
|
|||
ldapsearch ... -x '(name=admin)' cn objectClass displayname memberof
|
||||
```
|
||||
|
||||
## Group Memberships
|
||||
|
||||
Group membership is defined in rfc2307bis or Active Directory style. This means groups are
|
||||
determined from the "memberof" attribute which contains a DN to a group.
|
||||
|
||||
## Service Accounts
|
||||
|
||||
If you have
|
||||
|
@ -131,7 +142,38 @@ ldapwhoami -H ldaps://idm.example.com -x -D "dn=token" -w "..."
|
|||
# u: demo_service@idm.example.com
|
||||
```
|
||||
|
||||
## Example
|
||||
## Changing the Basedn
|
||||
|
||||
By default the basedn of the LDAP server is derived from the domain name. For example a domain name
|
||||
of `idm.example.com` will become `dc=idm,dc=example,dc=com`.
|
||||
|
||||
However, you may wish to change this to something shorter or at a higher level within your domain
|
||||
name.
|
||||
|
||||
<!-- deno-fmt-ignore-start -->
|
||||
|
||||
{{#template ../templates/kani-warning.md
|
||||
imagepath=../images
|
||||
title=Warning!
|
||||
text=Changing the LDAP Basedn will require you to reconfigure your client applications so they search the correct basedn. Be careful when changing this value!
|
||||
}}
|
||||
|
||||
<!-- deno-fmt-ignore-end -->
|
||||
|
||||
As an admin you can change the domain ldap basedn with:
|
||||
|
||||
```bash
|
||||
kanidm system domain set-ldap-basedn <new basedn>
|
||||
kanidm system domain set-ldap-basedn o=kanidm -D admin
|
||||
```
|
||||
|
||||
Basedns are validated to ensure they are either `dc=`, `ou=` or `o=`. They must have one or more of
|
||||
these components and must only contain alphanumeric characters.
|
||||
|
||||
After the basedn is changed, the new value will take effect after a server restart. If you have a
|
||||
replicated topology, you must restart all servers.
|
||||
|
||||
## Examples
|
||||
|
||||
Given a default install with domain "idm.example.com" the configured LDAP DN will be
|
||||
"dc=idm,dc=example,dc=com".
|
||||
|
@ -162,11 +204,6 @@ spn: test1@idm.example.com
|
|||
entryuuid: 22a65b6c-80c8-4e1a-9b76-3f3afdff8400
|
||||
```
|
||||
|
||||
It is recommended that client applications filter accounts that can login with `(class=account)` and
|
||||
groups with `(class=group)`. If possible, group membership is defined in RFC2307bis or Active
|
||||
Directory style. This means groups are determined from the "memberof" attribute which contains a DN
|
||||
to a group.
|
||||
|
||||
LDAP binds can use any unique identifier of the account. The following are all valid bind DNs for
|
||||
the object listed above (if it was a POSIX account, that is).
|
||||
|
||||
|
@ -180,6 +217,10 @@ ldapwhoami ... -x -D 'spn=test1@idm.example.com,dc=idm,dc=example,dc=com'
|
|||
ldapwhoami ... -x -D 'name=test1,dc=idm,dc=example,dc=com'
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Can't contact LDAP Server (-1)
|
||||
|
||||
Most LDAP clients are very picky about TLS, and can be very hard to debug or display errors. For
|
||||
example these commands:
|
||||
|
||||
|
|
|
@ -1704,6 +1704,14 @@ impl KanidmClient {
|
|||
.await
|
||||
}
|
||||
|
||||
pub async fn idm_domain_set_ldap_basedn(&self, new_basedn: &str) -> Result<(), ClientError> {
|
||||
self.perform_put_request(
|
||||
"/v1/domain/_attr/domain_ldap_basedn",
|
||||
vec![new_basedn.to_string()],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn idm_domain_get_ssid(&self) -> Result<String, ClientError> {
|
||||
self.perform_get_request("/v1/domain/_attr/domain_ssid")
|
||||
.await
|
||||
|
|
|
@ -1151,48 +1151,6 @@ lazy_static! {
|
|||
);
|
||||
}
|
||||
|
||||
// 28 - domain admins acp
|
||||
pub const 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": [],
|
||||
"acp_receiver_group": ["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": [
|
||||
"domain_display_name",
|
||||
"domain_name",
|
||||
"domain_ssid",
|
||||
"domain_uuid",
|
||||
"es256_private_key_der",
|
||||
"fernet_private_key_str",
|
||||
"cookie_private_key",
|
||||
"name",
|
||||
"uuid"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"domain_display_name",
|
||||
"domain_ssid",
|
||||
"es256_private_key_der",
|
||||
"cookie_private_key",
|
||||
"fernet_private_key_str"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"domain_display_name",
|
||||
"domain_ssid"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref E_IDM_ACP_DOMAIN_ADMIN_PRIV_V1: EntryInitNew = entry_init!(
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
|
@ -1219,6 +1177,7 @@ lazy_static! {
|
|||
("acp_search_attr", Value::new_iutf8("uuid")),
|
||||
("acp_search_attr", Value::new_iutf8("domain_display_name")),
|
||||
("acp_search_attr", Value::new_iutf8("domain_name")),
|
||||
("acp_search_attr", Value::new_iutf8("domain_ldap_basedn")),
|
||||
("acp_search_attr", Value::new_iutf8("domain_ssid")),
|
||||
("acp_search_attr", Value::new_iutf8("domain_uuid")),
|
||||
("acp_search_attr", Value::new_iutf8("es256_private_key_der")),
|
||||
|
@ -1226,10 +1185,12 @@ lazy_static! {
|
|||
("acp_search_attr", Value::new_iutf8("cookie_private_key")),
|
||||
("acp_modify_removedattr", Value::new_iutf8("domain_display_name")),
|
||||
("acp_modify_removedattr", Value::new_iutf8("domain_ssid")),
|
||||
("acp_modify_removedattr", Value::new_iutf8("domain_ldap_basedn")),
|
||||
("acp_modify_removedattr", Value::new_iutf8("es256_private_key_der")),
|
||||
("acp_modify_removedattr", Value::new_iutf8("cookie_private_key")),
|
||||
("acp_modify_removedattr", Value::new_iutf8("fernet_private_key_str")),
|
||||
("acp_modify_presentattr", Value::new_iutf8("domain_display_name")),
|
||||
("acp_modify_presentattr", Value::new_iutf8("domain_ldap_basedn")),
|
||||
("acp_modify_presentattr", Value::new_iutf8("domain_ssid"))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -235,6 +235,34 @@ pub const JSON_SCHEMA_ATTR_DOMAIN_NAME: &str = r#"{
|
|||
}
|
||||
}"#;
|
||||
|
||||
pub const JSON_SCHEMA_ATTR_DOMAIN_LDAP_BASEDN: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"The domain's optional ldap basedn. If unset defaults to domain components of domain name."
|
||||
],
|
||||
"unique": [
|
||||
"true"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"domain_ldap_basedn"
|
||||
],
|
||||
"syntax": [
|
||||
"UTF8STRING_INSENSITIVE"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000131"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub const JSON_SCHEMA_ATTR_DOMAIN_DISPLAY_NAME: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
|
@ -1650,7 +1678,8 @@ pub const JSON_SCHEMA_CLASS_DOMAIN_INFO: &str = r#"
|
|||
"domain_info"
|
||||
],
|
||||
"systemmay": [
|
||||
"domain_ssid"
|
||||
"domain_ssid",
|
||||
"domain_ldap_basedn"
|
||||
],
|
||||
"systemmust": [
|
||||
"name",
|
||||
|
|
|
@ -224,6 +224,8 @@ pub const UUID_SCHEMA_ATTR_EMAILALTERNATIVE: Uuid = uuid!("00000000-0000-0000-00
|
|||
pub const UUID_SCHEMA_ATTR_TOTP_IMPORT: Uuid = uuid!("00000000-0000-0000-0000-ffff00000128");
|
||||
pub const UUID_SCHEMA_ATTR_REPLICATED: Uuid = uuid!("00000000-0000-0000-0000-ffff00000129");
|
||||
pub const UUID_SCHEMA_ATTR_PRIVATE_COOKIE_KEY: Uuid = uuid!("00000000-0000-0000-0000-ffff00000130");
|
||||
pub const _UUID_SCHEMA_ATTR_DOMAIN_LDAP_BASEDN: Uuid =
|
||||
uuid!("00000000-0000-0000-0000-ffff00000131");
|
||||
|
||||
// System and domain infos
|
||||
// I'd like to strongly criticise william of the past for making poor choices about these allocations.
|
||||
|
|
|
@ -67,13 +67,16 @@ impl LdapServer {
|
|||
.qs_read
|
||||
.internal_search_uuid(UUID_DOMAIN_INFO)?;
|
||||
|
||||
let domain_name = domain_entry
|
||||
.get_ava_single_iname("domain_name")
|
||||
let basedn = domain_entry
|
||||
.get_ava_single_iutf8("domain_ldap_basedn")
|
||||
.map(|s| s.to_string())
|
||||
.or_else(|| {
|
||||
domain_entry
|
||||
.get_ava_single_iname("domain_name")
|
||||
.map(|domain_name| ldap_domain_to_dc(domain_name))
|
||||
})
|
||||
.ok_or(OperationError::InvalidEntryState)?;
|
||||
|
||||
let basedn = ldap_domain_to_dc(domain_name.as_str());
|
||||
|
||||
let dnre = Regex::new(format!("^((?P<attr>[^=]+)=(?P<val>[^=]+),)?{basedn}$").as_str())
|
||||
.map_err(|_| OperationError::InvalidEntryState)?;
|
||||
|
||||
|
@ -84,27 +87,27 @@ impl LdapServer {
|
|||
dn: "".to_string(),
|
||||
attributes: vec![
|
||||
LdapPartialAttribute {
|
||||
atype: "objectClass".to_string(),
|
||||
atype: "objectclass".to_string(),
|
||||
vals: vec!["top".as_bytes().to_vec()],
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
atype: "vendorName".to_string(),
|
||||
atype: "vendorname".to_string(),
|
||||
vals: vec!["Kanidm Project".as_bytes().to_vec()],
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
atype: "vendorVersion".to_string(),
|
||||
vals: vec!["kanidm_ldap_1.0.0".as_bytes().to_vec()],
|
||||
atype: "vendorversion".to_string(),
|
||||
vals: vec![env!("CARGO_PKG_VERSION").as_bytes().to_vec()],
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
atype: "supportedLDAPVersion".to_string(),
|
||||
atype: "supportedldapversion".to_string(),
|
||||
vals: vec!["3".as_bytes().to_vec()],
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
atype: "supportedExtension".to_string(),
|
||||
atype: "supportedextension".to_string(),
|
||||
vals: vec!["1.3.6.1.4.1.4203.1.11.3".as_bytes().to_vec()],
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
atype: "supportedFeatures".to_string(),
|
||||
atype: "supportedfeatures".to_string(),
|
||||
vals: vec!["1.3.6.1.4.1.4203.1.5.1".as_bytes().to_vec()],
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
|
@ -1161,4 +1164,91 @@ mod tests {
|
|||
_ => assert!(false),
|
||||
};
|
||||
}
|
||||
|
||||
#[idm_test]
|
||||
async fn test_ldap_rootdse_basedn_change(idms: &IdmServer, _idms_delayed: &IdmServerDelayed) {
|
||||
let ldaps = LdapServer::new(idms).await.expect("failed to start ldap");
|
||||
|
||||
let anon_t = ldaps.do_bind(idms, "", "").await.unwrap().unwrap();
|
||||
assert!(anon_t.effective_session == LdapSession::UnixBind(UUID_ANONYMOUS));
|
||||
|
||||
let sr = SearchRequest {
|
||||
msgid: 1,
|
||||
base: "".to_string(),
|
||||
scope: LdapSearchScope::Base,
|
||||
filter: LdapFilter::Present("objectclass".to_string()),
|
||||
attrs: vec!["*".to_string()],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
|
||||
trace!(?r1);
|
||||
|
||||
// The result, and the ldap proto success msg.
|
||||
assert!(r1.len() == 2);
|
||||
match &r1[0].op {
|
||||
LdapOp::SearchResultEntry(lsre) => {
|
||||
assert_entry_contains!(
|
||||
lsre,
|
||||
"",
|
||||
("objectclass", "top"),
|
||||
("vendorname", "Kanidm Project"),
|
||||
("supportedldapversion", "3"),
|
||||
("defaultnamingcontext", "dc=example,dc=com")
|
||||
);
|
||||
}
|
||||
_ => assert!(false),
|
||||
};
|
||||
|
||||
drop(ldaps);
|
||||
|
||||
// Change the domain basedn
|
||||
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
// make the admin a valid posix account
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("uuid", PartialValue::Uuid(UUID_DOMAIN_INFO))),
|
||||
ModifyList::new_purge_and_set(
|
||||
"domain_ldap_basedn",
|
||||
Value::new_iutf8("o=kanidmproject"),
|
||||
),
|
||||
)
|
||||
};
|
||||
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
||||
// Now re-test
|
||||
let ldaps = LdapServer::new(idms).await.expect("failed to start ldap");
|
||||
|
||||
let anon_t = ldaps.do_bind(idms, "", "").await.unwrap().unwrap();
|
||||
assert!(anon_t.effective_session == LdapSession::UnixBind(UUID_ANONYMOUS));
|
||||
|
||||
let sr = SearchRequest {
|
||||
msgid: 1,
|
||||
base: "".to_string(),
|
||||
scope: LdapSearchScope::Base,
|
||||
filter: LdapFilter::Present("objectclass".to_string()),
|
||||
attrs: vec!["*".to_string()],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
|
||||
trace!(?r1);
|
||||
|
||||
// The result, and the ldap proto success msg.
|
||||
assert!(r1.len() == 2);
|
||||
match &r1[0].op {
|
||||
LdapOp::SearchResultEntry(lsre) => {
|
||||
assert_entry_contains!(
|
||||
lsre,
|
||||
"",
|
||||
("objectclass", "top"),
|
||||
("vendorname", "Kanidm Project"),
|
||||
("supportedldapversion", "3"),
|
||||
("defaultnamingcontext", "o=kanidmproject")
|
||||
);
|
||||
}
|
||||
_ => assert!(false),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,21 @@ use std::iter::once;
|
|||
use compact_jwt::JwsSigner;
|
||||
use kanidm_proto::v1::OperationError;
|
||||
use rand::prelude::*;
|
||||
use regex::Regex;
|
||||
use tracing::trace;
|
||||
|
||||
use crate::event::{CreateEvent, ModifyEvent};
|
||||
use crate::plugins::Plugin;
|
||||
use crate::prelude::*;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref DOMAIN_LDAP_BASEDN_RE: Regex = {
|
||||
#[allow(clippy::expect_used)]
|
||||
Regex::new(r"^(dc|o|ou)=[a-z][a-z0-9]*(,(dc|o|ou)=[a-z][a-z0-9]*)*$")
|
||||
.expect("Invalid domain ldap basedn regex")
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Domain {}
|
||||
|
||||
impl Plugin for Domain {
|
||||
|
@ -59,6 +68,16 @@ impl Domain {
|
|||
if e.attribute_equality("class", &PVCLASS_DOMAIN_INFO)
|
||||
&& e.attribute_equality("uuid", &PVUUID_DOMAIN_INFO)
|
||||
{
|
||||
// Validate the domain ldap basedn syntax.
|
||||
if let Some(basedn) = e
|
||||
.get_ava_single_iutf8("domain_ldap_basedn") {
|
||||
|
||||
if !DOMAIN_LDAP_BASEDN_RE.is_match(basedn) {
|
||||
error!("Invalid domain_ldap_basedn. Must pass regex \"{}\"", *DOMAIN_LDAP_BASEDN_RE);
|
||||
return Err(OperationError::InvalidState);
|
||||
}
|
||||
}
|
||||
|
||||
// We always set this, because the DB uuid is authoritative.
|
||||
let u = Value::Uuid(qs.get_domain_uuid());
|
||||
e.set_ava("domain_uuid", once(u));
|
||||
|
|
|
@ -16,7 +16,7 @@ pub struct Protected {}
|
|||
|
||||
lazy_static! {
|
||||
static ref ALLOWED_ATTRS: HashSet<&'static str> = {
|
||||
let mut m = HashSet::with_capacity(8);
|
||||
let mut m = HashSet::with_capacity(16);
|
||||
// Allow modification of some schema class types to allow local extension
|
||||
// of schema types.
|
||||
//
|
||||
|
@ -24,6 +24,7 @@ lazy_static! {
|
|||
m.insert("may");
|
||||
// Allow modification of some domain info types for local configuration.
|
||||
m.insert("domain_ssid");
|
||||
m.insert("domain_ldap_basedn");
|
||||
m.insert("fernet_private_key_str");
|
||||
m.insert("es256_private_key_der");
|
||||
m.insert("badlist_password");
|
||||
|
|
|
@ -465,6 +465,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
JSON_SCHEMA_ATTR_SYNC_COOKIE,
|
||||
JSON_SCHEMA_ATTR_GRANT_UI_HINT,
|
||||
JSON_SCHEMA_ATTR_OAUTH2_RS_ORIGIN_LANDING,
|
||||
JSON_SCHEMA_ATTR_DOMAIN_LDAP_BASEDN,
|
||||
JSON_SCHEMA_CLASS_PERSON,
|
||||
JSON_SCHEMA_CLASS_ORGPERSON,
|
||||
JSON_SCHEMA_CLASS_GROUP,
|
||||
|
|
|
@ -41,7 +41,7 @@ lazy_static! {
|
|||
Regex::new("(?P<name>[^@]+)@(?P<realm>[^@]+)").expect("Invalid SPN regex found")
|
||||
};
|
||||
pub static ref DISALLOWED_NAMES: HashSet<&'static str> = {
|
||||
let mut m = HashSet::with_capacity(10);
|
||||
let mut m = HashSet::with_capacity(16);
|
||||
m.insert("root");
|
||||
m.insert("nobody");
|
||||
m.insert("nogroup");
|
||||
|
@ -52,6 +52,7 @@ lazy_static! {
|
|||
m.insert("mail");
|
||||
m.insert("man");
|
||||
m.insert("administrator");
|
||||
m.insert("dn=token");
|
||||
m
|
||||
};
|
||||
|
||||
|
|
|
@ -4,14 +4,15 @@ use crate::DomainOpt;
|
|||
impl DomainOpt {
|
||||
pub fn debug(&self) -> bool {
|
||||
match self {
|
||||
DomainOpt::SetDomainDisplayName(copt) => copt.copt.debug,
|
||||
DomainOpt::SetDisplayName(copt) => copt.copt.debug,
|
||||
DomainOpt::SetLdapBasedn { copt, .. } => copt.debug,
|
||||
DomainOpt::Show(copt) | DomainOpt::ResetTokenKey(copt) => copt.debug,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn exec(&self) {
|
||||
match self {
|
||||
DomainOpt::SetDomainDisplayName(opt) => {
|
||||
DomainOpt::SetDisplayName(opt) => {
|
||||
eprintln!(
|
||||
"Attempting to set the domain's display name to: {:?}",
|
||||
opt.new_display_name
|
||||
|
@ -25,6 +26,17 @@ impl DomainOpt {
|
|||
Err(e) => eprintln!("{:?}", e),
|
||||
}
|
||||
}
|
||||
DomainOpt::SetLdapBasedn { copt, new_basedn } => {
|
||||
eprintln!(
|
||||
"Attempting to set the domain's ldap basedn to: {:?}",
|
||||
new_basedn
|
||||
);
|
||||
let client = copt.to_client(OpType::Write).await;
|
||||
match client.idm_domain_set_ldap_basedn(&new_basedn).await {
|
||||
Ok(_) => println!("Success"),
|
||||
Err(e) => eprintln!("{:?}", e),
|
||||
}
|
||||
}
|
||||
DomainOpt::Show(copt) => {
|
||||
let client = copt.to_client(OpType::Read).await;
|
||||
match client.idm_domain_get().await {
|
||||
|
|
|
@ -743,9 +743,20 @@ pub enum PwBadlistOpt {
|
|||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum DomainOpt {
|
||||
#[clap[name = "set-domain-display-name"]]
|
||||
#[clap[name = "set-display-name"]]
|
||||
/// Set the domain display name
|
||||
SetDomainDisplayName(OptSetDomainDisplayName),
|
||||
SetDisplayName(OptSetDomainDisplayName),
|
||||
#[clap[name = "set-ldap-basedn"]]
|
||||
/// Change the basedn of this server. Takes effect after a server restart.
|
||||
/// Examples are `o=organisation` or `dc=domain,dc=name`. Must be a valid ldap
|
||||
/// dn containing only alphanumerics, and dn components must be org (o), domain (dc) or
|
||||
/// orgunit (ou).
|
||||
SetLdapBasedn {
|
||||
#[clap(flatten)]
|
||||
copt: CommonOpt,
|
||||
#[clap(name = "new-basedn")]
|
||||
new_basedn: String,
|
||||
},
|
||||
#[clap(name = "show")]
|
||||
/// Show information about this system's domain
|
||||
Show(CommonOpt),
|
||||
|
|
Loading…
Reference in a new issue