Hot questions for Using AspectJ in spring security

Top Java Programmings / AspectJ / spring security

Question:

What the difference between these below...

@org.aspectj.lang.annotation.Aspect
public class Test {
   //@Pointcut, @Around etc etc..
}

And

public aspect Test {

}

And what is the better to use for security among..

  • Spring Security &
  • AOP

in spring app


Answer:

Check here

Aspect declarations are supported by the org.aspectj.lang.annotation.Aspect annotation. The declaration:

 @Aspect
 public class Foo {}

Is equivalent to:

 public aspect Foo {}

NOTE: The first one is detected by spring. The later requires AspectJ.

And for the second question. The comparison is impossible. Because the first one is a framework and the later is a paradigm. Spring security uses AOP to secure method calls, AOP by itself is not a security mechanism. Unless of course, you are going to build your own security using AOP, which is re-inventing the wheel.

Question:

I am trying to configure spring global method security with AspectJ advice mode so I can use @PreAuthorize annotations in all @Configurable annotated classes. This my java configs:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, mode = AdviceMode.ASPECTJ)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration

and:

@EnableCaching
@SpringBootApplication
@EnableSpringConfigured
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class WebApplication extends WebMvcConfigurerAdapter 

This is my @Configurable class:

@Configurable
public class Entity {
    @PreAuthorize("hasPermission(this, 'publish')")
    public void method() { }
}

I also added spring-security-aspects as dependency. From AspectJ logs I can clearly see that Spring security related aspects are applied on my @Configurable classes however as soon as I create instance of these classes I get this exception:

Post-processor tried to replace bean instance of type [com.example.Entity] with (proxy) object of type [com.sun.proxy.$Proxy130] - not supported for aspect-configured classes!

I am using spring boot version 1.2.1 therefore spring security version is 3.2.5 . This seems to be bug that was discussed here : Spring Security AspectJMode with @EnableGlobalMethodSecurity not working

However this bug should not affect my version of spring security... Is there any workaround for this issue?


Answer:

Ok I have solved this. It was problem with spring boot's SecurityAutoConfiguration class. I had to exclude it from auto configuration and configre spring security manually - not very big deal, but anyway...

Question:

I've got this annotation and an aspect class

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AroundHere {
}

@Aspect
@Component
public class SomeAspect {
    @Around("@annotation(com.annotation.AroundHere)")
    public Object redirectIfNotEditingStatus(ProceedingJoinPoint pjp) throws Throwable {

        System.out.println("hi");

        return pjp.proceed();
    }
}

I want to print "hi" on some methods which has the @AroundHere annotation. It works fine on the service layer, but not working on the contollers. I suspect Spring Security because it scans all the controller components.

How can I make them work on the controllers?


Answer:

Most probably it's not working for you because aop:aspectj-autoproxy is defined in one app context and you have your controllers in a different app context. As a rule, BeanFactoryProcessors (which are doing the actual work when aop:aspectj-autoproxy is in the context) act only on the beans in the container where they are defined. So, for example, if you have aspectj-autoproxy defined in the root app context, it will not act on the beans defined in *-servlet.xml context.

You can find the relevant piece of documentation related to this subject here:

BeanPostProcessors are scoped per-container. This is only relevant if you are using container hierarchies. If you define a BeanPostProcessor in one container, it will only post-process the beans in that container. In other words, beans that are defined in one container are not post-processed by a BeanPostProcessor defined in another container, even if both containers are part of the same hierarchy.

Question:

I'm trying to build a simple logging tool that using AspectJ can print the HttpServletRequest body.

For this I created a simple PointCut that catches all executions of javax Filter.doFilter, HttpServlet doPost, doGet, service etc.

I then replace the HttpServletRequest with my own request wrapper that copies the request's body so it can be called more than once so I'll be able to log it. See - https://github.com/Alotor/test-binding/blob/master/src/java/grails/util/http/MultiReadHttpServletRequest.java.

It worked fine so far until I tried to log the body in an application that uses Spring security filters. Now I can't login, seems that somehow the implementation of the HttpServletRequstWrapper is important for Spring, but I can't figure out where and why.

My code (a bit modified from the original, but it gives the idea):

aspect MyAspect {
     pointcut httpCalls(HttpServletRequest req, HttpServletResponse resp):
        args(req, resp, ..) && (execution(void             javax.servlet.Servlet+.service(..))
                || execution(void javax.servlet.Servlet+.doGet(..))
                ...
                || execution(void javax.servlet.Filter.doFilter(..));

   Object around(HttpServletRequest req, HttpServletResponse resp):httpCalls(req,resp) {
    ...
    if (!ThreadContext.getContext().wasReplaced()) { // we need to replace the request
        reqWrapper = new MultiReadHttpServletRequest(req);
        ThreadContext.getContext().setWasReplaced(true);           
        obj = proceed(reqWrapper, resp);
        TraceContextFactory.getFactory().getContext().setWasReplaced(false);
    } else { 
        obj = proceed(req, resp);
    }
    return obj;
  }

}

Any idea why I can't login and this fails to work with Spring security? I saw that they are using their own wrappers, but since the API is the same it should have worked.

For clarification - I'm running an application on tomcat, and I'm not instrumenting org.apache.catalina (it doesn't work, probably due to class loading order that prevents the aspectj from weaving tomcat source code).

Edit:

I see now the the problem is inside the UsernamePasswordAuthenticationFilter.java:

 protected String obtainUsername(HttpServletRequest request) {
    return request.getParameter(usernameParameter);
}

The above returns null in case I use my Wrapper, otherwise it returns "guest", which is the username I used. I did override the inputstream and the reader, but the actual call to getParameter(...) is done through the underlying request which uses the original input stream from org.apache.catalina.connector.RequestFacade.

http://localhost:8081/someApp/j_spring_security_check:

Thanks,

Lin


Answer:

I couldn't login because spring security called tomcat's org.apache.coyote.Request to read the parameters. The request doesn't use an InputStream, but a BufferInput. Either way, it doesn't use my wrapped InputStream.

There are 2 solutions:

  • request.getParametersMap() - In case of post calls (such as login, for example spring security j_spring_security_check), you can use request.getParametersMap() and to generate the request body from it.
  • Use java reflection to replace org.apach.coyote.Request's inputBuffer with your own implementation that allows to read more than once from the stream.

I chose the first option since the latter is too risky IMHO.