Skip to content

Commit

Permalink
Merge pull request #18 from fiji-flo/nomore-mozilians-groups
Browse files Browse the repository at this point in the history
disable non DinoPark managed groups
  • Loading branch information
fiji-flo authored Sep 28, 2020
2 parents 8c8e88f + 1d2c08d commit 8f6ba05
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 155 deletions.
34 changes: 30 additions & 4 deletions src/api/sudo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ use serde::Deserialize;
use std::sync::Arc;
use uuid::Uuid;

#[derive(Clone, Deserialize)]
pub struct ConsolidateQuery {
dry_run: bool,
}

#[derive(Clone, Deserialize)]
pub struct ChangeTrust {
trust: TrustType,
Expand Down Expand Up @@ -93,6 +98,23 @@ async fn add_admin<T: AsyncCisClientTrait>(
Ok(HttpResponse::Ok().json(""))
}

#[guard(Staff, Admin, Medium)]
async fn consolidate_users_with_cis<T: AsyncCisClientTrait>(
pool: web::Data<Pool>,
scope_and_user: ScopeAndUser,
query: web::Query<ConsolidateQuery>,
cis_client: web::Data<T>,
) -> Result<HttpResponse, ApiError> {
operations::users::consolidate_users_with_cis(
&pool,
&scope_and_user,
query.dry_run,
Arc::clone(&*cis_client),
)
.await?;
Ok(HttpResponse::Ok().json(""))
}

#[guard(Staff, Admin, Medium)]
async fn update_cis_for_user<T: AsyncCisClientTrait>(
pool: web::Data<Pool>,
Expand Down Expand Up @@ -269,23 +291,27 @@ async fn delete_user(
pub fn sudo_app<T: AsyncCisClientTrait + 'static>() -> impl HttpServiceFactory {
web::scope("/sudo")
.service(web::resource("/groups/reserve/{group_name}").route(web::post().to(reserve_group)))
.service(web::resource("/groups/inactive").route(web::get().to(list_inactive_groups)))
.service(
web::resource("/groups/inactive/{group_name}")
.route(web::delete().to(delete_inactive_group)),
)
.service(web::resource("/groups/inactive").route(web::get().to(list_inactive_groups)))
.service(
web::resource("/trust/groups/{group_name}").route(web::put().to(change_trust::<T>)),
)
.service(web::resource("/member/{group_name}").route(web::post().to(add_member::<T>)))
.service(
web::resource("/member/{group_name}/{user_uuid}")
.route(web::delete().to(remove_member::<T>)),
)
.service(web::resource("/user/inactive").route(web::delete().to(delete_inactive_users)))
.service(web::resource("/user/{uuid}").route(web::delete().to(delete_user)))
.service(web::resource("/member/{group_name}").route(web::post().to(add_member::<T>)))
.service(web::resource("/user/uuids/staff").route(web::get().to(all_staff_uuids)))
.service(web::resource("/user/uuids/members").route(web::get().to(all_member_uuids)))
.service(
web::resource("/user/consolidate")
.route(web::delete().to(consolidate_users_with_cis::<T>)),
)
.service(web::resource("/user/inactive").route(web::delete().to(delete_inactive_users)))
.service(web::resource("/user/{uuid}").route(web::delete().to(delete_user)))
.service(
web::resource("/user/cis/{user_uuid}").route(web::post().to(update_cis_for_user::<T>)),
)
Expand Down
146 changes: 10 additions & 136 deletions src/cis/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,65 +13,26 @@ use cis_profile::schema::PublisherAuthority;
use failure::format_err;
use failure::Error;
use futures::TryFutureExt;
use log::warn;
use std::collections::BTreeMap;
use std::sync::Arc;
use uuid::Uuid;

fn update_groups_and_sign_values_field(
fn update_groups_and_sign(
field: &mut AccessInformationProviderSubObject,
groups: Vec<String>,
store: &SecretStore,
now: &DateTime<Utc>,
) -> Result<(), Error> {
if let Some(KeyValue(values)) = &field.values {
field.values = Some(KeyValue({
let mut btm = BTreeMap::new();
for group in values.iter().filter_map(|(k, v)| match v {
Some(s) if s.is_empty() => None,
_ => Some(k),
}) {
btm.insert(group.clone(), None);
}
for group in groups {
btm.insert(group, Some(String::default()));
}
btm
}));
} else {
field.metadata.created = *now;
field.values = Some(KeyValue({
let mut btm = BTreeMap::new();
for group in groups {
btm.insert(group, Some(String::default()));
}
btm
}));
}
if field.metadata.display.is_none() {
field.metadata.display = Some(Display::Staff);
}
field.metadata.last_modified = *now;
field.signature.publisher.name = PublisherAuthority::Mozilliansorg;
store.sign_attribute(field)
}

fn insert_kv_and_sign_values_field(
field: &mut AccessInformationProviderSubObject,
kv: (String, Option<String>),
store: &SecretStore,
now: &DateTime<Utc>,
) -> Result<(), Error> {
if let Some(KeyValue(ref mut values)) = &mut field.values {
values.insert(kv.0, kv.1);
} else {
if field.values.is_none() {
field.metadata.created = *now;
field.values = Some(KeyValue({
let mut btm = BTreeMap::new();
btm.insert(kv.0, kv.1);
btm
}));
}
field.values = Some(KeyValue({
let mut btm = BTreeMap::new();
for group in groups {
btm.insert(group, Some(String::default()));
}
btm
}));
if field.metadata.display.is_none() {
field.metadata.display = Some(Display::Staff);
}
Expand All @@ -80,31 +41,6 @@ fn insert_kv_and_sign_values_field(
store.sign_attribute(field)
}

fn remove_kv_and_sign_values_field(
field: &mut AccessInformationProviderSubObject,
keys: &[&str],
store: &SecretStore,
now: &DateTime<Utc>,
) -> Result<(), Error> {
if let Some(KeyValue(ref mut values)) = &mut field.values {
let mut changed = false;
for key in keys {
if values.remove(*key).is_some() {
changed = true;
} else {
warn!("group {} was not present when trying to delete", key);
}
}
if changed {
field.metadata.last_modified = *now;
field.signature.publisher.name = PublisherAuthority::Mozilliansorg;
return store.sign_attribute(field);
}
}
warn!("groups {:?} where not present when trying to delete", keys);
Ok(())
}

pub async fn _send_groups_to_cis(
cis_client: Arc<impl AsyncCisClientTrait>,
groups: Vec<String>,
Expand All @@ -114,7 +50,7 @@ pub async fn _send_groups_to_cis(
let mut update_profile = Profile::default();
update_profile.access_information.mozilliansorg = profile.access_information.mozilliansorg;
update_profile.active = profile.active;
match update_groups_and_sign_values_field(
match update_groups_and_sign(
&mut update_profile.access_information.mozilliansorg,
groups,
cis_client.get_secret_store(),
Expand Down Expand Up @@ -145,65 +81,3 @@ pub async fn send_groups_to_cis(
drop(connection);
_send_groups_to_cis(cis_client, groups, user_profile.profile).await
}

pub async fn add_group_to_profile(
cis_client: Arc<impl AsyncCisClientTrait>,
group_name: String,
profile: Profile,
) -> Result<(), Error> {
let now = &Utc::now();
let mut update_profile = Profile::default();
update_profile.access_information.mozilliansorg = profile.access_information.mozilliansorg;
update_profile.active = profile.active;
match insert_kv_and_sign_values_field(
&mut update_profile.access_information.mozilliansorg,
(group_name, Some(String::default())),
cis_client.get_secret_store(),
&now,
) {
Ok(_) => {
if let Some(user_id) = profile.user_id.value.clone() {
cis_client
.update_user(&user_id, update_profile)
.map_ok(|_| ())
.await
} else {
Err(format_err!("invalid user_id"))
}
}
Err(e) => Err(e),
}
}

pub async fn remove_group_from_profile(
cis_client: Arc<impl AsyncCisClientTrait>,
group_names: &[&str],
profile: Profile,
) -> Result<(), Error> {
if group_names.is_empty() {
return Ok(());
}
let now = &Utc::now();
let mut update_profile = Profile::default();
update_profile.access_information.mozilliansorg = profile.access_information.mozilliansorg;
update_profile.active = profile.active;
match remove_kv_and_sign_values_field(
&mut update_profile.access_information.mozilliansorg,
group_names,
cis_client.get_secret_store(),
&now,
) {
Ok(_) => {
if let Some(user_id) = profile.user_id.value.clone() {
log::debug!("updating profile");
cis_client
.update_user(&user_id, update_profile)
.map_ok(|_| ())
.await
} else {
Err(format_err!("invalid user_id"))
}
}
Err(e) => Err(e),
}
}
24 changes: 19 additions & 5 deletions src/db/internal/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,14 +425,10 @@ pub fn all_members(connection: &PgConnection) -> Result<Vec<Uuid>, Error> {
}

use diesel::pg::expression::dsl::array;
use diesel::pg::types::sql_types::Array;
use diesel::pg::types::sql_types::Jsonb;
use diesel::pg::Pg;
use diesel::sql_types::Text;

sql_function! {
fn jsonb_extract_path(from_json: Jsonb, path_elems: Array<Text>) -> Jsonb
}
use serde_json::json;

diesel_infix_operator!(ExtrPath, " #> ", Jsonb, backend: Pg);

Expand All @@ -457,3 +453,21 @@ pub fn all_inactive(connection: &PgConnection) -> Result<Vec<Uuid>, Error> {
.get_results::<Uuid>(connection)
.map_err(Into::into)
}

pub fn all_with_groups(connection: &PgConnection) -> Result<Vec<Uuid>, Error> {
schema::profiles::table
.filter(
extr_path(
schema::profiles::profile,
array::<Text, _>((
"access_information".to_string(),
"mozilliansorg".to_string(),
"values".to_string(),
)),
)
.ne_all(vec![json!(null), json!({})]),
)
.select(schema::profiles::user_uuid)
.get_results::<Uuid>(connection)
.map_err(Into::into)
}
1 change: 1 addition & 0 deletions src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;
pub fn establish_connection(database_url: &str) -> Pool {
let manager = ConnectionManager::<PgConnection>::new(database_url);
r2d2::Pool::builder()
.max_size(25)
.build(manager)
.expect("Failed to create pool.")
}
19 changes: 9 additions & 10 deletions src/db/operations/members.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::cis::operations::remove_group_from_profile;
use crate::cis::operations::send_groups_to_cis;
use crate::db::internal;
use crate::db::logs::add_to_comment_body;
Expand Down Expand Up @@ -317,12 +316,8 @@ async fn _revoke_membership<'a>(
}
let exit_on_error = group_names.len() == 1;
let connection = pool.get()?;
let user_profile = internal::user::user_profile_by_uuid(&connection, &user.user_uuid)?;
drop(connection);
log::debug!("removing group from profile");
remove_group_from_profile(cis_client, group_names, user_profile.profile).await?;
log::debug!("removed group from profile");
let connection = pool.get()?;
let user_profile_slim =
internal::user::slim_user_profile_by_uuid(&connection, &user.user_uuid)?;
for group_name in group_names {
if let Err(e) = db_leave(
&host.user_uuid,
Expand All @@ -343,11 +338,15 @@ async fn _revoke_membership<'a>(
}
if notify {
send_email(
user_profile.email.clone(),
user_profile_slim.email.clone(),
&Template::DeleteMember(group_name.to_string()),
);
}
}
drop(connection);
log::debug!("removing group from profile");
send_groups_to_cis(pool, cis_client, &user.user_uuid).await?;
log::debug!("removed group from profile");
Ok(())
}

Expand Down Expand Up @@ -432,6 +431,7 @@ pub fn renew(
&user.user_uuid,
))?;
let connection = pool.get()?;

internal::member::renew(&host.user_uuid, &connection, group_name, user, expiration)
}

Expand All @@ -442,6 +442,7 @@ pub fn role_for_current(
) -> Result<Option<RoleType>, Error> {
let connection = pool.get()?;
let user = internal::user::user_by_id(&connection, &scope_and_user.user_id)?;

internal::member::role_for(&connection, &user.user_uuid, group_name)
.map(|role| role.map(|role| role.typ))
}
Expand All @@ -459,8 +460,6 @@ pub fn get_curator_emails(
&group_name,
&user.user_uuid,
))?;
// let group = internal::group::get_group(&connection, group_name)?;
// internal::member::get_curator_emails(&connection, group.id)

internal::member::get_curator_emails_by_group_name(&connection, group_name)
}
Expand Down
Loading

0 comments on commit 8f6ba05

Please sign in to comment.