Page 1 of 2 12 LastLast
Results 1 to 10 of 14

Thread: Messaging Thread Boundries and Authenticated Principal

  1. #1
    Join Date
    Jul 2010
    Posts
    139

    Default 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. #2
    Join Date
    Jan 2008
    Location
    Mohnton, PA USA (that's near Philadelphia)
    Posts
    2,148

    Default

    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?

  3. #3
    Join Date
    Jul 2010
    Posts
    139

    Lightbulb

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

  4. #4
    Join Date
    Jul 2010
    Posts
    139

    Post

    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" />

  5. #5
    Join Date
    Apr 2011
    Posts
    5

    Default

    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?

  6. #6
    Join Date
    Oct 2005
    Location
    Boston, MA
    Posts
    2,853

    Default

    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.

  7. #7
    Join Date
    Apr 2011
    Posts
    5

    Default

    Quote 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?

  8. #8
    Join Date
    Oct 2005
    Location
    Boston, MA
    Posts
    2,853

    Default

    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.

  9. #9
    Join Date
    Apr 2011
    Posts
    5

    Default

    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>

  10. #10
    Join Date
    Oct 2005
    Location
    Boston, MA
    Posts
    2,853

    Default

    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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •