Announcement Announcement Module
Collapse
No announcement yet.
Pre/Post annotation & weaving Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Pre/Post annotation & weaving

    Hi all,

    what do I have to do in order to find out more about how the Pre/Post annotations are handled? I have a relatively big application (too big to post, that is) and in this app I have one method taht has an annotation of the form
    @PreAuthorize("denyAll")

    I also have set:
    <security:global-method-security pre-post-annotations="enabled" jsr250-annotations="enabled" secured-annotations="enabled"/>

    The denyAll annotation is not honored (I can access the method without ado ), and I would like to know if there is some weaving missing, which classes are woven etc., giving me maybe some idea of what's going wrong.

    BTW: I have checked my classpath for duplicates. I am using spring 3.0.0.RC1 (except from the orm-package which is 3.0.0.RC3) with spring-security 3.0.0.RC1.

    Best,
    Wolfgang

  • #2
    A few things may be relevant:

    Is the method on a Spring bean (declared in the application context)?
    Is your application context divided up into different parts? If so, are the beans in a child context (typically the -servlet.xml) of the main application context?
    Do the other annotation types work?

    Why are you mixing Spring versions (orm RC3 with RC1 of everything else) ?

    Comment


    • #3
      Hi,

      I seem to have a similar problem. I am using Spring Security RC1 with Spring RC2. I cannot get the pre-post-annotations to work. If I add @PreAuthorize to a class or to a method, nothing happens, I can set any hasRole("xxxxx") and the class or method will still work.

      I am using it in a Spring MVC application, so I have one applicationContext file, where all of the beans are created by context:component-scan. I also have added my controllers in the -servlet.xml file the same way. However, nothing seems to help.

      // Andréas

      Comment


      • #4
        Originally posted by Luke Taylor View Post
        A few things may be relevant:

        Is the method on a Spring bean (declared in the application context)?
        Is your application context divided up into different parts? If so, are the beans in a child context (typically the -servlet.xml) of the main application context?
        Do the other annotation types work?

        Why are you mixing Spring versions (orm RC3 with RC1 of everything else) ?
        Luke, thank you very much for taking the time.

        It is a spring bean.

        I have copied the conf into the root application context.

        I have removed the version mix, but unfortunately without positive consequences.

        The app I am writing about is a rather untidy "legacy" JSP app (lots of code in the JSP, no spring-mvc). However, some beans are now spring generated, spring support for ibatis is used and works nicely. So far the app does not use annotations at all.

        Some years ago, I did some AOP in a non-web-non-spring project (not Spring-AOP) and I am aware that you can have strange things happen to you when doing AOP. So I would be very thankful for:

        a) A pointer to how I can find out (e.g. by logging, which log, which class?) which paths and objects are trying to be woven.

        b) Some suggestions about annotations that I can test without changing the whole app (pertaining to your question if other annotations work, Luke).

        Cheers + thanks
        Wolfgang

        Comment


        • #5
          The <global-method-security> element uses Spring's autoproxying mechanism, so you should see something like:

          Code:
          [DEBUG,DefaultListableBeanFactory] Creating shared instance of singleton bean 'bankService'
          [DEBUG,DefaultListableBeanFactory] Creating instance of bean 'bankService'
          [DEBUG,DefaultListableBeanFactory] Returning cached instance of singleton bean 'bankDao'
          [DEBUG,DefaultListableBeanFactory] Eagerly caching bean 'bankService' to allow for resolving potential circular references
          [DEBUG,DefaultListableBeanFactory] Returning cached instance of singleton bean 'org.springframework.security.methodSecurityMetadataSourceAdvisor'
          [DEBUG,PrePostAnnotationSecurityMetadataSource] @org.springframework.security.access.prepost.PreAuthorize(value=hasRole('ROLE_SUPERVISOR') or hasRole('ROLE_TELLER') and (#account.balance + #amount >= -#account.overdraft)) found on specific method: public bigbank.Account bigbank.BankServiceImpl.post(bigbank.Account,double)
          [DEBUG,DelegatingMethodSecurityMetadataSource] Adding security method [CacheKey[bigbank.BankServiceImpl; public bigbank.Account bigbank.BankServiceImpl.post(bigbank.Account,double)]] with attributes [[authorize: 'hasRole('ROLE_SUPERVISOR') or hasRole('ROLE_TELLER') and (#account.balance + #amount >= -#account.overdraft)', filter: 'null', filterTarget: 'null']]
          [DEBUG,InfrastructureAdvisorAutoProxyCreator] Creating implicit proxy for bean 'bankService' with 0 common interceptors and 1 specific interceptors
          [DEBUG,JdkDynamicAopProxy] Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [bigbank.BankServiceImpl@315cb235]
          [DEBUG,DefaultListableBeanFactory] Finished creating instance of bean 'bankService'
          [DEBUG,DefaultListableBeanFactory] Returning cached instance of singleton bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler#0'
          in the log. Try the tutorial sample application out to see how it works first. It is probably easier to find your way around.

          Regarding other annotations, I was meaning the @Secured annotations. They should essentially be using the same mechanism.

          Comment


          • #6
            Originally posted by Luke Taylor View Post
            The <global-method-security> element uses Spring's autoproxying mechanism, so you should see something like:

            Code:
            [DEBUG,DefaultListableBeanFactory] Creating shared instance of singleton bean 'bankService'
            [DEBUG,DefaultListableBeanFactory] Creating instance of bean 'bankService'
            [DEBUG,DefaultListableBeanFactory] Returning cached instance of singleton bean 'bankDao'
            [DEBUG,DefaultListableBeanFactory] Eagerly caching bean 'bankService' to allow for resolving potential circular references
            [DEBUG,DefaultListableBeanFactory] Returning cached instance of singleton bean 'org.springframework.security.methodSecurityMetadataSourceAdvisor'
            [DEBUG,PrePostAnnotationSecurityMetadataSource] @org.springframework.security.access.prepost.PreAuthorize(value=hasRole('ROLE_SUPERVISOR') or hasRole('ROLE_TELLER') and (#account.balance + #amount >= -#account.overdraft)) found on specific method: public bigbank.Account bigbank.BankServiceImpl.post(bigbank.Account,double)
            [DEBUG,DelegatingMethodSecurityMetadataSource] Adding security method [CacheKey[bigbank.BankServiceImpl; public bigbank.Account bigbank.BankServiceImpl.post(bigbank.Account,double)]] with attributes [[authorize: 'hasRole('ROLE_SUPERVISOR') or hasRole('ROLE_TELLER') and (#account.balance + #amount >= -#account.overdraft)', filter: 'null', filterTarget: 'null']]
            [DEBUG,InfrastructureAdvisorAutoProxyCreator] Creating implicit proxy for bean 'bankService' with 0 common interceptors and 1 specific interceptors
            [DEBUG,JdkDynamicAopProxy] Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [bigbank.BankServiceImpl@315cb235]
            [DEBUG,DefaultListableBeanFactory] Finished creating instance of bean 'bankService'
            [DEBUG,DefaultListableBeanFactory] Returning cached instance of singleton bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler#0'
            in the log. Try the tutorial sample application out to see how it works first. It is probably easier to find your way around.

            Regarding other annotations, I was meaning the @Secured annotations. They should essentially be using the same mechanism.
            Hi Luke,

            I try to be precise with my problem solution, as it highlights some nice ways you can fall on your face using Spring Security. It's not the fault of Spring Security, but rather that one has to be aware of what Auto Proxying really means.

            @Secured did not work either, I will come to that below.

            Thanks for your time, I just solved the problem.

            The first big thing was fixing the library versions. Instead of what I said before, it DID change something important. Now, the autoproxies could be generated in the proper fashion. I looked for the string "Pre/Post" as before in the logs, and there they were.

            However, things did not work, yet. The reason being that Autoproxy weaving is not the same as AspectJ weaving. Throughout my legacy app, there are methods that need an instance of the service (let's call it daService) that has the @PreAuthorize annotation. However, as these methods are often static (yuck!), the corresponding objects are never instantiated. So no spring injection. And as a consequence I am using a static service.getInstance() method (that hands "this" out), and I vowed to clean that up later.

            This, in fact *bypasses* the effects of the PreAuthorize annotation. The "this" "daService" is handing out is the "this" behind the authorizing auto proxy generated by the PreAuthorize annotation. Calls to daService then bypass this.

            What I thus had to do is to simply generate a daServiceProxy which is parametrized with a Spring-generated daService instance. On instantiation, Spring will automatically hand through to daServiceProxy an autoproxied daService, and things magically begin to work.

            There is still some stuff to do till everything really works (I intend to use rules in the @PreAuthoritze annotation etc.), but the problem I asked you about is solved.

            Luke, I thank you a lot for asking the right questions.

            Cheers,
            Wolfgang

            Comment


            • #7
              Hi Wolfgang,

              Yes, with Spring AOP, you need to be using a reference to the proxy, otherwise you are bypassing the security interceptor. This will also apply to things like transactions.

              Dependency injection is definitely an improvement on the evil singleton pattern.

              I'm glad you worked things out. Good luck with your conversion .

              Luke.

              Comment


              • #8
                @Luke

                Does this mean that if I call a method from within the same class the @Pre/@Post will not be properly handled?

                I am seeing a problem like this where I have an interface like

                Code:
                @PreAuthorize("hasRole('ROLE_ADMIN')")
                @PostFilter(
                	"hasPermission(filterObject, read) or " +
                	"hasPermission(filterObject, admin)")
                public List<Bean> findByOwner(Owner owner);
                    
                @PreAuthorize("hasRole('ROLE_ADMIN')")
                public Map<Owner,List<Bean>> findByOwnerList(List<Owner> owners);
                Then I have the implementing methods basically as follows

                Code:
                public List<Bean> findByOwner(Owner owner) {
                	// query code omitted for simplicity
                	return query.getResultList();
                }
                
                public Map<Owner,List<Bean>> findByOwnerList(List<Owner> owners) {
                	Map<Owner,List<Bean>> map = new HashMap<Owner,List<Bean>>();
                	for(Owner owner : owners) {
                		map.put(owner, findByOwner(owner));
                	}
                	return map;
                }
                If I call findByOwner by itself I will get back the appropriate object list with the ones filtered out based on the ACLs. However if I call findByOwnerList the resulting list of the same Owner will contain all the objects and WILL NOT have filtered out the objects based on ACLs. It appears as though the security isn't being enforced. It seems as though the only security that is enforced is basically the entry point call and all calls made from within the same class will not have their security enforced.

                Is this problem related to the issue talked about here? If so what is the correct approach to actually get this working correctly?

                Comment


                • #9
                  @Luke

                  Can you confirm the explained behavior I mentioned in my previous post?

                  Comment


                  • #10
                    Originally posted by split3 View Post
                    Is this problem related to the issue talked about here? If so what is the correct approach to actually get this working correctly?
                    Hi split3,
                    I think I can confirm this. IMHO it's exactly that issue and I am quite sure Luke will not correct me on this opinion.

                    You have to get at the instance of the spring-created bean. I am not sure how you handle that most elegantly. The kludge I chose was to create a singleton and to have Spring inject the bean into that. This will surely work.

                    Cheers,
                    Wolfgang

                    Comment


                    • #11
                      Could this problem be prevented with compile time weaving?

                      Comment


                      • #12
                        Originally posted by split3 View Post
                        Could this problem be prevented with compile time weaving?
                        Well, my compile-time weaving experiences are pretty low, and I wrote my last aspectJ app some while ago, so take my answer as a guess:

                        If spring will use compile time weaving also for the security annotations, then compile time weaving should indeed do the trick.

                        Comment

                        Working...
                        X