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,
|
||||
..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
|
||||
|
@ -107,7 +117,6 @@ pub async fn populate(_client: &KanidmOrcaClient, profile: Profile) -> Result<St
|
|||
|
||||
let model = Model::Basic;
|
||||
|
||||
// =======
|
||||
// Data is ready, make changes to the server. These should be idempotent if possible.
|
||||
let p = Person {
|
||||
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.
|
||||
|
||||
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.
|
||||
let baseline = persons.len() / 2;
|
||||
let baseline = persons.len() / 5;
|
||||
let inverse = persons.len() - baseline;
|
||||
// Randomly add extra from the inverse
|
||||
let extra = Uniform::new(0, inverse);
|
||||
|
|
|
@ -13,6 +13,8 @@ pub enum TransitionAction {
|
|||
Logout,
|
||||
PrivilegeReauth,
|
||||
WriteAttributePersonMail,
|
||||
ReadSelfAccount,
|
||||
ReadSelfMemberOf,
|
||||
}
|
||||
|
||||
// Is this the right way? Should transitions/delay be part of the actor model? Should
|
||||
|
@ -44,12 +46,16 @@ pub enum ActorRole {
|
|||
None,
|
||||
PeoplePiiReader,
|
||||
PeopleSelfWriteMail,
|
||||
PeopleSelfReadProfile,
|
||||
PeopleSelfReadMemberOf,
|
||||
}
|
||||
|
||||
impl ActorRole {
|
||||
pub fn requires_membership_to(&self) -> Option<&[&str]> {
|
||||
match self {
|
||||
ActorRole::None => None,
|
||||
ActorRole::None
|
||||
| ActorRole::PeopleSelfReadProfile
|
||||
| ActorRole::PeopleSelfReadMemberOf => None,
|
||||
ActorRole::PeoplePiiReader => Some(&["idm_people_pii_read"]),
|
||||
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>(
|
||||
result: Result<T, ClientError>,
|
||||
details: EventDetail,
|
||||
|
|
|
@ -51,6 +51,12 @@ impl ActorModel for ActorBasic {
|
|||
let values = &[mail.as_str()];
|
||||
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);
|
||||
|
@ -61,28 +67,43 @@ impl ActorModel for ActorBasic {
|
|||
|
||||
impl ActorBasic {
|
||||
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 {
|
||||
State::Unauthenticated => Transition {
|
||||
delay: None,
|
||||
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 {
|
||||
delay: Some(Duration::from_millis(100)),
|
||||
delay: Some(Duration::from_millis(1000)),
|
||||
action: TransitionAction::PrivilegeReauth,
|
||||
},
|
||||
State::AuthenticatedWithReauth => {
|
||||
if roles.contains(&ActorRole::PeopleSelfWriteMail) {
|
||||
Transition {
|
||||
// Since this is the basic model we don't want to get too fancy and do too many things, but since the struct Person
|
||||
// already comes with a BTreeSet of roles we don't want to change that, so we arbitrarily choose to use just the first role
|
||||
// (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)),
|
||||
action: TransitionAction::WriteAttributePersonMail,
|
||||
}
|
||||
} else {
|
||||
Transition {
|
||||
delay: Some(Duration::from_secs(5)),
|
||||
action: TransitionAction::Logout,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ActorRole::PeopleSelfReadProfile => Transition {
|
||||
delay: Some(Duration::from_millis(150)),
|
||||
action: TransitionAction::ReadSelfAccount,
|
||||
},
|
||||
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,
|
||||
TransitionAction::WriteAttributePersonMail,
|
||||
TransitionAction::WriteAttributePersonMail
|
||||
| TransitionAction::ReadSelfAccount
|
||||
| TransitionAction::ReadSelfMemberOf,
|
||||
TransitionResult::Ok,
|
||||
) => {
|
||||
self.state = State::AuthenticatedWithReauth;
|
||||
|
|
|
@ -40,7 +40,7 @@ async fn preflight_person(
|
|||
if let Some(need_groups) = role.requires_membership_to() {
|
||||
for group_name in need_groups {
|
||||
client
|
||||
.group_add_members(&group_name, &[person.username.as_str()])
|
||||
.group_add_members(group_name, &[person.username.as_str()])
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ pub enum EventDetail {
|
|||
Login,
|
||||
Logout,
|
||||
PersonSetSelfMail,
|
||||
PersonGetSelfAccount,
|
||||
PersonGetSelfMemberOf,
|
||||
PersonReauth,
|
||||
Error,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue