@@ -24,6 +24,7 @@ use tokio::sync::Mutex;
2424use crate :: {
2525 handlers:: http:: { modal:: utils:: rbac_utils:: get_metadata, rbac:: RBACError } ,
2626 rbac:: {
27+ map:: roles,
2728 user:: { self , User as ParseableUser } ,
2829 Users ,
2930 } ,
@@ -48,7 +49,7 @@ pub async fn post_user(
4849 let _ = storage:: put_staging_metadata ( & metadata) ;
4950 let created_role = user. roles . clone ( ) ;
5051 Users . put_user ( user. clone ( ) ) ;
51- Users . put_role ( & username, created_role. clone ( ) ) ;
52+ Users . add_roles ( & username, created_role. clone ( ) ) ;
5253 }
5354
5455 Ok ( generated_password)
@@ -73,34 +74,103 @@ pub async fn delete_user(username: web::Path<String>) -> Result<impl Responder,
7374 Ok ( format ! ( "deleted user: {username}" ) )
7475}
7576
76- // Handler PUT /user/{username}/roles => Put roles for user
77- // Put roles for given user
78- pub async fn put_role (
77+ // Handler PATCH /user/{username}/role/sync/add => Add roles to a user
78+ pub async fn add_roles_to_user (
7979 username : web:: Path < String > ,
80- role : web:: Json < HashSet < String > > ,
80+ roles_to_add : web:: Json < HashSet < String > > ,
8181) -> Result < String , RBACError > {
8282 let username = username. into_inner ( ) ;
83- let role = role . into_inner ( ) ;
83+ let roles_to_add = roles_to_add . into_inner ( ) ;
8484
8585 if !Users . contains ( & username) {
8686 return Err ( RBACError :: UserDoesNotExist ) ;
8787 } ;
88+
89+ // check if all roles exist
90+ let mut non_existent_roles = Vec :: new ( ) ;
91+ roles_to_add. iter ( ) . for_each ( |r| {
92+ if roles ( ) . get ( r) . is_none ( ) {
93+ non_existent_roles. push ( r. clone ( ) ) ;
94+ }
95+ } ) ;
96+
97+ if !non_existent_roles. is_empty ( ) {
98+ return Err ( RBACError :: RolesDoNotExist ( non_existent_roles) ) ;
99+ }
100+
101+ // update parseable.json first
102+ let mut metadata = get_metadata ( ) . await ?;
103+ if let Some ( user) = metadata
104+ . users
105+ . iter_mut ( )
106+ . find ( |user| user. username ( ) == username)
107+ {
108+ user. roles . extend ( roles_to_add. clone ( ) ) ;
109+ } else {
110+ // should be unreachable given state is always consistent
111+ return Err ( RBACError :: UserDoesNotExist ) ;
112+ }
113+
114+ let _ = storage:: put_staging_metadata ( & metadata) ;
115+ // update in mem table
116+ Users . add_roles ( & username. clone ( ) , roles_to_add. clone ( ) ) ;
117+
118+ Ok ( format ! ( "Roles updated successfully for {username}" ) )
119+ }
120+
121+ // Handler PATCH /user/{username}/role/sync/add => Add roles to a user
122+ pub async fn remove_roles_from_user (
123+ username : web:: Path < String > ,
124+ roles_to_remove : web:: Json < HashSet < String > > ,
125+ ) -> Result < String , RBACError > {
126+ let username = username. into_inner ( ) ;
127+ let roles_to_remove = roles_to_remove. into_inner ( ) ;
128+
129+ if !Users . contains ( & username) {
130+ return Err ( RBACError :: UserDoesNotExist ) ;
131+ } ;
132+
133+ // check if all roles exist
134+ let mut non_existent_roles = Vec :: new ( ) ;
135+ roles_to_remove. iter ( ) . for_each ( |r| {
136+ if roles ( ) . get ( r) . is_none ( ) {
137+ non_existent_roles. push ( r. clone ( ) ) ;
138+ }
139+ } ) ;
140+
141+ if !non_existent_roles. is_empty ( ) {
142+ return Err ( RBACError :: RolesDoNotExist ( non_existent_roles) ) ;
143+ }
144+
145+ // check that user actually has these roles
146+ let user_roles: HashSet < String > = HashSet :: from_iter ( Users . get_role ( & username) ) ;
147+ let roles_not_with_user: HashSet < String > =
148+ HashSet :: from_iter ( roles_to_remove. difference ( & user_roles) . cloned ( ) ) ;
149+
150+ if !roles_not_with_user. is_empty ( ) {
151+ return Err ( RBACError :: RolesNotAssigned ( Vec :: from_iter (
152+ roles_not_with_user,
153+ ) ) ) ;
154+ }
155+
88156 // update parseable.json first
89157 let mut metadata = get_metadata ( ) . await ?;
90158 if let Some ( user) = metadata
91159 . users
92160 . iter_mut ( )
93161 . find ( |user| user. username ( ) == username)
94162 {
95- user. roles . clone_from ( & role) ;
163+ let diff: HashSet < String > =
164+ HashSet :: from_iter ( user. roles . difference ( & roles_to_remove) . cloned ( ) ) ;
165+ user. roles = diff;
96166 } else {
97167 // should be unreachable given state is always consistent
98168 return Err ( RBACError :: UserDoesNotExist ) ;
99169 }
100170
101171 let _ = storage:: put_staging_metadata ( & metadata) ;
102172 // update in mem table
103- Users . put_role ( & username. clone ( ) , role . clone ( ) ) ;
173+ Users . remove_roles ( & username. clone ( ) , roles_to_remove . clone ( ) ) ;
104174
105175 Ok ( format ! ( "Roles updated successfully for {username}" ) )
106176}
0 commit comments