Skip to content

Commit

Permalink
CB-4686 add new client event for updating session info (#2462)
Browse files Browse the repository at this point in the history
* CB-4810 add new client event for updating session info

* CB-4810 update request parameters on creating web session

* CB-4810 deprecate update session gql functions

* CB-4810 fix tests

* CB-4810 add params to session state event

* CB-4810 add params to gql schema

* CB-4686 feat: migrates touch session from REST to WebSockets

* CB-4686 fix: do not open websocket if session is expired

* Revert "CB-4686 fix: do not open websocket if session is expired"

This reverts commit 1f6ba77.

* CB-4686 setData uses performUpdate for the SessionResource

* CB-4686 unsubscribes from the websocket when session expired event arrived

* Revert "CB-4686 unsubscribes from the websocket when session expired event arrived"

This reverts commit 7aeffff.

* CB-4810 rename client event

* CB-4686 pr fixes

* CB-4686 makes onDataOutdated execution manual

* CB-4686 fix: onDataOutdated.execute executes in the end of the performUpdate

---------

Co-authored-by: s.teleshev <[email protected]>
Co-authored-by: Alexey <[email protected]>
Co-authored-by: mr-anton-t <[email protected]>
Co-authored-by: Daria Marutkina <[email protected]>
  • Loading branch information
5 people authored Mar 27, 2024
1 parent a6a01c2 commit ad37e89
Show file tree
Hide file tree
Showing 27 changed files with 160 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,20 +125,21 @@ public class WebSession extends BaseWebSession
private final Map<String, DBWSessionHandler> sessionHandlers;

public WebSession(
@NotNull HttpSession httpSession,
@NotNull HttpServletRequest request,
@NotNull WebAuthApplication application,
@NotNull Map<String, DBWSessionHandler> sessionHandlers
) throws DBException {
super(httpSession.getId(), application);
super(request.getSession().getId(), application);
this.lastAccessTime = this.createTime;
setLocale(CommonUtils.toString(httpSession.getAttribute(ATTR_LOCALE), this.locale));
setLocale(CommonUtils.toString(request.getSession().getAttribute(ATTR_LOCALE), this.locale));
this.sessionHandlers = sessionHandlers;
//force authorization of anonymous session to avoid access error,
//because before authorization could be called by any request,
//but now 'updateInfo' is called only in special requests,
//and the order of requests is not guaranteed.
//look at CB-4747
refreshSessionAuth();
updateSessionParameters(request);
}

@Nullable
Expand Down Expand Up @@ -525,17 +526,10 @@ public List<WebServerMessage> getSessionMessages() {
}
}

public synchronized void updateInfo(
HttpServletRequest request,
HttpServletResponse response
) throws DBWebException {
public synchronized void updateInfo(boolean isOldHttpSessionUsed) {
log.debug("Update session lifetime " + getSessionId() + " for user " + getUserId());
touchSession();
HttpSession httpSession = request.getSession();
this.lastRemoteAddr = request.getRemoteAddr();
this.lastRemoteUserAgent = request.getHeader("User-Agent");
this.cacheExpired = false;
if (!httpSession.isNew()) {
if (isOldHttpSessionUsed) {
try {
// Persist session
if (!isAuthorizedInSecurityManager()) {
Expand All @@ -555,6 +549,12 @@ public synchronized void updateInfo(
}
}

public synchronized void updateSessionParameters(HttpServletRequest request) {
this.lastRemoteAddr = request.getRemoteAddr();
this.lastRemoteUserAgent = request.getHeader("User-Agent");
this.cacheExpired = false;
}

@Association
public List<WebConnectionInfo> getConnections() {
synchronized (connections) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -566,9 +566,9 @@ extend type Mutation {
closeSession: Boolean

# Refreshes session on server and returns its state
touchSession: Boolean @deprecated(reason: "use updateSession instead")
touchSession: Boolean @deprecated(reason: "use events to update session")
# Refreshes session on server and returns session state
updateSession: SessionInfo! @since(version: "24.0.0")
updateSession: SessionInfo! @since(version: "24.0.0") @deprecated(reason: "use events to update session")

# Refresh session connection list
refreshSessionConnections: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ enum CBServerEventId {
enum CBClientEventId {
cb_client_topic_subscribe,
cb_client_topic_unsubscribe,
cb_client_projects_active
cb_client_projects_active,
cb_client_session_ping
}

# Client subscribes on topic to receive only related events
Expand Down Expand Up @@ -114,8 +115,12 @@ type WSSocketConnectedEvent implements CBServerEvent {
type WSSessionStateEvent implements CBServerEvent {
id: CBServerEventId!
topicId: CBEventTopic
lastAccessTime: Int!
remainingTime: Int!
isValid: Boolean
isCacheExpired: Boolean
locale: String!
actionParameters: Object
}

# Session expired event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import io.cloudbeaver.DBWebException;
import io.cloudbeaver.model.session.BaseWebSession;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.websocket.CBWebSessionEventHandler;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WriteCallback;
Expand Down Expand Up @@ -76,6 +77,12 @@ public void onWebSocketText(String message) {
this.webSession.getEventsFilter().setSubscribedProjects(projectEvent.getProjectIds());
break;
}
case SESSION_PING: {
if (webSession instanceof WebSession session) {
session.updateInfo(true);
}
break;
}
default:
var e = new DBWebException("Unknown websocket client event: " + clientEvent.getId());
log.error(e.getMessage(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.security.exception.SMAccessTokenExpiredException;
import org.jkiss.dbeaver.runtime.DBWorkbench;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
Expand All @@ -54,6 +55,7 @@ public Object createWebSocket(@NotNull JettyServerUpgradeRequest request, JettyS
var httpRequest = request.getHttpServletRequest();
var webSession = webSessionManager.getOrRestoreSession(httpRequest);
if (webSession != null) {
webSession.updateSessionParameters(httpRequest);
// web client session
return createNewEventsWebSocket(webSession);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ WebSession openSession(
@WebAction(authRequired = false)
boolean touchSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse servletResponse) throws DBWebException;

@Deprecated
@WebAction(authRequired = false)
WebSession updateSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response)
throws DBWebException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,13 @@ public boolean closeSession(HttpServletRequest request) throws DBWebException {
}

@Override
@Deprecated
public boolean touchSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws DBWebException {
return CBPlatform.getInstance().getSessionManager().touchSession(request, response);
}

@Override
@Deprecated
public WebSession updateSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response)
throws DBWebException {
WebSessionManager sessionManager = CBPlatform.getInstance().getSessionManager();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ protected CBApplication getApplication() {
return application;
}

@Deprecated
public boolean touchSession(@NotNull HttpServletRequest request,
@NotNull HttpServletResponse response) throws DBWebException {
WebSession webSession = getWebSession(request, response, false);
webSession.updateInfo(request, response);
webSession.updateSessionParameters(request);
webSession.updateInfo(!request.getSession().isNew());
return true;
}

Expand All @@ -105,14 +107,14 @@ public WebSession getWebSession(
var baseWebSession = sessionMap.get(sessionId);
if (baseWebSession == null && CBApplication.getInstance().isConfigurationMode()) {
try {
webSession = createWebSessionImpl(httpSession);
webSession = createWebSessionImpl(request);
} catch (DBException e) {
throw new DBWebException("Failed to create web session", e);
}
sessionMap.put(sessionId, webSession);
} else if (baseWebSession == null) {
try {
webSession = createWebSessionImpl(httpSession);
webSession = createWebSessionImpl(request);
} catch (DBException e) {
throw new DBWebException("Failed to create web session", e);
}
Expand Down Expand Up @@ -174,7 +176,7 @@ public WebSession getOrRestoreSession(@NotNull HttpServletRequest request) {
return null;
}

webSession = createWebSessionImpl(httpSession);
webSession = createWebSessionImpl(request);
restorePreviousUserSession(webSession, oldAuthInfo);

sessionMap.put(sessionId, webSession);
Expand Down Expand Up @@ -208,8 +210,8 @@ private void restorePreviousUserSession(
}

@NotNull
protected WebSession createWebSessionImpl(@NotNull HttpSession httpSession) throws DBException {
return new WebSession(httpSession, application, getSessionHandlers());
protected WebSession createWebSessionImpl(@NotNull HttpServletRequest request) throws DBException {
return new WebSession(request, application, getSessionHandlers());
}

@NotNull
Expand Down Expand Up @@ -330,7 +332,13 @@ public void sendSessionsStates() {
})
.forEach(session -> {
try {
session.addSessionEvent(new WSSessionStateEvent(session.getRemainingTime(), session.isValid()));
session.addSessionEvent(new WSSessionStateEvent(
session.getLastAccessTimeMillis(),
session.getRemainingTime(),
session.isValid(),
((WebSession) session).isCacheExpired(),
((WebSession) session).getLocale(),
((WebSession) session).getActionParameters()));
} catch (Exception e) {
log.error("Failed to refresh session state: " + session.getSessionId(), e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ type NewConfiguration = AuthConfiguration & { [NEW_CONFIGURATION_SYMBOL]: boolea

@injectable()
export class AuthConfigurationsResource extends CachedMapResource<string, AuthConfiguration, GetAuthProviderConfigurationsQueryVariables> {
constructor(private readonly graphQLService: GraphQLService, permissionsResource: SessionPermissionsResource) {
constructor(
private readonly graphQLService: GraphQLService,
permissionsResource: SessionPermissionsResource,
) {
super(() => new Map(), []);

permissionsResource.require(this, EAdminPermission.admin).outdateResource(this);
Expand All @@ -51,6 +54,7 @@ export class AuthConfigurationsResource extends CachedMapResource<string, AuthCo
}

this.set(configuration.id, configuration);
this.onDataOutdated.execute(configuration.id);
});

return this.get(config.id)!;
Expand Down
4 changes: 4 additions & 0 deletions webapp/packages/core-authentication/src/UserInfoResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
if (this.data) {
this.data.configurationParameters[key] = value;
}

this.onDataOutdated.execute();
});

return this.data;
Expand Down Expand Up @@ -210,6 +212,8 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
delete this.data?.configurationParameters[item];
}
});

this.onDataOutdated.execute();
});
return this.data;
}
Expand Down
2 changes: 2 additions & 0 deletions webapp/packages/core-authentication/src/UsersResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ export class UsersResource extends CachedMapResource<string, AdminUser, UserReso
if (user) {
user.authRole = authRole;
}

this.onDataOutdated.execute(userId);
});

if (!skipUpdate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ export class ConnectionExecutionContextResource extends CachedMapResource<string
}

async create(key: IConnectionInfoParams, defaultCatalog?: string, defaultSchema?: string): Promise<IConnectionExecutionContextInfo> {
return await this.performUpdate(getContextBaseId(key, ''), [], async () => {
const contextKey = getContextBaseId(key, '');
return await this.performUpdate(contextKey, [], async () => {
const { context } = await this.graphQLService.sdk.executionContextCreate({
...key,
defaultCatalog,
Expand All @@ -85,7 +86,10 @@ export class ConnectionExecutionContextResource extends CachedMapResource<string
this.markOutdated(); // TODO: should be removed, currently multiple contexts for same connection may change catalog/schema for all contexts of connection
});

return this.get(baseContext.id)!;
const result = this.get(baseContext.id)!;
this.onDataOutdated.execute(contextKey);

return result;
});
}

Expand All @@ -107,6 +111,7 @@ export class ConnectionExecutionContextResource extends CachedMapResource<string

context.defaultCatalog = defaultCatalog;
context.defaultSchema = defaultSchema;
this.onDataOutdated.execute(contextId);
});

this.markOutdated();
Expand All @@ -126,6 +131,7 @@ export class ConnectionExecutionContextResource extends CachedMapResource<string
connectionId: context.connectionId,
projectId: context.projectId,
});
this.onDataOutdated.execute(contextId);
});

runInAction(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ export const ConnectionFolderProjectKey = resourceKeyAliasFactory('@connection-f

@injectable()
export class ConnectionFolderResource extends CachedMapResource<IConnectionFolderParam, ConnectionFolder> {
constructor(private readonly graphQLService: GraphQLService, sessionDataResource: SessionDataResource, appAuthService: AppAuthService) {
constructor(
private readonly graphQLService: GraphQLService,
sessionDataResource: SessionDataResource,
appAuthService: AppAuthService,
) {
super();

appAuthService.requireAuthentication(this);
Expand Down Expand Up @@ -70,6 +74,7 @@ export class ConnectionFolderResource extends CachedMapResource<IConnectionFolde
folderPath: key.folderId,
});
this.delete(key);
this.onDataOutdated.execute(key);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
projectId: connectionKey.projectId,
connectionId: connectionKey.connectionId,
});

this.onDataOutdated.execute(connectionKey);
return subjects;
});

Expand Down Expand Up @@ -396,6 +398,7 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
...this.getIncludesMap(key),
});
this.set(createConnectionParam(connection), connection);
this.onDataOutdated.execute(key);
});

return this.get(key)!;
Expand All @@ -413,6 +416,7 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
});

this.set(createConnectionParam(connection), connection);
this.onDataOutdated.execute(key);
});

return this.get(key)!;
Expand All @@ -428,6 +432,7 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
});

this.set(createConnectionParam(connection), connection);
this.onDataOutdated.execute(key);
});
return this.get(key)!;
}
Expand All @@ -442,6 +447,7 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
});

this.set(createConnectionParam(connection), connection);
this.onDataOutdated.execute(key);
});

const connection = this.get(key)!;
Expand All @@ -460,6 +466,7 @@ export class ConnectionInfoResource extends CachedMapResource<IConnectionInfoPar
});
this.delete(key);
});
this.onDataOutdated.execute(key);
}

// async updateSessionConnections(): Promise<boolean> {
Expand Down
Loading

0 comments on commit ad37e89

Please sign in to comment.