diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebNetworkHandlerConfigInput.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebNetworkHandlerConfigInput.java index fbb4873d8f..156fc96c2e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebNetworkHandlerConfigInput.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebNetworkHandlerConfigInput.java @@ -62,6 +62,7 @@ public class WebNetworkHandlerConfigInput { return JSONUtils.getString(cfg, "password"); } + @Deprecated // use secured properties public String getKey() { return JSONUtils.getString(cfg, "key"); } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java index 64b96c9479..9a5cbd6de0 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java @@ -82,7 +82,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent { synchronized (sessionEventHandlers) { for (CBWebSessionEventHandler eventHandler : sessionEventHandlers) { try { - eventHandler.handeWebSessionEvent(event); + eventHandler.handleWebSessionEvent(event); } catch (DBException e) { log.error(e.getMessage(), e); addSessionError(e); @@ -158,7 +158,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent { synchronized (sessionEventHandlers) { for (CBWebSessionEventHandler sessionEventHandler : sessionEventHandlers) { try { - sessionEventHandler.handeWebSessionEvent(sessionExpiredEvent); + sessionEventHandler.handleWebSessionEvent(sessionExpiredEvent); } catch (DBException e) { log.warn("Failed to send session expiration event", e); } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/WebDataSourceUtils.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/WebDataSourceUtils.java index 352236a4a2..41174d4395 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/WebDataSourceUtils.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/WebDataSourceUtils.java @@ -136,6 +136,7 @@ public class WebDataSourceUtils { handlerCfg.setUserName(webConfig.getUserName()); handlerCfg.setPassword(webConfig.getPassword()); setSecureProperties(handlerCfg, webConfig, false); + handlerCfg.setSecureProperty(SSHConstants.PROP_KEY_VALUE, webConfig.getKey()); // backward compatibility } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/CBWebSessionEventHandler.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/CBWebSessionEventHandler.java index 52796d684c..fb9e22f078 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/CBWebSessionEventHandler.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/CBWebSessionEventHandler.java @@ -20,7 +20,7 @@ import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.websocket.event.WSEvent; public interface CBWebSessionEventHandler { - void handeWebSessionEvent(WSEvent event) throws DBException; + void handleWebSessionEvent(WSEvent event) throws DBException; void close(); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java new file mode 100644 index 0000000000..26188ed695 --- /dev/null +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java @@ -0,0 +1,53 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 DBeaver Corp and others + * + * 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 io.cloudbeaver.server.websockets; + +import com.google.gson.Gson; +import org.eclipse.jetty.websocket.api.WebSocketAdapter; +import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.websocket.WSUtils; +import org.jkiss.dbeaver.model.websocket.event.WSEvent; + +import java.io.IOException; + +public class CBAbstractWebSocket extends WebSocketAdapter { + private static final Log log = Log.getLog(CBAbstractWebSocket.class); + protected static final Gson gson = WSUtils.gson; + + public void handleEvent(WSEvent event) { + if (isNotConnected()) { + return; + } + try { + getRemote().sendString(gson.toJson(event)); + } catch (IOException e) { + handleEventException(e); + } + } + + protected void handleEventException(Exception e) { + log.error("Failed to send websocket message", e); + } + + public void close() { + var session = getSession(); + // the socket may not be connected to the client + if (session != null) { + getSession().close(); + } + } +} diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBEventsWebSocket.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBEventsWebSocket.java index a71c589f74..c927564af0 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBEventsWebSocket.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBEventsWebSocket.java @@ -16,26 +16,20 @@ */ package io.cloudbeaver.server.websockets; -import com.google.gson.Gson; import io.cloudbeaver.DBWebException; import io.cloudbeaver.model.session.BaseWebSession; import io.cloudbeaver.websocket.CBWebSessionEventHandler; import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.api.WebSocketAdapter; import org.eclipse.jetty.websocket.api.WriteCallback; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.model.websocket.WSUtils; import org.jkiss.dbeaver.model.websocket.event.WSClientEvent; import org.jkiss.dbeaver.model.websocket.event.WSClientEventType; import org.jkiss.dbeaver.model.websocket.event.WSEvent; import org.jkiss.dbeaver.model.websocket.event.client.WSUpdateActiveProjectsClientEvent; import org.jkiss.dbeaver.model.websocket.event.session.WSSocketConnectedEvent; -import java.io.IOException; - -public class CBEventsWebSocket extends WebSocketAdapter implements CBWebSessionEventHandler { - private static final Gson gson = WSUtils.gson; +public class CBEventsWebSocket extends CBAbstractWebSocket implements CBWebSessionEventHandler { private static final Log log = Log.getLog(CBEventsWebSocket.class); @NotNull @@ -53,7 +47,7 @@ public class CBEventsWebSocket extends WebSocketAdapter implements CBWebSessionE public void onWebSocketConnect(Session session) { super.onWebSocketConnect(session); this.webSession.addEventHandler(this); - handeWebSessionEvent(new WSSocketConnectedEvent(webSession.getApplication().getApplicationRunId())); + handleEvent(new WSSocketConnectedEvent(webSession.getApplication().getApplicationRunId())); log.debug("EventWebSocket connected to the " + webSession.getSessionId() + " session"); } @@ -103,30 +97,15 @@ public class CBEventsWebSocket extends WebSocketAdapter implements CBWebSessionE webSession.addSessionError(cause); } - public void awaitClosure() throws InterruptedException { - log.debug("Awaiting closure from remote"); + @Override + public void handleWebSessionEvent(WSEvent event) { + super.handleEvent(event); } @Override - public void handeWebSessionEvent(WSEvent event) { - if (isNotConnected()) { - return; - } - try { - getRemote().sendString(gson.toJson(event)); - } catch (IOException e) { - log.error("Failed to send websocket message", e); - webSession.addSessionError(e); - } - } - - @Override - public void close() { - var session = getSession(); - // the socket may not be connected to the client - if (session != null) { - getSession().close(); - } + protected void handleEventException(Exception e) { + super.handleEventException(e); + webSession.addSessionError(e); } @NotNull diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBExpiredSessionWebSocket.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBExpiredSessionWebSocket.java new file mode 100644 index 0000000000..0cf4091346 --- /dev/null +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBExpiredSessionWebSocket.java @@ -0,0 +1,29 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 DBeaver Corp and others + * + * 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 io.cloudbeaver.server.websockets; + +import org.eclipse.jetty.websocket.api.Session; +import org.jkiss.dbeaver.model.websocket.event.session.WSAccessTokenExpiredEvent; + +public class CBExpiredSessionWebSocket extends CBAbstractWebSocket { + @Override + public void onWebSocketConnect(Session session) { + super.onWebSocketConnect(session); + handleEvent(new WSAccessTokenExpiredEvent()); + close(); + } +} diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBJettyWebSocketManager.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBJettyWebSocketManager.java index 6d6f498006..d9ca213bc7 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBJettyWebSocketManager.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBJettyWebSocketManager.java @@ -27,14 +27,15 @@ import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.security.exception.SMAccessTokenExpiredException; +import javax.servlet.http.HttpServletRequest; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import javax.servlet.http.HttpServletRequest; public class CBJettyWebSocketManager implements JettyWebSocketCreator { private static final Log log = Log.getLog(CBJettyWebSocketManager.class); @@ -64,6 +65,8 @@ public class CBJettyWebSocketManager implements JettyWebSocketCreator { return null; } return createNewEventsWebSocket(headlessSession); + } catch (SMAccessTokenExpiredException e) { + return new CBExpiredSessionWebSocket(); } catch (DBException e) { log.error("Error resolve websocket session", e); return null;