I am building a Stateless Spring (4.2.4.RELEASE) Solution using STOMP over Websockets with SockJS and a Rest Endpoint using JWT to connect mobile devices with Full Duplex communication. I am using Tomcat 8.0.33 as a Web Server and testing using html with sockjs javascript client. The stomp protocol works fine using the http fallback but I can't make it using only a websocket protocol. I tried CORS in many ways but I am not sure that is a Tomcat Problem or just bad spring configuration. I tested my html even in the same domain and port and SockJS is still falling back into xhr or iframes.
WebScoketConfig.java
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer
{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry)
{
RequestUpgradeStrategy upgradeStrategy = new TomcatRequestUpgradeStrategy();
registry.addEndpoint("/ws").setHandshakeHandler(new DefaultHandshakeHandler(upgradeStrategy))
.setAllowedOrigins("*").withSockJS().setSessionCookieNeeded(false)
.setStreamBytesLimit(512 * 1024)
.setHttpMessageCacheSize(1000)
.setDisconnectDelay(30 * 1000);
}
#Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(50);
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry)
{
registry.enableSimpleBroker("/queue/", "/topic/");
// registry.enableStompBrokerRelay("/queue/", "/topic/");
registry.setApplicationDestinationPrefixes("/myapp");
}
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.setMessageSizeLimit(500 * 1024);
registration.setSendBufferSizeLimit(1024 * 1024);
registration.setSendTimeLimit(20000);
}
}
WebSecurityConfig.java
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/**").permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
}
}
I solved my problem, actually the code was good but the antivirus (Kaspersky) was closing the connection on my client browser just after opened. It forces SockJS to fallback into a different strategy. I tested the client with the antivirus turned off and the Websocket transport was beautifully running. Tested on mac & linux as well.
Related
I am using Angular, Spring Boot, and WebSocket in my project. I'm testing on my local machine socket connection is working fine but when I deployed my build on the production server it is not working properly. sometimes connection was established and sometimes not. I'm new to this technology.
I already configured the message broker and WebSocket application endpoints here is my code
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer, WebSocketConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("http://localhost:4200", "https://www.xxxxxx.com/").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/chatparticipant", "/messages", "/unAssignedParticipant");
}
#Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxBinaryMessageBufferSize(1024000);
return container;
}
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new WebSocketHandler(), "/socket").setAllowedOrigins(Pl4ChatConfig.ALLOWED_ORIGIN);
}
}
we're getting error messages:
WebSocket connection to 'wss://xxxxx.com/ws/709/2pjkwf4q/websocket' failed:
I have a working Spring Boot server with Authentication/Authorization. When trying to open a connection with SockJS it is blocked by my other security measures.
I don't fully understand how the flow of security works in Java yet, but I have an itch that I need to pass the JWT token with the handshake when trying to connect with SockJS. From what I understand this is not possible with SockJS. So I am just wandering what the best approach to getting the socket started with JWT. Also, I know I don't have CSRF enabled so some tips on that would be nice too.
In WebSecurityConfig.java:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors();
httpSecurity.csrf().disable()
.authorizeRequests()
.antMatchers("/authenticate", "/login", "/register").permitAll()
.anyRequest().authenticated().and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
In WebSocketConfig.java:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("http://localhost:5000")
.withSockJS();
}
}
In my Vue app. Trying to connect with JS:
connect() {
this.socket = new SockJS("http://localhost:8080/ws");
this.stompClient = Stomp.over(this.socket);
this.stompClient.connect(
{
token: 'Bearer ' + localStorage.getItem('user-token')
},
frame => {
this.connected = true;
console.log(frame);
this.stompClient.subscribe("/topic/greetings", tick => {
console.log(tick);
this.received_messages.push(JSON.parse(tick.body).content);
});
},
error => {
console.log(error);
this.connected = false;
})
},
If I remove all the security config I can connect to the WebSocket just fine.
I expect to be able to connect to the WebSocket but right now I am getting a 401 and I cant find a way to authenticate when doing the handshake.
Self-awnser
I did a work around by disabling security for the handshake paths in WebSecurityConfig.java like this
.antMatchers(
"/authenticate",
"/login",
"/register",
"/secured/chat/**").permitAll()
I guess I have to authenticate the user through the socket now, as this makes the socket open to anyone, something I didn't really want.
I have created Apache CXF SOAP webservice in Spring Boot as per below config:
#Bean
public ServletRegistrationBean wsDispatcherServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/service/*");
}
#Bean
public Endpoint pegaEndpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus, "/service/");
endpoint.publish("ws");
return endpoint;
}
Now I want to use httpBasic authentication to call a web service, but at the same time I want the WSDL to be publicly accessible.
Is that possible to configure with Spring Security?
I have below code in Java Configuration class for security, but it doesnt really work -
the basic authentication is enforced on both web service calls and wsdl accessed by http://localhost:8080/service/ws?WSDL
Can Spring Security differentiate based on the URL param?
Or can I set a WSDL location to be different that the URL used to call the web service?
#Autowired
private void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().
antMatchers("/service/**").hasRole("USER").and().httpBasic().and().
csrf().disable();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/service/ws?wsdl");
}
I ended up doing below. Apparently ant matchers dont recognize any URL parameters so I used regex one:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().regexMatchers("/service/ws\\?WSDL");
}
Permit all on the wsdl should do it -
http
.authorizeRequests()
.antMatchers("/service/ws?wsdl").permitAll()
.antMatchers("/service/**").hasRole("USER").and().httpBasic().and().
csrf().disable();
I have rest service with java back-end. i use Spring Security. What steps do I need to do in order to make authorization available to Android apps?
At the moment all works in the web version. This is Spring Security config.
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
AuthenticationService authenticationService;
#Override
protected void configure(HttpSecurity http) throws Exception {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
// отключена защита csrf на время тестов
http.csrf().disable().addFilterBefore(filter,CsrfFilter.class);
http.authorizeRequests().antMatchers("/account/**").hasRole("USER")
.antMatchers("/user/**").hasRole("ADMIN")
.and().formLogin();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(authenticationService);
}
P.S. Or any steps to do and no matter who acts as the client.
(i can authonticate via postman) I'm interested in the approach, whether it is necessary separately to implement in order to log in via the Android app was possible?
I use Spring 4.2.3 via spring-boot (1.3.0) at server and binaryjs 0.2.1 at client.
Binaryjs successfully send data over websocket to server, but i can't receive it (bytes).
How to declare method, that will be receive byte[] from websocket (and save, e.g. into temporary file)?
Spring websocket config:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/test");
}
}
I do not use withSockJS because SockJS can't send bytearray data
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/test").withSockJS();
}