mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
added profile and memberof
search to the basic model (#2712)
Co-authored-by: Firstyear <william@blackhats.net.au>
This commit is contained in:
parent
a0f743d8c8
commit
9354c180af
|
@ -68,6 +68,16 @@ pub async fn populate(_client: &KanidmOrcaClient, profile: Profile) -> Result<St
|
||||||
role: ActorRole::PeopleSelfWriteMail,
|
role: ActorRole::PeopleSelfWriteMail,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
Group {
|
||||||
|
name: "role_people_self_read_account".to_string(),
|
||||||
|
role: ActorRole::PeopleSelfReadProfile,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
name: "role_people_self_read_memberof".to_string(),
|
||||||
|
role: ActorRole::PeopleSelfReadMemberOf,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// PHASE 3 - generate persons
|
// PHASE 3 - generate persons
|
||||||
|
@ -107,7 +117,6 @@ pub async fn populate(_client: &KanidmOrcaClient, profile: Profile) -> Result<St
|
||||||
|
|
||||||
let model = Model::Basic;
|
let model = Model::Basic;
|
||||||
|
|
||||||
// =======
|
|
||||||
// Data is ready, make changes to the server. These should be idempotent if possible.
|
// Data is ready, make changes to the server. These should be idempotent if possible.
|
||||||
let p = Person {
|
let p = Person {
|
||||||
preflight_state: PreflightState::Present,
|
preflight_state: PreflightState::Present,
|
||||||
|
@ -132,9 +141,9 @@ pub async fn populate(_client: &KanidmOrcaClient, profile: Profile) -> Result<St
|
||||||
// to each role always will exist and be operational.
|
// to each role always will exist and be operational.
|
||||||
|
|
||||||
for group in groups.iter_mut() {
|
for group in groups.iter_mut() {
|
||||||
// For now, our baseline is 50%. We can adjust this in future per
|
// For now, our baseline is 20%. We can adjust this in future per
|
||||||
// role for example.
|
// role for example.
|
||||||
let baseline = persons.len() / 2;
|
let baseline = persons.len() / 5;
|
||||||
let inverse = persons.len() - baseline;
|
let inverse = persons.len() - baseline;
|
||||||
// Randomly add extra from the inverse
|
// Randomly add extra from the inverse
|
||||||
let extra = Uniform::new(0, inverse);
|
let extra = Uniform::new(0, inverse);
|
||||||
|
|
|
@ -13,6 +13,8 @@ pub enum TransitionAction {
|
||||||
Logout,
|
Logout,
|
||||||
PrivilegeReauth,
|
PrivilegeReauth,
|
||||||
WriteAttributePersonMail,
|
WriteAttributePersonMail,
|
||||||
|
ReadSelfAccount,
|
||||||
|
ReadSelfMemberOf,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this the right way? Should transitions/delay be part of the actor model? Should
|
// Is this the right way? Should transitions/delay be part of the actor model? Should
|
||||||
|
@ -44,12 +46,16 @@ pub enum ActorRole {
|
||||||
None,
|
None,
|
||||||
PeoplePiiReader,
|
PeoplePiiReader,
|
||||||
PeopleSelfWriteMail,
|
PeopleSelfWriteMail,
|
||||||
|
PeopleSelfReadProfile,
|
||||||
|
PeopleSelfReadMemberOf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActorRole {
|
impl ActorRole {
|
||||||
pub fn requires_membership_to(&self) -> Option<&[&str]> {
|
pub fn requires_membership_to(&self) -> Option<&[&str]> {
|
||||||
match self {
|
match self {
|
||||||
ActorRole::None => None,
|
ActorRole::None
|
||||||
|
| ActorRole::PeopleSelfReadProfile
|
||||||
|
| ActorRole::PeopleSelfReadMemberOf => None,
|
||||||
ActorRole::PeoplePiiReader => Some(&["idm_people_pii_read"]),
|
ActorRole::PeoplePiiReader => Some(&["idm_people_pii_read"]),
|
||||||
ActorRole::PeopleSelfWriteMail => Some(&["idm_people_self_write_mail"]),
|
ActorRole::PeopleSelfWriteMail => Some(&["idm_people_self_write_mail"]),
|
||||||
}
|
}
|
||||||
|
@ -149,6 +155,38 @@ pub async fn logout(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn person_get_self_account(
|
||||||
|
client: &KanidmClient,
|
||||||
|
person: &Person,
|
||||||
|
) -> Result<(TransitionResult, EventRecord), Error> {
|
||||||
|
let start = Instant::now();
|
||||||
|
let result = client.idm_person_account_get(&person.username).await;
|
||||||
|
let duration = Instant::now().duration_since(start);
|
||||||
|
Ok(parse_call_result_into_transition_result_and_event_record(
|
||||||
|
result,
|
||||||
|
EventDetail::PersonGetSelfAccount,
|
||||||
|
start,
|
||||||
|
duration,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn person_get_self_memberof(
|
||||||
|
client: &KanidmClient,
|
||||||
|
person: &Person,
|
||||||
|
) -> Result<(TransitionResult, EventRecord), Error> {
|
||||||
|
let start = Instant::now();
|
||||||
|
let result = client
|
||||||
|
.idm_person_account_get_attr(&person.username, "memberof")
|
||||||
|
.await;
|
||||||
|
let duration = Instant::now().duration_since(start);
|
||||||
|
Ok(parse_call_result_into_transition_result_and_event_record(
|
||||||
|
result,
|
||||||
|
EventDetail::PersonGetSelfMemberOf,
|
||||||
|
start,
|
||||||
|
duration,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_call_result_into_transition_result_and_event_record<T>(
|
fn parse_call_result_into_transition_result_and_event_record<T>(
|
||||||
result: Result<T, ClientError>,
|
result: Result<T, ClientError>,
|
||||||
details: EventDetail,
|
details: EventDetail,
|
||||||
|
|
|
@ -51,6 +51,12 @@ impl ActorModel for ActorBasic {
|
||||||
let values = &[mail.as_str()];
|
let values = &[mail.as_str()];
|
||||||
model::person_set_self_mail(client, person, values).await
|
model::person_set_self_mail(client, person, values).await
|
||||||
}
|
}
|
||||||
|
TransitionAction::ReadSelfAccount => {
|
||||||
|
model::person_get_self_account(client, person).await
|
||||||
|
}
|
||||||
|
TransitionAction::ReadSelfMemberOf => {
|
||||||
|
model::person_get_self_memberof(client, person).await
|
||||||
|
}
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
self.next_state(transition.action, result);
|
self.next_state(transition.action, result);
|
||||||
|
@ -61,28 +67,43 @@ impl ActorModel for ActorBasic {
|
||||||
|
|
||||||
impl ActorBasic {
|
impl ActorBasic {
|
||||||
fn next_transition(&mut self, roles: &BTreeSet<ActorRole>) -> Transition {
|
fn next_transition(&mut self, roles: &BTreeSet<ActorRole>) -> Transition {
|
||||||
|
let logout_transition = Transition {
|
||||||
|
delay: Some(Duration::from_secs(5)),
|
||||||
|
action: TransitionAction::Logout,
|
||||||
|
};
|
||||||
match self.state {
|
match self.state {
|
||||||
State::Unauthenticated => Transition {
|
State::Unauthenticated => Transition {
|
||||||
delay: None,
|
delay: None,
|
||||||
action: TransitionAction::Login,
|
action: TransitionAction::Login,
|
||||||
},
|
},
|
||||||
|
// Doing some tests with more people I noticed that if the delay is too low somehow??! the server could start processing the reauth request before
|
||||||
|
// the auth one, yielding an error,
|
||||||
|
// TODO!!: understand why that happens
|
||||||
State::Authenticated => Transition {
|
State::Authenticated => Transition {
|
||||||
delay: Some(Duration::from_millis(100)),
|
delay: Some(Duration::from_millis(1000)),
|
||||||
action: TransitionAction::PrivilegeReauth,
|
action: TransitionAction::PrivilegeReauth,
|
||||||
},
|
},
|
||||||
State::AuthenticatedWithReauth => {
|
// Since this is the basic model we don't want to get too fancy and do too many things, but since the struct Person
|
||||||
if roles.contains(&ActorRole::PeopleSelfWriteMail) {
|
// already comes with a BTreeSet of roles we don't want to change that, so we arbitrarily choose to use just the first role
|
||||||
Transition {
|
// (which is always deterministic thanks to the rng seed used to choose the roles)
|
||||||
|
State::AuthenticatedWithReauth => match roles.first() {
|
||||||
|
Some(role) => match role {
|
||||||
|
ActorRole::PeopleSelfWriteMail => Transition {
|
||||||
delay: Some(Duration::from_millis(200)),
|
delay: Some(Duration::from_millis(200)),
|
||||||
action: TransitionAction::WriteAttributePersonMail,
|
action: TransitionAction::WriteAttributePersonMail,
|
||||||
}
|
},
|
||||||
} else {
|
ActorRole::PeopleSelfReadProfile => Transition {
|
||||||
Transition {
|
delay: Some(Duration::from_millis(150)),
|
||||||
delay: Some(Duration::from_secs(5)),
|
action: TransitionAction::ReadSelfAccount,
|
||||||
action: TransitionAction::Logout,
|
},
|
||||||
}
|
ActorRole::PeopleSelfReadMemberOf => Transition {
|
||||||
}
|
delay: Some(Duration::from_millis(330)),
|
||||||
}
|
action: TransitionAction::ReadSelfMemberOf,
|
||||||
|
},
|
||||||
|
ActorRole::PeoplePiiReader | ActorRole::None => logout_transition,
|
||||||
|
},
|
||||||
|
None => logout_transition,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +119,9 @@ impl ActorBasic {
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
State::AuthenticatedWithReauth,
|
State::AuthenticatedWithReauth,
|
||||||
TransitionAction::WriteAttributePersonMail,
|
TransitionAction::WriteAttributePersonMail
|
||||||
|
| TransitionAction::ReadSelfAccount
|
||||||
|
| TransitionAction::ReadSelfMemberOf,
|
||||||
TransitionResult::Ok,
|
TransitionResult::Ok,
|
||||||
) => {
|
) => {
|
||||||
self.state = State::AuthenticatedWithReauth;
|
self.state = State::AuthenticatedWithReauth;
|
||||||
|
|
|
@ -40,7 +40,7 @@ async fn preflight_person(
|
||||||
if let Some(need_groups) = role.requires_membership_to() {
|
if let Some(need_groups) = role.requires_membership_to() {
|
||||||
for group_name in need_groups {
|
for group_name in need_groups {
|
||||||
client
|
client
|
||||||
.group_add_members(&group_name, &[person.username.as_str()])
|
.group_add_members(group_name, &[person.username.as_str()])
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ pub enum EventDetail {
|
||||||
Login,
|
Login,
|
||||||
Logout,
|
Logout,
|
||||||
PersonSetSelfMail,
|
PersonSetSelfMail,
|
||||||
|
PersonGetSelfAccount,
|
||||||
|
PersonGetSelfMemberOf,
|
||||||
PersonReauth,
|
PersonReauth,
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue