From 83d4dbc6e5426f30c1a74655460e052c11204350 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 22 Feb 2019 15:15:27 +0200 Subject: [PATCH] Websockets reverted --- application/pom.xml | 2 +- .../ThingsboardWebFluxSecurityConfig.java | 60 ------------- .../server/config/WebSocketConfiguration.java | 51 ++++------- .../controller/plugin/TbWebSocketHandler.java | 85 +++++++----------- .../webflux/WebfluxAuthenticationManager.java | 48 ----------- .../JwtTokenSecurityContextRepository.java | 86 ------------------- .../DefaultTelemetryWebSocketService.java | 2 +- .../TelemetryWebSocketMsgEndpoint.java | 2 +- pom.xml | 4 +- 9 files changed, 54 insertions(+), 286 deletions(-) delete mode 100644 application/src/main/java/org/thingsboard/server/config/ThingsboardWebFluxSecurityConfig.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/security/auth/webflux/WebfluxAuthenticationManager.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/security/auth/webflux/jwt/JwtTokenSecurityContextRepository.java diff --git a/application/pom.xml b/application/pom.xml index 91fe9f71f2..91965dfed5 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -126,7 +126,7 @@ org.springframework.boot - spring-boot-starter-webflux + spring-boot-starter-websocket io.jsonwebtoken diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardWebFluxSecurityConfig.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardWebFluxSecurityConfig.java deleted file mode 100644 index db8f599350..0000000000 --- a/application/src/main/java/org/thingsboard/server/config/ThingsboardWebFluxSecurityConfig.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright © 2016-2019 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.ReactiveAuthenticationManager; -import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.SecurityWebFiltersOrder; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.context.ServerSecurityContextRepository; - -//@EnableWebFluxSecurity -//@EnableReactiveMethodSecurity -public class ThingsboardWebFluxSecurityConfig { - - private static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; - - @Autowired - private ReactiveAuthenticationManager webfluxAuthenticationManager; - - @Autowired - private ServerSecurityContextRepository jwtTokenSecurityContextRepository; - - @Bean - public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - return http - .cors() - .and() - .csrf().disable() - .formLogin().disable() - .httpBasic().disable() - .exceptionHandling() - .and() - .authenticationManager(webfluxAuthenticationManager) - .securityContextRepository(jwtTokenSecurityContextRepository) - .authorizeExchange() - .pathMatchers(WS_TOKEN_BASED_AUTH_ENTRY_POINT) - .authenticated() - .and() - .build(); - } - -} diff --git a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java index 6c08b1b9a6..b8b703e4fc 100644 --- a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java @@ -21,63 +21,44 @@ import org.springframework.http.HttpStatus; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository; -import org.springframework.web.reactive.HandlerMapping; -import org.springframework.web.reactive.HandlerResult; -import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; -import org.springframework.web.reactive.socket.WebSocketHandler; -import org.springframework.web.reactive.socket.server.support.HandshakeWebSocketService; -import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter; -import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; +import org.springframework.web.socket.server.HandshakeInterceptor; +import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean; +import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.controller.plugin.TbWebSocketHandler; import org.thingsboard.server.service.security.model.SecurityUser; -import reactor.core.publisher.Mono; -import java.util.HashMap; import java.util.Map; @Configuration -public class WebSocketConfiguration { +@EnableWebSocket +public class WebSocketConfiguration implements WebSocketConfigurer { public static final String WS_PLUGIN_PREFIX = "/api/ws/plugins/"; private static final String WS_PLUGIN_MAPPING = WS_PLUGIN_PREFIX + "**"; -/* @Bean + @Bean public ServletServerContainerFactoryBean createWebSocketContainer() { ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); container.setMaxTextMessageBufferSize(32768); container.setMaxBinaryMessageBufferSize(32768); return container; - }*/ - - @Bean - public HandlerMapping handlerMapping() { - Map map = new HashMap<>(); - map.put(WS_PLUGIN_MAPPING, wsHandler()); - - SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); - mapping.setUrlMap(map); - mapping.setOrder(-1); // before annotated controllers - return mapping; } - @Bean - public WebSocketHandlerAdapter handlerAdapter() { - return new WebSocketHandlerAdapter(); - } - -/* @Override + @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(wsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*") .addInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, - Map attributes) throws Exception { + Map attributes) throws Exception { SecurityUser user = null; try { user = getCurrentUser(); @@ -92,23 +73,23 @@ public class WebSocketConfiguration { @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, - Exception exception) { + Exception exception) { //Do nothing } }); - }*/ + } @Bean public WebSocketHandler wsHandler() { return new TbWebSocketHandler(); } -/* protected SecurityUser getCurrentUser() throws ThingsboardException { + protected SecurityUser getCurrentUser() throws ThingsboardException { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.getPrincipal() instanceof SecurityUser) { return (SecurityUser) authentication.getPrincipal(); } else { throw new ThingsboardException("You aren't authorized to perform this operation!", ThingsboardErrorCode.AUTHENTICATION); } - }*/ + } } diff --git a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java index d20e4db433..169bba8895 100644 --- a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java +++ b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java @@ -16,51 +16,48 @@ package org.thingsboard.server.controller.plugin; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.BeanCreationNotAllowedException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; -import org.springframework.web.reactive.socket.CloseStatus; -import org.springframework.web.reactive.socket.WebSocketHandler; -import org.springframework.web.reactive.socket.WebSocketSession; +import org.springframework.util.StringUtils; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.adapter.NativeWebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.msg.tools.TbRateLimits; +import org.thingsboard.server.config.WebSocketConfiguration; import org.thingsboard.server.service.security.model.SecurityUser; +import org.thingsboard.server.service.security.model.UserPrincipal; +import org.thingsboard.server.service.telemetry.SessionEvent; import org.thingsboard.server.service.telemetry.TelemetryWebSocketMsgEndpoint; +import org.thingsboard.server.service.telemetry.TelemetryWebSocketService; import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef; -import reactor.core.publisher.Mono; +import javax.websocket.*; import java.io.IOException; -import java.security.Principal; +import java.net.URI; +import java.security.InvalidParameterException; +import java.util.Queue; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.LinkedBlockingQueue; @Service @Slf4j -public class TbWebSocketHandler implements WebSocketHandler, TelemetryWebSocketMsgEndpoint { +public class TbWebSocketHandler extends TextWebSocketHandler implements TelemetryWebSocketMsgEndpoint { - @Override - public Mono handle(WebSocketSession session) { - return session.receive() - .doOnNext(message -> { - Principal principal = session.getHandshakeInfo().getPrincipal().block(); - if (principal instanceof SecurityUser) { - SecurityUser currentUser = (SecurityUser) principal; - log.info("[{}][{}] Processing {}", currentUser.getTenantId(), session.getId(), message.getPayloadAsText()); - } else { - log.info("[{}] Principal {}", session.getId(), principal); - log.info("[{}] Processing {}", session.getId(), message.getPayloadAsText()); - } - }) - .then(); - } + private static final ConcurrentMap internalSessionMap = new ConcurrentHashMap<>(); + private static final ConcurrentMap externalSessionMap = new ConcurrentHashMap<>(); - @Override - public void send(TelemetryWebSocketSessionRef sessionRef, int subscriptionId, String msg) throws IOException { - - } - - @Override - public void close(TelemetryWebSocketSessionRef sessionRef, CloseStatus withReason) throws IOException { - - } - -// private static final ConcurrentMap internalSessionMap = new ConcurrentHashMap<>(); -// private static final ConcurrentMap externalSessionMap = new ConcurrentHashMap<>(); -/* @Autowired private TelemetryWebSocketService webSocketService; @@ -105,22 +102,6 @@ public class TbWebSocketHandler implements WebSocketHandler, TelemetryWebSocketM } } - @Override - public Mono handle(WebSocketSession session) { - return session.receive() - .doOnNext(message -> { - Principal principal = session.getHandshakeInfo().getPrincipal().block(); - if (principal instanceof SecurityUser) { - SecurityUser currentUser = (SecurityUser) principal; - log.info("[{}][{}] Processing {}", currentUser.getTenantId(), session.getId(), message.getPayloadAsText()); - } else { - log.info("[{}] Principal {}", session.getId(), principal); - log.info("[{}] Processing {}", session.getId(), message.getPayloadAsText()); - } - }) - .then(); - } - @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { super.afterConnectionEstablished(session); @@ -410,5 +391,5 @@ public class TbWebSocketHandler implements WebSocketHandler, TelemetryWebSocketM } } } - */ -} + +} \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/WebfluxAuthenticationManager.java b/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/WebfluxAuthenticationManager.java deleted file mode 100644 index 35bee6e9bd..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/WebfluxAuthenticationManager.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright © 2016-2019 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.service.security.auth.webflux; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.ReactiveAuthenticationManager; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Component; -import org.thingsboard.server.service.security.auth.JwtAuthenticationToken; -import org.thingsboard.server.service.security.model.SecurityUser; -import org.thingsboard.server.service.security.model.token.JwtTokenFactory; -import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; -import reactor.core.publisher.Mono; - -@Component -public class WebfluxAuthenticationManager implements ReactiveAuthenticationManager { - - @Autowired - private JwtTokenFactory tokenFactory; - - @Override - public Mono authenticate(Authentication authentication) { - try { - if (authentication.getCredentials() != null && authentication.getCredentials() instanceof RawAccessJwtToken) { - RawAccessJwtToken rawAccessToken = (RawAccessJwtToken) authentication.getCredentials(); - SecurityUser securityUser = tokenFactory.parseAccessJwtToken(rawAccessToken); - JwtAuthenticationToken auth = new JwtAuthenticationToken(securityUser); - return Mono.just(auth); - } - return Mono.empty(); - } catch (Exception e) { - return Mono.error(e); - } - } -} diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/jwt/JwtTokenSecurityContextRepository.java b/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/jwt/JwtTokenSecurityContextRepository.java deleted file mode 100644 index f6fe103fc5..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/jwt/JwtTokenSecurityContextRepository.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright © 2016-2019 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.service.security.auth.webflux.jwt; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.ReactiveAuthenticationManager; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.security.web.server.context.ServerSecurityContextRepository; -import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; -import org.springframework.web.server.ServerWebExchange; -import org.thingsboard.server.config.ThingsboardSecurityConfiguration; -import org.thingsboard.server.service.security.auth.JwtAuthenticationToken; -import org.thingsboard.server.service.security.auth.jwt.extractor.TokenExtractor; -import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; -import reactor.core.publisher.Mono; - -import java.util.List; - -@Component -public class JwtTokenSecurityContextRepository implements ServerSecurityContextRepository { - - public static final String DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME = "SPRING_SECURITY_CONTEXT"; - - @Autowired - private ReactiveAuthenticationManager webfluxAuthenticationManager; - - @Override - public Mono save(ServerWebExchange exchange, SecurityContext context) { - return exchange.getSession() - .doOnNext(session -> { - if (context == null) { - session.getAttributes().remove(WebSessionServerSecurityContextRepository.DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME); - } else { - session.getAttributes().put(WebSessionServerSecurityContextRepository.DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME, context); - } - }) - .flatMap(session -> session.changeSessionId()); - } - - @Override - public Mono load(ServerWebExchange exchange) { - ServerHttpRequest request = exchange.getRequest(); - String token = extractTokenFromQuery(request); - if (!StringUtils.isEmpty(token)) { - RawAccessJwtToken rawToken = new RawAccessJwtToken(token); - Authentication auth = new JwtAuthenticationToken(rawToken); - return this.webfluxAuthenticationManager.authenticate(auth).map((authentication) -> { - return new SecurityContextImpl(authentication); - }); - } else { - return Mono.empty(); - } - } - - private String extractTokenFromQuery(ServerHttpRequest request) { - String token = null; - if (request.getQueryParams() != null) { - List tokenParamValue = request.getQueryParams().get(ThingsboardSecurityConfiguration.JWT_TOKEN_QUERY_PARAM); - if (tokenParamValue != null && !tokenParamValue.isEmpty()) { - token = tokenParamValue.get(0); - } - } - return token; - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java index 68646153a6..86747150c9 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java @@ -26,7 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; -import org.springframework.web.reactive.socket.CloseStatus; +import org.springframework.web.socket.CloseStatus; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/TelemetryWebSocketMsgEndpoint.java b/application/src/main/java/org/thingsboard/server/service/telemetry/TelemetryWebSocketMsgEndpoint.java index ca3a91600f..8c18f2d42b 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/TelemetryWebSocketMsgEndpoint.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/TelemetryWebSocketMsgEndpoint.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.service.telemetry; -import org.springframework.web.reactive.socket.CloseStatus; +import org.springframework.web.socket.CloseStatus; import java.io.IOException; diff --git a/pom.xml b/pom.xml index eb0650a124..d3ff7a1635 100755 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ 1.5.0 2.5 1.4 - 2.9.0 + 2.9.7 2.2.6 2.11 2.4.2 @@ -424,7 +424,7 @@ org.springframework.boot - spring-boot-starter-webflux + spring-boot-starter-websocket ${spring-boot.version}