You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by Nicolas Antoniazzi <ni...@gmail.com> on 2010/12/23 14:39:33 UTC

Permission on instance

Hello,

I am using shiro for the server side of a gwt application. I did not find a
clear explanation in the documentation about instance permission handling.
My permissions are stored in a database. With a users_roles table and a
roles_permissions table.

The doc says that we can use instance level for permission
("item:delete:13") with the WildcardPermission default system, where 13 is
the ID of the item.

Now, my question is :
1 - how to associate levels to permissions ? Do I have to store the
permission name + the level (edit, create, delete, ...) in the
roles_permissions table ?
example :
admin | item:create
admin | item:delete
admin | item:edit

2 - how to set up the instance access ?
If I grant access to everything, I suppose that I could something like : (if
previous example is correct)
admin | item:create:*
admin | item:delete:*
admin | item:edit:*

But if I only want to grant edit access on an item to users that have
created this item, how can I do ? I suppose that there should have a method
to overload somewhere but I am a bit lost.

Thanks,
Nicolas.

Re: Permission on instance

Posted by Nicolas Antoniazzi <ni...@gmail.com>.
Thanks both for your answers :

@Kalle :
I did not understood if RequiresAssociation could work without something
like JPA or Hibernate to manage permissions on entities ?
In my case, we are using myBatis which is a low level system.

@Jared :
I was thinking about overriding the wildcard system with special keywords
like you propose. I think that is a great idea.
I am going to try you solution. Thanks for the code !

Nicolas.


2010/12/23 Kalle Korhonen <ka...@gmail.com>

> On Thu, Dec 23, 2010 at 9:33 AM, Nicolas Antoniazzi
> <ni...@gmail.com> wrote:
> > Thanks Jared,
> > It's interresting. This was my first idea, but how to handle the fact
> that
> > severals users have access to the same permission on the item.
> > 1 - user that is the original creator of document can delete it (ok with
> > your code)
>
> I made a proposal for simplifying these types of permissions:
> http://www.mail-archive.com/dev@shiro.apache.org/msg00343.html,
> @RequiresAssociation will likely find its way to Shiro core at some
> point.
>
> Kalle
>

Re: Permission on instance

Posted by Kalle Korhonen <ka...@gmail.com>.
On Thu, Dec 23, 2010 at 9:33 AM, Nicolas Antoniazzi
<ni...@gmail.com> wrote:
> Thanks Jared,
> It's interresting. This was my first idea, but how to handle the fact that
> severals users have access to the same permission on the item.
> 1 - user that is the original creator of document can delete it (ok with
> your code)

I made a proposal for simplifying these types of permissions:
http://www.mail-archive.com/dev@shiro.apache.org/msg00343.html,
@RequiresAssociation will likely find its way to Shiro core at some
point.

Kalle

Re: Permission on instance

Posted by Jared Bunting <ja...@digitalreasoning.com>.
Just threw together an example of the sort of thing I¹m thinking
of...thoughts?  

The RelationshipPermission itself is quite hacky...but I couldn¹t find a
better way to tie into the WildcardPermission ³implies² method.  Also, I¹m
not sure if there are situations in which SecurityUtils.getSubject() isn¹t
sufficient, so you might want to pass the subject to
Relationship.satisfies(...) ­ but you¹d have to get it from there at some
point since it doesn¹t get passed to PermissionResolver ­ either that or
have your realm create RelationshipPermission objects directly.

public interface Relationship {
    boolean satisfies(String required);

    String getName();
}

public interface RelationshipSource {
    Relationship lookup(String name);
}

public class UndefinedRelationshipException extends ConfigurationException {
    public UndefinedRelationshipException(String name) {
        super(String.format("No relationship named '%s' is defined.",
name));
    }
}

public class RelationshipPermissionResolver implements PermissionResolver,
RelationshipSource {

    private Map<String, Relationship> relationships =
Collections.emptyMap();

    public RelationshipPermissionResolver() {
        this.relationships = new HashMap<String, Relationship>();
    }

    public void setRelationships(Map<String, Relationship> relationships) {
        this.relationships = relationships;
    }

    @Override
    public Permission resolvePermission(String permissionString) {
        return new RelationshipPermission(permissionString, this);
    }

    @Override
    public Relationship lookup(String name) {
        Relationship relationship = relationships.get(name);
        if(relationship == null) {
            throw new UndefinedRelationshipException(name);
        }
        return relationship;
    }
}

public class RelationshipPermission extends WildcardPermission {

    private RelationshipSource source;

    public RelationshipPermission(String wildcardString, RelationshipSource
source) {
        super(wildcardString);
        this.source = source;
    }

    public RelationshipPermission(String wildcardString, boolean
caseSensitive, RelationshipSource source) {
        super(wildcardString, caseSensitive);
        this.source = source;
    }

    @Override
    protected void setParts(String wildcardString, boolean caseSensitive) {
        super.setParts(wildcardString, caseSensitive);
        List<Set<String>> parts = this.getParts();
        for(int i = 0; i < parts.size(); i++) {
            parts.set(i, new RelationshipSet(parts.get(i)));
        }
    }

    private class RelationshipSet extends AbstractSetDecorator<String> {

        private RelationshipSet(Set<String> strings) {
            super(strings);
        }

        @Override
        public boolean containsAll(Collection<?> coll) {
            for(Object object: coll) {
                if(!contains(object)) {
                    return false;
                }
            }
            return true;
        }

        @Override
        public boolean contains(Object object) {
            if(super.contains(object)) {
                return true;
            } else {
                if(object instanceof String) {
                    String string = (String) object;
                    for(String member: this.getSet()) {
                        if(member != null && member.startsWith("$")) {
                            Relationship relationship =
source.lookup(member.substring(1));
                            if(relationship.satisfies(string)) {
                                return true;
                            }
                        }
                    }
                }
                return false;
            }
        }
    }
}

public class ExampleRelationship implements Relationship {
    
    DocumentLookup documentLookup;
    
    @Override
    public boolean satisfies(String required) {
        Subject subject = SecurityUtils.getSubject();
        return subject != null &&
documentLookup.lookupDocumentByName(required).isOwner(subject);
    }

    @Override
    public String getName() {
        return "example";
    }
}



On 12/23/10 1:20 PM, "Jared Bunting" <ja...@digitalreasoning.com>
wrote:

> Nicolas,
> 
> The other thing that I¹ve considered doing (but haven¹t yet) is writing a
> custom Permission, and having my realm assign it to all users, that
> essentially lets me put properties in it.
> 
> So, CustomPermission ³document:delete:${ownedDocument}² would imply
> WildcardPermission ³dataStore:delete:5² iff the user owns document 5.  This
> way, admins could get ³dataStore:delete:*² and other people (say, managers)
> might get ³document:delete:${deptOwnership}².  I haven¹t worked out yet
> exactly how to define the property comparisons but they would probably point
> at some sort of global comparison singleton that accepts the subject.   One of
> my concerns is that then the permission object would be tied to a singleton ­
> not sure if that would present an issue or not.
> 
> Kalle¹s annotation seems to standardize how to do the second situation I
> mentioned before, but I¹m not sure how it would answer the other issues you
> proposed.  
> 
> I would love to get some more perspective on this, as I seem to be facing many
> of the same issues.
> 
> Thanks,
> Jared
> 
> On 12/23/10 11:33 AM, "Nicolas Antoniazzi" <ni...@gmail.com>
> wrote:
> 
>> Thanks Jared,
>> 
>> It's interresting. This was my first idea, but how to handle the fact that
>> severals users have access to the same permission on the item.
>> 1 - user that is the original creator of document can delete it (ok with your
>> code)
>> 2 - admin user should be allowed to delete the document too (so, you have to
>> add this case in the code)...
>> 3 ... Maybe other roles should have the right of deleting it too...
>> It could become a bit hard to maintain. 
>> 
>> 2010/12/23 Jared Bunting <ja...@digitalreasoning.com>
>>> I can tell you what I am currently doing to handle this situation, but I too
>>> am curious if there is a better way.
>>> 
>>> I have two slightly different situations that I am handling differently.  
>>> 
>>> In the first, we¹ll call the item ³dataStore² - there are only a few of them
>>> (but still created dynamically by the application), and users have different
>>> access to individual ones depending on if they¹re added as data consumers or
>>> data creators  (read/write).  For this, I have simply customized my realm
>>> logic to build permissions based on a separate table.  For any users in the
>>> data_store_reader table, they get the permission: dataStore:read:id1,id2,id5
>>> ­ where the ids are the names of datastores that they have access to.
>>> 
>>> In the second, we¹ll call the item ³document².  There are lots of them,
>>> they¹re created and deleted all the time.  Only the original creator has
>>> access to them.  For this situation, I have ignored the concept of
>>> permissions altogether.  In the item methods themselves (either directly, or
>>> via aop, I haven¹t decided which is best, it probably depends on the exact
>>> situation) I simply do something along the lines of:
>>> 
>>> If(!SecurityUtils.getSubject().isAuthenticated()) {
>>>   throw new UnauthenticatedException(³User must be logged in to access
>>> documents.²);
>>> } else If(!this.getOwner().equals(SecurityUtils.getSubject().getPrincipal())
>>> {
>>>   throw new UnauthorizedException(³Document ³ + this.getId() + ³ is not
>>> owned by ³ + SecurityUtils.getSubject().getPrincipal());
>>> }
>>> 
>>> I¹d be happy to further discuss any techniques and would love to hear from
>>> anyone else regarding other/better ways of approaching this sort of
>>> situation.
>>> 
>>> Thanks,
>>> Jared  
>>> 
>>> 
>>> On 12/23/10 7:39 AM, "Nicolas Antoniazzi" <nicolas.antoniazzi@gmail.com
>>> <ht...@gmail.com> > wrote:
>>> 
>>>> Hello,
>>>> 
>>>> I am using shiro for the server side of a gwt application. I did not find a
>>>> clear explanation in the documentation about instance permission handling.
>>>> My permissions are stored in a database. With a users_roles table and a
>>>> roles_permissions table.
>>>> 
>>>> The doc says that we can use instance level for permission
>>>> ("item:delete:13") with the WildcardPermission default system, where 13 is
>>>> the ID of the item.
>>>> 
>>>> Now, my question is : 
>>>> 1 - how to associate levels to permissions ? Do I have to store the
>>>> permission name + the level (edit, create, delete, ...) in the
>>>> roles_permissions table ?
>>>> example :
>>>> admin | item:create
>>>> admin | item:delete
>>>> admin | item:edit
>>>> 
>>>> 2 - how to set up the instance access ?
>>>> If I grant access to everything, I suppose that I could something like :
>>>> (if previous example is correct)
>>>> admin | item:create:*
>>>> admin | item:delete:*
>>>> admin | item:edit:*
>>>> 
>>>> But if I only want to grant edit access on an item to users that have
>>>> created this item, how can I do ? I suppose that there should have a method
>>>> to overload somewhere but I am a bit lost.
>>>> 
>>>> Thanks,
>>>> Nicolas.
>>>> 
>> 
>> 
> 


Re: Permission on instance

Posted by Jared Bunting <ja...@digitalreasoning.com>.
Nicolas,

The other thing that I¹ve considered doing (but haven¹t yet) is writing a
custom Permission, and having my realm assign it to all users, that
essentially lets me put properties in it.

So, CustomPermission ³document:delete:${ownedDocument}² would imply
WildcardPermission ³dataStore:delete:5² iff the user owns document 5.  This
way, admins could get ³dataStore:delete:*² and other people (say, managers)
might get ³document:delete:${deptOwnership}².  I haven¹t worked out yet
exactly how to define the property comparisons but they would probably point
at some sort of global comparison singleton that accepts the subject.   One
of my concerns is that then the permission object would be tied to a
singleton ­ not sure if that would present an issue or not.

Kalle¹s annotation seems to standardize how to do the second situation I
mentioned before, but I¹m not sure how it would answer the other issues you
proposed.  

I would love to get some more perspective on this, as I seem to be facing
many of the same issues.

Thanks,
Jared

On 12/23/10 11:33 AM, "Nicolas Antoniazzi" <ni...@gmail.com>
wrote:

> Thanks Jared,
> 
> It's interresting. This was my first idea, but how to handle the fact that
> severals users have access to the same permission on the item.
> 1 - user that is the original creator of document can delete it (ok with your
> code)
> 2 - admin user should be allowed to delete the document too (so, you have to
> add this case in the code)...
> 3 ... Maybe other roles should have the right of deleting it too...
> It could become a bit hard to maintain. 
> 
> 2010/12/23 Jared Bunting <ja...@digitalreasoning.com>
>> I can tell you what I am currently doing to handle this situation, but I too
>> am curious if there is a better way.
>> 
>> I have two slightly different situations that I am handling differently.  
>> 
>> In the first, we¹ll call the item ³dataStore² - there are only a few of them
>> (but still created dynamically by the application), and users have different
>> access to individual ones depending on if they¹re added as data consumers or
>> data creators  (read/write).  For this, I have simply customized my realm
>> logic to build permissions based on a separate table.  For any users in the
>> data_store_reader table, they get the permission: dataStore:read:id1,id2,id5
>> ­ where the ids are the names of datastores that they have access to.
>> 
>> In the second, we¹ll call the item ³document².  There are lots of them,
>> they¹re created and deleted all the time.  Only the original creator has
>> access to them.  For this situation, I have ignored the concept of
>> permissions altogether.  In the item methods themselves (either directly, or
>> via aop, I haven¹t decided which is best, it probably depends on the exact
>> situation) I simply do something along the lines of:
>> 
>> If(!SecurityUtils.getSubject().isAuthenticated()) {
>>   throw new UnauthenticatedException(³User must be logged in to access
>> documents.²);
>> } else If(!this.getOwner().equals(SecurityUtils.getSubject().getPrincipal())
>> {
>>   throw new UnauthorizedException(³Document ³ + this.getId() + ³ is not owned
>> by ³ + SecurityUtils.getSubject().getPrincipal());
>> }
>> 
>> I¹d be happy to further discuss any techniques and would love to hear from
>> anyone else regarding other/better ways of approaching this sort of
>> situation.
>> 
>> Thanks,
>> Jared  
>> 
>> 
>> On 12/23/10 7:39 AM, "Nicolas Antoniazzi" <nicolas.antoniazzi@gmail.com
>> <ht...@gmail.com> > wrote:
>> 
>>> Hello,
>>> 
>>> I am using shiro for the server side of a gwt application. I did not find a
>>> clear explanation in the documentation about instance permission handling.
>>> My permissions are stored in a database. With a users_roles table and a
>>> roles_permissions table.
>>> 
>>> The doc says that we can use instance level for permission
>>> ("item:delete:13") with the WildcardPermission default system, where 13 is
>>> the ID of the item.
>>> 
>>> Now, my question is : 
>>> 1 - how to associate levels to permissions ? Do I have to store the
>>> permission name + the level (edit, create, delete, ...) in the
>>> roles_permissions table ?
>>> example :
>>> admin | item:create
>>> admin | item:delete
>>> admin | item:edit
>>> 
>>> 2 - how to set up the instance access ?
>>> If I grant access to everything, I suppose that I could something like : (if
>>> previous example is correct)
>>> admin | item:create:*
>>> admin | item:delete:*
>>> admin | item:edit:*
>>> 
>>> But if I only want to grant edit access on an item to users that have
>>> created this item, how can I do ? I suppose that there should have a method
>>> to overload somewhere but I am a bit lost.
>>> 
>>> Thanks,
>>> Nicolas.
>>> 
> 
> 


Re: Permission on instance

Posted by Nicolas Antoniazzi <ni...@gmail.com>.
Thanks Jared,

It's interresting. This was my first idea, but how to handle the fact that
severals users have access to the same permission on the item.
1 - user that is the original creator of document can delete it (ok with
your code)
2 - admin user should be allowed to delete the document too (so, you have to
add this case in the code)...
3 ... Maybe other roles should have the right of deleting it too...
It could become a bit hard to maintain.

2010/12/23 Jared Bunting <ja...@digitalreasoning.com>

>  I can tell you what I am currently doing to handle this situation, but I
> too am curious if there is a better way.
>
> I have two slightly different situations that I am handling differently.
>
> In the first, we’ll call the item “dataStore” - there are only a few of
> them (but still created dynamically by the application), and users have
> different access to individual ones depending on if they’re added as data
> consumers or data creators  (read/write).  For this, I have simply
> customized my realm logic to build permissions based on a separate table.
>  For any users in the data_store_reader table, they get the permission:
> dataStore:read:id1,id2,id5 – where the ids are the names of datastores that
> they have access to.
>
> In the second, we’ll call the item “document”.  There are lots of them,
> they’re created and deleted all the time.  Only the original creator has
> access to them.  For this situation, I have ignored the concept of
> permissions altogether.  In the item methods themselves (either directly, or
> via aop, I haven’t decided which is best, it probably depends on the exact
> situation) I simply do something along the lines of:
>
> If(!SecurityUtils.getSubject().isAuthenticated()) {
>   throw new UnauthenticatedException(“User must be logged in to access
> documents.”);
> } else
> If(!this.getOwner().equals(SecurityUtils.getSubject().getPrincipal()) {
>   throw new UnauthorizedException(“Document “ + this.getId() + “ is not
> owned by “ + SecurityUtils.getSubject().getPrincipal());
> }
>
> I’d be happy to further discuss any techniques and would love to hear from
> anyone else regarding other/better ways of approaching this sort of
> situation.
>
> Thanks,
> Jared
>
>
> On 12/23/10 7:39 AM, "Nicolas Antoniazzi" <ni...@gmail.com>
> wrote:
>
> Hello,
>
> I am using shiro for the server side of a gwt application. I did not find a
> clear explanation in the documentation about instance permission handling.
> My permissions are stored in a database. With a users_roles table and a
> roles_permissions table.
>
> The doc says that we can use instance level for permission
> ("item:delete:13") with the WildcardPermission default system, where 13 is
> the ID of the item.
>
> Now, my question is :
> 1 - how to associate levels to permissions ? Do I have to store the
> permission name + the level (edit, create, delete, ...) in the
> roles_permissions table ?
> example :
> admin | item:create
> admin | item:delete
> admin | item:edit
>
> 2 - how to set up the instance access ?
> If I grant access to everything, I suppose that I could something like :
> (if previous example is correct)
> admin | item:create:*
> admin | item:delete:*
> admin | item:edit:*
>
> But if I only want to grant edit access on an item to users that have
> created this item, how can I do ? I suppose that there should have a method
> to overload somewhere but I am a bit lost.
>
> Thanks,
> Nicolas.
>
>

Re: Permission on instance

Posted by Jared Bunting <ja...@digitalreasoning.com>.
I can tell you what I am currently doing to handle this situation, but I too
am curious if there is a better way.

I have two slightly different situations that I am handling differently.

In the first, we¹ll call the item ³dataStore² - there are only a few of them
(but still created dynamically by the application), and users have different
access to individual ones depending on if they¹re added as data consumers or
data creators  (read/write).  For this, I have simply customized my realm
logic to build permissions based on a separate table.  For any users in the
data_store_reader table, they get the permission: dataStore:read:id1,id2,id5
­ where the ids are the names of datastores that they have access to.

In the second, we¹ll call the item ³document².  There are lots of them,
they¹re created and deleted all the time.  Only the original creator has
access to them.  For this situation, I have ignored the concept of
permissions altogether.  In the item methods themselves (either directly, or
via aop, I haven¹t decided which is best, it probably depends on the exact
situation) I simply do something along the lines of:

If(!SecurityUtils.getSubject().isAuthenticated()) {
  throw new UnauthenticatedException(³User must be logged in to access
documents.²);
} else If(!this.getOwner().equals(SecurityUtils.getSubject().getPrincipal())
{
  throw new UnauthorizedException(³Document ³ + this.getId() + ³ is not
owned by ³ + SecurityUtils.getSubject().getPrincipal());
}

I¹d be happy to further discuss any techniques and would love to hear from
anyone else regarding other/better ways of approaching this sort of
situation.

Thanks,
Jared  

On 12/23/10 7:39 AM, "Nicolas Antoniazzi" <ni...@gmail.com>
wrote:

> Hello,
> 
> I am using shiro for the server side of a gwt application. I did not find a
> clear explanation in the documentation about instance permission handling.
> My permissions are stored in a database. With a users_roles table and a
> roles_permissions table.
> 
> The doc says that we can use instance level for permission ("item:delete:13")
> with the WildcardPermission default system, where 13 is the ID of the item.
> 
> Now, my question is : 
> 1 - how to associate levels to permissions ? Do I have to store the permission
> name + the level (edit, create, delete, ...) in the roles_permissions table ?
> example :
> admin | item:create
> admin | item:delete
> admin | item:edit
> 
> 2 - how to set up the instance access ?
> If I grant access to everything, I suppose that I could something like : (if
> previous example is correct)
> admin | item:create:*
> admin | item:delete:*
> admin | item:edit:*
> 
> But if I only want to grant edit access on an item to users that have created
> this item, how can I do ? I suppose that there should have a method to
> overload somewhere but I am a bit lost.
> 
> Thanks,
> Nicolas.
>