Oops. In the instance-level approach, the 2nd code check would be:
if (SecurityUtils.getSubject().isPermitted("post:read:" + postId) ) {
//show the post
}
This is the correct check to execute at runtime - an instance-specific
check, and _not_ SecurityUtils.getSubject().isPermitted("post:read")).
This latter check (isPermitted("post:read")) says "if the current
user has the ability to read all posts, show the current post". This
is slightly incorrect, because what you _really_ want to check is
"does the current user have the ability to read the current post".
The difference is subtle, but it is a crucial point to understand when
using implication logic to build security policies.
If the user is assigned the "post:read" permission, then that
_implies_ post:read:postId Runtime permissions checks should be as
specific as possible, while permission assignments can be (and usually
are) more general (e.g. "post:read").
Regards,
Les
On Wed, Dec 1, 2010 at 1:26 PM, Les Hazlewood <[email protected]> wrote:
> There are a number of ways to solve this.
>
> One way is that you assign permissions to a user that reflect the
> instances they can interact with.
>
> For example, if you assign the user the "post:read" permission (using
> Shiro's WildcardPermission syntax), then that user will be able to
> read all posts, e.g. subject.isPermitted("post:read") === true
>
> You can further assign permissions according to individual Post
> instances. Maybe you assign a permission at the time the user creates
> the post:
>
> Post post = new Post();
> ...
> long postId = postDAO.create(post);
> String editPostPermString = "post:edit:" + postId;
>
> long currentUserId = (long)SecurityUtils.getSubject().getPrincipal();
>
> userService.assignPermission(currentUserId, editPostPermString);
>
> Then, when a user visits a post page, you can check:
>
> if ( SecurityUtils.getSubject().isPermitted("post:edit:" + requestPostId) ) {
> //show the edit button
> }
> if ( SecurityUtils.getSubject().isPermitted("post:edit") ) {
> //general read request by anyone - show the post.
> }
>
> Don't forget to 'unassign' the permission from the user when you
> delete the post to make sure you don't have 'permission assignment
> orphans'. The downside of this approach is that the number of
> individual permissions assigned to the user can be very large, so your
> Realm implementation and the data model supporting the permission
> checks must be efficient.
>
> Another approach is to combine the WildcardPermission check and a data
> model check:
>
> For example:
>
> Post post = blogService.getPost(request.getParameter("postId"));
>
> boolean read = SecurityUtils.getSubject().isPermitted("post:read");
> boolean edit = isPostEditable(post);
>
> private boolean isPostEditable(Post post) {
> User currentUser =
> userService.findUser(SecurityUtils.getSubject().getPrincipal());
> if (currentUser.getId() == post.getAuthor().getId()) {
> return true;
> }
> return false;
> }
>
> You could also find this out via a join query:
>
> select p.author_id from posts p where p.id = ?
>
> As you can see, the 2nd approach is _very_ dependent upon your data
> model, so it would be difficult for Shiro to support this 'out of the
> box'. If anyone has any ideas that can make this even easier, please
> speak up!
>
> This is just a high-level approach of how you might do this in your
> own app, but hopefully this gives you some ideas.
>
> HTH,
>
> Les
>
>
> On Wed, Dec 1, 2010 at 12:30 PM, acec acec <[email protected]> wrote:
>> Hi, all
>> If I want to support the following function by shiro:
>>
>> The user can read all post, but can only edit/delete his own post.
>>
>> Is there any example for this kind of function?
>>
>> Thanks.
>> Acec