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