Hi Shane, if I'm following your thought the idea is to have security on object-level and not just check methods (resource level) as I was thinking with @CheckPermissions on the method level.
About filterDeniedInvocations I got it borrowed from SecurityInterceptor. I'm checking permissions on the method level only without going too deep with object-level. Thanks for clarify. On Wed, Apr 18, 2012 at 7:02 PM, Shane Bryzak <[email protected]> wrote: > 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. > >
