My sentiments exactly.

There are a lot of SNACs (shiny new ACronyms) popping up every few months that 
“some other framework” may have that are “missing” from Shiro,
like many variants of **BAC (which are very much too vaguely defined, and not 
in any way standard)
All of this can easily be solved by a few lines of custom code (in custom realm 
etc.)
You can’t possibly chase all those vague acronyms and succeed.

Saying that, I am not opposed to adding some sort of additional abstraction 
layer for **BAC, but it has to be well defined.

Here is what I see as viable options:
- Write an implementation yourself on top of Shiro, get traction in the wild, 
and then contribute it to Shiro, if still makes sense.
- Point out specific code / features / documentation in another framework that 
implements your feature that has traction in the industry,
i.e. has proven useful in the wild, and propose inclusion of such specific 
functionality in Shiro.

> On Jul 7, 2016, at 3:02 AM, Richard Bradley <[email protected]> 
> wrote:
> 
> Could you explain what the benefit of this is over just implementing those 
> restrictions in plain old Java code directly?
> 
> Each of the use cases you have given could be translated into plain old Java 
> code more or less 1-1 and the resulting code would be:
> 1. simpler
> 2. more maintainable
> 3. more accessible to newcomers (no new language needs to be learnt)
> 4. benefit from IDE support and static analysis support
> 5. likely more reliable (there are fewer moving parts; no AOP framework is 
> needed etc.; no chance of bugs in the implementation of @RequiresAttributes 
> or misunderstandings in its usage)
> 6. easier to test
> 
> The only downside I can see is that it might be slightly harder to statically 
> verify that a developer has remembered to address security (in the proposed 
> version you might be able to write a unit tests that asserts that all 
> relevant methods have a non-empty "@RequiresAttributes" annotation).
> 
> Here are the examples from below rewritten in POJ:
> 
> Assume the following helper code is imported in each case:
> 
> public class AuthenticationHelper {
>  public static void assertAuth(bool ok) {
>    if (!ok) {
>      throw new AuthenticationException("Insufficient permissions");
>    }
>  }
> 
>  public static User currentUser() {
>    // create a domain-specific User class from Shiro's 
> SecurityUtils.getSubject()
>  }
> }
> 
> Example of use case #1:
> 
> public class ProfileEditor {
> 
>    // all users implicitly have permission to edit their own profile,
>    // so don't need RequiresPermissions, but we do need to check
>    // that the profile belongs to this user
>    public void store(Profile userProfile) {
>      assertAuth(currentUser().id == userProfile.userId);
> 
>        // TODO: store the changes
>    }
> 
> }
> 
> Example of use case #2:
> 
> public class Project {
>    List<String> getMemberIds() {
>        // TODO: return list of member ids in this project
>    }
> 
>    // the user has role "project manager" with a "settings:edit" permission
>    // BUT... it's only for this project, not for all projects!
>    @RequiresPermissions("settings:edit")
>    public void editSettings(String key, String newValue) {
>       assertAuth(getMemberIds().contains(currentUser().id));
> 
>        // TODO: change the setting
>    }
> 
> }
> 
> Example of use case #3:
> 
> public class ClassifiedDocumentRepository {
> 
>    @RequiresPermissions("documents:store")
>    public void storeDocument(@Map("document") Document doc) {
>        assertAuth(currentUser().clearanceLevel >= document.clearanceLevel);
>        // TODO: store the document
>    }
> 
>    // applying access control on return value here with special variable 
> $return
>    @RequiresPermissions("documents:retrieve")
>    public Document retrieveDocument(String documentId) {
>        // TODO: find the document and its metadata
> 
>        Document document = ...
> 
>        assertAuth(currentUser().clearanceLevel >= document.clearanceLevel);
>        return document;
>    }
> 
> 
> }
> 
> Best,
> 
> 
> Rich
> 
> 
> 
> -----Original Message-----
> From: jbuhacoff [mailto:[email protected]]
> Sent: 07 July 2016 05:19
> To: [email protected]
> Subject: Attribute-based access control
> 
> Hi, I've been using Shiro for a couple of years now in various projects with 
> annotations and the wildcard permission syntax. Now I have a new requirement 
> for ABAC, and I think it should be possible to add this capability to Shiro.
> I have a proposal below, and wanted to get some comments.  If there's 
> interest,  I would develop it myself and contribute the code & documentation.
> 
> Here are some use cases:
> 
> 1. a "my profile" or "my settings" feature:  user should be able to edit own 
> things but not everything in the table.
> 
> 2. project or organization based permissions:  user should be able to read 
> documents in a project while user is associated with the project or team, 
> possibly combined with a general "can read documents" permission.
> 
> 3. clearance level:  user has a "can read documents" permission but this 
> needs to be matched with the user's clearance level and the document's 
> clearance level.
> 
> I see attribute-based access control as being a nice complement and 
> orthogonal to the permission-based access control.  A given method could be 
> annotated with either one or both together to achieve the right level of 
> control.
> 
> My proposal is to add a new annotation  @RequiresAttributes   and to let its
> value be a boolean expression to be evaluated.  Of course the expression will 
> need to be able to refer to the current user, the object in question, and 
> maybe even other things like the time of day, the https client certificate, 
> or whatever. Getting these bits of info into the context of the expression 
> language would be a combination of three things:  1) the realm can set some 
> context when the user is authenticated based on information available at that 
> time (user attributes, connection attributes, etc.) , 2) there could be 
> generic "attribute injectors" like for calendar/time, system properties, or 
> other things that are neither user nor object in question;
> 3)  a new @Map annotation that can be applied to method parameters in order 
> to give them a specific name in the expression.
> 
> Also there is a special case when we might want to apply attribute-based 
> permissions on the return value of a method. For this we have another 
> annotation @RequiresAttributesOnReturn which would be applied with around 
> advice, calling proceed() and then checking permissions using the return 
> value of the original method bound to a special variable $return.
> 
> Both @RequiresAttributes and @RequiresAttributesOnReturn would have 
> corresponding methods that could be called directly from anywhere in the code 
> in order to perform the same evaluation without annotations.
> 
> Special variable $this would be available to expressions annotated on 
> instance methods.
> 
> Variables and methods of objects would be accessible via dot notation, with 
> automatic use of bean-style "getter" methods when they exist.
> 
> In all the following examples, $user is a variable bound by the 
> authentication realm to a User object with methods String getId() and Integer 
> getClearanceLevel().
> 
> Example of use case #1:
> 
> public class ProfileEditor {
> 
>    // all users implicitly have permission to edit their own profile,
>    // so don't need RequiresPermissions, but we do need to check
>    // that the profile belongs to this user
>    @RequiresAttributes("$user.id = $profile.userId")
>    public void store(@Map("profile") Profile userProfile) {
>        // TODO: store the changes
>    }
> 
> }
> 
> Example of use case #2:
> 
> public class Project {
>    List<String> getMemberIds() {
>        // TODO: return list of member ids in this project
>    }
> 
>    // the user has role "project manager" with a "settings:edit" permission
>    // BUT... it's only for this project, not for all projects!
>    // also special variable $this refers to enclosing class instance
>    @RequiresPermissions("settings:edit")
>    @RequiresAttributes("$this.memberIds.contains($user.id)")
>    public void editSettings(String key, String newValue) {
>        // TODO: change the setting
>    }
> 
> }
> 
> Example of use case #3:
> 
> public class ClassifiedDocumentRepository {
> 
>    @RequiresPermissions("documents:store")
>    @RequiresAttributes("$user.clearanceLevel >= $document.clearanceLevel")
>    public void storeDocument(@Map("document") Document doc) {
>        // TODO: store the document
>    }
> 
>    // applying access control on return value here with special variable 
> $return
>    @RequiresPermissions("documents:retrieve")
>    @RequiresAttributesOnReturn("$user.clearanceLevel >=
> $return.clearanceLevel")
>    public Document retrieveDocument(String documentId) {
>        // TODO: find the document and its metadata
>        return document;
>    }
> 
> 
> }
> 
> 
> 
> 
> 
> 
> 
> --
> View this message in context: 
> http://shiro-user.582556.n2.nabble.com/Attribute-based-access-control-tp7581093.html
> Sent from the Shiro User mailing list archive at Nabble.com.
> 
> Richard Bradley
> Tel : 020 7485 7500 ext 3230 | Fax : 020 7485 7575
> 
> softwire
> Sunday Times Best Small Companies - UK top 25 six years running
> Web : www.softwire.com<http://www.softwire.com/> | Follow us on Twitter : 
> @SoftwireUK<https://twitter.com/SoftwireUK>
> Addr : 110 Highgate Studios, 53-79 Highgate Road, London NW5 1TL
> Softwire Technology Limited. Registered in England no. 3824658. Registered 
> Office : Gallery Court, 28 Arcadia Avenue, Finchley, London. N3 2FG
> 

Reply via email to