Subject being changed!

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

Subject being changed!

dan
Hi --

I am upgrading to Shiro 1.2 and have the following problem.  In the code, I determine the role of an arbitrary user by calling this method and then doing a hasRole(...):

        public Subject getSubjectByLogin(final String login) {
                PrincipalCollection principals = new SimplePrincipalCollection(login, REALM_NAME);
                return new Subject.Builder().principals(principals).buildSubject();
        }

It worked fine with Shiro 1.1.  With Shiro 1.2, searching through the forum, I saw a similar issue and changed the method to use WebSubject:

        public Subject getSubjectByLogin(final String login) {
                PrincipalCollection principals = new SimplePrincipalCollection(login, REALM_NAME);
                final FacesContext faces = FacesContext.getCurrentInstance();
       
                HttpServletResponse resp = (HttpServletResponse)faces.getExternalContext().getResponse();
                HttpServletRequest reqs = (HttpServletRequest)faces.getExternalContext().getRequest();
       
                WebSubject.Builder b = new WebSubject.Builder(reqs, resp);
                return b.principals(principals).buildSubject();
        }

This worked better but it has the side effect of changing the Subject object of the logged in user to the one was  being checked.  The effect is that any subsequent click takes me to a accessDenied page because the changed subject has lesser privledges.

So... can you comment on how to retrieve the role of an arbitrary user?

Thanks,
Dan

PS.  I am still wanting to implement Guice support but had to back off on that until this upgrade issue was resolved! ;|

dan
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

dan
I think I answered my own question.  It works if I change the method to:

        public Subject getSubjectByLogin(final String login) {
                PrincipalCollection principals = new SimplePrincipalCollection(login, REALM_NAME);
                return new Subject.Builder(SecurityUtils.getSecurityManager()).buildSubject();
        }

I'm not exactly sure why it works this way and not the original way.  

Thanks,
Dan
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

Les Hazlewood-2
Hi Dan,

I'm not sure why that would make a difference:

the Subject.Builder default constructor implementation currently
delegates to the constructor accepting a SecurityManager, using
SecurityUtils.getSecurityManager(), i.e.

new Subject.Builder() === new
Subject.Builder(SecurityUtils.getSecurityManager());

I'm glad to see that it worked for you though!

Best,

Les
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

Les Hazlewood
Administrator
In reply to this post by dan
> It worked fine with Shiro 1.1.  With Shiro 1.2, searching through the forum,
> I saw a similar issue and changed the method to use WebSubject:
>
>        public Subject getSubjectByLogin(final String login) {
>                PrincipalCollection principals = new SimplePrincipalCollection(login,
> REALM_NAME);
>                final FacesContext faces = FacesContext.getCurrentInstance();
>
>                HttpServletResponse resp =
> (HttpServletResponse)faces.getExternalContext().getResponse();
>                HttpServletRequest reqs =
> (HttpServletRequest)faces.getExternalContext().getRequest();
>
>                WebSubject.Builder b = new WebSubject.Builder(reqs, resp);
>                return b.principals(principals).buildSubject();
>        }
>
> This worked better but it has the side effect of changing the Subject object
> of the logged in user to the one was  being checked.  The effect is that any
> subsequent click takes me to a accessDenied page because the changed subject
> has lesser privledges.

Unless you're manipulating thread state, this cannot happen by using
the Builder alone.

Building a subject (i.e. builder.buildSubject();) does not change the
current user - it only creates a Subject instance.  The Subject
instance returned from .buildSubject() is definitely usable, but it is
not bound to the current thread, and it is not the same as what is
returned from SecurityUtils.getSubject();

> So... can you comment on how to retrieve the role of an arbitrary user?

Strictly speaking, Shiro does not have APIs to ad-hoc query for
information for arbitrary users.  This is because querying for such
information is *very* application and datasource specific.  It might
be a goal of the project to create such an abstraction API at a later
date, but that is currently not in scope.

By manually creating subject instances for known users and relying on
the back-end authorization query that goes through the Realm(s), you
get close to your desired behavior I think, which should work pretty
well.

Cheers,

Les
dan
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

dan
Hi Les,

Thanks for your insight...

I went back to my original method:

  public Subject getSubjectByLogin(final String login) {
                PrincipalCollection principals = new SimplePrincipalCollection(login, REALM_NAME);
                return new Subject.Builder().principals(principals).buildSubject();
        }

and I now see that the buildSubject() portion is throwing this exception:

      SessionContext must be an HTTP compatible implementation.

and I suppose this is the root of my problems.  Are you surprised this code works for Shiro 1.1?

Are you suggesting that I add a method to my realm, such as hasRole(login) and I would not even use the Subject object?  

(In our app, we have a backoffice area where we display users and their roles.  It seems like a common use case to me!)

Thanks again,
Dan

Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

Jared Bunting-2
In reply to this post by dan
Do you have a stack trace for this error?  It seems like a bug to me.

On Tue 13 Mar 2012 05:49:21 PM CDT, dan wrote:

> Hi --
>
> I am upgrading to Shiro 1.2 and have the following problem.  In the code, I
> determine the role of an arbitrary user by calling this method and then
> doing a hasRole(...):
>
> public Subject getSubjectByLogin(final String login) {
> PrincipalCollection principals = new SimplePrincipalCollection(login,
> REALM_NAME);
> return new Subject.Builder().principals(principals).buildSubject();
> }
>
> It worked fine with Shiro 1.1.  With Shiro 1.2, searching through the forum,
> I saw a similar issue and changed the method to use WebSubject:
>
> public Subject getSubjectByLogin(final String login) {
> PrincipalCollection principals = new SimplePrincipalCollection(login,
> REALM_NAME);
> final FacesContext faces = FacesContext.getCurrentInstance();
>
> HttpServletResponse resp =
> (HttpServletResponse)faces.getExternalContext().getResponse();
> HttpServletRequest reqs =
> (HttpServletRequest)faces.getExternalContext().getRequest();
>
> WebSubject.Builder b = new WebSubject.Builder(reqs, resp);
> return b.principals(principals).buildSubject();
> }
>
> This worked better but it has the side effect of changing the Subject object
> of the logged in user to the one was  being checked.  The effect is that any
> subsequent click takes me to a accessDenied page because the changed subject
> has lesser privledges.
>
> So... can you comment on how to retrieve the role of an arbitrary user?
>
> Thanks,
> Dan
>
> PS.  I am still wanting to implement Guice support but had to back off on
> that until this upgrade issue was resolved! ;|
>
>
>
> --
> View this message in context: http://shiro-user.582556.n2.nabble.com/Subject-being-changed-tp7370203p7370203.html
> Sent from the Shiro User mailing list archive at Nabble.com.


Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

Les Hazlewood-2
It is not a bug - someone (or something) is attempting to create a Session when:

1.  The SessionManager in use at runtime is a
ServletContainerSessionManager instance.  This is the default
SessionManager implementation for a Shiro-enabled web application, and
it delegates to the Servlet container (e.g. Jetty/Tomcat) to do the
'real' session management.

and

2.  The Subject instance on which subject.getSession() is being called
is not aware of an HTTP request/response pair.  (In a web app, the
Shiro Filter creates WebSubject instances automatically, which are
aware of their 'source' request/response pair).

So in your situation, subject.getSession() is being called, and the
Subject implementation (under the hood) says,

'Hey, SessionManager, create me a new Session please!'

The ServletContainerSessionManager replies (with the exception):

"I'm a web-only SessionManager, and I need a ServletRequest to do that
for you.  Because you're not providing me with a request/response
pair, I can't help you!'.

The easiest solution for this is to use the WebSubject.Builder when
your underlying SessionManager is web-only, and it should work fine.
(Shiro 'native' SessionManagers can function both with and without web
requests, but the ServletContainer-based ones cannot - they are web
only).

HTH,

--
Les Hazlewood
CTO, Stormpath | http://www.stormpath.com | 888.391.5282
twitter: @lhazlewood | http://twitter.com/lhazlewood
blog: http://leshazlewood.com
stormpath blog: http://www.stormpath.com/blog/index

On Tue, Mar 13, 2012 at 6:08 PM, Jared Bunting
<[hidden email]> wrote:

> Do you have a stack trace for this error?  It seems like a bug to me.
>
> On Tue 13 Mar 2012 05:49:21 PM CDT, dan wrote:
>> Hi --
>>
>> I am upgrading to Shiro 1.2 and have the following problem.  In the code, I
>> determine the role of an arbitrary user by calling this method and then
>> doing a hasRole(...):
>>
>>       public Subject getSubjectByLogin(final String login) {
>>               PrincipalCollection principals = new SimplePrincipalCollection(login,
>> REALM_NAME);
>>               return new Subject.Builder().principals(principals).buildSubject();
>>       }
>>
>> It worked fine with Shiro 1.1.  With Shiro 1.2, searching through the forum,
>> I saw a similar issue and changed the method to use WebSubject:
>>
>>       public Subject getSubjectByLogin(final String login) {
>>               PrincipalCollection principals = new SimplePrincipalCollection(login,
>> REALM_NAME);
>>               final FacesContext faces = FacesContext.getCurrentInstance();
>>
>>               HttpServletResponse resp =
>> (HttpServletResponse)faces.getExternalContext().getResponse();
>>               HttpServletRequest reqs =
>> (HttpServletRequest)faces.getExternalContext().getRequest();
>>
>>               WebSubject.Builder b = new WebSubject.Builder(reqs, resp);
>>               return b.principals(principals).buildSubject();
>>       }
>>
>> This worked better but it has the side effect of changing the Subject object
>> of the logged in user to the one was  being checked.  The effect is that any
>> subsequent click takes me to a accessDenied page because the changed subject
>> has lesser privledges.
>>
>> So... can you comment on how to retrieve the role of an arbitrary user?
>>
>> Thanks,
>> Dan
>>
>> PS.  I am still wanting to implement Guice support but had to back off on
>> that until this upgrade issue was resolved! ;|
>>
>>
>>
>> --
>> View this message in context: http://shiro-user.582556.n2.nabble.com/Subject-being-changed-tp7370203p7370203.html
>> Sent from the Shiro User mailing list archive at Nabble.com.
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

Les Hazlewood-2
P.S. You can also avoid this problem by not using/creating a Session
with the built Subject.

On Tue, Mar 13, 2012 at 7:25 PM, Les Hazlewood <[hidden email]> wrote:

> It is not a bug - someone (or something) is attempting to create a Session when:
>
> 1.  The SessionManager in use at runtime is a
> ServletContainerSessionManager instance.  This is the default
> SessionManager implementation for a Shiro-enabled web application, and
> it delegates to the Servlet container (e.g. Jetty/Tomcat) to do the
> 'real' session management.
>
> and
>
> 2.  The Subject instance on which subject.getSession() is being called
> is not aware of an HTTP request/response pair.  (In a web app, the
> Shiro Filter creates WebSubject instances automatically, which are
> aware of their 'source' request/response pair).
>
> So in your situation, subject.getSession() is being called, and the
> Subject implementation (under the hood) says,
>
> 'Hey, SessionManager, create me a new Session please!'
>
> The ServletContainerSessionManager replies (with the exception):
>
> "I'm a web-only SessionManager, and I need a ServletRequest to do that
> for you.  Because you're not providing me with a request/response
> pair, I can't help you!'.
>
> The easiest solution for this is to use the WebSubject.Builder when
> your underlying SessionManager is web-only, and it should work fine.
> (Shiro 'native' SessionManagers can function both with and without web
> requests, but the ServletContainer-based ones cannot - they are web
> only).
>
> HTH,
>
> --
> Les Hazlewood
> CTO, Stormpath | http://www.stormpath.com | 888.391.5282
> twitter: @lhazlewood | http://twitter.com/lhazlewood
> blog: http://leshazlewood.com
> stormpath blog: http://www.stormpath.com/blog/index
>
> On Tue, Mar 13, 2012 at 6:08 PM, Jared Bunting
> <[hidden email]> wrote:
>> Do you have a stack trace for this error?  It seems like a bug to me.
>>
>> On Tue 13 Mar 2012 05:49:21 PM CDT, dan wrote:
>>> Hi --
>>>
>>> I am upgrading to Shiro 1.2 and have the following problem.  In the code, I
>>> determine the role of an arbitrary user by calling this method and then
>>> doing a hasRole(...):
>>>
>>>       public Subject getSubjectByLogin(final String login) {
>>>               PrincipalCollection principals = new SimplePrincipalCollection(login,
>>> REALM_NAME);
>>>               return new Subject.Builder().principals(principals).buildSubject();
>>>       }
>>>
>>> It worked fine with Shiro 1.1.  With Shiro 1.2, searching through the forum,
>>> I saw a similar issue and changed the method to use WebSubject:
>>>
>>>       public Subject getSubjectByLogin(final String login) {
>>>               PrincipalCollection principals = new SimplePrincipalCollection(login,
>>> REALM_NAME);
>>>               final FacesContext faces = FacesContext.getCurrentInstance();
>>>
>>>               HttpServletResponse resp =
>>> (HttpServletResponse)faces.getExternalContext().getResponse();
>>>               HttpServletRequest reqs =
>>> (HttpServletRequest)faces.getExternalContext().getRequest();
>>>
>>>               WebSubject.Builder b = new WebSubject.Builder(reqs, resp);
>>>               return b.principals(principals).buildSubject();
>>>       }
>>>
>>> This worked better but it has the side effect of changing the Subject object
>>> of the logged in user to the one was  being checked.  The effect is that any
>>> subsequent click takes me to a accessDenied page because the changed subject
>>> has lesser privledges.
>>>
>>> So... can you comment on how to retrieve the role of an arbitrary user?
>>>
>>> Thanks,
>>> Dan
>>>
>>> PS.  I am still wanting to implement Guice support but had to back off on
>>> that until this upgrade issue was resolved! ;|
>>>
>>>
>>>
>>> --
>>> View this message in context: http://shiro-user.582556.n2.nabble.com/Subject-being-changed-tp7370203p7370203.html
>>> Sent from the Shiro User mailing list archive at Nabble.com.
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

Jared Bunting-2
That's what it sounds like to me, but I guess I'm a bit confused.  
That's what I was hoping to see a stack trace.

It seems to me that, no matter what my setup, I should always be able
to successfully invoke the code (Provided that
SecurityUtils.getSecurityManager() returns successfully) :

new Subject.Builder().buildSubject();

-Jared

On Tue 13 Mar 2012 09:28:52 PM CDT, Les Hazlewood wrote:

> P.S. You can also avoid this problem by not using/creating a Session
> with the built Subject.
>
> On Tue, Mar 13, 2012 at 7:25 PM, Les Hazlewood <[hidden email]> wrote:
>> It is not a bug - someone (or something) is attempting to create a Session when:
>>
>> 1.  The SessionManager in use at runtime is a
>> ServletContainerSessionManager instance.  This is the default
>> SessionManager implementation for a Shiro-enabled web application, and
>> it delegates to the Servlet container (e.g. Jetty/Tomcat) to do the
>> 'real' session management.
>>
>> and
>>
>> 2.  The Subject instance on which subject.getSession() is being called
>> is not aware of an HTTP request/response pair.  (In a web app, the
>> Shiro Filter creates WebSubject instances automatically, which are
>> aware of their 'source' request/response pair).
>>
>> So in your situation, subject.getSession() is being called, and the
>> Subject implementation (under the hood) says,
>>
>> 'Hey, SessionManager, create me a new Session please!'
>>
>> The ServletContainerSessionManager replies (with the exception):
>>
>> "I'm a web-only SessionManager, and I need a ServletRequest to do that
>> for you.  Because you're not providing me with a request/response
>> pair, I can't help you!'.
>>
>> The easiest solution for this is to use the WebSubject.Builder when
>> your underlying SessionManager is web-only, and it should work fine.
>> (Shiro 'native' SessionManagers can function both with and without web
>> requests, but the ServletContainer-based ones cannot - they are web
>> only).
>>
>> HTH,
>>
>> --
>> Les Hazlewood
>> CTO, Stormpath | http://www.stormpath.com | 888.391.5282
>> twitter: @lhazlewood | http://twitter.com/lhazlewood
>> blog: http://leshazlewood.com
>> stormpath blog: http://www.stormpath.com/blog/index
>>
>> On Tue, Mar 13, 2012 at 6:08 PM, Jared Bunting
>> <[hidden email]> wrote:
>>> Do you have a stack trace for this error?  It seems like a bug to me.
>>>
>>> On Tue 13 Mar 2012 05:49:21 PM CDT, dan wrote:
>>>> Hi --
>>>>
>>>> I am upgrading to Shiro 1.2 and have the following problem.  In the code, I
>>>> determine the role of an arbitrary user by calling this method and then
>>>> doing a hasRole(...):
>>>>
>>>>       public Subject getSubjectByLogin(final String login) {
>>>>               PrincipalCollection principals = new SimplePrincipalCollection(login,
>>>> REALM_NAME);
>>>>               return new Subject.Builder().principals(principals).buildSubject();
>>>>       }
>>>>
>>>> It worked fine with Shiro 1.1.  With Shiro 1.2, searching through the forum,
>>>> I saw a similar issue and changed the method to use WebSubject:
>>>>
>>>>       public Subject getSubjectByLogin(final String login) {
>>>>               PrincipalCollection principals = new SimplePrincipalCollection(login,
>>>> REALM_NAME);
>>>>               final FacesContext faces = FacesContext.getCurrentInstance();
>>>>
>>>>               HttpServletResponse resp =
>>>> (HttpServletResponse)faces.getExternalContext().getResponse();
>>>>               HttpServletRequest reqs =
>>>> (HttpServletRequest)faces.getExternalContext().getRequest();
>>>>
>>>>               WebSubject.Builder b = new WebSubject.Builder(reqs, resp);
>>>>               return b.principals(principals).buildSubject();
>>>>       }
>>>>
>>>> This worked better but it has the side effect of changing the Subject object
>>>> of the logged in user to the one was  being checked.  The effect is that any
>>>> subsequent click takes me to a accessDenied page because the changed subject
>>>> has lesser privledges.
>>>>
>>>> So... can you comment on how to retrieve the role of an arbitrary user?
>>>>
>>>> Thanks,
>>>> Dan
>>>>
>>>> PS.  I am still wanting to implement Guice support but had to back off on
>>>> that until this upgrade issue was resolved! ;|
>>>>
>>>>
>>>>
>>>> --
>>>> View this message in context: http://shiro-user.582556.n2.nabble.com/Subject-being-changed-tp7370203p7370203.html
>>>> Sent from the Shiro User mailing list archive at Nabble.com.


dan
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

dan
Hi Jered,

Here's the stacktrace.  You're a step ahead of me!  I guess I didn't realize a session would be created when I just ask for it to build a new subject.

Dan

        Caused by: java.lang.IllegalArgumentException: SessionContext must be an HTTP compatible implementation.
        at org.apache.shiro.web.session.mgt.ServletContainerSessionManager.createSession(ServletContainerSessionManager.java:103)
        at org.apache.shiro.web.session.mgt.ServletContainerSessionManager.start(ServletContainerSessionManager.java:64)
        at org.apache.shiro.mgt.SessionsSecurityManager.start(SessionsSecurityManager.java:121)
        at org.apache.shiro.subject.support.DelegatingSubject.getSession(DelegatingSubject.java:336)
        at org.apache.shiro.subject.support.DelegatingSubject.getSession(DelegatingSubject.java:314)
        at org.apache.shiro.mgt.DefaultSubjectDAO.mergePrincipals(DefaultSubjectDAO.java:182)
        at org.apache.shiro.mgt.DefaultSubjectDAO.saveToSession(DefaultSubjectDAO.java:163)
        at org.apache.shiro.mgt.DefaultSubjectDAO.save(DefaultSubjectDAO.java:144)
        at org.apache.shiro.mgt.DefaultSecurityManager.save(DefaultSecurityManager.java:383)
        at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:350)
        at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:846)
dan
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

dan
In reply to this post by Les Hazlewood-2
Hi Les,

> The easiest solution for this is to use the WebSubject.Builder when
> your underlying SessionManager is web-only, and it should work fine.
> (Shiro 'native' SessionManagers can function both with and without web
> requests, but the ServletContainer-based ones cannot - they are web
> only).

But to use WebSubject, it requires that I pass in httpServletRequest and httpServletResponse parameters, which I don't have!!  (I don't have these parameters because as part of one web request, I'm trying to determine the roles of another user, part of our backoffice section.)  Is there a back-door?

> P.S. You can also avoid this problem by not using/creating a Session
> with the built Subject.

Can you explain this?  I don't see an API that let's me create a Subject without a corresponding session.

Dan

Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

Les Hazlewood-2
In reply to this post by dan
> Here's the stacktrace.  You're a step ahead of me!  I guess I didn't realize
> a session would be created when I just ask for it to build a new subject.

It won't.  Just building a Subject will not automatically create a
Session.  You have to call subject.getSession() or
subject.getSession(true) to create a session if the Subject does not
already have one.

Cheers,

Les
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

Les Hazlewood-2
My apologies, I should have looked at the stack trace further.  Just
building a Subject _should not_ create a session unless there is a
session available during building.

Please open a Jira issue and we can address this.

In the meantime, as a workaround, you can interact with your Realm
directly to return a Subject's AuthorizationInfo from its
getAuthorizationInfo(PrincipalCollection) method.  This is protected,
so you'll probably have to create a subclass and create a public
method that exposes getAuthorizationInfo.

Thanks,

Les

On Wed, Mar 14, 2012 at 10:57 AM, Les Hazlewood <[hidden email]> wrote:

>> Here's the stacktrace.  You're a step ahead of me!  I guess I didn't realize
>> a session would be created when I just ask for it to build a new subject.
>
> It won't.  Just building a Subject will not automatically create a
> Session.  You have to call subject.getSession() or
> subject.getSession(true) to create a session if the Subject does not
> already have one.
>
> Cheers,
>
> Les
dan
Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

dan
Hi Les,

Ok, that's cool, it's good to understand this. I did create a jira ticket for it.  

The workaround is straight-forward.  I think that if I call my realm directly, I don't get the benefit of my caching manager, so this is really a short-term workaround.

Thanks,
Dan

PS I guess Jered wasn't smoking crack!

Reply | Threaded
Open this post in threaded view
|

Re: Subject being changed!

Les Hazlewood-2
> Ok, that's cool, it's good to understand this. I did create a jira ticket
> for it.

Thanks!!!

> The workaround is straight-forward.  I think that if I call my realm
> directly, I don't get the benefit of my caching manager, so this is really a
> short-term workaround.

You should receive this benefit today - a configured Shiro
CacheManager should be available to any of Shiro's Realm
implementations, and getAuthorizationInfo will try to hit the cache
first.

Best,

Les