1616// under the License.
1717package org .apache .cloudstack .acl ;
1818
19+ import java .util .ArrayList ;
1920import java .util .HashMap ;
2021import java .util .HashSet ;
2122import java .util .List ;
@@ -48,7 +49,7 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
4849 private List <PluggableService > services ;
4950 private Map <RoleType , Set <String >> annotationRoleBasedApisMap = new HashMap <RoleType , Set <String >>();
5051
51- private static final Logger logger = Logger .getLogger (DynamicRoleBasedAPIAccessChecker .class .getName ());
52+ private static final Logger LOGGER = Logger .getLogger (DynamicRoleBasedAPIAccessChecker .class .getName ());
5253
5354 protected DynamicRoleBasedAPIAccessChecker () {
5455 super ();
@@ -57,22 +58,58 @@ protected DynamicRoleBasedAPIAccessChecker() {
5758 }
5859 }
5960
60- private void denyApiAccess (final String commandName ) throws PermissionDeniedException {
61- throw new PermissionDeniedException ("The API " + commandName + " is denied for the account's role." );
61+ @ Override
62+ public List <String > getApisAllowedToUser (Role role , User user , List <String > apiNames ) throws PermissionDeniedException {
63+ if (!isEnabled ()) {
64+ return apiNames ;
65+ }
66+
67+ List <RolePermission > allPermissions = roleService .findAllPermissionsBy (role .getId ());
68+ List <String > allowedApis = new ArrayList <>();
69+ for (String api : apiNames ) {
70+ if (checkApiPermissionByRole (role , api , allPermissions )) {
71+ allowedApis .add (api );
72+ }
73+ }
74+ return allowedApis ;
6275 }
6376
64- public boolean isDisabled () {
65- return !roleService .isEnabled ();
77+ /**
78+ * Checks if the given Role of an Account has the allowed permission for the given API.
79+ *
80+ * @param role to be used on the verification
81+ * @param apiName to be verified
82+ * @param allPermissions list of role permissions for the given role
83+ * @return if the role has the permission for the API
84+ */
85+ public boolean checkApiPermissionByRole (Role role , String apiName , List <RolePermission > allPermissions ) {
86+ for (final RolePermission permission : allPermissions ) {
87+ if (!permission .getRule ().matches (apiName )) {
88+ continue ;
89+ }
90+
91+ if (!Permission .ALLOW .equals (permission .getPermission ())) {
92+ return false ;
93+ }
94+
95+ if (LOGGER .isTraceEnabled ()) {
96+ LOGGER .trace (String .format ("The API [%s] is allowed for the role %s by the permission [%s]." , apiName , role , permission .getRule ().toString ()));
97+ }
98+ return true ;
99+ }
100+ return annotationRoleBasedApisMap .get (role .getRoleType ()) != null &&
101+ annotationRoleBasedApisMap .get (role .getRoleType ()).contains (apiName );
66102 }
67103
68104 @ Override
69105 public boolean checkAccess (User user , String commandName ) throws PermissionDeniedException {
70- if (isDisabled ()) {
106+ if (! isEnabled ()) {
71107 return true ;
72108 }
109+
73110 Account account = accountService .getAccount (user .getAccountId ());
74111 if (account == null ) {
75- throw new PermissionDeniedException ("The account id=" + user . getAccountId () + " for user id=" + user .getId () + "is null" );
112+ throw new PermissionDeniedException (String . format ( "The account id [%s] for user id [%s] is null." , user .getAccountId (), user . getUuid ()) );
76113 }
77114
78115 return checkAccess (account , commandName );
@@ -81,37 +118,32 @@ public boolean checkAccess(User user, String commandName) throws PermissionDenie
81118 public boolean checkAccess (Account account , String commandName ) {
82119 final Role accountRole = roleService .findRole (account .getRoleId ());
83120 if (accountRole == null || accountRole .getId () < 1L ) {
84- denyApiAccess ( commandName );
121+ throw new PermissionDeniedException ( String . format ( "The account [%s] has role null or unknown." , account ) );
85122 }
86123
87- // Allow all APIs for root admins
88124 if (accountRole .getRoleType () == RoleType .Admin && accountRole .getId () == RoleType .Admin .getId ()) {
125+ LOGGER .info (String .format ("Account [%s] is Root Admin or Domain Admin, all APIs are allowed." , account ));
89126 return true ;
90127 }
91128
92- // Check against current list of permissions
93- for (final RolePermission permission : roleService .findAllPermissionsBy (accountRole .getId ())) {
94- if (permission .getRule ().matches (commandName )) {
95- if (Permission .ALLOW .equals (permission .getPermission ())) {
96- return true ;
97- } else {
98- denyApiAccess (commandName );
99- }
100- }
101- }
102-
103- // Check annotations
104- if (annotationRoleBasedApisMap .get (accountRole .getRoleType ()) != null
105- && annotationRoleBasedApisMap .get (accountRole .getRoleType ()).contains (commandName )) {
129+ List <RolePermission > allPermissions = roleService .findAllPermissionsBy (accountRole .getId ());
130+ if (checkApiPermissionByRole (accountRole , commandName , allPermissions )) {
106131 return true ;
107132 }
108-
109- // Default deny all
110- throw new UnavailableCommandException ("The API " + commandName + " does not exist or is not available for this account." );
133+ throw new UnavailableCommandException (String .format ("The API [%s] does not exist or is not available for the account %s." , commandName , account ));
111134 }
112135
136+ /**
137+ * Only one strategy should be used between StaticRoleBasedAPIAccessChecker and DynamicRoleBasedAPIAccessChecker
138+ * Default behavior is to use the Dynamic version. The StaticRoleBasedAPIAccessChecker is the legacy version.
139+ * If roleService is enabled, then it uses the DynamicRoleBasedAPIAccessChecker, otherwise, it will use the
140+ * StaticRoleBasedAPIAccessChecker.
141+ */
113142 @ Override
114143 public boolean isEnabled () {
144+ if (!roleService .isEnabled ()) {
145+ LOGGER .trace ("RoleService is disabled. We will not use DynamicRoleBasedAPIAccessChecker." );
146+ }
115147 return roleService .isEnabled ();
116148 }
117149
0 commit comments