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 >> > >
