SpringBoot AngularJS webSocket integration - angularjs

I'm trying to create webSocket on springBoot application.
this is config class:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/sub");
config.setApplicationDestinationPrefixes("/send");
}
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
}
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
}
#Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
}
#Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
}
#Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
return true;
}
}
Now from AngularJS I'm trying to connect to websocket using SockJS and Stomp
var socket = new SockJS('/api/ws');
var stompClient = Stomp.over(socket);
stompClient.connect({}, function (frames) {
stompClient.subscribe('/subs/hello', function (data) {
console.log(data);
});
});
When I open console I get this message:
admin-components.js:112173 WebSocket connection to 'wss://proxy.beta.corp.payment21.com/api/ws/135/hwq2yv3q/websocket' failed: Error during WebSocket handshake: Unexpected response code: 502
After 30 seconds I get this:
VM333 sockjs.min.js:2 Uncaught Error: Incompatibile SockJS! Main site uses: "1.4.0", the iframe: "1.0.0".
at s (VM333 sockjs.min.js:2)
And after 30 more seconds:
And it is working...
When I go to network to see details in the frames it says
(Opcode -1)
What is the problem here? Is it the spring configuration or SockJS?

Based on the Spring documentation the supported client SockJS version is 1.0.x
On the browser side, applications can use the sockjs-client (version 1.0.x). It emulates the W3C WebSocket API and communicates with the server to select the best transport option, depending on the browser in which it runs.

Related

Spring & React - WebSocket connection to 'ws://127.0.0.1:8000/' failed:

I am new to React, Spring and WebSocket and I'm trying to make a WebSocket using Spring to connect to the React app.
It works on Firefox but not on Chrome or Edge.
I can't modify the React app and the app connects with HTTP.
The configuration class
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(), "/");
}
}
The SocketHandler class
#Component
public class SocketHandler implements WebSocketHandler {
#Override
public void handleTextMessage(WebSocketSession session, WebSocketMessage<?> message)
throws Exception {
System.out.println("I received");
session.sendMessage(new TextMessage("Hi how may we help you?"));
}
}
I've tried to use certificates or org.springframework.security but none of it works.

IBM Watson Speech To Text API returns error 403

i am trying to call IBM STT Api with this code:
String auth = new IamAuthenticator("AuthApi").requestToken().getAccessToken();
client = new WebSocketClient(new URI(String.format("wss://%s/speech-to-text/api/v1/recognize?access_token=%s",uri,auth))) {
#Override
public void onOpen(ServerHandshake handshakedata) {
clientInterface.OnOpen();
}
#Override
public void onMessage(String message) {
clientInterface.OnMessage(message);
}
#Override
public void onClose(int code, String reason, boolean remote) {
clientInterface.OnClose();
}
#Override
public void onError(Exception ex) {
clientInterface.OnError(ex);
}
};
But i always get this: Invalid status code received: 403 Status line: HTTP/1.1 403 Forbidden.
any help?
Thanks

Get 403 status when using Spring Websocket and SockJS in AngularJS

I got this error and my web socket cannot run:
403
Here is my configure for websocket:
#Configuration
#EnableWebSocketMessageBroker
public class SpringWebSocketConfig extends
AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setUserDestinationPrefix("/ws-secured/user/");
config.setApplicationDestinationPrefixes("/ws");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-secured/init-api").withSockJS();
registry.setErrorHandler(new ApplicationStompSubProtocolErrorHandler());
}
}
and websocket security:
#Configuration
public class SpringWebSocketSecurityConfig extends
AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry
messages) {
messages.simpTypeMatchers(
SimpMessageType.CONNECT,
SimpMessageType.MESSAGE,
SimpMessageType.SUBSCRIBE).authenticated()
.simpTypeMatchers(
SimpMessageType.UNSUBSCRIBE,
SimpMessageType.DISCONNECT).permitAll()
.anyMessage().denyAll();
}
#Override
protected boolean sameOriginDisabled() {
return true;
}
}
For more information, here is my csrf configure in Spring Sec:
http.headers().frameOptions().sameOrigin().and().authorizeRequests();
http
.csrf()
.ignoringAntMatchers("/ws-secured/**")
.and()
.headers()
.frameOptions().sameOrigin();
I have also pass my csrf token to the header:
$stomp.connect('/ws-secured/init-api', {'X-CSRF-TOKEN' : csrf_token}, function(data) {
I have searched through the Internet but cannot find the answer. I am using Tomcat 7. Do you have any ideas?

Spring Oauth2 + User Registration

I have problem with Spring Oauth2 again. I know this topic is not easy to suggest sth or check the codes because we have too much configuration.
My project has 3 different servers, Authentication server, resource server and front-end server. I want to put register.html to user's registration in front-end project(under Angularjs files) but when I make request to the related url (http://localhost:7080/app/#register) its redirecting to the login page (http://localhost:9080/auth-service/login) only for a second i can see my register.html content but after that its going to login page.
The question is, where should i put this register.html, it should be under front-end project or authentication server ?
My authentication server and front-end server codes are;
#Configuration
public class AuthServerSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.parentAuthenticationManager(authenticationManager);
auth.authenticationProvider(userAuthProviderService());
}
private CsrfMatcher csrfRequestMatcher = new CsrfMatcher();
#Override
protected void configure(final HttpSecurity http) throws Exception {
/*http.csrf().disable();*/
http.csrf().requireCsrfProtectionMatcher(csrfRequestMatcher);
http
.formLogin().loginPage("/login").defaultSuccessUrl("/")
/*.failureUrl("")*/.successHandler(new AuthSuccessHandler()).permitAll()
.and()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access","/register")
.and()
.authorizeRequests().anyRequest().authenticated();
}
#Bean
public UserAuthProviderService userAuthProviderService(){
return new UserAuthProviderService();
}
private class CsrfMatcher implements RequestMatcher {
#Override
public boolean matches(HttpServletRequest request) {
return false;
}
}
}
#Configuration
#EnableAutoConfiguration
#RestController
#EnableZuulProxy
#EnableOAuth2Sso
#EnableOAuth2Client
public class UIServiceMain {
public static void main(String[] args) {
SpringApplication.run(UIServiceMain.class, args);
}
#Configuration
protected static class SecurityConfiguration extends OAuth2SsoConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.logout().and()
.antMatcher("/**").authorizeRequests()
.antMatchers("/index.html", "/home.html", "/", "/login","/register.html").permitAll().anyRequest()
.authenticated().and().csrf().disable();
http.headers().frameOptions().disable(); //FOR EMBED MAP
}
//unused
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null
&& !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
//unused
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
}
in your UI server try to create websecurity with /register.hml enabled, something like this
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/register.html")
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
edit:
or maybe in your current configuration remove .antMatcher("/**").authorizeRequests() and add and() .authorizeRequests().anyRequest().authenticated()
so finally it could be something like this:
#Override
public void configure(HttpSecurity http) throws Exception {
http.logout().and()
.antMatchers("/index.html", "/home.html", "/", "/login","/register.html").permitAll().anyRequest()
.authenticated()
.and().csrf().disable();
http.headers().frameOptions().disable() //FOR EMBED MAP
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
Couple of things:
I can't think of a good reason not to put your *.html anywhere other than front end server.
Also, in general, you should permit access to your static UI components publically, like #bilak mentioned:
.antMatchers("/index.html", "/home.html", "/", "/login","/register.html").permitAll()
If you are able to see register.html page at all (assuming unauthenticated user) then it is public already
Perhaps, there is a webservice call on register.html's load event that is behind Spring security that is triggering the auth flow.

Transport error in WebSocketServerSockJsSession - Cannot load platform configurator on a Spring Stomp websocket

I'm trying to add web sockets to my AngularJS application.
I set up the web socket using Spring 4 on the server and Stomp SockJS on the client.
I access the page at http://localhost:9000/#/project/1/bts after a grunt serve command.
But I get a 500 response when doing the web socket handshake:
WebSocket connection to 'ws://localhost:8080/nitro-project-rest/api/socket/bts/405/bmtcztq4/websocket' failed: Error during WebSocket handshake: Unexpected response code: 500
The server has this to say upon each failed websocket request:
SEVERE: Servlet.service() for servlet [NITRo] in context with path [/nitro-project-rest] threw exception [Request processing failed; nested exception is org.springframework.web.socket.sockjs.SockJsException: Uncaught failure in SockJS request, uri=http://localhost:8080/nitro-project-rest/api/socket/bts/970/2xoe6kls/websocket; nested exception is org.springframework.web.socket.sockjs.SockJsTransportFailureException: WebSocket handshake failure; nested exception is java.lang.RuntimeException: Cannot load platform configurator] with root cause
java.lang.RuntimeException: Cannot load platform configurator
More on the error:
2017-02-06 10:36:04,241 DEBUG [http-bio-8080-exec-10] o.s.w.s.h.LoggingWebSocketHandlerDecorator Transport error in WebSocketServerSockJsSession[id=nqj286ob]
java.lang.RuntimeException: Cannot load platform configurator
at javax.websocket.server.ServerEndpointConfig$Configurator.fetchContainerDefaultConfigurator(ServerEndpointConfig.java:123)
at javax.websocket.server.ServerEndpointConfig$Configurator.getContainerDefaultConfigurator(ServerEndpointConfig.java:128)
at javax.websocket.server.ServerEndpointConfig$Configurator.checkOrigin(ServerEndpointConfig.java:192)
The funny thing is the push notification works fine. I can see the webpage being updated live when the expected event occurs. So my websocket works fine, in spite of this exception. This exception occurs at page load time.
When I manually type the url:
http://localhost:8080/nitro-project-rest/api/socket/bts
in the Chromium web browser it displays: Welcome to SockJS!
Here is my web socket connection service:
function StompService(endpoint) {
this.stompClient = Stomp.client(ENV.NITRO_PROJECT_WS_URL + '/socket/' + endpoint);
}
StompService.prototype.connect = function(onConnect, onError) {
this.stompClient.connect({}, function(frame) {
$rootScope.$apply(function() {
onConnect.apply(stompClient, frame);
});
}, function(frame) {
$rootScope.$apply(function() {
onError.apply(stompClient, frame);
});
}, '/');
};
And the controller:
var stomp = new SocketService(BTS_WS_ENDPOINT);
stomp.connect(function() {
$scope.client.subscribe('status', function(message) {
$scope.messages.push(message.body);
});
}, function() {
});
With the server side configuration and controller:
#Configuration
#EnableWebSocketMessageBroker
#ComponentScan(basePackages = "com.nsn.nitro.project.rest.socket")
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// Prefix for destinations towards the server
config.setApplicationDestinationPrefixes("/app");
// Prefix for destinations towards the client
config.enableSimpleBroker("/topic");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// All controllers need to be added to the endpoint registry
registry.addEndpoint("/socket/bts").withSockJS();
}
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
}
#Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(4).maxPoolSize(10);
}
}
#Controller
public class BTSSocketController {
private static Logger logger = LoggerFactory.getLogger(BTSSocketController.class);
#MessageMapping("/socket/bts")
#SendTo("/topic/status")
public BTSMessage status(BTSMessage message) throws Exception {
logger.debug("==========>> Received the message " + message.getBtsId());
message.setStatus(BTSStatus.ONAIR);
return message;
}
}
I'm running Spring Security with Basic Authentication and the following configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(simpleCORSFilter, ChannelProcessingFilter.class);
http
.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().httpBasic().authenticationEntryPoint(restAuthenticationEntryPoint)
.and().authorizeRequests().antMatchers("/socket/**").permitAll()
.and().authorizeRequests().antMatchers("/resources/**").permitAll()
.and().authorizeRequests().antMatchers(RESTConstants.SLASH + RESTConstants.ADMINS + RESTConstants.SLASH + RESTConstants.LOGIN).permitAll()
.and().authorizeRequests().antMatchers("/**").hasRole("ADMIN").anyRequest().authenticated();
}
#Component
public class SimpleCORSFilter implements Filter {
private static final String ORIGIN = "Origin";
private static final String OPTIONS = "OPTIONS";
private static final String OK = "OK";
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
if (httpServletRequest.getHeader(ORIGIN) != null) {
String origin = httpServletRequest.getHeader(ORIGIN);
httpServletResponse.setHeader("Access-Control-Allow-Origin", origin);
httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Accept-Language,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization,X-Filename,Content-Disposition,Content-Length");
// Allow more than the 6 default headers to be returned, as the content length is required for a download file request to get the file size
httpServletResponse.setHeader("Access-Control-Expose-Headers", "Accept-Language,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization,X-Filename,Content-Disposition,Content-Length");
}
if (httpServletRequest.getMethod().equals(OPTIONS)) {
try {
httpServletResponse.getWriter().print(OK);
httpServletResponse.getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
My Java dependencies are:
[INFO] +- javax.websocket:javax.websocket-api:jar:1.1:provided
[INFO] +- org.springframework:spring-web:jar:4.3.6.RELEASE:compile
[INFO] +- org.springframework:spring-webmvc:jar:4.3.6.RELEASE:compile
[INFO] +- org.springframework:spring-test:jar:4.3.6.RELEASE:compile
[INFO] +- org.springframework:spring-messaging:jar:4.3.6.RELEASE:compile
[INFO] +- org.springframework:spring-websocket:jar:4.3.6.RELEASE:compile
My Js dependencies are:
"sockjs": "~0.3.4",
"stomp-websocket": "~2.3.4",
To help anyone else who stumbles across this while searching for the "Welcome to SockJS" error: if you are trying to connect to a SockJS address using a regular websocket connection, add /websocket to the end of your url.

Resources