[katello-devel] Permission Matrix discussion

Lukas Zapletal lzap at redhat.com
Wed Jul 13 08:50:11 UTC 2011


 >>>
So I looked at the "Org" table in the latest version of the 
https://fedorahosted.org/katello/wiki/PermissionMatrix and see that 
there is an inconsistency between the way Lukas (1st proposal) and 
Justin (2nd) seem to define the permission. 	
 >>>

Well Justin's version is pretty same as my "rough version" and the only 
difference is instead of database rules

allowed_to?(create_env, organizations, org_id)
allowed_to?(read_env, organizations, org_id)
allowed_to?(update_env, organizations, org_id)
allowed_to?(destroy_env, organizations, org_id)

there are

allowed_to?(read, organizations, org_id)
allowed_to?(update, organizations, org_id)

The former version gives us possibility to assign particular verbs 
(CRUD) on (all) environments without additional checks (but there's need 
of creating tags), the latter integrates all CUD operations into one 
(update). I have no problem with that :-)

Now let me analyze this more deeply how to actually implement this (2nd) 
approach.

There is no need of modifying our RBAC codebase, and it is very easy to 
implement all cases from the wiki page, including the 2nd one. If you 
look here

https://engineering.redhat.com/trac/kalpana/wiki/Authorization

and open up authorization.rb method enforce_permission

<snip>

   # performs permission checks - do not override this method and
   # create check_permissions(operation) instead and return true if
   # permission is granted or call access_denied(operation) explicitely
   # for an intermediate denial

   def enforce_permissions operation
     # we get called again with the operation being set to create
     return true if operation == :update and new_record?

     # method A - developer defined permissions
     #            (can veto using SecurityViolation)
     if respond_to? :check_permissions
       return true if check_permissions operation
     end

     # method B - database (user) defined permissions
     return true if enforce_db_permissions operation

     # authorization unsuccessful
     access_denied operation
   end

   # enforce permissions from database for regular users

   def enforce_db_permissions(operation)
     User.allowed_to?(operation, type_name, self.id.to_s) or
       User.allowed_to?(operation, type_name)
   end

</snip>

you can see the RBAC stack is calling developer-defined checks first 
(check_permission method). In this case it will contain our 
"allowed_to?(update, organizations, org_id)" statement:

Now there are two more scenarios here:

A) If the permission is not found (allowed_to? returns false) we can 
raise SecurityViolation and access is denied. That's the simple case 
which does not allow finer granularity.

B) Or we can just return false here and the RBAC code will try to 
perform one additional check (see enforce_db_permissions method) - it 
tries to find this rule (assuming update operation) with (and also 
without) the record id. In this case (environments) it would be 
something like:

allowed_to?(:update, 'environments', 'id')

When a permission is found access is granted, denied otherwise. If we 
allow user to define permissions on environment resources in the UI (he 
currently can as all database tables are able to return tags (ids) and 
they are included there the granularity can be quite fine here.

Its upon us if we allow users to "post-define" (its not redefinition 
because developer-defined check goes first) rules or not. If we hide 
environment from the permission UI pane he wont be able to do that. The 
framework is ready.

Please note user would be also allowed to create permission for "all" 
environments providing "any" option in the UI screen. Because this 
permission whould be stored without an id and the RBAC code checks for 
this as well.

So at the end of the day it would be something like:

<snip>

   def check_permissions operation
     allowed_to?(:update, type_name, id) || raise SecurityViolation
   end

</snip>

for the first case (not allowing user to "post-define" additional 
permission), or

<snip>

   def check_permissions operation
     allowed_to?(:update, type_name, id)
   end

</snip>

allowing him to do that.

Wrapping up I am perfectly fine with the 2nd approach. It will just need 
one more line in the check_permission method - but that's the reason why 
did I created such a framework. The "S2 - fine appoach" would not need 
that giving the same result without explicit check_permission 
implementation, but also creating more tags in the RBAC tables (and some 
code for that).

Protecting REST resources is another story, but I would strongly suggest 
to start with protecting controllers and database resources first. The 
latter is being discussed now. Framework for the former is also 
in-place, the only issue is to unify protection of API and UI 
controllers (probably conventions over configuration, or with aliases).

LZ

-- 
Later,

  Lukas Zapletal | E32E400A
  RHN Satellite Engineering
  Red Hat Czech s.r.o. Brno




More information about the katello-devel mailing list