1818
1919import java .util .ArrayList ;
2020import java .util .Collections ;
21+ import java .util .HashMap ;
22+ import java .util .HashSet ;
2123import java .util .Iterator ;
2224import java .util .List ;
2325import java .util .Map ;
26+ import java .util .Set ;
2427
2528import javax .inject .Inject ;
2629
@@ -405,42 +408,100 @@ public List<Role> findRolesByName(String name) {
405408 public Pair <List <Role >, Integer > findRolesByName (String name , String keyword , Long startIndex , Long limit ) {
406409 if (StringUtils .isNotBlank (name ) || StringUtils .isNotBlank (keyword )) {
407410 Pair <List <RoleVO >, Integer > data = roleDao .findAllByName (name , keyword , startIndex , limit , isCallerRootAdmin ());
408- int removed = removeRootAdminRolesIfNeeded (data .first ());
411+ int removed = removeRolesIfNeeded (data .first ());
409412 return new Pair <List <Role >,Integer >(ListUtils .toListOfInterface (data .first ()), Integer .valueOf (data .second () - removed ));
410413 }
411414 return new Pair <List <Role >, Integer >(new ArrayList <Role >(), 0 );
412415 }
413416
414417 /**
415- * Removes roles of the given list that have the type '{@link RoleType#Admin}' if the user calling the method is not a 'root admin'.
416- * The actual removal is executed via {@link #removeRootAdminRoles(List)}. Therefore, if the method is called by a 'root admin', we do nothing here.
418+ * Removes roles from the given list if the role has different or more permissions than the user's calling the method role
417419 */
418- protected int removeRootAdminRolesIfNeeded (List <? extends Role > roles ) {
419- if (!isCallerRootAdmin ()) {
420- return removeRootAdminRoles (roles );
421- }
422- return 0 ;
423- }
424-
425- /**
426- * Remove all roles that have the {@link RoleType#Admin}.
427- */
428- protected int removeRootAdminRoles (List <? extends Role > roles ) {
429- if (CollectionUtils .isEmpty (roles )) {
420+ protected int removeRolesIfNeeded (List <? extends Role > roles ) {
421+ if (roles .isEmpty ()) {
430422 return 0 ;
431423 }
432- Iterator <? extends Role > rolesIterator = roles .iterator ();
424+
425+ Long callerRoleId = getCurrentAccount ().getRoleId ();
426+ Map <String , Permission > callerRolePermissions = getRoleRulesAndPermissions (callerRoleId );
427+
433428 int count = 0 ;
429+ Iterator <? extends Role > rolesIterator = roles .iterator ();
434430 while (rolesIterator .hasNext ()) {
435431 Role role = rolesIterator .next ();
436- if ( RoleType . Admin == role . getRoleType ()) {
437- count ++;
438- rolesIterator . remove () ;
432+
433+ if ( role . getId () == callerRoleId || roleHasPermission ( callerRolePermissions , role )) {
434+ continue ;
439435 }
436+
437+ count ++;
438+ rolesIterator .remove ();
440439 }
440+
441441 return count ;
442442 }
443443
444+ /**
445+ * Checks if the role of the caller account has compatible permissions of the specified role.
446+ * For each permission of the role of the caller, the target role needs to contain the same permission.
447+ *
448+ * @param sourceRolePermissions the permissions of the caller role.
449+ * @param targetRole the role that the caller role wants to access.
450+ * @return True if the role can be accessed with the given permissions; false otherwise.
451+ */
452+ protected boolean roleHasPermission (Map <String , Permission > sourceRolePermissions , Role targetRole ) {
453+ Set <String > rulesAlreadyCompared = new HashSet <>();
454+ for (RolePermission rolePermission : findAllPermissionsBy (targetRole .getId ())) {
455+ boolean permissionIsRegex = rolePermission .getRule ().getRuleString ().contains ("*" );
456+
457+ for (String apiName : accountManager .getApiNameList ()) {
458+ if (!rolePermission .getRule ().matches (apiName ) || rulesAlreadyCompared .contains (apiName )) {
459+ continue ;
460+ }
461+
462+ if (rolePermission .getPermission () == Permission .ALLOW && (!sourceRolePermissions .containsKey (apiName ) || sourceRolePermissions .get (apiName ) == Permission .DENY )) {
463+ return false ;
464+ }
465+
466+ rulesAlreadyCompared .add (apiName );
467+
468+ if (!permissionIsRegex ) {
469+ break ;
470+ }
471+ }
472+ }
473+
474+ return true ;
475+ }
476+
477+ /**
478+ * Given a role ID, returns a {@link Map} containing the API name as the key and the {@link Permission} for the API as the value.
479+ *
480+ * @param roleId ID from role.
481+ */
482+ public Map <String , Permission > getRoleRulesAndPermissions (Long roleId ) {
483+ Map <String , Permission > roleRulesAndPermissions = new HashMap <>();
484+
485+ for (RolePermission rolePermission : findAllPermissionsBy (roleId )) {
486+ boolean permissionIsRegex = rolePermission .getRule ().getRuleString ().contains ("*" );
487+
488+ for (String apiName : accountManager .getApiNameList ()) {
489+ if (!rolePermission .getRule ().matches (apiName )) {
490+ continue ;
491+ }
492+
493+ if (!roleRulesAndPermissions .containsKey (apiName )) {
494+ roleRulesAndPermissions .put (apiName , rolePermission .getPermission ());
495+ }
496+
497+ if (!permissionIsRegex ) {
498+ break ;
499+ }
500+ }
501+ }
502+ return roleRulesAndPermissions ;
503+ }
504+
444505 @ Override
445506 public List <Role > findRolesByType (RoleType roleType ) {
446507 return findRolesByType (roleType , null , null ).first ();
@@ -458,14 +519,14 @@ public Pair<List<Role>, Integer> findRolesByType(RoleType roleType, Long startIn
458519 @ Override
459520 public List <Role > listRoles () {
460521 List <? extends Role > roles = roleDao .listAll ();
461- removeRootAdminRolesIfNeeded (roles );
522+ removeRolesIfNeeded (roles );
462523 return ListUtils .toListOfInterface (roles );
463524 }
464525
465526 @ Override
466527 public Pair <List <Role >, Integer > listRoles (Long startIndex , Long limit ) {
467528 Pair <List <RoleVO >, Integer > data = roleDao .listAllRoles (startIndex , limit , isCallerRootAdmin ());
468- int removed = removeRootAdminRolesIfNeeded (data .first ());
529+ int removed = removeRolesIfNeeded (data .first ());
469530 return new Pair <List <Role >,Integer >(ListUtils .toListOfInterface (data .first ()), Integer .valueOf (data .second () - removed ));
470531 }
471532
0 commit comments