mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
dbeaver/pro#5249 Migrate authUpdateStatus to websocket (#3369)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 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.
|
||||
@@ -41,7 +41,7 @@ public interface DBWConstants {
|
||||
GLOBAL,
|
||||
EMBEDDED
|
||||
}
|
||||
|
||||
String TASK_STATUS_FINISHED = "Finished";
|
||||
//public static final String PERMISSION_USER = "user";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 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.model;
|
||||
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
|
||||
public interface CustomCancelableJob {
|
||||
void cancelJob(@NotNull WebSession webSession, @NotNull WebAsyncTaskInfo taskInfo);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 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.
|
||||
@@ -35,6 +35,7 @@ public class WebAsyncTaskInfo {
|
||||
private Throwable jobError;
|
||||
|
||||
private AbstractJob job;
|
||||
private boolean cancelled = false;
|
||||
|
||||
public WebAsyncTaskInfo(@NotNull String id, @NotNull String name) {
|
||||
this.id = id;
|
||||
@@ -107,5 +108,4 @@ public class WebAsyncTaskInfo {
|
||||
public void setJob(AbstractJob job) {
|
||||
this.job = job;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.util.Map;
|
||||
/**
|
||||
* WebAuthInfo
|
||||
*/
|
||||
//TODO: create serializable model?
|
||||
public class WebAuthInfo implements SMSessionPrincipal, WebUserAuthToken {
|
||||
|
||||
private static final Log log = Log.getLog(WebAuthInfo.class);
|
||||
|
||||
+25
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package io.cloudbeaver.model.session;
|
||||
|
||||
import io.cloudbeaver.*;
|
||||
import io.cloudbeaver.model.CustomCancelableJob;
|
||||
import io.cloudbeaver.model.WebAsyncTaskInfo;
|
||||
import io.cloudbeaver.model.WebConnectionInfo;
|
||||
import io.cloudbeaver.model.WebServerMessage;
|
||||
@@ -544,15 +545,36 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
AbstractJob job = taskInfo.getJob();
|
||||
if (job instanceof CustomCancelableJob cancelableJob) {
|
||||
cancelableJob.cancelJob(this, taskInfo);
|
||||
}
|
||||
if (job != null) {
|
||||
job.cancel();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public WebAsyncTaskInfo createAndRunAsyncTask(@NotNull String taskName, @NotNull WebAsyncTaskProcessor<?> runnable) {
|
||||
|
||||
public WebAsyncTaskInfo createAsyncTask(@NotNull String taskName) {
|
||||
int taskId = TASK_ID.incrementAndGet();
|
||||
WebAsyncTaskInfo asyncTask = getAsyncTask(String.valueOf(taskId), taskName, true);
|
||||
return asyncTask;
|
||||
}
|
||||
|
||||
public List<WebAsyncTaskInfo> findTasksByJob(@NotNull Class<? extends AbstractJob> jobClass) {
|
||||
synchronized (asyncTasks) {
|
||||
List<WebAsyncTaskInfo> result = new ArrayList<>();
|
||||
for (WebAsyncTaskInfo task : asyncTasks.values()) {
|
||||
if (task.getJob() != null && jobClass.isAssignableFrom(task.getJob().getClass())) {
|
||||
result.add(task);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public WebAsyncTaskInfo createAndRunAsyncTask(@NotNull String taskName, @NotNull WebAsyncTaskProcessor<?> runnable) {
|
||||
WebAsyncTaskInfo asyncTask = createAsyncTask(taskName);
|
||||
|
||||
AbstractJob job = new AbstractJob(taskName) {
|
||||
@Override
|
||||
@@ -571,7 +593,7 @@ public class WebSession extends BaseWebSession
|
||||
runnable.run(taskMonitor);
|
||||
asyncTask.setResult(runnable.getResult());
|
||||
asyncTask.setExtendedResult(runnable.getExtendedResults());
|
||||
asyncTask.setStatus("Finished");
|
||||
asyncTask.setStatus(DBWConstants.TASK_STATUS_FINISHED);
|
||||
} catch (InvocationTargetException e) {
|
||||
addSessionError(e.getTargetException());
|
||||
asyncTask.setJobError(e.getTargetException());
|
||||
|
||||
+10
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.registry;
|
||||
|
||||
import io.cloudbeaver.auth.SMAuthProviderFederated;
|
||||
import org.eclipse.core.runtime.IConfigurationElement;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
@@ -229,4 +230,13 @@ public class WebAuthProviderDescriptor extends AbstractDescriptor {
|
||||
public boolean isServiceProvider() {
|
||||
return serviceProvider;
|
||||
}
|
||||
|
||||
public boolean isFederated() {
|
||||
try {
|
||||
implType.checkObjectClass(SMAuthProviderFederated.class);
|
||||
return true;
|
||||
} catch (DBException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,7 @@ enum CBServerEventId {
|
||||
|
||||
cb_transaction_count @since(version: "24.3.3")
|
||||
|
||||
cb_session_task_info_updated @since(version: "24.3.1"),
|
||||
cb_web_session_auth @since(version: "25.0.1")
|
||||
cb_session_task_info_updated @since(version: "24.3.1")
|
||||
}
|
||||
|
||||
# Events sent by client
|
||||
@@ -227,12 +226,6 @@ type WSTransactionalCountEvent implements CBServerEvent {
|
||||
transactionalCount: Int!
|
||||
}
|
||||
|
||||
type WSWebSessionAuthEvent implements CBServerEvent {
|
||||
id: CBServerEventId!
|
||||
topicId: CBEventTopic!
|
||||
userTokens: [UserAuthToken!]
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
emptyEvent: Boolean
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 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.
|
||||
@@ -201,10 +201,10 @@ public interface DBWServiceCore extends DBWService {
|
||||
///////////////////////////////////////////
|
||||
// Async tasks
|
||||
|
||||
@WebAction
|
||||
@WebAction(authRequired = false)
|
||||
WebAsyncTaskInfo getAsyncTaskInfo(WebSession webSession, String taskId, Boolean removeOnFinish) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
@WebAction(authRequired = false)
|
||||
boolean cancelAsyncTask(WebSession webSession, String taskId) throws DBWebException;
|
||||
|
||||
}
|
||||
|
||||
@@ -19,15 +19,10 @@
|
||||
<sessionHandler id="LocalSessionHandler" class="io.cloudbeaver.service.auth.local.LocalSessionHandler"/>
|
||||
</extension>
|
||||
|
||||
<!--TODO: uncomment after frontend migration-->
|
||||
<!-- <extension point="org.jkiss.dbeaver.ws.event.handler">-->
|
||||
<!-- <eventHandler class="io.cloudbeaver.service.auth.handler.WSAuthSessionEventHandler">-->
|
||||
<!-- <topic id="cb_session_auth"/>-->
|
||||
<!-- </eventHandler>-->
|
||||
<!-- </extension>-->
|
||||
|
||||
<extension point="org.jkiss.dbeaver.ws.event">
|
||||
<event topicId="cb_session" id="cb_web_session_auth"
|
||||
class="io.cloudbeaver.service.auth.handler.WebSessionAuthEvent"/>
|
||||
<extension point="org.jkiss.dbeaver.ws.event.handler">
|
||||
<eventHandler class="io.cloudbeaver.service.auth.handler.WSAuthSessionEventHandler">
|
||||
<topic id="cb_session_auth"/>
|
||||
</eventHandler>
|
||||
</extension>
|
||||
|
||||
</plugin>
|
||||
|
||||
@@ -81,17 +81,25 @@ type AuthProviderInfo {
|
||||
required: Boolean!
|
||||
}
|
||||
|
||||
type AuthInfo {
|
||||
redirectLink: String
|
||||
|
||||
type AuthInfo {
|
||||
redirectLink: String @deprecated
|
||||
|
||||
authId: String @deprecated
|
||||
|
||||
authStatus: AuthStatus!
|
||||
authStatus: AuthStatus! @deprecated
|
||||
|
||||
userTokens: [UserAuthToken!]
|
||||
}
|
||||
|
||||
type FederatedAuthInfo @since(version: "25.0.3") {
|
||||
redirectLink: String!
|
||||
taskInfo: AsyncTaskInfo!
|
||||
}
|
||||
|
||||
type FederatedAuthResult @since(version: "25.0.3") {
|
||||
userTokens: [UserAuthToken!]! @since(version: "25.0.3")
|
||||
}
|
||||
|
||||
type LogoutInfo @since(version: "23.3.3") {
|
||||
redirectLinks: [String!]!
|
||||
@@ -158,6 +166,10 @@ extend type Query {
|
||||
# If forceSessionsLogout=true then kill another sessions
|
||||
authLogin(provider: ID!, configuration: ID, credentials: Object, linkUser: Boolean, forceSessionsLogout: Boolean): AuthInfo!
|
||||
|
||||
@since(version: "25.0.3")
|
||||
federatedAuthTaskResult(taskId: String!): FederatedAuthResult!
|
||||
|
||||
@deprecated
|
||||
authUpdateStatus(authId: ID!, linkUser: Boolean): AuthInfo!
|
||||
|
||||
# Logouts user. If provider not specified then all authorizations are revoked from session.
|
||||
@@ -187,4 +199,6 @@ extend type Mutation {
|
||||
# Updates user preferences
|
||||
setUserPreferences(preferences: Object!): UserInfo! @since(version: "24.0.1")
|
||||
|
||||
@since(version: "25.0.3")
|
||||
federatedLogin(provider: ID!, configuration: ID, linkUser: Boolean, forceSessionsLogout: Boolean): FederatedAuthInfo!
|
||||
}
|
||||
|
||||
+17
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 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.
|
||||
@@ -39,8 +39,23 @@ public interface DBWServiceAuth extends DBWService {
|
||||
@Nullable String providerConfigurationId,
|
||||
@Nullable Map<String, Object> credentials,
|
||||
boolean linkWithActiveUser,
|
||||
boolean forceSessionsLogout) throws DBWebException;
|
||||
boolean forceSessionsLogout
|
||||
) throws DBWebException;
|
||||
|
||||
@WebAction(authRequired = false)
|
||||
WebAsyncAuthStatus federatedLogin(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String providerId,
|
||||
@Nullable String providerConfigurationId,
|
||||
boolean linkWithActiveUser,
|
||||
boolean forceSessionsLogout
|
||||
) throws DBWebException;
|
||||
|
||||
@WebAction(authRequired = false)
|
||||
WebAsyncAuthTaskResult federatedAuthTaskResult(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String taskId
|
||||
) throws DBWebException;
|
||||
|
||||
@WebAction(authRequired = false)
|
||||
WebAuthStatus authUpdateStatus(@NotNull WebSession webSession, @NotNull String authId, boolean linkWithActiveUser) throws DBWebException;
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 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.service.auth;
|
||||
|
||||
import io.cloudbeaver.model.CustomCancelableJob;
|
||||
import io.cloudbeaver.model.WebAsyncTaskInfo;
|
||||
import io.cloudbeaver.model.session.WebAuthInfo;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.utils.WebEventUtils;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.runtime.AbstractJob;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WebAsyncAuthJob extends AbstractJob implements CustomCancelableJob {
|
||||
@NotNull
|
||||
private final String authId;
|
||||
private final boolean linkWithUser;
|
||||
//result from task do used, because it cannot be serialized into 'object' gql type and separate request is used
|
||||
//to get auth result
|
||||
@Nullable
|
||||
private List<WebAuthInfo> authResult;
|
||||
|
||||
public WebAsyncAuthJob(@NotNull String name, @NotNull String authId, boolean linkWithUser) {
|
||||
super(name);
|
||||
this.authId = authId;
|
||||
this.linkWithUser = linkWithUser;
|
||||
}
|
||||
|
||||
//do nothing, this job is workaround to use exist async process
|
||||
@Override
|
||||
protected IStatus run(DBRProgressMonitor monitor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getAuthId() {
|
||||
return authId;
|
||||
}
|
||||
|
||||
public boolean isLinkWithUser() {
|
||||
return linkWithUser;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<WebAuthInfo> getAuthResult() {
|
||||
return authResult;
|
||||
}
|
||||
|
||||
public void setAuthResult(@Nullable List<WebAuthInfo> authResult) {
|
||||
this.authResult = authResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelJob(@NotNull WebSession webSession, @NotNull WebAsyncTaskInfo taskInfo) {
|
||||
taskInfo.setRunning(false);
|
||||
taskInfo.setJobError(new DBException("Canceled by the user"));
|
||||
WebEventUtils.sendAsyncTaskEvent(webSession, taskInfo);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 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.service.auth;
|
||||
|
||||
import io.cloudbeaver.model.WebAsyncTaskInfo;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
|
||||
public class WebAsyncAuthStatus {
|
||||
@NotNull
|
||||
private final String redirectLink;
|
||||
|
||||
@NotNull
|
||||
private final WebAsyncTaskInfo taskInfo;
|
||||
|
||||
public WebAsyncAuthStatus(@NotNull String redirectLink, @NotNull WebAsyncTaskInfo taskInfo) {
|
||||
this.redirectLink = redirectLink;
|
||||
this.taskInfo = taskInfo;
|
||||
}
|
||||
|
||||
@Property
|
||||
@NotNull
|
||||
public String getRedirectLink() {
|
||||
return redirectLink;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Property
|
||||
public WebAsyncTaskInfo getTaskInfo() {
|
||||
return taskInfo;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 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.service.auth;
|
||||
|
||||
import io.cloudbeaver.model.session.WebAuthInfo;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WebAsyncAuthTaskResult {
|
||||
@NotNull
|
||||
private final List<WebAuthInfo> userTokens;
|
||||
|
||||
public WebAsyncAuthTaskResult(@NotNull List<WebAuthInfo> userTokens) {
|
||||
this.userTokens = userTokens;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Property
|
||||
public List<WebAuthInfo> getUserTokens() {
|
||||
return userTokens;
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 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.
|
||||
@@ -44,6 +44,10 @@ public class WebServiceBindingAuth extends WebServiceBindingBase<DBWServiceAuth>
|
||||
CommonUtils.toBoolean(env.getArgument("linkUser")),
|
||||
CommonUtils.toBoolean(env.getArgument("forceSessionsLogout"))
|
||||
))
|
||||
.dataFetcher("federatedAuthTaskResult", env -> getService(env).federatedAuthTaskResult(
|
||||
getWebSession(env, false),
|
||||
env.getArgument("taskId")
|
||||
))
|
||||
.dataFetcher("authLogoutExtended", env -> getService(env).authLogout(
|
||||
getWebSession(env, false),
|
||||
env.getArgument("provider"),
|
||||
@@ -78,6 +82,13 @@ public class WebServiceBindingAuth extends WebServiceBindingBase<DBWServiceAuth>
|
||||
.dataFetcher("setUserPreferences",
|
||||
env -> getService(env).setUserConfigurationParameters(getWebSession(env),
|
||||
env.getArgument("preferences")))
|
||||
.dataFetcher("federatedLogin", env -> getService(env).federatedLogin(
|
||||
getWebSession(env, false),
|
||||
env.getArgument("provider"),
|
||||
env.getArgument("configuration"),
|
||||
CommonUtils.toBoolean(env.getArgument("linkUser")),
|
||||
CommonUtils.toBoolean(env.getArgument("forceSessionsLogout"))
|
||||
))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
+41
-11
@@ -16,11 +16,18 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.auth.handler;
|
||||
|
||||
import io.cloudbeaver.DBWConstants;
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.model.session.*;
|
||||
import io.cloudbeaver.model.WebAsyncTaskInfo;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebAuthInfo;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.model.session.WebSessionAuthProcessor;
|
||||
import io.cloudbeaver.server.WebAppSessionManager;
|
||||
import io.cloudbeaver.server.WebAppUtils;
|
||||
import io.cloudbeaver.server.WebApplication;
|
||||
import io.cloudbeaver.service.auth.WebAsyncAuthJob;
|
||||
import io.cloudbeaver.utils.WebEventUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
@@ -48,6 +55,27 @@ public class WSAuthSessionEventHandler implements WSEventHandler<WSAuthEvent> {
|
||||
log.trace("No web session found in current node with id '" + sessionId + "'");
|
||||
return;
|
||||
}
|
||||
List<WebAsyncTaskInfo> allAuthJobs = webSession.findTasksByJob(WebAsyncAuthJob.class);
|
||||
WebAsyncTaskInfo relatedTask = allAuthJobs.stream().filter(
|
||||
task -> {
|
||||
WebAsyncAuthJob job = (WebAsyncAuthJob) task.getJob();
|
||||
return job.getAuthId().equals(authInfo.getAuthAttemptId());
|
||||
})
|
||||
.findFirst().orElse(null);
|
||||
if (relatedTask == null) {
|
||||
String message = "No related authentication task was found in'" + sessionId + "',"
|
||||
+ " probably authentication was canceled";
|
||||
log.warn(message);
|
||||
webSession.addWarningMessage(message);
|
||||
return;
|
||||
}
|
||||
if (!relatedTask.isRunning()) {
|
||||
String message = "Related authentication task was canceled";
|
||||
log.warn(message);
|
||||
webSession.addWarningMessage(message);
|
||||
return;
|
||||
}
|
||||
WebAsyncAuthJob relatedJob = (WebAsyncAuthJob) relatedTask.getJob();
|
||||
switch (authInfo.getAuthStatus()) {
|
||||
case SUCCESS:
|
||||
boolean linkCredentialsWithActiveUser = !webApplication.isConfigurationMode()
|
||||
@@ -58,23 +86,25 @@ public class WSAuthSessionEventHandler implements WSEventHandler<WSAuthEvent> {
|
||||
authInfo,
|
||||
linkCredentialsWithActiveUser
|
||||
).authenticateSession();
|
||||
List<WebUserAuthTokenInfo> tokenInfos = newInfos
|
||||
.stream()
|
||||
.map(WebUserAuthTokenInfo::new)
|
||||
.toList();
|
||||
webSession.addSessionEvent(new WebSessionAuthEvent(tokenInfos));
|
||||
relatedJob.setAuthResult(newInfos);
|
||||
} catch (DBException e) {
|
||||
webSession.addSessionError(e);
|
||||
relatedTask.setJobError(e);
|
||||
}
|
||||
|
||||
break;
|
||||
case ERROR:
|
||||
webSession.addSessionEvent(new WebSessionAuthEvent(new DBWebException(authInfo.getError(), authInfo.getErrorCode())));
|
||||
var error = new DBWebException(authInfo.getError(), authInfo.getErrorCode());
|
||||
relatedTask.setJobError(error);
|
||||
break;
|
||||
case IN_PROGRESS, EXPIRED:
|
||||
log.error("Invalid auth status: " + authInfo.getAuthStatus());
|
||||
default:
|
||||
log.error("Unknown auth status: " + authInfo.getAuthStatus());
|
||||
String message = "Invalid auth status: " + authInfo.getAuthStatus();
|
||||
log.error(message);
|
||||
var exception = new DBWebException(message);
|
||||
webSession.addSessionError(exception);
|
||||
relatedTask.setJobError(new DBWebException(message));
|
||||
}
|
||||
relatedTask.setRunning(false);
|
||||
relatedTask.setStatus(DBWConstants.TASK_STATUS_FINISHED);
|
||||
WebEventUtils.sendAsyncTaskEvent(webSession, relatedTask);
|
||||
}
|
||||
}
|
||||
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 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.service.auth.handler;
|
||||
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.websocket.WSConstants;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSAbstractEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WebSessionAuthEvent extends WSAbstractEvent {
|
||||
@Nullable
|
||||
private final List<WebUserAuthTokenInfo> userTokens;
|
||||
|
||||
private final DBWebException error;
|
||||
|
||||
protected WebSessionAuthEvent(@NotNull List<WebUserAuthTokenInfo> userTokens) {
|
||||
super("cb_web_session_auth", WSConstants.TOPIC_SESSION);
|
||||
this.userTokens = userTokens;
|
||||
this.error = null;
|
||||
}
|
||||
protected WebSessionAuthEvent(@NotNull DBWebException error) {
|
||||
super("cb_web_session_auth", WSConstants.TOPIC_SESSION);
|
||||
this.userTokens = null;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<WebUserAuthTokenInfo> getUserTokens() {
|
||||
return userTokens;
|
||||
}
|
||||
|
||||
public DBWebException getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 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.service.auth.handler;
|
||||
|
||||
import io.cloudbeaver.model.session.WebAuthInfo;
|
||||
import io.cloudbeaver.model.session.WebUserAuthToken;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public class WebUserAuthTokenInfo implements WebUserAuthToken {
|
||||
@NotNull
|
||||
private final String authProvider;
|
||||
@Nullable
|
||||
private final String authConfiguration;
|
||||
@NotNull
|
||||
private final OffsetDateTime loginTime;
|
||||
@NotNull
|
||||
private final String userId;
|
||||
@NotNull
|
||||
private final String displayName;
|
||||
@Nullable
|
||||
private final String message;
|
||||
|
||||
public WebUserAuthTokenInfo(
|
||||
@NotNull WebAuthInfo authInfo
|
||||
) {
|
||||
this(
|
||||
authInfo.getAuthProvider(),
|
||||
authInfo.getAuthConfiguration(),
|
||||
authInfo.getDisplayName(),
|
||||
authInfo.getLoginTime(),
|
||||
authInfo.getMessage(),
|
||||
authInfo.getUserId()
|
||||
);
|
||||
}
|
||||
|
||||
public WebUserAuthTokenInfo(
|
||||
@NotNull String authProvider,
|
||||
@Nullable String authConfiguration,
|
||||
@NotNull String displayName,
|
||||
@NotNull OffsetDateTime loginTime,
|
||||
@Nullable String message,
|
||||
@NotNull String userId
|
||||
) {
|
||||
this.authConfiguration = authConfiguration;
|
||||
this.authProvider = authProvider;
|
||||
this.displayName = displayName;
|
||||
this.loginTime = loginTime;
|
||||
this.message = message;
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getAuthConfiguration() {
|
||||
return authConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getAuthProvider() {
|
||||
return authProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public OffsetDateTime getLoginTime() {
|
||||
return loginTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
}
|
||||
+96
-32
@@ -20,6 +20,7 @@ import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.auth.SMSignOutLinkProvider;
|
||||
import io.cloudbeaver.auth.provider.local.LocalAuthProvider;
|
||||
import io.cloudbeaver.model.WebAsyncTaskInfo;
|
||||
import io.cloudbeaver.model.WebPropertyInfo;
|
||||
import io.cloudbeaver.model.app.ServletAppConfiguration;
|
||||
import io.cloudbeaver.model.session.WebAuthInfo;
|
||||
@@ -30,10 +31,7 @@ import io.cloudbeaver.registry.WebAuthProviderDescriptor;
|
||||
import io.cloudbeaver.registry.WebAuthProviderRegistry;
|
||||
import io.cloudbeaver.registry.WebMetaParametersRegistry;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.service.auth.DBWServiceAuth;
|
||||
import io.cloudbeaver.service.auth.WebAuthStatus;
|
||||
import io.cloudbeaver.service.auth.WebLogoutInfo;
|
||||
import io.cloudbeaver.service.auth.WebUserInfo;
|
||||
import io.cloudbeaver.service.auth.*;
|
||||
import io.cloudbeaver.service.auth.model.user.WebAuthProviderInfo;
|
||||
import io.cloudbeaver.service.security.SMUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
@@ -72,6 +70,89 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
|
||||
boolean linkWithActiveUser,
|
||||
boolean forceSessionsLogout
|
||||
) throws DBWebException {
|
||||
try {
|
||||
var smAuthInfo = initiateAuthentication(webSession, providerId, providerConfigurationId, authParameters, forceSessionsLogout);
|
||||
//TODO deprecated, use asyncAuthLogin for federated auth, exits for backward compatibility
|
||||
linkWithActiveUser = linkWithActiveUser && CBApplication.getInstance().getAppConfiguration()
|
||||
.isLinkExternalCredentialsWithUser();
|
||||
if (smAuthInfo.getAuthStatus() == SMAuthStatus.IN_PROGRESS) {
|
||||
//run async auth process
|
||||
return new WebAuthStatus(smAuthInfo.getAuthAttemptId(), smAuthInfo.getRedirectUrl(), smAuthInfo.getAuthStatus());
|
||||
} else {
|
||||
//run it sync
|
||||
var authProcessor = new WebSessionAuthProcessor(webSession, smAuthInfo, linkWithActiveUser);
|
||||
return new WebAuthStatus(smAuthInfo.getAuthStatus(), authProcessor.authenticateSession());
|
||||
}
|
||||
} catch (SMTooManySessionsException e) {
|
||||
throw new DBWebException("User authentication failed", e.getErrorType(), e);
|
||||
} catch (Exception e) {
|
||||
throw new DBWebException("User authentication failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebAsyncAuthStatus federatedLogin(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String providerId,
|
||||
@Nullable String providerConfigurationId,
|
||||
boolean linkWithActiveUser,
|
||||
boolean forceSessionsLogout
|
||||
) throws DBWebException {
|
||||
WebAuthProviderDescriptor providerDescriptor = WebAuthProviderRegistry.getInstance().getAuthProvider(providerId);
|
||||
if (providerDescriptor == null) {
|
||||
throw new DBWebException("Provider '" + providerId + "' not found");
|
||||
}
|
||||
if (!providerDescriptor.isFederated()) {
|
||||
throw new DBWebException("Provider '" + providerId + "' is not federated");
|
||||
}
|
||||
try {
|
||||
var smAuthInfo = initiateAuthentication(webSession, providerId, providerConfigurationId, Map.of(), forceSessionsLogout);
|
||||
if (smAuthInfo.getAuthStatus() != SMAuthStatus.IN_PROGRESS) {
|
||||
throw new DBWebException("Unexpected auth status: " + smAuthInfo.getAuthStatus());
|
||||
}
|
||||
if (CommonUtils.isEmpty(smAuthInfo.getRedirectUrl())) {
|
||||
throw new DBWebException("Missing redirect URL");
|
||||
}
|
||||
WebAsyncTaskInfo authTask = webSession.createAsyncTask(providerId + " authentication");
|
||||
authTask.setRunning(true);
|
||||
authTask.setJob(
|
||||
new WebAsyncAuthJob(providerId + " authentication job", smAuthInfo.getAuthAttemptId(), linkWithActiveUser)
|
||||
);
|
||||
return new WebAsyncAuthStatus(smAuthInfo.getRedirectUrl(), authTask);
|
||||
} catch (SMTooManySessionsException e) {
|
||||
throw new DBWebException("User authentication failed", e.getErrorType(), e);
|
||||
} catch (Exception e) {
|
||||
throw new DBWebException("User authentication failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebAsyncAuthTaskResult federatedAuthTaskResult(@NotNull WebSession webSession, @NotNull String taskId) throws DBWebException {
|
||||
WebAsyncTaskInfo taskInfo = webSession.asyncTaskStatus(taskId, true);
|
||||
if (taskInfo == null) {
|
||||
throw new DBWebException("Task '" + taskId + "' not found");
|
||||
}
|
||||
if (taskInfo.isRunning()) {
|
||||
throw new DBWebException("Task '" + taskId + "' is running");
|
||||
}
|
||||
if (taskInfo.getJob() == null || !WebAsyncAuthJob.class.isAssignableFrom(taskInfo.getJob().getClass())) {
|
||||
throw new DBWebException("Task '" + taskId + "' is not async auth task");
|
||||
}
|
||||
WebAsyncAuthJob job = (WebAsyncAuthJob) taskInfo.getJob();
|
||||
List<WebAuthInfo> userTokens = job.getAuthResult();
|
||||
if (CommonUtils.isEmpty(userTokens)) {
|
||||
userTokens = List.of();
|
||||
}
|
||||
return new WebAsyncAuthTaskResult(userTokens);
|
||||
}
|
||||
|
||||
private static SMAuthInfo initiateAuthentication(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String providerId,
|
||||
@Nullable String providerConfigurationId,
|
||||
@Nullable Map<String, Object> authParameters,
|
||||
boolean forceSessionsLogout
|
||||
) throws DBException {
|
||||
if (CommonUtils.isEmpty(providerId)) {
|
||||
throw new DBWebException("Missing auth provider parameter");
|
||||
}
|
||||
@@ -87,34 +168,17 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
|
||||
String currentSmSessionId = (webSession.getUser() == null || CBApplication.getInstance().isConfigurationMode())
|
||||
? null
|
||||
: webSession.getUserContext().getSmSessionId();
|
||||
|
||||
try {
|
||||
var smAuthInfo = securityController.authenticate(
|
||||
webSession.getSessionId(),
|
||||
currentSmSessionId,
|
||||
webSession.getSessionParameters(),
|
||||
WebSession.CB_SESSION_TYPE,
|
||||
providerId,
|
||||
providerConfigurationId,
|
||||
authParameters,
|
||||
forceSessionsLogout
|
||||
);
|
||||
|
||||
linkWithActiveUser = linkWithActiveUser && CBApplication.getInstance().getAppConfiguration().isLinkExternalCredentialsWithUser();
|
||||
if (smAuthInfo.getAuthStatus() == SMAuthStatus.IN_PROGRESS) {
|
||||
//run async auth process
|
||||
return new WebAuthStatus(smAuthInfo.getAuthAttemptId(), smAuthInfo.getRedirectUrl(), smAuthInfo.getAuthStatus());
|
||||
} else {
|
||||
//run it sync
|
||||
var authProcessor = new WebSessionAuthProcessor(webSession, smAuthInfo, linkWithActiveUser);
|
||||
return new WebAuthStatus(smAuthInfo.getAuthStatus(), authProcessor.authenticateSession());
|
||||
}
|
||||
} catch (SMTooManySessionsException e) {
|
||||
throw new DBWebException("User authentication failed", e.getErrorType(), e);
|
||||
} catch (Exception e) {
|
||||
throw new DBWebException("User authentication failed", e);
|
||||
}
|
||||
|
||||
var smAuthInfo = securityController.authenticate(
|
||||
webSession.getSessionId(),
|
||||
currentSmSessionId,
|
||||
webSession.getSessionParameters(),
|
||||
WebSession.CB_SESSION_TYPE,
|
||||
providerId,
|
||||
providerConfigurationId,
|
||||
authParameters,
|
||||
forceSessionsLogout
|
||||
);
|
||||
return smAuthInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -8,11 +8,12 @@
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { AutoRunningTask, type ITask } from '@cloudbeaver/core-executor';
|
||||
import { WindowsService } from '@cloudbeaver/core-routing';
|
||||
import { type AuthInfo, AuthStatus, type UserInfo } from '@cloudbeaver/core-sdk';
|
||||
import { type UserInfo } from '@cloudbeaver/core-sdk';
|
||||
import { uuid } from '@cloudbeaver/core-utils';
|
||||
import { AsyncTaskInfoService } from '@cloudbeaver/core-root';
|
||||
|
||||
import { type AuthProviderConfiguration, AuthProvidersResource } from './AuthProvidersResource.js';
|
||||
import { type ILoginOptions, UserInfoResource } from './UserInfoResource.js';
|
||||
import { type AuthProviderConfiguration } from './AuthProvidersResource.js';
|
||||
import { type IFederatedLoginOptions, type ILoginOptions, UserInfoResource } from './UserInfoResource.js';
|
||||
|
||||
export interface IUserAuthConfiguration {
|
||||
providerId: string;
|
||||
@@ -27,59 +28,50 @@ export class AuthInfoService {
|
||||
|
||||
constructor(
|
||||
private readonly userInfoResource: UserInfoResource,
|
||||
private readonly authProvidersResource: AuthProvidersResource,
|
||||
private readonly windowsService: WindowsService,
|
||||
private readonly asyncTaskInfoService: AsyncTaskInfoService,
|
||||
) {}
|
||||
|
||||
login(providerId: string, options: ILoginOptions): ITask<UserInfo | null> {
|
||||
return new AutoRunningTask(async () => await this.userInfoResource.login(providerId, options)).then(authInfo =>
|
||||
this.federatedAuthentication(providerId, options, authInfo),
|
||||
);
|
||||
async login(providerId: string, options: ILoginOptions): Promise<UserInfo | null> {
|
||||
await this.userInfoResource.login(providerId, options);
|
||||
return this.userInfoResource.data;
|
||||
}
|
||||
|
||||
private federatedAuthentication(
|
||||
providerId: string,
|
||||
options: ILoginOptions,
|
||||
{ redirectLink, authId, authStatus }: AuthInfo,
|
||||
): ITask<UserInfo | null> {
|
||||
let window: Window | null = null;
|
||||
let id = providerId;
|
||||
federatedLogin(providerId: string, options: IFederatedLoginOptions): ITask<UserInfo | null> {
|
||||
let redirectWindow: Window | null = null;
|
||||
|
||||
if (options.configurationId) {
|
||||
const configuration = this.authProvidersResource.getConfiguration(providerId, options.configurationId);
|
||||
const task = this.asyncTaskInfoService.create(async () => {
|
||||
const result = await this.userInfoResource.requestFederatedLogin(providerId, options);
|
||||
|
||||
if (configuration) {
|
||||
id = configuration.id;
|
||||
if (result.redirectLink) {
|
||||
const id = uuid();
|
||||
redirectWindow = this.windowsService.open(id, {
|
||||
url: result.redirectLink,
|
||||
target: id,
|
||||
width: 600,
|
||||
height: 700,
|
||||
});
|
||||
|
||||
if (redirectWindow) {
|
||||
redirectWindow.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (redirectLink) {
|
||||
id = uuid();
|
||||
window = this.windowsService.open(id, {
|
||||
url: redirectLink,
|
||||
target: id,
|
||||
width: 600,
|
||||
height: 700,
|
||||
});
|
||||
|
||||
if (window) {
|
||||
window.focus();
|
||||
}
|
||||
}
|
||||
return result.taskInfo;
|
||||
});
|
||||
|
||||
return new AutoRunningTask(
|
||||
() => {
|
||||
if (authId && authStatus === AuthStatus.InProgress) {
|
||||
return this.userInfoResource.finishFederatedAuthentication(authId, options.linkUser);
|
||||
async () => {
|
||||
await this.asyncTaskInfoService.run(task);
|
||||
await this.userInfoResource.syncData();
|
||||
|
||||
if (redirectWindow) {
|
||||
this.windowsService.close(redirectWindow);
|
||||
}
|
||||
|
||||
return AutoRunningTask.resolve(this.userInfoResource.data);
|
||||
},
|
||||
() => {
|
||||
if (window) {
|
||||
this.windowsService.close(window);
|
||||
}
|
||||
return this.userInfoResource.data;
|
||||
},
|
||||
() => this.asyncTaskInfoService.cancel(task.id),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { AutoRunningTask, type ISyncExecutor, type ITask, SyncExecutor, whileTas
|
||||
import { CachedDataResource, type ResourceKeySimple, ResourceKeyUtils } from '@cloudbeaver/core-resource';
|
||||
import { SessionResource } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
type FederatedAuthInfo,
|
||||
type AuthInfo,
|
||||
type AuthLogoutQuery,
|
||||
AuthStatus,
|
||||
@@ -36,6 +37,8 @@ export interface ILoginOptions {
|
||||
forceSessionsLogout?: boolean;
|
||||
}
|
||||
|
||||
export type IFederatedLoginOptions = Omit<ILoginOptions, 'credentials'>;
|
||||
|
||||
export const ANONYMOUS_USER_ID = 'anonymous';
|
||||
|
||||
@injectable()
|
||||
@@ -126,15 +129,27 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
|
||||
});
|
||||
|
||||
if (authInfo.userTokens && authInfo.authStatus === AuthStatus.Success) {
|
||||
this.resetIncludes();
|
||||
this.setData(await this.loader());
|
||||
this.sessionResource.markOutdated();
|
||||
await this.syncData();
|
||||
}
|
||||
|
||||
return authInfo as AuthInfo;
|
||||
}
|
||||
|
||||
finishFederatedAuthentication(authId: string, linkUser?: boolean): ITask<UserInfo | null> {
|
||||
async requestFederatedLogin(
|
||||
provider: string,
|
||||
{ configurationId, linkUser, forceSessionsLogout }: IFederatedLoginOptions,
|
||||
): Promise<FederatedAuthInfo> {
|
||||
const { result } = await this.graphQLService.sdk.federatedLogin({
|
||||
provider,
|
||||
configuration: configurationId,
|
||||
linkUser,
|
||||
forceSessionsLogout,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
autoLogin(authId: string, linkUser?: boolean): ITask<UserInfo | null> {
|
||||
let activeTask: ITask<AuthInfo> | undefined;
|
||||
|
||||
return new AutoRunningTask<UserInfo | null>(
|
||||
@@ -164,9 +179,7 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
|
||||
const authInfo = await activeTask;
|
||||
|
||||
if (authInfo.userTokens && authInfo.authStatus === AuthStatus.Success) {
|
||||
this.resetIncludes();
|
||||
this.setData(await this.loader());
|
||||
this.sessionResource.markOutdated();
|
||||
await this.syncData();
|
||||
}
|
||||
|
||||
return this.data;
|
||||
@@ -272,6 +285,12 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
|
||||
return this.data?.configurationParameters[key];
|
||||
}
|
||||
|
||||
async syncData(): Promise<void> {
|
||||
this.resetIncludes();
|
||||
this.setData(await this.loader());
|
||||
this.sessionResource.markOutdated();
|
||||
}
|
||||
|
||||
protected async loader(key: void, includes?: ReadonlyArray<string>): Promise<UserInfo | null> {
|
||||
try {
|
||||
const { user } = await this.graphQLService.sdk.getActiveUser({
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
mutation federatedLogin($provider: ID!, $configuration: ID, $linkUser: Boolean, $forceSessionsLogout: Boolean) {
|
||||
result: federatedLogin(provider: $provider, configuration: $configuration, linkUser: $linkUser, forceSessionsLogout: $forceSessionsLogout) {
|
||||
redirectLink
|
||||
taskInfo {
|
||||
...AsyncTaskInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,7 +219,7 @@ export class AuthenticationService extends Bootstrap {
|
||||
const action = contexts.getContext(sessionActionContext);
|
||||
|
||||
if (isAutoLoginSessionAction(data)) {
|
||||
const user = await this.userInfoResource.finishFederatedAuthentication(data['auth-id'], false);
|
||||
const user = await this.userInfoResource.autoLogin(data['auth-id'], false);
|
||||
|
||||
if (user) {
|
||||
//we request this method/request bc login form can be opened automatically.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,7 +40,7 @@ interface IData {
|
||||
tabIds: string[];
|
||||
|
||||
login: (linkUser: boolean, provider?: AuthProvider, configuration?: AuthProviderConfiguration) => Promise<void>;
|
||||
loginFederated: (provider: AuthProvider, configuration: AuthProviderConfiguration, onClose?: () => void) => Promise<void>;
|
||||
federatedLogin: (provider: AuthProvider, configuration: AuthProviderConfiguration) => Promise<void>;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
@@ -223,22 +223,23 @@ export function useAuthDialogState(accessRequest: boolean, providerId: string |
|
||||
try {
|
||||
this.state.setActiveProvider(provider, configuration ?? null);
|
||||
|
||||
const loginTask = authInfoService.login(provider.id, {
|
||||
configurationId: configuration?.id,
|
||||
credentials: {
|
||||
...state.credentials,
|
||||
if (provider.federated && configuration) {
|
||||
await this.federatedLogin(provider, configuration);
|
||||
} else {
|
||||
await authInfoService.login(provider.id, {
|
||||
configurationId: configuration?.id,
|
||||
credentials: {
|
||||
...state.credentials.credentials,
|
||||
user: state.credentials.credentials['user']?.trim(),
|
||||
password: state.credentials.credentials['password']?.trim(),
|
||||
...state.credentials,
|
||||
credentials: {
|
||||
...state.credentials.credentials,
|
||||
user: state.credentials.credentials['user']?.trim(),
|
||||
password: state.credentials.credentials['password']?.trim(),
|
||||
},
|
||||
},
|
||||
},
|
||||
forceSessionsLogout: state.forceSessionsLogout,
|
||||
linkUser,
|
||||
});
|
||||
this.authTask = loginTask;
|
||||
|
||||
await loginTask;
|
||||
forceSessionsLogout: state.forceSessionsLogout,
|
||||
linkUser,
|
||||
});
|
||||
}
|
||||
} catch (exception: any) {
|
||||
const gqlError = errorOf(exception, GQLError);
|
||||
|
||||
@@ -265,6 +266,15 @@ export function useAuthDialogState(accessRequest: boolean, providerId: string |
|
||||
|
||||
return;
|
||||
},
|
||||
async federatedLogin(provider: AuthProvider, configuration: AuthProviderConfiguration): Promise<void> {
|
||||
this.authTask = authInfoService.federatedLogin(provider.id, {
|
||||
configurationId: configuration.id,
|
||||
forceSessionsLogout: state.forceSessionsLogout,
|
||||
linkUser: false,
|
||||
});
|
||||
|
||||
await this.authTask;
|
||||
},
|
||||
}),
|
||||
{
|
||||
state: observable.ref,
|
||||
|
||||
Reference in New Issue
Block a user