hi shane,

imo we just need a solution for your @CheckPermission example.
e.g. a custom annotation which can use the custom Operation (e.g. the
custom enum) directly. the custom annotation would be meta-annotated with a
marker annotation.

the rest shouldn't be a problem.

regards,
gerhard



2012/4/23 Shane Bryzak <[email protected]>

> On 23/04/12 18:03, Marek Posolda wrote:
>
>> Hi all,
>>
>>
>> On 22.4.2012 19:27, Christian Kaltepoth wrote:
>>
>>> I prefer the method signature Shane suggested in his initial mail.
>>> Providing a single method with an object parameter makes most sense to
>>> me:
>>>
>>>   Identity.hasPermission(Object resource, String operation)
>>>
>>> This way the developer is completely free to choose how to identify
>>> the resource. I think in most cases the object itself will be used.
>>> And the JSF example Shane showed is a very good example for this.
>>>
>>> Of cause people may need other ways to refer to resources like in the
>>> ResourceIdentifier concept Marek showed. But actually I see something
>>> like this more as an usage pattern and I don't think it belongs
>>> directly into the API. Perhaps we could provide something like
>>> ResourceIdentifier as an utility class that people can use if they
>>> want to refer to resources this way. But the API of Identity should be
>>> as simple as possible. And the object parameter will allow people to
>>> use any object they want. Even something like ResourceIdentifier.
>>>
>> That's the question. I think that API should be clear and using single
>> method:
>>
>> Identity.hasPermission(Object resource, String operation)
>>
>>
>> is not clear enough. As in some cases, your argument is directly secured
>> object and in other cases it's only ResourceIdentifier for this object.
>> Also it would mean that you will need to ask for the type of object in your
>> PermissionResolver implementation:
>>
>> if (resource instanceof ResourceIdentifier)
>> {
>>  // compute permissions for ResourceIdentifier
>> }
>> else
>> {
>>  // Argument is "resource" so compute permissions for this resource
>> }
>>
>>
>>
>>
>> On the other hand, using single method:
>> Identity.hasPermission(**ResourceIdentifier resource, Operation
>> operation)
>>
>> may not be appropriate enough for some use-cases. Let's imagine that you
>> have Customer and CustomerResourceIdntifier objects:
>>
>> public class Customer
>> {
>>   private String ID;
>>   private String customerName;
>>
>>   // getters and setters here
>> }
>>
>> public class CustomerResourceIdentifier implements ResourceIdentifier
>> {
>>     private String customerId;
>>
>>     // getters and setters
>> }
>>
>>
>> And you want to create PermissionResolver, which will compute permission
>> based on customer name. With the API method:
>>
>> Identity.hasPermission(**ResourceIdentifier resourceIdentifier,
>> Operation operation)
>>
>>
>> you can't manage to do it (unless you change implementation of
>> CustomerResourceIdentifier to encapsulate customerName)
>>
>>
>>  Operation
>>>
>> I agree that big advantage of this approach is type-safety. On the other
>> hand, using String directly is more flexible as you have more freedom.
>> Let's imagine that you have some permission rules stored in database and
>> you want to add new type of operation like "ADMINISTER". With using String
>> as argument, you can directly create records in DB and use this new
>> "ADMINISTER" argument without doing any changes in Java code. With the
>> Operation approach, you would need to add this new ADMINISTER operation
>> into your Operation enum:
>>
>
> This is exactly why the operation cannot be an enum - permissions will be
> stored in the database as string values, and if we use an enum value there
> will be no way of knowing which enum class the operation(s) string needs to
> be converted back into.  I should have actually expanded on the details of
> this a little bit earlier which would have made this more obvious.
>
> Another use case which I didn't mention is the ability to use bit flags to
> set permissions.  This is extremely important for a database with millions
> of records - instead of using a String in the database to store the
> operations it is possible to use a numerical value instead, with each bit
> representing a different operation.  It also allows us to define available
> permissions for a particular domain object, which is important when
> building management interfaces.
>
> Let's say we have the following entity:
>
> @Entity
> @Permissions({
>    @Permission(operation="create"**),
>    @Permission(operation="read"),
>    @Permission(operation="update"**),
>    @Permission(operation="delete"**)
> })
> public class Customer
> {
>  // snip
> }
>
> The @Permissions annotation tells the PermissionManager that we're allowed
> to assign four specific permissions; create, read, update and delete for
> the Customer entity.  We can take this a step further and define a bit mask
> value for each of these:
>
> @Entity
> @Permissions({
>    @Permission(operation="create"**, mask = 1),
>    @Permission(operation="read", mask = 2),
>    @Permission(operation="update"**, mask = 4),
>    @Permission(operation="delete"**, mask = 8)
> })
> public class Customer
> {
>  // snip
> }
>
> By providing mask values, the PermissionManager knows that the cumulative
> permissions for this entity will be stored in the database as a numerical
> value.  So a user with create, read and update permissions for a particular
> customer will have a stored operation value of 1 (create) + 2 (read) + 4
> (update) = 7.
>
>
>
>
>> public enum CrudOperation implements Operation
>> {
>>    CREATE, READ, UPDATE, DELETE, ADMINISTER
>> }
>>
>> I wanted to point this out, but I agree that for most cases is type-safe
>> approach with Operation interface probably better:-)
>>
>> So after all, my opinion is to have two methods:
>>
>> Identity.hasPermission(Object object, Operation operation) throws
>> AuthorizationException;
>> Identity.hasPermission(**ResourceIdentifier resourceIdentifier,
>> Operation operation) throws AuthorizationException;
>>
>
> +1, I think that having two methods is the best solution, with the caveat
> that overloading like this doesn't cause issues with EL.  The Object
> parameter version of this method will most likely delegate to the
> ResourceIdentifier method anyway, as a ResourceIdentifier will be required
> for all lookups.  By the way, we should make this as transparent as
> possible - out of the box, DeltaSpike should provide a ResourceIdentifier
> implementation for entity beans that will build a unique identifier based
> on the class name and the primary key value.  Another alternative that we
> should support is allowing the user to specify which ResourceIdentifier to
> use on the domain class itself:
>
> @Entity
> @Identifier(**CustomerResourceIdentifier.**class)
> public class Customer
> {
>
> }
>
> Yet another alternative that we should support is the packaging of
> additional ResourceIdentifier implementations with an application, that are
> automatically discovered and iterated through when the permission check
> can't determine which ResourceIdentifier to use.  With that in mind, the
> ResourceIdentifier interface should look like this:
>
> public interface ResourceIdentifier
> {
>    boolean canIdentify(Class targetClass);
>    String getIdentifier(Object resource);
> }
>
> The canIdentify() method will return true if the specified class is one
> that this ResourceIdentifier is capable of generating identifier strings
> for.
>
>
>>
>> Thanks,
>> Marek
>>
>
>

Reply via email to