Instance level security w/ Permissions

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Instance level security w/ Permissions

Daniel J. Lauk
Hello, list.

I am considering rewriting my app's instance level security code.
Currently I use roles and evaluate certain fields on my objects for
governing instance level access.
I think, using permissions would help clean up the code a lot.

Now my question is -- just to be sure:
When I change the relationship of a user to a domain object, I'd have
to change permissions as well, right?

That means, put very abstract, that the code has to change like that:

//old
void changeReviewer(User aUser) {
    if (aUser == null)
        throw new BadParamException("aUser is null");
    this.setReviewer(aUser);
}

//new
void changeReviewer(User aUser) {
    if (aUser == null)
        throw new BadParamException("aUser is null");
    User oldReviewer = this.getReviewer();
    Transaction t = new Transaction();
    try {
        this.setReviewer(aUser);
        permDao.delete("entry:review:" + this.id, oldReviewer);
        permDao.create("entry:review:" + this.id, aUser);
        t.commit();
    } catch (Exception e) {
        t.rollback();
    }
}

Is this correct or am I horribly over complicating things right now?
I'm still not 100% sure about how to use permissions...

Thanks in advance!

Cheers,
DJ
Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

pledbrook
Hi Daniel,

> Now my question is -- just to be sure:
> When I change the relationship of a user to a domain object, I'd have
> to change permissions as well, right?

It depends. Rather than start with permissions and domain classes, I
think it will be easier to answer your question if you start with the
security rules you want to implement. For example, "I have lots of
books, each of which can only have one reviewer. The reviewer may
change but only the current one can review a particular book."

One thing you might want to consider: in this example model, each book
effectively has an associated permission record. If you have lots of
books, that means lots of permissions! Of course, if that's what the
model requires, then that's what you have to do :)

Cheers,

Peter
Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

Les Hazlewood-2
In reply to this post by Daniel J. Lauk
Hi DJ,

Instance-level permissions are very powerful indeed, however, you don't want to create hundreds or thousands of them.  Typically my applications use a mix of logic that requires knowledge of how the application works as well as permission checks:

Based on your example, I would only check if someone is allowed to review an entry if they are NOT the reviewer already assigned to the entry.

For example:
------------------
Subject currentSubject = SecurityUtils.getSubject();
User user = userDAO.findUser(currentSubject.getPrincipal());

if ( currentUser.equals(entry.getReviewer()) ||
     currentSubject.isPermitted("entry:review:" + entry.getId() ) ) {

    //allow them to review the entry
} else {
    //don't allow - show them an error message?
}
------------------

This is an example of implied permissioning - where you allow the review, because of your knowledge of the domain model - combined with explicit permissioning (with actual JSecurity permission checks).

This improves performance in three immediately noticeable ways:

1)  Due to Java's boolean 'short-circuiting', the JSecurity permission check is never executed unless the current user is _not_ the one assigned directly to it.  In most applications, the permission check is not executed frequently since the person 'assigned' to an entity is usually the one that interacts with it the most.

2)  When a JSecurity permission check *is* required, there are fewer instance-level permissions to filter through.  That is, if there are 10 permissions assigned to the user and or his roles, this is a faster check than say, if there were 100 permissions to check through.

3)  The lower the number of Permission instances in your RDBMS, the faster the queries are when constituting a user's authorization state.  Of course this is mitigated by appropriate 2nd-level caching in a Hibernate/JPA application too.

I hope that helps!  Please let me know if you have more questions.

Cheers,

Les

On Mon, Jan 26, 2009 at 9:35 AM, Daniel J. Lauk <[hidden email]> wrote:
Hello, list.

I am considering rewriting my app's instance level security code.
Currently I use roles and evaluate certain fields on my objects for
governing instance level access.
I think, using permissions would help clean up the code a lot.

Now my question is -- just to be sure:
When I change the relationship of a user to a domain object, I'd have
to change permissions as well, right?

That means, put very abstract, that the code has to change like that:

//old
void changeReviewer(User aUser) {
   if (aUser == null)
       throw new BadParamException("aUser is null");
   this.setReviewer(aUser);
}

//new
void changeReviewer(User aUser) {
   if (aUser == null)
       throw new BadParamException("aUser is null");
   User oldReviewer = this.getReviewer();
   Transaction t = new Transaction();
   try {
       this.setReviewer(aUser);
       permDao.delete("entry:review:" + this.id, oldReviewer);
       permDao.create("entry:review:" + this.id, aUser);
       t.commit();
   } catch (Exception e) {
       t.rollback();
   }
}

Is this correct or am I horribly over complicating things right now?
I'm still not 100% sure about how to use permissions...

Thanks in advance!

Cheers,
DJ

Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

Les Hazlewood-2
Oops - I meant to say "hundreds or thousands of them per user or per role".  I know of more than a few JSecurity-enabled applications with thousands of permissions, but they are spread across many users and/or roles.  The idea is to try to keep the number per role low if possible.

On Mon, Jan 26, 2009 at 10:22 AM, Les Hazlewood <[hidden email]> wrote:
Hi DJ,

Instance-level permissions are very powerful indeed, however, you don't want to create hundreds or thousands of them.  Typically my applications use a mix of logic that requires knowledge of how the application works as well as permission checks:

Based on your example, I would only check if someone is allowed to review an entry if they are NOT the reviewer already assigned to the entry.

For example:
------------------
Subject currentSubject = SecurityUtils.getSubject();
User user = userDAO.findUser(currentSubject.getPrincipal());

if ( currentUser.equals(entry.getReviewer()) ||
     currentSubject.isPermitted("entry:review:" + entry.getId() ) ) {

    //allow them to review the entry
} else {
    //don't allow - show them an error message?
}
------------------

This is an example of implied permissioning - where you allow the review, because of your knowledge of the domain model - combined with explicit permissioning (with actual JSecurity permission checks).

This improves performance in three immediately noticeable ways:

1)  Due to Java's boolean 'short-circuiting', the JSecurity permission check is never executed unless the current user is _not_ the one assigned directly to it.  In most applications, the permission check is not executed frequently since the person 'assigned' to an entity is usually the one that interacts with it the most.

2)  When a JSecurity permission check *is* required, there are fewer instance-level permissions to filter through.  That is, if there are 10 permissions assigned to the user and or his roles, this is a faster check than say, if there were 100 permissions to check through.

3)  The lower the number of Permission instances in your RDBMS, the faster the queries are when constituting a user's authorization state.  Of course this is mitigated by appropriate 2nd-level caching in a Hibernate/JPA application too.

I hope that helps!  Please let me know if you have more questions.

Cheers,

Les


On Mon, Jan 26, 2009 at 9:35 AM, Daniel J. Lauk <[hidden email]> wrote:
Hello, list.

I am considering rewriting my app's instance level security code.
Currently I use roles and evaluate certain fields on my objects for
governing instance level access.
I think, using permissions would help clean up the code a lot.

Now my question is -- just to be sure:
When I change the relationship of a user to a domain object, I'd have
to change permissions as well, right?

That means, put very abstract, that the code has to change like that:

//old
void changeReviewer(User aUser) {
   if (aUser == null)
       throw new BadParamException("aUser is null");
   this.setReviewer(aUser);
}

//new
void changeReviewer(User aUser) {
   if (aUser == null)
       throw new BadParamException("aUser is null");
   User oldReviewer = this.getReviewer();
   Transaction t = new Transaction();
   try {
       this.setReviewer(aUser);
       permDao.delete("entry:review:" + this.id, oldReviewer);
       permDao.create("entry:review:" + this.id, aUser);
       t.commit();
   } catch (Exception e) {
       t.rollback();
   }
}

Is this correct or am I horribly over complicating things right now?
I'm still not 100% sure about how to use permissions...

Thanks in advance!

Cheers,
DJ


Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

Daniel J. Lauk
Les, Peter,

thanks for the details.

>> Instance-level permissions are very powerful indeed, however, you don't
>> want to create hundreds or thousands of them.  Typically my applications use
>> a mix of logic that requires knowledge of how the application works as well
>> as permission checks:

So reducing the count of entries in the DB will speed things up? ;-)

>> Based on your example, I would only check if someone is allowed to review
>> an entry if they are NOT the reviewer already assigned to the entry.

Well, actually, nobody but the assigned reviewer is allowed.
As I will have the field around for DB queries anyway, I guess that
permissions don't add value from the app logic point of view.
Nevertheless they add value from the point of view that permissions go
along with functionality as opposed to roles.

Please correct me, if I'm wrong.

Cheers,
DJ
Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

Les Hazlewood-2
On Mon, Jan 26, 2009 at 11:58 AM, Daniel J. Lauk <[hidden email]> wrote:
Les, Peter,

thanks for the details.

>> Instance-level permissions are very powerful indeed, however, you don't
>> want to create hundreds or thousands of them.  Typically my applications use
>> a mix of logic that requires knowledge of how the application works as well
>> as permission checks:

So reducing the count of entries in the DB will speed things up? ;-)

:)

>> Based on your example, I would only check if someone is allowed to review
>> an entry if they are NOT the reviewer already assigned to the entry.

Well, actually, nobody but the assigned reviewer is allowed.
As I will have the field around for DB queries anyway, I guess that
permissions don't add value from the app logic point of view.

Well, that depends on your app logic ;)

For example, most of my applications have a 'root' user and/or a 'administrator' role.  Now, when the root user logs in, or someone who has the 'administrator' role logs in, I would want them to be able to see the entry if they so desired.  The 'administrator' role would be assigned the "entry:review" permission, allowing them to 'review' any entry.  Again, that would be my desire for my application - your application may not allow even an administrator to see such a thing.

Nevertheless they add value from the point of view that permissions go
along with functionality as opposed to roles.

Absolutely correct. 

In permission-based systems, Permissions describe raw application functionality - they are the 'what' can be done in an application and have no concept of 'who' can do something.

Similarly a Role is merely a named collection of Permissions. They aggregate raw functionality into a 'bundle' of sorts that describes the ability to do multiple things.  There is still no 'who' at this level.

The users are the 'who'.  'Who' can do 'what' is usually achieved by assigning one or more roles to a user, for example, user.getRoles().add(aRole);

If you have a dynamic role system, where you can add/delete roles at runtime, your application code _must_ check against permissions, not roles.

Cheers,

Les

Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

Daniel J. Lauk
>> Well, actually, nobody but the assigned reviewer is allowed.
>> As I will have the field around for DB queries anyway, I guess that
>> permissions don't add value from the app logic point of view.
>
> Well, that depends on your app logic ;)

Point taken. :-)
Actually, I don't mind to have this logic around. The one thing I
dislike though, is that I have to duplicate the code into the view of
my web application to hide unavailable functionality from the UI. I
hoped that with permissions it could turn out to a *simple* check.

> In permission-based systems, Permissions describe raw application
> functionality - they are the 'what' can be done in an application and have
> no concept of 'who' can do something.

Thanks for clarifying. I think I got that now. I'm only a little
clumsy at using it. Although -- coming from the grails plugin -- I
have to say that Peter's talk (w/ slides) made it a lot easier.

> Similarly a Role is merely a named collection of Permissions. They aggregate
> raw functionality into a 'bundle' of sorts that describes the ability to do
> multiple things.  There is still no 'who' at this level.
>
> The users are the 'who'.  'Who' can do 'what' is usually achieved by
> assigning one or more roles to a user, for example,
> user.getRoles().add(aRole);
>
> If you have a dynamic role system, where you can add/delete roles at
> runtime, your application code _must_ check against permissions, not roles.

That much was clear.

Thanks for the explanation and patience :-)

Cheers,
DJ
Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

Les Hazlewood-2
On Mon, Jan 26, 2009 at 2:25 PM, Daniel J. Lauk <[hidden email]> wrote:
>> Well, actually, nobody but the assigned reviewer is allowed.
>> As I will have the field around for DB queries anyway, I guess that
>> permissions don't add value from the app logic point of view.
>
> Well, that depends on your app logic ;)

Point taken. :-)
Actually, I don't mind to have this logic around. The one thing I
dislike though, is that I have to duplicate the code into the view of
my web application to hide unavailable functionality from the UI. I
hoped that with permissions it could turn out to a *simple* check.

You can still do this of course so you don't have to duplicate UI code - it is just a trade-off.  More rather than less permissions mean a little extra processing time.  But, if you don't assign hundreds per user or role, then it won't really matter for most applications.  The performance 'hit' will be negligible for most applications, especially if you use 2nd-level caching to minimize or eliminate RDBMS round trips.
 
> In permission-based systems, Permissions describe raw application
> functionality - they are the 'what' can be done in an application and have
> no concept of 'who' can do something.

Thanks for clarifying. I think I got that now. I'm only a little
clumsy at using it. Although -- coming from the grails plugin -- I
have to say that Peter's talk (w/ slides) made it a lot easier.

One thing that Peter (rightfully) tries to clarify as well is the difference between a permission assignment and a permission check.  Both situations use a permission instance, so that overlap sometimes confuses people.

Assignment: 

//allows the administrator role to 'edit' _any_ 'user':
adminstratorRole.addPermission( "user:edit" ); 

Check:

long idOfUserToEdit = //get the user ID being edited - perhaps as a query parameter

//now construct the permission instance to use during the check:
String editSpecificUser = "user:edit:" + idOfUserToEdit;

if ( currentSubject.hasPermission( editSpecificUser ) ) {

    //show the edit button
} else {
    //don't show them the edit button?  Gray it out?
}
 
Notice how the permission being checked is similar to the permission that was originally assigned.  That is because Permissions don't work as a simple equality check, there is _implication_ logic that occurs: "user:edit" permission (assigned) 'implies' the "user:edit:1234" permission (checked).

This does make permissions sometimes harder to understand, but once you get the concept of implication down, you can really harness their power. 

Thanks for the explanation and patience :-)

My pleasure :)

Cheers,

Les

Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

Jeremy Haile
In reply to this post by Daniel J. Lauk
>
> Actually, I don't mind to have this logic around. The one thing I
> dislike though, is that I have to duplicate the code into the view of
> my web application to hide unavailable functionality from the UI. I
> hoped that with permissions it could turn out to a *simple* check.

I understand wanting to avoid code duplication, but in my experience  
this is a common security paradigm.  You check permissions in the view  
to make sure you don't show a user something they can't do.  You then  
check the permission on the server in your business logic because you  
don't trust the view (what if they knew the URL that you hid in the  
view).
 
Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

Daniel J. Lauk
In reply to this post by Les Hazlewood-2
> You can still do this of course so you don't have to duplicate UI code - it
> is just a trade-off.  More rather than less permissions mean a little extra
> processing time.  But, if you don't assign hundreds per user or role, then
> it won't really matter for most applications.  The performance 'hit' will be
> negligible for most applications, especially if you use 2nd-level caching to
> minimize or eliminate RDBMS round trips.

I have never looked at it that way. Of course execution time is a
tradeoff as well. D'oh.
Thanks for the pointer. I'll have to ponder on all that again.

> One thing that Peter (rightfully) tries to clarify as well is the difference
> between a permission assignment and a permission check.  Both situations use
> a permission instance, so that overlap sometimes confuses people.

Yes, that actually was clear from the beginning. Almost. Not upon
first reading but definitely within my first day trying to learn
JSecurity :-)
The actual problem I had was the way the plugin works. I did not
understand that the domain class "JsecPermission" in fact was not a
JSecurity Permission in the sense of org.jsecurity.authz.Permission.
Instead it's "just" the DB entry to create one.

Anyway, by now I improved on Grails and Groovy and I think I got it now :-)

> Notice how the permission being checked is similar to the permission that
> was originally assigned.  That is because Permissions don't work as a simple
> equality check, there is _implication_ logic that occurs: "user:edit"
> permission (assigned) 'implies' the "user:edit:1234" permission (checked).
>
> This does make permissions sometimes harder to understand, but once you get
> the concept of implication down, you can really harness their power.

Yes. I think that is really powerful.
In particular the WildcardPermission is ingenious! I think I won't
have to code any custom permission classes.
The tradeoff is type safety -- I still don't know if that term
references data types or typing ;-) -- but with Groovy I just gave up
on types and stick to testing ;-)

Cheers,
DJ
Reply | Threaded
Open this post in threaded view
|

Re: Instance level security w/ Permissions

Daniel J. Lauk
In reply to this post by Jeremy Haile
> I understand wanting to avoid code duplication, but in my experience this is
> a common security paradigm.  You check permissions in the view to make sure
> you don't show a user something they can't do.  You then check the
> permission on the server in your business logic because you don't trust the
> view (what if they knew the URL that you hid in the view).

Actually, I think asking for the permission twice is "cleaner" than
having to duplicate something like 'only if the user has role
"reviewer" and is assigned as one of the reviewers and has not
reviewed yet'.
In this case the permission check would behave like invoking a method
that checks for all that and you only have to change the way the
permission works to have both (controller and view) work the same way.

But I dislike the notion of having hundreds of permission DB entries...

Cheers,
DJ