On 19/04/12 06:35, Bruno Oliveira wrote:
On Tue, Apr 17, 2012 at 7:52 PM, Shane Bryzak<[email protected]>  wrote:

I'd like to kick off a discussion around the Authorization API,
specifically object permissions.  This API is used to determine whether the
currently authenticated user has the necessary privileges to perform an
operation on a particular domain object.  I'll start by outlining my
proposal covering the simple use cases of this API and we can then proceed
from there.

First of all, the developer needs a gateway into the permission API so
that they can perform permission checks within their own application.  This
is provided by the hasPermission() method:

Hi Shane, good catch start to talk about it. Are you thinking about
something using CDI interceptors or observers? To permission checks?

Hi Bruno. Probably both, we definitely need a programmatic API (the hasPermission() method below) but I think a security binding type is also useful (also detailed below).



Identity.hasPermission(Object resource, String operation)

Does 'operation' here means CRUD operations?

CRUD would be supported here but the operation is not limited to CRUD, it can potentially be anything.



A permission has three aspects; 1) The application resource for which the
permission is granted, 2) The operation that has been granted for that
resource, and 3) The recipient of the permission, which may be either a
User, Group or Role.

For example, if we wish to check whether the user has permission to edit a
Customer instance the code might look like this:

@Inject Identity identity;

public void editCustomer(Customer customer)
{
    if (!identity.hasPermission(**customer, "EDIT"))
    {
        throw new AuthorizationException("**Insufficient privileges to
edit this customer");
    }

    // snip code
}

I like your idea. Currently I'm working on something similar to it with
interceptors:

@RequestScoped
public class DummyService {

     @SecurityRole(name = "admin")
     public void editCustomer(Customer customer) {
         //Something here
     }
}

This is an example of coarse-grained security, whereas ACL is fine-grained (object-level) security.



We could potentially also do some clever stuff with method-level
annotations here.  Off the top of my head, something like this might work:

@CheckPermissions
public void editCustomer(@CheckPermission(**"EDIT") Customer customer)

It would be great to specify "EDIT" on top of the method only
with @CheckPermission annotation.

How would you support specifying permission checks on multiple parameters of different types?


The @CheckPermissions annotation would be a security binding type with a
matching authorizer that would scan the parameter list and perform any
checks on parameters annotated with @CheckPermission.  Anyway we can refine
this idea in ongoing discussions.

Do you think that's a good idea do something like this?

@AroundInvoke
  public Object filterDeniedInvocations(InvocationContext invocationContext)
throws Exception {
       //read annotation value here with parameter list and perform checks
}

Not sure what you're suggesting here - could you please elaborate?


In the default implementation, the Identity.hasPermission() method
essentially contains no code, instead it delegates the permission check to
the PermissionMapper bean, an implementation-only bean which contains a
list of PermissionResolver instances that are used to perform the
permission check.

public class DefaultIdentity implements Identity
{
    // snip code

    public boolean hasPermission(Object resource, String operation)
    {
        return permissionMapper.**resolvePermission(resource, operation);
    }
}

The PermissionMapper bean provides the resolvePermission() method, which
basically iterates through the known PermissionResolvers, and if one of
them returns true for the permission check, then a true result is returned.

public class PermissionMapper
{
    @Inject Instance<PermissionResolver>  resolvers;

    public boolean resolvePermission(Object resource, String operation)
    {
        for (PermissionResolver resolver : resolvers)
        {
            if (resolver.hasPermission(**resource, operation)) return true;
        }
        return false;
    }
}

We can do some clever stuff here, like caching which permission resolver
returns a true result for a particular class of resource, and then always
using that resolver for that class, etc.

How do you think to cache it?

This is really just an implementation detail, but I think a Map<Class,PermissionResolver> would be sufficient.


PermissionResolver is an API interface, the implementations of which do
the actual work of checking the permission.

public interface PermissionResolver
{
    boolean hasPermission(Object resource, String operation);
}

We would provide one PermissionResolver implementation out of the box with
DeltaSpike; PersistentPermissionResolver would provide permission checks
for ACL-style object permissions and provide a key piece of functionality
required by a complete permission management API.  Developers can easily
provide their own PermissionResolver implementations with custom business
logic by simply deploying a PermissionResolver bean in their own
application.

This pretty much covers the basics of the object permission API, at least
on the consuming side.  We can discuss this area first before moving onto
the permission management API shortly.

What do you think about a separated branch to prototype it? Let me know if
I could help with something.



I guess it will depend on whether we introduce any/many changes as a result of discussion. This is just a small part of the authorization API and really requires some of the other parts (in particular permission management) to be really useful.

Reply via email to