Spring Boot WebSockets unable to find the current user (principal) - spring

After signing-in, the websockets cannot find the current user by session.getPrincipal() (it returns null).
Here is the Java code for WebSockets:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue", "/topic");
config.setApplicationDestinationPrefixes("/socket");
config.setUserDestinationPrefix("/user");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/app").withSockJS();
}
}
It seems like a Spring Boot bug - I am using 1.3.8 RELEASE. After refreshing the page, it gets the logged-in user properly.
And here is the front-end (subscription)
ngstomp.subscribeTo('/user/queue/message')
.callback(function(response) {
console.log('Test');
})
.withBodyInJson()
.connect();
I tried this solution: https://www.javacodegeeks.com/2014/11/spring-boot-based-websocket-application-and-capturing-http-session-id.html
But it's not working.
Please help me!

Why you required to have session.getPricncipal(). Spring provides Principal object to be injected automatically in your controller as following.
#MessageMapping("/message")
public String processMessageFromClient(#Payload String message, Principal principal) throws Exception {
messagingTemplate.convertAndSendToUser(principal.getName(), "/queue/reply", name);
return name;
}
Reference: Spring Boot Websocket Example

Related

Spring Boot not blocking request to the endpoint

Im having an issue with spring boot. I am trying to block one specific endpoint called /users/name/ but when i configure it on httpSecurity I can still call the endpoint. I need to block this specific endpoint below is my code.
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthConfigClass extends
WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests().antMatchers("/users/name/").permitAll()
.anyRequest().authenticated().and().httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication().withUser("admin")
.password("{noop}password").roles("USER");
}
}
And this is the RestController. Note please that the intention of this app is to make it vulnerable to attacks like the OWASP TOP API so no worries about security issues please tough I accept suggestions.
#Api(value="Users Endpoint and maintenance only for prvileged users")
#RequestMapping("/users")
public class RestControllerMain {
private final UserRespository userRespository;
#Autowired
public RestControllerMain(UserRespository userRespository) {
this.userRespository = userRespository;
}
//Excessive Data Exposure OWASP TOP 10
#RequestMapping(value="/", method=RequestMethod.GET)
public Iterable<User> getAllUsers() {
return userRespository.findAll();
}
#RequestMapping(value="/", method=RequestMethod.POST)
public void UserInsert(#RequestBody User user) {
userRespository.save(user);
}
//null pointer exception and SQL injection OWASP TOP 10 API.
#RequestMapping(value="/name/{user}", method=RequestMethod.GET)
public String mainUser(#PathVariable ("user")String username) {
if(!username.matches("/[\\t\\r\\n]|(--[^\\r\\n]*)|(\\/\\*[\\w\\W]*?(?=\\*)\\*\\/)/gi\n" )) {
return "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘VALUE’’.";
}
return "SQL Injection not found";
}
//XSS Also in the OWASP TOP API.
#RequestMapping(value="/search", method=RequestMethod.GET)
public String getMeUSer(#RequestBody User user) {
return "Nice to meet you" + user.getName();
}
// OWASP TOP 10 API. Broken Object Level
#RequestMapping(value="/{id}")
public Optional<User> getUserById(#PathVariable Long id) {
return userRespository.findById(id);
}
}
Please help me figure this I ended up following a tutorial.
As I understood, you want to require authentication for "users/name/{user}" endpoint, but your configuration states
.antMatchers("/users/name/")
whereas it should be
.antMatchers("/users/name/**")
where "**" means any matching pattern. But you if want to grant access after checking the privileges, as you stated in the description of controller, you should configure Spring's authorization and add
#Secured("ROLE_VIEWER, ROLE_ADMIN")
before service or controller methods, which will block any user who doesn't have those roles.

How do I Combine REST and Websocket in Spring Boot?

Where to put these blocks of code for websocket configuration in spring boot REST API? In a REST contoller?
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/chat");
}
}
It should remain in separate class which is under package that spring scanning, its a configuration class
This is not a controller, it is a configuration file, and it has to go with the configuration files. Along with filter configurations, security, servlet configurations...in short, where are the #Configuration, package *.*.configuration

AuthenticationSuccessEvent Listener for two spring applications connected through Shared Redis session

I am having two spring-boot application with shared session through Redis..
application-1 contains the login flow and application-2 uses the same session created on application-1,
Now i wanted to listen to the successful authentication on application-2.
Tried using InteractiveAuthenticationSuccessEvent listener as below ..
#EventListener({AuthenticationSuccessEvent.class, InteractiveAuthenticationSuccessEvent.class})
public void processAuthenticationSuccessEvent(AbstractAuthenticationEvent e) {
logger.info("Autenticación successful ....");
e.getAuthentication().getName();
}
Added the below code in securityConfig
#EnableWebSecurity
#Configuration
#Component
#Order
class SecurityConfig extends WebSecurityConfigurerAdapter {
.....
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationEventPublisher(authenticationEventPublisher());
}
#Bean
public DefaultAuthenticationEventPublisher authenticationEventPublisher() {
return new DefaultAuthenticationEventPublisher();
}
}
But 'InteractiveAuthenticationSuccessEvent' in application-2 is not triggered on authenticating on application-1..
Can someone guide me on this ?
I have used Redis PubSub to resolve my problem by listening to the Authentication Event from Application-1 to Application-2..

Spring Boot WebSockets notifications

In my Spring Boot application I'm trying to implement a notifications functionality based on WebSockets.
I have provided a following configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/notifications").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/queue");
}
}
and trying to use SimpMessagingTemplate in order to send a message from server side to a specific client(user).
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
public void sendMessages() {
simpMessagingTemplate.convertAndSendToUser(%user%, "/horray", "Hello, World!");
}
Right now I don't understand a few things:
What value should be used for %user% parameter of
simpMessagingTemplate.convertAndSendToUser method ?
What is the correlation between my /notifications endpoint
registered in WebSocketConfig.registerStompEndpoints method and
destination parameter of
simpMessagingTemplate.convertAndSendToUser method and how to properly use it?
How to protect the users from reading other people's messages on the
client ?
The user parameter is the name that the client use when he subscribes the destination, see Spring Reference Chapter 26.4.11 User Destinations
Destination vs Endpoint:
Endpoint is the url where the websocket/message brocker is listening
Destination is the topic or subject within the message brocker

Spring SimpMessagingTemplate

I have an application which receive some data from RabbitMQ. Everything works fine, I mean in class where I have annotation #EnableScheduling.
#Scheduled(fixedDelay = 5000)
public void volumeGraphData() {
Random r = new Random();
Graph graph = new Graph();
graph.setVolume(r.nextInt(500));
String json = gson.toJson(graph);
MessageBuilder<byte[]> messageBuilder = MessageBuilder.withPayload(json.getBytes());
simpMessagingTemplate.send("/" + volumeGraph, messageBuilder.build());
}
But when I would like to process messages received by Queue Listener from RabbitMQ (this works too) and pass them through to specific context for Stomp WebSocket using SimpMessagingTemplate I cannot do that. SimpMessagingTemplate is defined in dispatcher-servlet.xml, but configuration related with RabbitMQ is in root context. I tried to move everything to one context, but it does not work. Anyone has similar case that one I have ?
I finally managed to fix this. So, basically you need move your beans related with Spring Messaging/WebSocket to one common bean.
That's why in my root context I have such lines :
<!-- Fix for IntelliJ 13.1 https://youtrack.jetbrains.com/issue/IDEA-123964 -->
<context:component-scan base-package="org.springframework.web.socket.config"/>
where in package pl.garciapl.program.service.config is located class responsible for configuration of WebSockets :
#Configuration
#EnableWebSocketMessageBroker
#Component("messageBroker")
public class MessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/test").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry messageBrokerRegistry) {
}
#Override
public void configureClientInboundChannel(ChannelRegistration channelRegistration) {
}
#Override
public void configureClientOutboundChannel(ChannelRegistration channelRegistration) {
}
#Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
messageConverters.add(new MappingJackson2MessageConverter());
return false;
}
}
Remember to store your beans which use SimpMessagingTemplate in the same context where you defined this above class.

Resources