Announcement Announcement Module
Collapse
No announcement yet.
Disappearing SecurityContext ThreadLocal Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Disappearing SecurityContext ThreadLocal

    Am i correct that SI message channel security interceptors only work as long as only synchronous channels are being used?

    In the following example, the Spring Security SecurityContext is present when the message is put into the queue but once the message is picked up by the polling consumer (in a different thread), the security context is gone.

    Code:
        <si-sec:secured-channels>
            <si-sec:access-policy pattern="requestChannel" send-access="ROLE_user" receive-access="ROLE_user"/>
        </si-sec:secured-channels>
    
        <!-- upstream beans removed for brevity -->
    
        <si:channel id="requestChannel">
            <si:queue capacity="10"/>
        </si:channel>
    
        <si-rmi:outbound-gateway 
            request-channel="requestChannel" reply-channel="rmiReplyChannel"
            remote-channel="rmiInboundChannel" 
            <si:poller fixed-delay="1000" />
        </si-rmi:outbound-gateway>
    Similarily, the SecurityContext is not passed on to the RMI inbound gateway. It is arguable, if the Authentication should be set to "not authenticated" downstream of the RMI inbound gateway, but losing the security context completely is unexpected.

    As a work-around, I'm thinking of putting the Authentication into a custom message header. As long as the token is Serializable, it should transfer ok between threads.

    Thoughts?

    Thanks,

  • #2
    Hi!
    SecurityContext is stored in the ThreadLocal variable (SecurityContextHolder). So it's normal that you don't have it in the other Thread, e.g. after receive Message from queue.
    My suggestion to use some ChannelInterceptor:
    Code:
    class SecurityContextPropagationChannelInterceptor extends ChannelInterceptorAdapter {
    
    	@Override
    	Message<?> preSend(Message<?> message, MessageChannel channel) {
    		if (message.headers.securityContext || !SecurityContextHolder.context.authentication) return message
    		return MessageBuilder.fromMessage(message).with {
    			setHeader 'securityContext', SecurityContextHolder.context
    			build()
    		}
    	}
    
    	@Override
    	Message<?> postReceive(Message<?> message, MessageChannel channel) {
    		if (message?.headers?.securityContext && (!SecurityContextHolder.context.authentication || SecurityContextHolder.context != message.headers.securityContext)) {
    			SecurityContextHolder.context = message.headers.securityContext
    		}
    		return message
    	}
    
    }
    As you see, your solution regarding "custom message header" is right one.

    Good luck,
    Artem

    Comment

    Working...
    X