Announcement Announcement Module
Collapse
No announcement yet.
@Secured not being invoke, even though they are enabled Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • @Secured not being invoke, even though they are enabled

    Continued issues with trying to integrate @Secured into a Dropwizard app, which is basically embedded Jetty + JAX-RS.

    I import my security XML file via my Spring config class

    Code:
    @Configuration
    @ImportResource("classpath:pros-schedule-security.xml")
    @ComponentScan(basePackageClasses = ScheduleService.class)
    The XML config is enabled with @Secured support

    Code:
    <beans:beans xmlns="http://www.springframework.org/schema/security"
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xmlns:context="http://www.springframework.org/schema/context"
                 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.1.xsd
          http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    
        <global-method-security secured-annotations="enabled" mode="aspectj" authentication-manager-ref="prosAuthenticationManager"/>
    
        <http use-expressions="true" create-session="stateless" realm="PROS" authentication-manager-ref="prosAuthenticationManager" auto-config="true">
            <http-basic />
            <intercept-url pattern="/**" access="isAuthenticated()"/>
        </http>
    </beans:beans>
    A @DELETE method on my JAX-RS class is configured to explicitly disallow access unless you have delete permissions

    Code:
        @DELETE @Secured("ROLE_DELETE")
        @Path("/{countryCode}")
        public Response delete(@PathParam("countryCode") String countryCode) {
    Yes, when I call a DELETE HTTP command with a user which does not have this permission it goes through.
    The log clearly shows that user only has ROLE_READ authority, but not ROLE_DELETE, yet is still able to successfully reach the method:

    Code:
    DEBUG [2012-11-11 20:20:22,871] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 at position 1 of 9 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
    DEBUG [2012-11-11 20:20:22,877] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 at position 2 of 9 in additional filter chain; firing Filter: 'LogoutFilter'
    DEBUG [2012-11-11 20:20:22,877] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 at position 3 of 9 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
    DEBUG [2012-11-11 20:20:22,877] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 at position 4 of 9 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
    DEBUG [2012-11-11 20:20:22,877] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 at position 5 of 9 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
    DEBUG [2012-11-11 20:20:22,883] org.springframework.security.web.authentication.www.BasicAuthenticationFilter: Basic Authentication Authorization header found for user 'read'
    DEBUG [2012-11-11 20:20:22,888] org.springframework.security.web.authentication.www.BasicAuthenticationFilter: Authentication success: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ca27776: Principal: read; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_READ
    DEBUG [2012-11-11 20:20:22,888] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 at position 6 of 9 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
    DEBUG [2012-11-11 20:20:22,889] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 at position 7 of 9 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
    DEBUG [2012-11-11 20:20:22,890] org.springframework.security.web.authentication.AnonymousAuthenticationFilter: SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ca27776: Principal: read; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_READ'
    DEBUG [2012-11-11 20:20:22,890] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 at position 8 of 9 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
    DEBUG [2012-11-11 20:20:22,890] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 at position 9 of 9 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
    DEBUG [2012-11-11 20:20:22,902] org.springframework.security.web.access.intercept.FilterSecurityInterceptor: Secure object: FilterInvocation: URL: /schedule/services/rest/country/23; Attributes: [isAuthenticated()]
    DEBUG [2012-11-11 20:20:22,902] org.springframework.security.web.access.intercept.FilterSecurityInterceptor: Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ca27776: Principal: read; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_READ
    DEBUG [2012-11-11 20:20:22,926] org.springframework.security.access.vote.AffirmativeBased: Voter: org.springframework.security.web.access.expression.WebExpressionVoter@273abfd5, returned: 1
    DEBUG [2012-11-11 20:20:22,926] org.springframework.security.web.access.intercept.FilterSecurityInterceptor: Authorization successful
    DEBUG [2012-11-11 20:20:22,926] org.springframework.security.web.access.intercept.FilterSecurityInterceptor: RunAsManager did not change Authentication object
    DEBUG [2012-11-11 20:20:22,927] org.springframework.security.web.FilterChainProxy: /schedule/services/rest/country/23 reached end of additional filter chain; proceeding with original chain
    DEBUG [2012-11-11 20:20:23,339] org.springframework.security.web.access.ExceptionTranslationFilter: Chain processed normally
    DEBUG [2012-11-11 20:20:23,339] org.springframework.security.web.context.SecurityContextPersistenceFilter: SecurityContextHolder now cleared, as request processing completed
    What am I doing wrong here? How come the @Secured annotation is getting totally ignored?

  • #2
    Is you web service class (that contains the delete method) declared as a Spring bean?

    According to the documentation:

    Note

    The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). If you want to secure instances which are not created by Spring (using the new operator, for example) then you need to use AspectJ.
    I think that what you see in the log concerns the BasicAuthenticationFilter which is used for securing web requests (and not method invocation). This filter is added according to the <http-basic> element.

    For your case, I guess your web service class is not declared as a Spring bean and this is why it is not secured. I don't know if annotating your class with @Component is appropriated since I think this class is instantiated by your REST framework (e.g. Jersey, CXF...). Maybe you should think about securing your service classes instead of your web service classes. Generally, the service classes are annotated with the @Service annotation and are scanned automatically if you enable this feature.

    EDIT:

    I've just seen you used the mode="aspectj" attribute. In this case, it should work if your web service class has been woven with the AnnotationSecurityAspect present in the spring-security-aspects module. Is it the case? You can use the Maven AspectJ plugin for this purpose.
    Last edited by Miko95; Nov 12th, 2012, 06:08 AM.

    Comment


    • #3
      No, this is a @Service class, all of them are. It gets full DI with other components like DAOs.

      When does the instrumentation of @Secured classes actually occur?

      With embedded Jetty in Dropwizard, the sequence of events id a bit different.

      First, we programmatically create the web app context.

      Then, we register the spring security filter chain and a custom context loader listener.

      Only add the end does Dropwizard fire up Jetty.

      Could the order of events or timing have an impact on how Spring security builds the AspectJ proxy on those classes?

      Comment


      • #4
        Sorry, I just saw your edit: we use Gradle. Do you mean that when we use AspectJ we have to a manually invoke this during the compilation process? That is maybe the part I am missing...

        Comment


        • #5
          This is the problem I think.

          You web service class is annotated with @Service and I guess you enabled the classpath scanning feature, so your service class is instantiated as a Spring bean. At this point, you can use Spring AOP (not AspectJ), just remove the mode="aspectj" attribute from your configuration.

          In the case your class doesn't implement an interface, you will have to use CGLIB in order to create the proxy.

          In the case you really wanted to use AspectJ instead of Spring AOP, meaning using compile time weaving instead of runtime weaving, the mode attribute must be set to "aspectj" (as you've done before) and your web service class must be woven by the AspectJ compile (possibly using a pluging as the maven aspectj plugin, but I don't know for Gradle).

          Comment


          • #6
            OK, that explains it. We switched to AspectJ because regular Spring proxies don't work with the Jersey JAX-RS implementation. It refuses to accept them as resource classes (hence we tried to switch to AspectJ to work around this issue).

            This is not a Spring-specific issue, it is a Jersey limitation, e.g. it has issues with Guice proxies too (from the posts I've seen from other Dropwizard users).

            Thanks for pointing me in the right direction.

            Comment


            • #7
              Glad to help, but as I said before, in the case your service layer is used by multiple interfaces, it may be more appropriated to secure it instead of securing the REST interface.

              Comment


              • #8
                In this case they are very simple REST services, nothing but passing on the input data into a DAO for basic input validation (using Hibernate Validators) and straight to DB. Each REST call is like 3-4 lines of code.

                I guess we could secure the DAO layer in this case and be done with it. That is probably a good option too, I just wanted to kick out the request as soon as it hits our logic and the REST endpoint is that.

                Thanks for your help.

                Comment


                • #9
                  Ok, so it is irrelevant for your case.

                  Also, it is possible web requests security may be enough for you so that you don't need to secure your methods. This is because in REST, the desired operation is known from the URI and HTTP method, and you have the possibility to use <intercept-url pattern="URI to secure" method="the method" access="the required role(s)" /> in your application context to secure URIs.

                  Comment


                  • #10
                    Yes, but:

                    a) I just posted another thread about missing support for PATCH HTTP method in the security XML schema (and we use PUT vs PATCH to properly differentiate add-or-replace vs update-existing entity in our APIs)

                    b) we need fine-grained permissions (e.g AUTH_ADD_COUNTRY, AUTH_ADD_SOME_OTHER_ENTITY, etc.) so that is why we needed method-level security...

                    Comment

                    Working...
                    X