views:

3095

answers:

4

I'm trying to get Tuckey UrlRewriteFilter to tidy up URLs for my webapp. One problem I've got is that when spring-security notices that an anonymous user is trying to access a protected resource it redirects to a URL which includes the servlet path.

What I'd like is, by example:

> GET http://localhost:8080/my-context/protected-resource
< Location: http://localhost:8080/my-context/login

What I currently get is:

> GET http://localhost:8080/my-context/protected-resource
< Location: http://localhost:8080/my-context/-/login

Relevant documents I've found so far:

DefaultRedirectStrategy, which does the actual redirect in question: http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/web/DefaultRedirectStrategy.html. It has a contextRelative property which is tempting but I don't think is going to cut it, if I can even find a way of configuring it.

A blog post that helped get me this far: http://nonrepeatable.blogspot.com/2009/11/using-spring-security-with-tuckey.html

What I'd like to know is:

  1. Can/should I convince Tuckey to rewrite the Location header. <outbound-rule> doesn't seem to help any here.
  2. Can/should I somehow tweak the SS config to emit the rewritten URL. I don't think this is quite as tidy, as it'd break if rewrite was disabled.

web.xml looks like

<filter>
 <filter-name>UrlRewriteFilter</filter-name>
 <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
 <init-param>
  <param-name>LogLevel</param-name>
  <param-value>log4j</param-value>
 </init-param>
</filter>
<filter-mapping>
 <filter-name>UrlRewriteFilter</filter-name>
 <url-pattern>/*</url-pattern>
 <dispatcher>REQUEST</dispatcher>
</filter-mapping>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<servlet>
    <servlet-name>my-servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>psms</servlet-name>
    <url-pattern>/-/*</url-pattern>
</servlet-mapping>

urlrewrite.xml looks like:

<urlrewrite>
    <rule>
     <from>^/(.*)$</from>
     <to>/-/$1</to>
    </rule>
</urlrewrite>

applicationContent-security.xml looks like:

<http auto-config="true">
    <!-- allow GET requests to /login without authentication -->
    <intercept-url pattern="/-/login" method="GET" filters="none"/>

    <intercept-url pattern="/-/admin/**" access="ROLE_ADMIN"/>
    <intercept-url pattern="/-/**" access="ROLE_USER"/>

    <form-login login-page="/-/login"
                login-processing-url="/-/login.do"
                authentication-failure-url="/-/login?login_error"
                default-target-url="/-/index"
                always-use-default-target="true"/>

    <logout logout-url="/-/logout"
            logout-success-url="/-/login"/>

    <access-denied-handler error-page="/-/access-denied"/>
</http>
A: 

I'v never used Tuckey, but after a quick look at the documentation I would try adding one rule for the login case:

<urlrewrite>
    <rule>
        <from>^/my-context/login$</from>
        <to>/my-context/login</to>
    </rule>
    <rule>
        <from>^/(.*)$</from>
        <to>/-/$1</to>
    </rule>
</urlrewrite>

EDIT
Ok, and something like this:

<urlrewrite>
    <rule>
        <from>^/-/login$</from>
        <to>/login</to>
    </rule>
    <rule>
        <from>^/(.*)$</from>
        <to>/-/$1</to>
    </rule>
</urlrewrite>
rodrigoap
The problem is not that inbound requests do not get rewritten, but rather than outbound Location headers as part of a redirect do no get rewritten.I've since worked out that an outbound-rule with the full protocol, host, port, context, etc will catch the Location header, but this is not great either.
ptomli
+1  A: 

I looked into this issue for our project last year and at that time the problem was that Tucky wasn't cooperating with response.encodeRedirectUrl() to rewrite redirect URLs. I contacted them but I haven't followed up on this.

My solution was to allow the messy URL to go back to the client but then clean it up with a Tucky redirect rule (a second redirect).

So add another rule that matches your ugly URL from the security redirect and issue your own redirect to the clean URL:

<rule>
    <from>^/whatever/ugly.*$</from>
    <to type="redirect">/login</to>
</rule>

Yes, it involves two redirects, but the client will never see it... which is probably the point.

Pat Niemeyer
A: 

Spring security is doing the redirect with an absolute URL like http://example.org/-/login

Try to use an outbound-rule without the ^ start of string marker to match the absolute url generated by spring.

<outbound-rule>
 <from>/-/login(.*)$</from>
 <to>/login$1</to>
</outbound-rule>
Serhii
A: 

I ran into the same problem, but it seems fixed in version 3.2.0 of Tuckey. i.e. the response.encodeRedirectUrl() is now wrapped by Tuckeys UrlRewriteWrappedResponse where the outbound rule execution takes place.

Bas