Announcement Announcement Module
Collapse
No announcement yet.
@Secured throws 404 on every class where it is added Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • @Secured throws 404 on every class where it is added

    I have a bizarre issue that I am about to give up on...

    We are running on top of DropWizard:
    http://dropwizard.codahale.com/

    and have integrated Spring and Spring Security into it.
    Everything seems to work fine...until I add an @Secured annotation to any JAX-RS resource class.
    It does not matter which method I add it (e.g. I can add it to a @DELETE method, but call a @GET method during testing).

    Regardless, any class annotated with even a single instance of @Secured immediately starts throwing a 404 not found.
    Remove the annotation and the class works again.

    Here's my spring security setup

    Code:
    <beans:beans xmlns="http://www.springframework.org/schema/security"
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    
        <global-method-security secured-annotations="enabled" proxy-target-class="true" />
    
        <http use-expressions="true" create-session="stateless" realm="PROS" authentication-manager-ref="prosAuthenticationManager">
            <http-basic />
            <intercept-url pattern="/" access="permitAll" />
            <intercept-url pattern="/**" access="isAuthenticated()"/>
        </http>
    
    </beans:beans>
    Here is the full stack trace...there is no error anywhere, but all of a sudden a 404 appears at the end...

    DEBUG [2012-11-10 23:43:44,054] org.eclipse.jetty.util.component.AbstractLifeCycle : STARTED org.eclipse.jetty.server.Server@68223f1b
    DEBUG [2012-11-10 23:43:51,401] org.eclipse.jetty.http.HttpParser: filled 242/242
    DEBUG [2012-11-10 23:43:51,419] org.eclipse.jetty.server.Server: REQUEST /schedule/services/rest/country on BlockingHttpConnection@74c0c457,g=HttpGenerator{s= 0,h=-1,b=-1,c=-1},p=HttpParser{s=-5,l=3,c=0},r=1
    DEBUG [2012-11-10 23:43:51,419] org.eclipse.jetty.server.handler.ContextHandler: scope null||/schedule/services/rest/country @ o.e.j.s.ServletContextHandler{/,null}
    DEBUG [2012-11-10 23:43:51,419] org.eclipse.jetty.server.handler.ContextHandler: scope null||/schedule/services/rest/country @ o.e.j.s.ServletContextHandler{/,file:/home/jacekf/src/schedule/out/production/schedule/}
    DEBUG [2012-11-10 23:43:51,419] org.eclipse.jetty.server.handler.ContextHandler: context=||/schedule/services/rest/country @ o.e.j.s.ServletContextHandler{/,file:/home/jacekf/src/schedule/out/production/schedule/}
    DEBUG [2012-11-10 23:43:51,419] org.eclipse.jetty.servlet.ServletHandler: servlet |/schedule/services/rest|/country -> com.sun.jersey.spi.container.servlet.ServletContai ner--1426788617
    DEBUG [2012-11-10 23:43:51,422] org.eclipse.jetty.servlet.ServletHandler: chain=com.yammer.dropwizard.servlets.ThreadNameFil ter-1107446185->springSecurityFilterChain->com.sun.jersey.spi.container.servlet.ServletConta iner--1426788617
    DEBUG [2012-11-10 23:43:51,424] org.eclipse.jetty.servlet.ServletHandler: call filter com.yammer.dropwizard.servlets.ThreadNameFilter-1107446185
    DEBUG [2012-11-10 23:43:51,425] org.eclipse.jetty.servlet.ServletHandler: call filter springSecurityFilterChain
    DEBUG [2012-11-10 23:43:51,430] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country at position 1 of 6 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
    DEBUG [2012-11-10 23:43:51,432] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country at position 2 of 6 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
    DEBUG [2012-11-10 23:43:51,435] org.springframework.security.web.authentication.www.BasicAuthenticationFilter: Basic Authentication Authorization header found for user 'read'
    DEBUG [2012-11-10 23:43:51,438] org.springframework.security.web.authentication.www.BasicAuthenticationFilter: Authentication success: org.springframework.security.authentication.Userna mePasswordAuthenticationToken@b7654d5f: Principal: read; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: READ
    DEBUG [2012-11-10 23:43:51,438] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country at position 3 of 6 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
    DEBUG [2012-11-10 23:43:51,439] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country at position 4 of 6 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
    DEBUG [2012-11-10 23:43:51,439] org.springframework.security.web.authentication.An onymousAuthenticationFilter: SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.Usern amePasswordAuthenticationToken@b7654d5f: Principal: read; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: READ'
    DEBUG [2012-11-10 23:43:51,439] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country at position 5 of 6 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
    DEBUG [2012-11-10 23:43:51,439] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country at position 6 of 6 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
    DEBUG [2012-11-10 23:43:51,439] org.springframework.security.web.util.AntPathReque stMatcher: Checking match of request : '/schedule/services/rest/country'; against '/'
    DEBUG [2012-11-10 23:43:51,440] org.springframework.security.web.access.intercept. FilterSecurityInterceptor: Secure object: FilterInvocation: URL: /schedule/services/rest/country; Attributes: [isAuthenticated()]
    DEBUG [2012-11-10 23:43:51,440] org.springframework.security.web.access.intercept. FilterSecurityInterceptor: Previously Authenticated: org.springframework.security.authentication.Userna mePasswordAuthenticationToken@b7654d5f: Principal: read; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: READ
    DEBUG [2012-11-10 23:43:51,454] org.springframework.security.access.vote.Affirmati veBased: Voter: org.springframework.security.web.access.expression .WebExpressionVoter@283040ee, returned: 1
    DEBUG [2012-11-10 23:43:51,454] org.springframework.security.web.access.intercept. FilterSecurityInterceptor: Authorization successful
    DEBUG [2012-11-10 23:43:51,454] org.springframework.security.web.access.intercept. FilterSecurityInterceptor: RunAsManager did not change Authentication object
    DEBUG [2012-11-10 23:43:51,454] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country reached end of additional filter chain; proceeding with original chain
    DEBUG [2012-11-10 23:43:51,454] org.eclipse.jetty.servlet.ServletHandler: call servlet com.sun.jersey.spi.container.servlet.ServletContai ner--1426788617
    DEBUG [2012-11-10 23:43:51,480] org.springframework.security.web.access.ExceptionT ranslationFilter: Chain processed normally
    DEBUG [2012-11-10 23:43:51,480] org.springframework.security.web.context.SecurityC ontextPersistenceFilter: SecurityContextHolder now cleared, as request processing completed
    DEBUG [2012-11-10 23:43:51,481] org.eclipse.jetty.server.Server: RESPONSE /schedule/services/rest/country 404 handled=true
    As I said I just need to add a single @Secured annotation to a class and it basically disappears from the app and any attempt to access its REST methods throws a 404, e.g.

    @DELETE @Secured("DELETE")
    @Path("/{countryCode}")
    public Response delete(@PathParam("countryCode") String countryCode) {
    Country entity = dao.findAndValidateById(countryCode);
    dao.delete(entity);
    return Response.ok().build();
    }
    Run this and you get a 404. Remove the @Secured and it works fine.

    Any help would be appreciated...I've spent the last 3 hours trying to get to the bottom of this....

  • #2
    Found the problem. It was some sort of issue between Jersey JAX-RS and how Spring Security proxies classes.

    With the default proxy, Jersey was failing to accept the JAX-RS Resource class and silently failed it.
    I only noticed that when Dropwizard displayed the list of resources and mine was missing.
    Hence the 404.

    I experimented with switching the proxy model to AspectJ

    Code:
    <global-method-security secured-annotations="enabled" mode="aspectj"/>
    and that worked fine with Jersey. It meant I had to bring in all the AspectJ dependencies into the app, but it worked, so I'll take it. :-)

    Comment

    Working...
    X