Hi Les,
Thanks for your answer and the effort to write it in such details.
1. Your approach with permissions is also considered and I am evaluating
strong points and weak points in all available ideas. Having your approach
_written_ , I also found a strong point in it. That is, that in this case we
would not have to worry about bookmarked links or some weird flows as the
check for permission is performed with every request. The weak point (not so
weak -- i am just moaning here :) ) is that I have to play with permissions
at runtime in a wide usage scenario which might be error prone in some
cases. However, this would not be a big problem ... good thing is that my
security domain model fully matches the one you mentioned.
2. Regarding the access to the active subjects, I personally do not find it
as a performance problem from the following reasons :
a) Subjects are already there, we would just need access to them ... For
example, a SubjectStore and a SubjectListener or so, that updates the store
on : login/logout etc. At the moment i have a similar solution implemented
for my problem (store the subjects in Realm implementation) and am writing
some test cases to see if it breaks somewhere.
b) You said it wouldn't be a good idea to allow access to this big number of
objects but there is already access to all active sessions via
DefaultSecurityManager -> DefaultSessionManager ->
SessionDAO.getActiveSessions(). Is this path meant to be used in sessions'
mgt/access ? Is it for JSecurity users or is it meant for JSecurity
developers ?
I will add a jira feature request because I think, first ... it might be
useful in some conditions and may help avoiding workarounds and second ...
it is a decent feature even if problems can be sorted in other ways as well.
3. This is more a semantic question :
Why method logout(Subject s) in DefaultSecurityManager behaves different
from logout() in DelegatingSubject ?
if you do :
DefaultSecurityManager dsm = .......
DelegatingSubject subject = ........
dsm.logout(subject);
subject.isAuthenticated() will return true
whereas if you do :
subject.logout();
subject.isAuthenticated() will return false;
This is because the logout method in DelegatingSubject sets the
authenticated flag to false (along with cleaning other refs) after a call to
logout method in DefaultSecurityManager
I find this a bit confusing and semantically wrong as by having the same
name and the same meaning, both operations must have the same efect on the
subject state.
Also, having 2 ways to logout/login might be confusing at times.
Best Regards,
Razvan
Les Hazlewood-2 wrote:
>
> Hi Razvan,
>
> You're correct in that there is a 1:1 relationship between Subject and
> Session. Each Subject has 1 and only 1 Session at any given time.
>
> But your problem might be better solved by using permissions rather than
> going through all open sessions and checking them manually. JSecurity
> doesn't support this directly - you'd have to create a Jira issue if you'd
> like the ability to acquire all active Subjects. But this can be a
> dangerous proposition, since if there are a lot of active sessions, it
> could
> return quite a few results - not something I'm sure would be a good idea
> to
> allow - we'd have to debate it on the dev list for sure.
>
> But instead, let me propose using Permissions to handle your requirements.
> I use them for very similar if not identical reasons in a few of my
> applications:
>
> If you perform a permission check for the area that is restricted, you can
> just change the user's permission model at runtime and the next time a
> permission check is executed, it can reflect the user's ability at the
> time
> the check is performed - not necessarily their permission state of when
> they
> logged in only.
>
> Here's a simple example:
>
> Lets say you restrict access to a download based on a permission. The
> check
> might look something like this:
>
> String specificProductDownloadPermission = "product:download:" +
> awesomeProduct.getId();
>
> if ( subject.isPermitted( specificProductDownloadPermission ) {
> //show the download link
> } else {
> //don't show it
> }
>
> You would also execute that same Permission check again when they hit the
> url that allows a download, to ensure that even if they had access to the
> url at one time, that they may not have it when they visit the url.
>
> This all implies that you can change Permissions at runtime and the User's
> authorization state immediately reflects those changes. If your realm
> extends JSecurity's AuthorizingRealm (
> http://www.jsecurity.org/api/org/jsecurity/realm/AuthorizingRealm.html),
> as
> most do, then by default JSecurity caches authorization info after login
> so
> the Realm does not need to 'hit' the data store that manages the
> permission
> relationships.
>
> However, you need these permission checks to occur at any time during the
> life of the Subject's Session, so you can't rely on this type of behavior.
> You need the checks to appear instantaneous, not cached after login.
>
> However, if you do this correctly, you don't need ot 'hit' the database
> even
> after disabling caching after login. The way I handle this for my
> applications is that I use a 2nd-level cache with Hibernate to store all
> my
> Roles and Permission objects (for all users). This gives the code a
> 'feel'
> that I'm checking the database every time, but in reality, I'm being saved
> from that overhead by Hibernate's use of 2nd-level cache.
>
> To support this, you would need to do 2 things:
>
> 1) Extend AuthenticatingRealm directly (not AuthorizingRealm). This
> requires you to implement all the Authorization methods yourself. Because
> you have to do this, then you should have 2) a domain model like the
> following (based on some of my applications):
>
> A User entity 'has a' collection of 1 or more Role objects. Each Role
> object 'has a' collection of 1 or more Permission instances.
>
> Consider a user.isPermitted() method, which would iterate over all of the
> Roles assigned to it:
>
> public boolean isPermitted( Permission permission ) {
> for( Role role : getRoles() ) {
> if ( role.isPermitted( permission ) {
> return true;
> }
> }
> return false;
> }
>
> The Role.isPermitted() method would iterate over its children permissions:
>
> public boolean isPermitted( Permission permission ) {
> for( Permission p : getPermissions() ) {
> if ( p.implies(permission) ) {
> return true;
> }
> }
> return false;
> }
>
> Then, you Realm implementation would delegate to the User.* calls. For
> example, the Realm.isPermitted method:
>
> realm.isPermitted( PrincipalCollection userPrincipals, String permission )
> {
> User user = getUser( userPrincipals ); //write a method to acquire
> your
> User instance
> //create a Permission instance based on the String:
> Permission perm = getPermissionResolver().resolvePermission(
> permission
> );
> return user.isPermitted( permission );
> }
>
> You would have to do this for all the Realm.* methods that aren't
> implemented by AuthenticatingRealm, which would be all the authorization
> methods.
>
> You can do this iteration at runtime because of the 2nd-level cache - it
> is
> much faster than executing a RDBMS query every time you have a permission
> check. As you can see though, it _does_ require manual effort on your
> part
> to implement these Realm methods yourself, as well as to have a domain
> model
> that supports this.
>
> This does however allow permission assignments (and revocations) to be
> changed at runtime: you can add or remove permissions from Roles, or you
> can add or remove Roles from Users, all at runtime, and without requiring
> them to log out and then log back in again. I've done this for goverment
> applications that require very strict control that can change at runtime,
> during a user's session - the requirement is that an administrator could
> change their access control at any time and the changes must be reflected
> immediately.
>
> I hope that helps! Please let me know if this makes sense. I've used it
> with great success for highly dynamic environments, and assuming you can
> use
> a 2nd-level cache, you can do this cleanly and effectively.
>
> Best,
>
> Les
>
> On Tue, Feb 10, 2009 at 10:27 AM, Razvan Dragut
> <[email protected]>wrote:
>
>> Hi everyone,
>>
>> I am new to JSecurity, I am using it, I have a scenario to implement, I
>> have some problems with it and I thought you could help :)
>>
>> scenario :
>>
>> A website that uses JSecurity to manage user's access to different parts
>> of
>> the site. Different parts of the site are subject to different terms and
>> conditions. Also, the download of different products are also subject
>> different terms and conditions. These terms and conditions may change
>> while
>> the users are still logged in ( rememberMe or active connection). What we
>> need is that once the terms and conditions for a particular product/part
>> of
>> the site is changing, some users must be kicked before doing any action
>> and
>> forced to re-login to accept the new terms and conditions. Having this
>> scenario, we need to access a list of all logged in subjects, check their
>> principals against our particular set of users and kick those who match.
>>
>>
>> problem :
>>
>> I've got the JSecurity sources and tried to follow code paths, debug etc
>> etc and went to the point where I have all the active sessions.
>> Unfortunately I haven't found a way to reach the subject associated with
>> that session and I can't get the subject's principals and check them
>> against
>> my separate list.
>>
>>
>> questions :
>>
>> What is the way to reach the subject via a session, in my case ?
>> Is there another way/s to get all the logged in subjects ?
>> Do you think is a good idea to keep a list of authenticated subjects in
>> my
>> Realm implementation ? Does it affect clustering or anything else (
>> mainly
>> distributed stuff ) ?
>>
>>
>> still digging :
>>
>> If you will point me to some listeners, none of the listeners
>> (AuthenticatingListener or SessionListener) does not know about the
>> subject
>> but only auth token, auth info, and session so I cannot really handle my
>> problem (storing the subject somewhere at login time or session
>> initiation
>> time) only by using listeners and without extending some JSecurity
>> classes
>> like SecurityManager impls which is not necessary a big effort but it
>> looks
>> like it (not very nice to maintain) for such a basic thing.
>>
>>
>> Kind Regards,
>>
>> Thanks in advance
>>
>> Razvan
>>
>>
>
>
--
View this message in context:
http://n2.nabble.com/Subject-Session-relationship-tp2303079p2309819.html
Sent from the JSecurity User mailing list archive at Nabble.com.