You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by "Alan D. Cabrera" <li...@toolazydogs.com> on 2010/11/14 19:33:11 UTC

unauthorizedUrl

Sometimes I want an area for those who have paid for a premium service, they would have a role paid.  Other areas are for if a user has been authenticated.  When unpaid users wander into the premium area it would be nice if they would be redirected to another page enticing them to upgrade their membership.

I envision something like:

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/signin/signIn.jspa?first=true"/>
        <property name="successUrl" value="/home.jsp"/>
        <property name="unauthorizedUrl" value="/unauthorized.jsap"/>
        <property name="filterChainDefinitions">
            <value>
                /signin/** = myFilter
                /admin/** = myFilter, roles[admin]
                /premium/** = myFilter, roles[paid], unauthorizedUrl[/upgrade.jspa]
            </value>
        </property>
    </bean>

Thoughts?


Regards,
Alan


Re: unauthorizedUrl

Posted by Les Hazlewood <lh...@apache.org>.
Oops - missed this.  Yes, Peter, you're right - all internal commas
currently need be quoted so they don't conflict with the 'outer'
commas delimiting the filter chain itself.

On Sun, Nov 14, 2010 at 11:23 PM, Peter Ledbrook <pe...@cacoethes.co.uk> wrote:
>> /premium/** = myFilter, myRoles[paid, unauthorizedUrl=/upgrade.jspa],
>> anotherFilter, ...
>
> Doesn't the comma-separated list inside the square brackets need to be quoted?
>
> Peter
>
> --
> Peter Ledbrook
> Grails Advocate
> SpringSource - A Division of VMware

Re: unauthorizedUrl

Posted by Peter Ledbrook <pe...@cacoethes.co.uk>.
> /premium/** = myFilter, myRoles[paid, unauthorizedUrl=/upgrade.jspa],
> anotherFilter, ...

Doesn't the comma-separated list inside the square brackets need to be quoted?

Peter

-- 
Peter Ledbrook
Grails Advocate
SpringSource - A Division of VMware

Re: unauthorizedUrl

Posted by Les Hazlewood <lh...@apache.org>.
> Looks similar to mine.  Why is the key value pair inside the set of roles?  Would it not be semantically better
>
>               /premium/** = myFilter, roles[paid], unauthorizedUrl[/upgrade.jspa]
>
> Is this a technical requirement or an "aesthetic" preference?

It is a technical requirement:  the value to the right of the equals
sign is an order-sensitive filter chain.  Each filter you specify is
executed in the order it is defined. This, and a lot more, is covered
in http://shiro.apache.org/web.html.

So in your example, you've specified the roles filter before the
unauthorizedUrl filter.  This means that if a request's Subject didn't
have the 'paid' role, the roles filter would redirect them to any
previously configured (Shiro-wide) unauthorizedUrl.  It doesn't 'know'
about any filters upstream or downstream in the chain.  The
unauthorizedUrl filter at the end of your chain in your example would
never execute because the roles filter would have short-circuited the
chain and issued a redirect already.

I should also stress that the inside of the brackets denotes that
filter's configuration for _that specific url_.  So while the roles
filter typically takes in a comma delimited list of roles, it would be
more semantically correct to say that the roles filter accepts a list
of url-specific String configuration parameters.

The roles filter (or any PathMatchingFilter implementation for that
matter) is free to interpret those strings however it wants.  At the
moment, the roles filter assumes those strings are all role names.
Your subclass could have role names, name/value pairs for additional
configuration, or whatever else you may want/need.

> Ahh, is this why your configuration is structured that particular way?

Yes - the config is an order-specific filter chain.  There is no
interpretation of a [urls] config line other than to construct a
filter chain from it.  Doing otherwise would be incredibly messy.
It's much easier (and more efficient) to allow users to specify the
intricacies of their rules based on simple filter chain ordering, just
as it has worked well in web.xml filter chain definitions for years.
I would just argue that the conciseness of Shiro's filter chain
definitions, and its greater power in path-specific config is
_muuuuch_ nicer than doing this stuff in web.xml.

I've said in presentations: if you used Shiro for nothing more than to
replace web.xml filter chain definitions and didn't even use any of
its security features, this feature alone would be worth having the
Shiro .jars in your classpath.

> I'll give the former a try.  I have a question.  What happens if a number of patterns match the URL:
>
>               /premium/A/** = myFilter, roles[paid], unauthorizedUrl[/upgradeA.jspa]
>               /premium/B/** = myFilter, roles[paid], unauthorizedUrl[/upgrade.Bjspa]
>               /premium/** = myFilter, roles[paid], unauthorizedUrl[/upgrade.jspa]
>
> and the user goes to /premium/A/storefront.jspa?  I don't anticipate doing this but am curious.

This is covered in http://shiro.apache.org/web.html in the 'Order
Matters!' note box.  Paths are matched based on the order they are
defined.  The first path to match the incoming request 'wins'.  In
your example, the /premium/A/** filter chain would be executed and all
other path chain definitions below it are ignored.  The documentation
page's note box gives a good example of why this is important too.

> Thanks.  Gotta go help w/ the stuffing...

Enjoy the turkey! :)

Cheers,

Les

Re: unauthorizedUrl

Posted by "Alan D. Cabrera" <li...@toolazydogs.com>.
Finally got some time to discuss this before my wife drags me back into the kitchen... :)

Take all of this with a grain of salt.  I haven't had time to dig into the code.

On Nov 14, 2010, at 11:24 AM, Les Hazlewood wrote:

> This particular example wouldn't work as things stand today - the
> filters are executed in the order in which they are defined, so the
> roles filter would execute and redirect to an unauthorized url before
> the 'unauthorizedUrl' filter has its chance to execute.

Is there an unauthorizedUrl filter?

> However, any filter extending from PathMatchingFilter (which includes
> all of Shiro's pre-defined authc/authz filters) support per-path
> configuration already, so you could do something like this:
> 
> /premium/** = myFilter, myRoles[paid, unauthorizedUrl=/upgrade.jspa],
> anotherFilter, ...

Looks similar to mine.  Why is the key value pair inside the set of roles?  Would it not be semantically better 

               /premium/** = myFilter, roles[paid], unauthorizedUrl[/upgrade.jspa]

Is this a technical requirement or an "aesthetic" preference?

> Where you subclass the existing RolesAuthorizationFilter (to create
> the 'myRoles' instance's class) and override the
> AccessControlFilter#onAccessDenied(request, response, mappedValue)
> method.  There you can look at the mappedValue (which is a String[]),
> see if one of those strings is your unauthorizedUrl=blah string.  If
> so, you call  WebUtils.issueRedirect(request, response,
> unauthorizedUrl);

Ahh, is this why your configuration is structured that particular way?

> Another approach is to have an 'unauthorizedUrl' filter that sits in
> the front of the chain, and all it does is set a request attribute
> indicating the overridden url.  Then the
> AuthorizationFilter#onAccessDenied method could be refactored to look
> for that request attribute, and if it exists, then use it.  If it
> doesn't exist, then fall back to its internal 'unauthorizedUrl'
> property.
> 
> I think I prefer the former rather than the latter because it feels
> more natural from a configuration standpoint (i.e. I only want to
> 'tell' the role filter to use this particular url - not the whole
> chain).  But there is no reason why both approaches can't exist - I
> can see use cases where you would actually want to override a property
> for the whole chain and not just a single filter in the chain.

Yeah, it seems that the looser collaboration in the latter implementation is a recipe for some piece of code dropping the ball in the collaboration.

I'll give the former a try.  I have a question.  What happens if a number of patterns match the URL:

               /premium/A/** = myFilter, roles[paid], unauthorizedUrl[/upgradeA.jspa]
               /premium/B/** = myFilter, roles[paid], unauthorizedUrl[/upgrade.Bjspa]
               /premium/** = myFilter, roles[paid], unauthorizedUrl[/upgrade.jspa]

and the user goes to /premium/A/storefront.jspa?  I don't anticipate doing this but am curious.

Thanks.  Gotta go help w/ the stuffing...


Regards,
Alan

> 
> HTH!
> 
> -- 
> Les Hazlewood
> Founder, Katasoft, Inc.
> Application Security Products & Professional Apache Shiro Support and Training:
> http://www.katasoft.com
> 
> On Sun, Nov 14, 2010 at 10:33 AM, Alan D. Cabrera <li...@toolazydogs.com> wrote:
>> Sometimes I want an area for those who have paid for a premium service, they would have a role paid.  Other areas are for if a user has been authenticated.  When unpaid users wander into the premium area it would be nice if they would be redirected to another page enticing them to upgrade their membership.
>> 
>> I envision something like:
>> 
>>    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
>>        <property name="securityManager" ref="securityManager"/>
>>        <property name="loginUrl" value="/signin/signIn.jspa?first=true"/>
>>        <property name="successUrl" value="/home.jsp"/>
>>        <property name="unauthorizedUrl" value="/unauthorized.jsap"/>
>>        <property name="filterChainDefinitions">
>>            <value>
>>                /signin/** = myFilter
>>                /admin/** = myFilter, roles[admin]
>>                /premium/** = myFilter, roles[paid], unauthorizedUrl[/upgrade.jspa]
>>            </value>
>>        </property>
>>    </bean>
>> 
>> Thoughts?
>> 
>> 
>> Regards,
>> Alan


Re: unauthorizedUrl

Posted by Les Hazlewood <lh...@apache.org>.
This particular example wouldn't work as things stand today - the
filters are executed in the order in which they are defined, so the
roles filter would execute and redirect to an unauthorized url before
the 'unauthorizedUrl' filter has its chance to execute.

However, any filter extending from PathMatchingFilter (which includes
all of Shiro's pre-defined authc/authz filters) support per-path
configuration already, so you could do something like this:

/premium/** = myFilter, myRoles[paid, unauthorizedUrl=/upgrade.jspa],
anotherFilter, ...

Where you subclass the existing RolesAuthorizationFilter (to create
the 'myRoles' instance's class) and override the
AccessControlFilter#onAccessDenied(request, response, mappedValue)
method.  There you can look at the mappedValue (which is a String[]),
see if one of those strings is your unauthorizedUrl=blah string.  If
so, you call  WebUtils.issueRedirect(request, response,
unauthorizedUrl);

Another approach is to have an 'unauthorizedUrl' filter that sits in
the front of the chain, and all it does is set a request attribute
indicating the overridden url.  Then the
AuthorizationFilter#onAccessDenied method could be refactored to look
for that request attribute, and if it exists, then use it.  If it
doesn't exist, then fall back to its internal 'unauthorizedUrl'
property.

I think I prefer the former rather than the latter because it feels
more natural from a configuration standpoint (i.e. I only want to
'tell' the role filter to use this particular url - not the whole
chain).  But there is no reason why both approaches can't exist - I
can see use cases where you would actually want to override a property
for the whole chain and not just a single filter in the chain.

HTH!

-- 
Les Hazlewood
Founder, Katasoft, Inc.
Application Security Products & Professional Apache Shiro Support and Training:
http://www.katasoft.com

On Sun, Nov 14, 2010 at 10:33 AM, Alan D. Cabrera <li...@toolazydogs.com> wrote:
> Sometimes I want an area for those who have paid for a premium service, they would have a role paid.  Other areas are for if a user has been authenticated.  When unpaid users wander into the premium area it would be nice if they would be redirected to another page enticing them to upgrade their membership.
>
> I envision something like:
>
>    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
>        <property name="securityManager" ref="securityManager"/>
>        <property name="loginUrl" value="/signin/signIn.jspa?first=true"/>
>        <property name="successUrl" value="/home.jsp"/>
>        <property name="unauthorizedUrl" value="/unauthorized.jsap"/>
>        <property name="filterChainDefinitions">
>            <value>
>                /signin/** = myFilter
>                /admin/** = myFilter, roles[admin]
>                /premium/** = myFilter, roles[paid], unauthorizedUrl[/upgrade.jspa]
>            </value>
>        </property>
>    </bean>
>
> Thoughts?
>
>
> Regards,
> Alan