Announcement Announcement Module
Collapse
No announcement yet.
Messaging Thread Boundries and Authenticated Principal Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Messaging Thread Boundries and Authenticated Principal

    My application is currently leveraging Spring Security's global-method-security to control access on various service methods within our application as such:

    Code:
      <global-method-security>
        <protect-pointcut expression="execution(* com.mycompany.*Example1Service.*(..))"
             access="ROLE_USER1"/>
        <protect-pointcut expression="execution(* com.mycompany.*Example2Service.*(..))"
             access="ROLE_USER2"/>
         ...
      </global-method-security>

    I need to keep the access controls on the service methods, and not on the message channels themselves.

    What's the best way to set an authenticated pripal using Spring Security's SecurityContext so it can be applied to all aspects throughout the context of a single messaging sequence within the application container?

    Right now I am setting the authenticated principal during the 1st step of the messaging sequence [i.e. SecurityContext.setAuthentication(<authenticatedTo ken>)] , but I am unsure of the thread boundaries within my messaging sequence. Currently, all messages are passing though only DirectChannels, but I feel certain I will need to add Publish/Subscribe channels as well.

  • #2
    Well, if I understand you correctly, the idea that comes to mind is this.
    Once authenticated you set the security principal at the very beginning which works fine if the flow is single-threaded. However if the thread boundaries are broken your security principal will not be propagated. So here is an idea:
    Store security principal in the messages itself (i.e., via message headers).
    Use global channel interceptor (to intercept on every cannel) and check if security is bound to the thread. If it does, then the interceptor doe nothing else, but if it doesn't, then the interceptor will access the security header and will set the security context for that thread.
    This way you don't have to worry when switching from direct channel to pub-sub, executor etc.
    Does that make sense?

    Comment


    • #3
      Actually, that sounds like a great idea, and I think it will work. Thanks!

      Comment


      • #4
        Actually, I was thinking that this would be a great feature to add to the Spring integration security component. Not sure how much the community would use this feature, but I would benefit from it. Example XML declaration:

        Examples setting from header or payload...
        Code:
        <!-- globally sets SecurityContext's Authentication object based on AutheticatedToken found in message. NOTE: AuthenticatedToken could be anywhere in Message, either as a seperate header or part of the message payload.
        -->
        <si-security:global-secured-context expression="headers.AUTH_TOKEN" />
        <si-security:global-secured-context expression="payload.authToken" />

        Comment


        • #5
          I am struggling with this problem as well, but the proposed solution (a global channel interceptor that sets the security context in the current thread from a message header if it has not been set) does not appear to work because the channel interceptor does not execute in the same thread as the subscriber.

          I have pub-sub channels set up with service activators such as the following:

          Code:
          <task:executor id="taskExecutor" pool-size="10" />
          <publish-subscribe-channel id="somePubSubChannel" task-executor="taskExecutor" />
          <service-activator id="myServiceActivator" input-channel="somePubSubChannel" ref="myService" method="doSomething"/>
          <beans:bean id="securityInterceptor" class="com.example.SecurityInterceptor" autowire="byName" />
          <channel-interceptor ref="securityInterceptor" pattern="*" />
          The securityInterceptor is invoked every time a message is sent to somePubSubChannel, but it is NOT invoked in the same thread as myService.doSomething, so initializing the security context from the message header does nothing.

          Can anyone offer a work around for this?

          Comment


          • #6
            Any time you cross a thread boundary, you will lose any context associated with that Thread (e.g. the SecurityContext). If you are okay with passing the value in a header as you cross the boundary, then you can again establish it on the new thread downstream (the one created/pooled by the task-executor in your case). One pattern that often applies is to have a true authentication/authorization at the entry point to your system, but then to have a simpler authentication only (ie. "system" user/role) once within the system. You might even decide to do something within a custom ThreadFactory implementation that you configure on the TaskExecutor.

            Comment


            • #7
              Originally posted by Mark Fisher View Post
              Any time you cross a thread boundary, you will lose any context associated with that Thread (e.g. the SecurityContext). If you are okay with passing the value in a header as you cross the boundary, then you can again establish it on the new thread downstream (the one created/pooled by the task-executor in your case). One pattern that often applies is to have a true authentication/authorization at the entry point to your system, but then to have a simpler authentication only (ie. "system" user/role) once within the system. You might even decide to do something within a custom ThreadFactory implementation that you configure on the TaskExecutor.
              That's what I'm attempting to do; the security context is lost when crossing the thread boundary, which is why I'm passing it as a message header. I simply want to intercept the message before it is sent to the service activator and (in the new thread) initialize the security context based on said message header. Otherwise, I have to do this manually every time like so:

              Code:
              public class MyService {
                  private SecurityService securityService;
                  public void doSomething(Object payload,
                                       @Header('securityContext') SecurityContext ctx){
                      securityService.initializeContext(ctx);
                      //service logic
                  }
              }
              I want to do this initialization automatically without having to manually inspect the header each time. Any ideas?

              Comment


              • #8
                Okay. I see what you're saying. The interceptor's preSend() is invoked immediately before the dispatcher delegates to the Executor. So, you really want something on the other side of that thread boundary. My first question would be if you actually require a pub-sub channel there? I only see one consumer, but you might just be providing a small excerpt.

                Comment


                • #9
                  I provided just a small excerpt. There could be any arbitrary number of subscribers- otherwise I'd just use direct channels and avoid this issue entirely

                  I'm currently considering creating my own subclass of AbstractSubscribableChannel that uses a custom implementation of MessageDispatcher to invoke the security initialization code in the new thread, but this seems like a horribly ugly solution to this problem. Alternatively, I suppose I could set up each one of my subscribers as a direct chain that starts with the security initialization, but this is similarly ugly:

                  Code:
                  <chain id="chainOne" input-channel="somePubSubChannel">
                      <service-activator ref="securityService" method="initSecurityContextFromHeader"/>
                      <service-activator ref="myService" method="doSomething"/>
                  </chain>
                  
                  <chain id="chainTwo" input-channel="somePubSubChannel">
                      <service-activator ref="securityService" method="initSecurityContextFromHeader"/>
                      <service-activator ref="myOtherService" method="doSomethingElse"/>
                  </chain>
                  
                  <chain id="chainThree" input-channel="somePubSubChannel">
                      <service-activator ref="securityService" method="initSecurityContextFromHeader"/>
                      <service-activator ref="myThirdService" method="doAThirdThing"/>
                  </chain>

                  Comment


                  • #10
                    One option would be to use a 'recipient-list-router' instead of a 'publish-subscribe-channel', that would then list the direct-channels that are inputs for the consumers (and those could use a naming convention that allows the channel-interceptor to apply to them). In order to get on the right side of the thread boundary, that recipient-list-router's own input-channel could be a direct channel with a <dispatcher>.

                    Not sure if that covers your case the same way. Let me know if you have any more ideas.

                    Comment


                    • #11
                      Mark,
                      Would setting up the SecurityContextHolder to transcend all threads, or just spawned threads, be a viable solution?
                      According to the documentation, you can configure the SecurityContextHolder to behave differently from the default (which uses ThreadLocal to store the SecurityContext, as this forum discussion assumes). Options include SecurityContextHolder.MODE_INHERITABLETHREADLOCAL which would propogate the security context to spawned threads. See this link for more details: http://static.springsource.org/sprin...w.html#d0e1543

                      Comment


                      • #12
                        Hello
                        SecurityContextHolder.MODE_INHERITABLETHREADLOCAL
                        will work only in spawned threads from main Servlet Reuest thread.
                        In the Spring Integration asynchronous mesasge flow provides theard for pollers from ThreadPool.
                        Off topic: Servlet Reuest threads are also taking from ThreadPool...
                        Already there is an issue about Security Context propagation in the JIRA: https://jira.springsource.org/browse/INT-2166

                        Artem Bilan

                        Comment


                        • #13
                          Thanks for the reply, Artem.

                          will work only in spawned threads from main Servlet Reuest thread.
                          Sure, that's the strategy for MODE_INHERITABLETHREADLOCAL. But what about MODE_GLOBAL?

                          From the docs, previously linked to:

                          Some applications aren't entirely suitable for using a ThreadLocal, because of the specific way they work with threads. For example, a Swing client might want all threads in a Java Virtual Machine to use the same security context. SecurityContextHolder can be configured with a strategy on startup to specify how you would like the context to be stored. For a standalone application you would use the SecurityContextHolder.MODE_GLOBAL strategy.

                          Comment


                          • #14
                            MODE_GLOBAL is a strategy about singleton for all application.
                            And Spring Security doc contains truth - it's for Swing

                            Comment

                            Working...
                            X