Spring Webflux Websocket Security - Basic Authentication - spring-security

PROBLEM: I am not getting Spring Security with Websockets to work in a Webflux project.
NOTE: I am using Kotlin instead of Java.
DEPENDENCIES:
Spring Boot 2.0.0
Spring Security 5.0.3
Spring WebFlux 5.0.4
IMPORTANT UPDATE: I have raised a Spring Issue bug (March 30) here and one of the Spring security maintainers said its NOT SUPPORTED but they can add it for Spring Security 5.1.0 M2.
LINK: Add WebFlux WebSocket Support #5188
Webflux Security Configuration
#EnableWebFluxSecurity
class SecurityConfig
{
#Bean
fun configure(http: ServerHttpSecurity): SecurityWebFilterChain
{
return http.authorizeExchange()
.pathMatchers("/").permitAll()
.anyExchange().authenticated()
.and().httpBasic()
.and().formLogin().disable().csrf().disable()
.build()
}
#Bean
fun userDetailsService(): MapReactiveUserDetailsService
{
val user = User.withDefaultPasswordEncoder()
.username("user")
.password("pass")
.roles("USER")
.build()
return MapReactiveUserDetailsService(user)
}
}
Webflux Websocket Configuration
#Configuration
class ReactiveWebSocketConfiguration
{
#Bean
fun webSocketMapping(handler: WebSocketHandler): HandlerMapping
{
val map = mapOf(Pair("/event", handler))
val mapping = SimpleUrlHandlerMapping()
mapping.order = -1
mapping.urlMap = map
return mapping
}
#Bean
fun handlerAdapter() = WebSocketHandlerAdapter()
#Bean
fun websocketHandler() = WebSocketHandler { session ->
// Should print authenticated principal BUT does show NULL
println("${session.handshakeInfo.principal.block()}")
// Just for testing we send hello world to the client
session.send(Mono.just(session.textMessage("hello world")))
}
}
Client Code
// Lets create a websocket and pass Basic Auth to it
new WebSocket("ws://user:pass#localhost:8000/event");
// ...
Obserservations
In the websocket handler the principal shows null
The client can connect without being authenticated. If I do WebSocket("ws://localhost:8000/event") without the Basic Auth it stills works! So Spring Security does not authenticate anything.
What I am missing?
What I do wrong?

I could advise you to implement your own authentication mechanism instead of exploiting Spring Security.
When WebSocket connection is about to establish it uses handshake mechanism accompanied by an UPGRADE request. Base on that, our idea would be to use our own handler for the request and perform authentication there.
Fortunately, Spring Boot has RequestUpgradeStrategy for such purpose. On top of that, based on the application server what you use, Spring provides a default implementation of those strategies. As I use Netty bellow the class would be ReactorNettyRequestUpgradeStrategy.
Here is the suggested prototype:
/**
* Based on {#link ReactorNettyRequestUpgradeStrategy}
*/
#Slf4j
#Component
public class BasicAuthRequestUpgradeStrategy implements RequestUpgradeStrategy {
private int maxFramePayloadLength = NettyWebSocketSessionSupport.DEFAULT_FRAME_MAX_SIZE;
private final AuthenticationService service;
public BasicAuthRequestUpgradeStrategy(AuthenticationService service) {
this.service = service;
}
#Override
public Mono<Void> upgrade(ServerWebExchange exchange, //
WebSocketHandler handler, //
#Nullable String subProtocol, //
Supplier<HandshakeInfo> handshakeInfoFactory) {
ServerHttpResponse response = exchange.getResponse();
HttpServerResponse reactorResponse = getNativeResponse(response);
HandshakeInfo handshakeInfo = handshakeInfoFactory.get();
NettyDataBufferFactory bufferFactory = (NettyDataBufferFactory) response.bufferFactory();
String originHeader = handshakeInfo.getHeaders()
.getOrigin();// you will get ws://user:pass#localhost:8080
return service.authenticate(originHeader)//returns Mono<Boolean>
.filter(Boolean::booleanValue)// filter the result
.doOnNext(a -> log.info("AUTHORIZED"))
.flatMap(a -> reactorResponse.sendWebsocket(subProtocol, this.maxFramePayloadLength, (in, out) -> {
ReactorNettyWebSocketSession session = //
new ReactorNettyWebSocketSession(in, out, handshakeInfo, bufferFactory, this.maxFramePayloadLength);
return handler.handle(session);
}))
.switchIfEmpty(Mono.just("UNATHORIZED")
.doOnNext(log::info)
.then());
}
private static HttpServerResponse getNativeResponse(ServerHttpResponse response) {
if (response instanceof AbstractServerHttpResponse) {
return ((AbstractServerHttpResponse) response).getNativeResponse();
} else if (response instanceof ServerHttpResponseDecorator) {
return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate());
} else {
throw new IllegalArgumentException("Couldn't find native response in " + response.getClass()
.getName());
}
}
}
Moreover, if you do not have crucial logical dependencies onto Spring Security in the project such as complex ACL logic, then I advise you to get rid of it and even do not use it at all.
The reason for that is that I see Spring Security as a violator of the reactive approach due to its, I would say, MVC legacy mindset. It entangles your application with tons of extra configurations and "not-on-the-surface" tunings and forces engineers to maintain those configurations, making them more and more complex. In most cases, things could be implemented very smoothly without touching Spring Security at all. Just create a component and use it in a proper way.
Hope it helps.

Related

Altering URL for Spring Security SAML2 Login

I have an application with multiple authentication types (i.e. Basic and a special Preauthorized login). I am attempting to add a SAML2 RelyingParty registration in my security configuration, where I am attempting to change the default path from:
/login/saml2/sso/{registrationId}
to
/auth/saml2/{registrationId}
So, I have the following setup:
public RelyingPartyRegistration provder1RelyingPartyRegistration() {
RelyingPartyRegistration registration = RelyingPartyRegistrations
.fromMetadataLocation("classpath:provider1/metadata.xml")
.registrationId("provider1")
.assertionConsumerServiceLocation("{baseUrl}/auth/saml2/{registrationId}")
.build();
return registration;
}
// #Bean
public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
Collection<RelyingPartyRegistration> registrations = Collections.unmodifiableList(Arrays.asList(provider1RelyingPartyRegistration()));
InMemoryRelyingPartyRegistrationRepository repository = new InMemoryRelyingPartyRegistrationRepository(registrations);
return repository;
}
// fluff
#Override
protected void configure(HttpSecurity http) throws Exception {
final RequestMatcher filterRequestMatcher = new OrRequestMatcher(
new AntPathRequestMatcher("/auth/basic"),
new AntPathRequestMatcher("/auth/preauth")
);
ApplicationAuthenticationProcessingFilter filter = new ApplicationAuthenticationProcessingFilter(filterRequestMatcher, authenticationManagerBean());
filter.setAuthenticationSuccessHandler(successHandler());
filter.setAuthenticationFailureHandler(failureHandler());
http
.authorizeRequests()
.antMatchers("/**").permitAll()
.and()
.addFilterAfter(filter, LogoutFilter.class)
// fluff
.and()
.saml2Login()
.relyingPartyRegistrationRepository(relyingPartyRegistrationRepository())
.loginProcessingUrl("/auth/saml2/{registrationId}")
;
}
Unfortunately, I get this:
14 Dec 10:55:34 WARN [https-openssl-nio-127.0.0.1-444-exec-2] (DispatcherServlet.java:1278) - No mapping for POST /svc/auth/saml2/provider1
Can anyone tell me what I'm doing wrong trying to change that path? My application does NOT use Spring Boot, so I'm stuck with manual configuration.
EDIT
Some debugging has led to this hitting this line in the Saml2LoginConfigurer:
Map<String, String> providerUrlMap = getIdentityProviderUrlMap(
this.authenticationRequestEndpoint.filterProcessingUrl, this.relyingPartyRegistrationRepository);
Somehow, there's a default authenticationRequestEndpoint (since I didn't define one) setting the filterProcessingUrl to a value of /saml2/authenticate/{registrationId}. So, how do I override this?
The loginProcessingUrl is called by the asserting party after the authentication succeeds, which contains in the request the SAMLResponse parameter.
What you are trying to change is the URL to process an authentication request (create the SAMLRequest and send to the asserting party), this is done by the Saml2WebSsoAuthenticationRequestFilter class. To change the redirectMatcher you have to provide an ObjectPostProcessor, see this issue.
ObjectPostProcessor<Saml2WebSsoAuthenticationRequestFilter> processor = new ObjectPostProcessor<>() {
#Override
public <O extends Saml2WebSsoAuthenticationRequestFilter> O postProcess(O filter) {
filter.setRedirectMatcher(new AntPathRequestMatcher("/my/custom/url"));
return filter;
}
};
http.saml2Login().addObjectPostProcessor(processor);
Take a look at SAML 2.0 Login Overview for more detail about the flow.

Azure AD SAML Authentication with Spring Security 5.3.2 (not SAML Extension)

I am attempting to replace CAS with Azure Active Directory SAML authentication (SSO) in a Spring Boot API. My version of Spring Security is 5.3.2. Spring boot is 2.3.0.
Documentation has been hard to find. I think this is explained by 8685. I found 8010 and attempted the workaround mentioned there, but my breakpoints there are not getting hit.
Given the current state of the transition from SAML Extension to Spring Security, should I be using the old SAML Extension? I can reach my "success" endpoint with a JSESSIONID and SAMLReponse, but it's encrypted. Is this something I need to do myself? (If so, how?) The SecurityContext / user details are not getting set. I see AccessDenied stack traces in my logs, but I think that's a symptom of the Anonymous user context.
Relevant code is below. I have application.yml and application.properties files, but all config is annotations-based. If you see anything way off base, please let me know! Any guidance would be appreciated.
Here is my SecurityConfig:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
RelyingPartyRegistration getSaml2AuthenticationConfiguration() throws Exception {
// remote IDP entity ID
String idpEntityId = "https://sts.windows.net/xxxxxxxxxxxx/";
// remote WebSSO Endpoint - Where to Send AuthNRequests to
String webSsoEndpoint = "https://login.microsoftonline.com/xxxxxxxxxxxx/saml2";
// local registration ID
String registrationId = "xxxxxxxxxxxx";
// local entity ID - autogenerated based on URL
String localEntityIdTemplate = "xxxxxxxxxxxx.local";
// local signing (and decryption key)
Saml2X509Credential signingCredential = getSigningCredential(); //private method not included
// IDP certificate for verification of incoming messages
Saml2X509Credential idpVerificationCertificate = getVerificationCertificate(); //private method not included
String acsUrlTemplate = "https://xxxxxxxxxxxx.local/success"; //REST endpoint, see below
return RelyingPartyRegistration.withRegistrationId(registrationId)
.providerDetails(config -> config.entityId(idpEntityId))
.providerDetails(config -> config.webSsoUrl(webSsoEndpoint)).credentials(c -> c.add(signingCredential))
.credentials(c -> c.add(idpVerificationCertificate)).localEntityIdTemplate(localEntityIdTemplate)
.assertionConsumerServiceUrlTemplate(acsUrlTemplate).build();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// Just a test
OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
http
.headers()
.frameOptions()
.sameOrigin()
.httpStrictTransportSecurity()
.disable()
.and()
.authorizeRequests()
//... more antMatchers and permitAlls
.antMatchers("/success").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/logout").permitAll()
.antMatchers("/error").permitAll().anyRequest().authenticated().and()
.csrf().disable()
.saml2Login(
saml2 -> {
try {
saml2
.authenticationManager(a -> {
// This code is never reached
Authentication result = provider.authenticate(a);
Saml2Authentication saml2Authentication = (Saml2Authentication) result;
return result;
}).relyingPartyRegistrationRepository(
new InMemoryRelyingPartyRegistrationRepository(getSaml2AuthenticationConfiguration())
)
.loginProcessingUrl("/login/{registrationId}");
} catch (Exception e) {
// It made me put this try/catch here... this isn't getting reached either
e.printStackTrace();
}
});
}
}
And my REST endpoint:
#RestController
public class HelloController {
#RequestMapping(value = "/success", method=RequestMethod.POST)
public String saml2Post(HttpServletRequest request) throws IOException {
String jSessionId = request.getHeader("cookie");
System.out.println(jSessionId);
String samlResponse = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
System.out.println(samlResponse);
return "login success";
}
}
And my gradle dependencies (Gradle 6.5):
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
compile 'org.springframework.security:spring-security-config'
compile 'org.springframework.security:spring-security-saml2-service-provider'
compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
implementation 'org.springframework.boot:spring-boot-starter-integration'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-mail'
compile 'org.springframework.security:spring-security-oauth2-client'
compile 'org.springframework.security:spring-security-oauth2-jose'
implementation 'joda-time:joda-time:2.10.6'
implementation 'com.google.guava:guava:29.0-jre'
implementation 'com.opencsv:opencsv:5.2'
implementation 'org.apache.commons:commons-lang3:3.10'
implementation 'net.minidev:json-smart:2.3'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc'
runtimeOnly 'org.hsqldb:hsqldb'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.springframework.integration:spring-integration-test'
testImplementation 'org.springframework.security:spring-security-test'
}

null principal returned by ServerRequest in webflux request handler

I have set up authentication in a Spring WebFlux application. The authentication mechanism appears to work fine. For example the following code is used to set up security web filter chain:
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange()
.pathMatchers("/path/to/resource").hasAuthority("A_ROLE")
.anyExchange().authenticated()
.and().httpBasic()
.and().build();
}
This works as expected in conjunction with the UserDetailsRepositoryReactiveAuthenticationManager and MapReactiveUserDetailsService. If a user doesn't have the required authority a forbidden error code is returned and otherwise the request is passed on to the handler.
I have a requirement to apply fine grained permission checks within the handler itself and figured that I should be able to retrieve the authorities from the request as follows:
public Mono<ServerResponse> getMyResource(ServerRequest serverRequest) {
Authentication authentication = (Authentication)serverRequest.principal().block();
...
}
However, I find that the principal is always null. First, is this the correct way to get a handle on the authorities, and if so is there possibly some upstream configuration I'm missing?
You are blocking the result before is available. You can simply flatmap it so that you don't have to block it.
public Mono<ServerResponse> getMyResource(ServerRequest serverRequest) {
return serverRequest.principal().flatMap((principal) -> ServerResponse.ok()
.body(fromObject("Hello " + principal.getName())));
}
UPDATE: If you want to retrieve the principal and body you could zip them.
public Mono<ServerResponse> getMyResource(ServerRequest serverRequest) {
return Mono.zip(
serverRequest.principal(),
serverRequest.bodyToMono(String.class)
).flatMap(tuple -> {
Principal principal = tuple.getT1();
String body = tuple.getT2();
return ServerResponse.ok().build();
});
}

How to secure reactor netServer with spring security?

I try to develop an "hybrid" server using spring boot webApplication with embedded tomcat and a netServer from reactor to scale-up my Rest Api.
There are no Spring controller, all the incoming request are handled by the netServer.
Never the less i'd like to have a login page using spring security remember me facilities to authenticate the user and use this authentication to secure incoming request on the reactor netServer.
I start to implements the netServer, according to this tutorial reactor thumbmailer
here is my netServer :
NetServer<FullHttpRequest, FullHttpResponse> server = new TcpServerSpec<FullHttpRequest, FullHttpResponse>(NettyTcpServer.class)
.env(env)
.dispatcher("sync")
.listen(8080)
.options(opts)
.consume(ch -> {
// attach an error handler
ch.when(Throwable.class, UserController.errorHandler(ch));
// filter requests by URI
Stream<FullHttpRequest> in = ch.in();
// serve image thumbnail to browser
in.filter((FullHttpRequest req) -> req.getUri().startsWith(UserController.GET_USER_PROFILE))
.consume(UserController.getUserProfile(ch));
})
.get();
So when a user try to load his profile, the incoming request is handled by the userController :
public static Consumer<FullHttpRequest> getUserProfile(NetChannel<FullHttpRequest, FullHttpResponse> channel) {
UserService userService = StaticContextAccessor.getBean(UserService.class);
return req -> {
try {
LoginDTO login = RestApiUtils.parseJson(LoginDTO.class, RestApiUtils.getJsonContent(req));
DefaultFullHttpResponse resp = new DefaultFullHttpResponse(HTTP_1_1, OK);
String result = userService.loadUserProfile(login);
resp.headers().set(CONTENT_TYPE, "application/json");
resp.headers().set(CONTENT_LENGTH, result.length());
resp.content().writeBytes(result.getBytes());
channel.send(resp);
} catch (Exception e) {
channel.send(badRequest(e.getMessage()));
}
};
}
Here is the hack : getUserProfile is a static methode, so i can't use GlobalMethodSecurity to secure it.
i then inject a userService in this controller using a StaticContextAccessor :
#Component
public class StaticContextAccessor {
private static StaticContextAccessor instance;
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void registerInstance() {
instance = this;
}
public static <T> T getBean(Class<T> clazz) {
return instance.applicationContext.getBean(clazz);
}
}
UserService :
#Service
#PreAuthorize("true")
public class UserServiceImpl implements UserService{
public String loadUserProfile(LoginDTO login){
//TODO load profile in mongo
return new GsonBuilder().create().toJson(login);
}
}
the service is managed by spring so i guess i could use spring GlobalMethodSecurity on it (i m still developping this part, but i'm not sure this is the best way to secure my netServer)
Is there a easier way to use Spring security on reactor netServer ???
My first web site version was developped with nodeJS to handle many concurent users, and i try to refactor it using a JVM nio solution.
So is spring / reactor / netty a good solution to have a highly scalable server, or should i use something like play! or vertx.io ?
Thank you so much
Have you tried bootstrapping your NetServer from within a JavaConfig #Bean method? Something like:
#Configuration
#EnableReactor
class AppConfig {
public Function<NetChannel, UserController> users() {
return new UserControllerFactory();
}
#Bean
public NetServer netServer(Environment env, Function<NetChannel, UserController> users) {
return new TcpServerSpec(NettyTcpServer.class)
.env(env)
.dispatcher("sync")
.listen(8080)
.options(opts)
.consume(ch -> {
// attach an error handler
ch.when(Throwable.class, UserController.errorHandler(ch));
// filter requests by URI
Stream<FullHttpRequest> in = ch.in();
// serve image thumbnail to browser
in.filter((FullHttpRequest req) -> req.getUri().startsWith(UserController.GET_USER_PROFILE))
.consume(users.apply(ch));
})
.get();
}
}
This should preserve your Spring Security support and enable you to share handlers as beans rather than as return values from static methods. In general, just about everything you need to do in a Reactor TCP app can be done using beans and injection and by returing the NetServer as a bean itself.

How to propagate spring security context to JMS?

I have a web application which sets a spring security context through a spring filter. Services are protected with spring annotations based on users roles. This works.
Asynchronous tasks are executed in JMS listeners (extend javax.jms.MessageListener). The setup of this listeners is done with Spring.
Messages are sent from the web application, at this time a user is authenticated. I need the same authentication in the JMS thread (user and roles) during message processing.
Today this is done by putting the spring authentication in the JMS ObjectMessage:
SecurityContext context = SecurityContextHolder.getContext();
Authentication auth = context.getAuthentication();
... put the auth object in jms message object
Then inside the JMS listener the authentication object is extracted and set in the context:
SecurityContext context = new SecurityContextImpl();
context.setAuthentication(auth);
SecurityContextHolder.setContext(context);
This works most of the time. But when there is a delay before the processing of a message, message will never be processed. I couldn't determine yet the cause of these messages loss, but I'm not sure the way we propagate authentication is good, even if it works in custer when the message is processed in another server.
Is this the right way to propagate a spring authentication ?
Regards,
Mickaƫl
I did not find better solution, but this one works for me just fine.
By sending of JMS Message I'am storing Authentication as Header and respectively by receiving recreating Security Context. In order to store Authentication as Header you have to serialise it as Base64:
class AuthenticationSerializer {
static String serialize(Authentication authentication) {
byte[] bytes = SerializationUtils.serialize(authentication);
return DatatypeConverter.printBase64Binary(bytes);
}
static Authentication deserialize(String authentication) {
byte[] decoded = DatatypeConverter.parseBase64Binary(authentication);
Authentication auth = (Authentication) SerializationUtils.deserialize(decoded);
return auth;
}
}
By sending just set Message header - you can create Decorator for Message Template, so that it will happen automatically. In you decorator just call such method:
private void attachAuthenticationContext(Message message){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String serialized = AuthenticationSerializer.serialize(auth);
message.setStringProperty("authcontext", serialized);
}
Receiving gets more complicated, but it can be also done automatically. Instead of applying #EnableJMS use following Configuration:
#Configuration
class JmsBootstrapConfiguration {
#Bean(name = JmsListenerConfigUtils.JMS_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
#Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public JmsListenerAnnotationBeanPostProcessor jmsListenerAnnotationProcessor() {
return new JmsListenerPostProcessor();
}
#Bean(name = JmsListenerConfigUtils.JMS_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME)
public JmsListenerEndpointRegistry defaultJmsListenerEndpointRegistry() {
return new JmsListenerEndpointRegistry();
}
}
class JmsListenerPostProcessor extends JmsListenerAnnotationBeanPostProcessor {
#Override
protected MethodJmsListenerEndpoint createMethodJmsListenerEndpoint() {
return new ListenerEndpoint();
}
}
class ListenerEndpoint extends MethodJmsListenerEndpoint {
#Override
protected MessagingMessageListenerAdapter createMessageListenerInstance() {
return new ListenerAdapter();
}
}
class ListenerAdapter extends MessagingMessageListenerAdapter {
#Override
public void onMessage(Message jmsMessage, Session session) throws JMSException {
propagateSecurityContext(jmsMessage);
super.onMessage(jmsMessage, session);
}
private void propagateSecurityContext(Message jmsMessage) throws JMSException {
String authStr = jmsMessage.getStringProperty("authcontext");
Authentication auth = AuthenticationSerializer.deserialize(authStr);
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
I have implemented for myself a different solution, which seems easier for me.
Already I have a message converter, the standard JSON Jackson message converter, which I need to configure on the JMSTemplate and the listeners.
So I created a MessageConverter implementation which wraps around another message converter, and propagates the security context via the JMS message properties.
(In my case, the propagated context is a JWT token which I can extract from the current context and apply to the security context of the listening thread).
This way the entire responsibility for propagation of security context is elegantly implemented in a single class, and requires only a little bit of configuration.
Thanks great but I am handling this in easy way . put one util file and solved .
public class AuthenticationSerializerUtil {
public static final String AUTH_CONTEXT = "authContext";
public static String serialize(Authentication authentication) {
byte[] bytes = SerializationUtils.serialize(authentication);
return DatatypeConverter.printBase64Binary(bytes);
}
public static Authentication deserialize(String authentication) {
byte[] decoded = DatatypeConverter.parseBase64Binary(authentication);
Authentication auth = (Authentication) SerializationUtils.deserialize(decoded);
return auth;
}
/**
* taking message and return string json from message & set current context
* #param message
* #return
*/
public static String jsonAndSetContext(Message message){
LongString authContext = (LongString)message.getMessageProperties().getHeaders().get(AUTH_CONTEXT);
Authentication auth = deserialize(authContext.toString());
SecurityContextHolder.getContext().setAuthentication(auth);
byte json[] = message.getBody();
return new String(json);
}
}

Resources