diff --git a/config/core/cloudbeaver.conf b/config/core/cloudbeaver.conf index 858d2b2911..076b785788 100644 --- a/config/core/cloudbeaver.conf +++ b/config/core/cloudbeaver.conf @@ -1,6 +1,7 @@ { server: { serverPort: "${CLOUDBEAVER_WEB_SERVER_PORT:8978}", + secureCookies: "${CLOUDBEAVER_SECURE_COOKIES:true}", contentRoot: "web", driversLocation: "drivers", diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderFederated.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderFederated.java index 3193905e12..87bd511a23 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderFederated.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderFederated.java @@ -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. @@ -30,27 +30,50 @@ import java.util.Map; public interface SMAuthProviderFederated extends SMSignOutLinkProvider { @NotNull - String getSignInLink(String id) throws DBException; + String getSignInLink(@NotNull String id, @NotNull String origin) throws DBException; @Override default String getUserSignOutLink( @NotNull SMAuthProviderCustomConfiguration providerConfig, - @NotNull Map userCredentials + @NotNull Map userCredentials, + @NotNull String origin ) throws DBException { - return getCommonSignOutLink(providerConfig.getId(), providerConfig.getParameters()); + return getCommonSignOutLink(providerConfig.getId(), providerConfig.getParameters(), origin); } @Nullable - String getMetadataLink(String id, @NotNull Map providerConfig) throws DBException; + default String getMetadataLink( + @NotNull String providerId, + @NotNull Map providerConfig, + @NotNull String origin + ) throws DBException { + return null; + } @Nullable - String getAcsLink(String id, @NotNull Map providerConfig) throws DBException; + default String getAcsLink( + @NotNull String providerId, + @NotNull Map providerConfig, + @NotNull String origin + ) throws DBException { + return null; + } @Nullable - String getEntityIdLink(String id, @NotNull Map providerConfig) throws DBException; + default String getEntityIdLink( + @NotNull String providerId, + @NotNull Map providerConfig, + @NotNull String origin + ) throws DBException { + return null; + } @Nullable - default String getRedirectLink(String id, @NotNull Map providerConfig) throws DBException { + default String getRedirectLink( + @NotNull String providerId, + @NotNull Map providerConfig, + @NotNull String origin + ) throws DBException { return null; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMSignOutLinkProvider.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMSignOutLinkProvider.java index 3cbd7f70b1..46d9d7b99a 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMSignOutLinkProvider.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMSignOutLinkProvider.java @@ -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. @@ -28,10 +28,15 @@ public interface SMSignOutLinkProvider { * @return a common link for logout, not related with the user context */ @NotNull - String getCommonSignOutLink(String id, @NotNull Map providerConfig) throws DBException; + String getCommonSignOutLink( + @NotNull String providerId, + @NotNull Map providerConfig, + @NotNull String origin + ) throws DBException; String getUserSignOutLink( @NotNull SMAuthProviderCustomConfiguration providerConfig, - @NotNull Map userCredentials + @NotNull Map userCredentials, + @NotNull String origin ) throws DBException; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/ServletAuthApplication.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/ServletAuthApplication.java index 699d604670..b22f8eb7d1 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/ServletAuthApplication.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/ServletAuthApplication.java @@ -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. @@ -18,12 +18,15 @@ package io.cloudbeaver.model.app; import io.cloudbeaver.auth.CBAuthConstants; +import org.jkiss.code.NotNull; +import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; public interface ServletAuthApplication extends ServletApplication { ServletAuthConfiguration getAuthConfiguration(); - String getAuthServiceURL(); + @Nullable + String getAuthServiceUriSegment(); default long getMaxSessionIdleTime() { return CBAuthConstants.MAX_SESSION_IDLE_TIME; @@ -32,4 +35,8 @@ public interface ServletAuthApplication extends ServletApplication { void flushConfiguration() throws DBException; String getDefaultAuthRole(); + + default String modifyOrigin(@NotNull String origin) { + return origin; + } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderConfiguration.java index 4a5ec8da69..3b12df2ecb 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderConfiguration.java @@ -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. @@ -20,6 +20,7 @@ import io.cloudbeaver.auth.CBAuthConstants; import io.cloudbeaver.auth.SMAuthProviderFederated; import io.cloudbeaver.auth.SMSignOutLinkProvider; import io.cloudbeaver.utils.ServletAppUtils; +import org.jkiss.code.NotNull; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.auth.SMAuthProvider; @@ -35,12 +36,21 @@ public class WebAuthProviderConfiguration { private static final Log log = Log.getLog(WebAuthProviderConfiguration.class); + @NotNull private final WebAuthProviderDescriptor providerDescriptor; + @NotNull private final SMAuthProviderCustomConfiguration config; + @NotNull + private final String origin; - public WebAuthProviderConfiguration(WebAuthProviderDescriptor providerDescriptor, SMAuthProviderCustomConfiguration config) { + public WebAuthProviderConfiguration( + @NotNull WebAuthProviderDescriptor providerDescriptor, + @NotNull SMAuthProviderCustomConfiguration config, + @NotNull String origin + ) { this.providerDescriptor = providerDescriptor; this.config = config; + this.origin = origin; } public String getProviderId() { @@ -75,19 +85,19 @@ public class WebAuthProviderConfiguration { public String getSignInLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); return instance instanceof SMAuthProviderFederated smAuthProviderFederated ? - buildRedirectUrl(smAuthProviderFederated.getSignInLink(getId())) + buildRedirectUrl(smAuthProviderFederated.getSignInLink(getId(), origin), origin) : null; } - private String buildRedirectUrl(String baseUrl) { - return baseUrl + "?" + CBAuthConstants.CB_REDIRECT_URL_REQUEST_PARAM + "=" + ServletAppUtils.getFullServerUrl(); + private String buildRedirectUrl(@NotNull String baseUrl, @NotNull String origin) { + return baseUrl + "?" + CBAuthConstants.CB_REDIRECT_URL_REQUEST_PARAM + "=" + origin; } @Property public String getSignOutLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); return instance instanceof SMSignOutLinkProvider smSignOutLinkProvider - ? smSignOutLinkProvider.getCommonSignOutLink(getId(), config.getParameters()) + ? smSignOutLinkProvider.getCommonSignOutLink(getId(), config.getParameters(), origin) : null; } @@ -95,7 +105,7 @@ public class WebAuthProviderConfiguration { public String getRedirectLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); return instance instanceof SMAuthProviderFederated smAuthProviderFederated - ? smAuthProviderFederated.getRedirectLink(getId(), config.getParameters()) + ? smAuthProviderFederated.getRedirectLink(getId(), config.getParameters(), origin) : null; } @@ -103,7 +113,7 @@ public class WebAuthProviderConfiguration { public String getMetadataLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); return instance instanceof SMAuthProviderFederated smAuthProviderFederated - ? smAuthProviderFederated.getMetadataLink(getId(), config.getParameters()) + ? smAuthProviderFederated.getMetadataLink(getId(), config.getParameters(), origin) : null; } @@ -111,7 +121,7 @@ public class WebAuthProviderConfiguration { public String getAcsLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); return instance instanceof SMAuthProviderFederated smAuthProviderFederated - ? smAuthProviderFederated.getAcsLink(getId(), config.getParameters()) + ? smAuthProviderFederated.getAcsLink(getId(), config.getParameters(), origin) : null; } @@ -119,7 +129,7 @@ public class WebAuthProviderConfiguration { public String getEntityIdLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); return instance instanceof SMAuthProviderFederated smAuthProviderFederated - ? smAuthProviderFederated.getEntityIdLink(getId(), config.getParameters()) + ? smAuthProviderFederated.getEntityIdLink(getId(), config.getParameters(), origin) : null; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/CBConstants.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/CBConstants.java index 0dab58fda0..787d71423e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/CBConstants.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/CBConstants.java @@ -32,6 +32,7 @@ public class CBConstants { public static final String PARAM_SERVER_PORT = "serverPort"; public static final String PARAM_SERVER_HOST = "serverHost"; public static final String PARAM_SERVER_NAME = "serverName"; + public static final String PARAM_SECURE_COOKIES = "secureCookies"; public static final String PARAM_SSL_CONFIGURATION_PATH = "sslConfigurationPath"; public static final String PARAM_CONTENT_ROOT = "contentRoot"; public static final String PARAM_SERVER_URL = "serverURL"; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/ServletAppUtils.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/ServletAppUtils.java index 0f187831d3..bb679e4e27 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/ServletAppUtils.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/ServletAppUtils.java @@ -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. @@ -36,12 +36,17 @@ import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.dbeaver.utils.GeneralUtils; import org.jkiss.utils.CommonUtils; +import java.net.URI; import java.nio.file.Path; import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; public class ServletAppUtils { + private static final String HEADER_ORIGIN = "Origin"; + private static final String HEADER_REFERER = "Referer"; + + private static final String HEADER_FORWARDED_SCHEME = "X-Forwarded-Scheme"; + private static final String HEADER_FORWARDED_HOST = "X-Forwarded-Host"; + private static final Log log = Log.getLog(ServletAppUtils.class); public static String getRelativePath(String path, String curDir) { @@ -168,16 +173,24 @@ public class ServletAppUtils { } @NotNull - public static StringBuilder getAuthApiPrefix(String serviceId) throws DBException { - return getAuthApiPrefix(getAuthApplication(), serviceId); + public static StringBuilder getAuthApiUri(@NotNull String serviceId, @NotNull String origin) throws DBException { + return getAuthApiUri(getAuthApplication(), serviceId, origin); } @NotNull - public static StringBuilder getAuthApiPrefix(ServletAuthApplication webAuthApplication, String serviceId) { - String authUrl = removeSideSlashes(webAuthApplication.getAuthServiceURL()); - StringBuilder apiPrefix = new StringBuilder(authUrl); - apiPrefix.append("/").append(serviceId).append("/"); - return apiPrefix; + public static StringBuilder getAuthApiUri( + @NotNull ServletAuthApplication webAuthApplication, + @NotNull String serviceId, + @NotNull String origin + ) throws DBException { + String finalOrigin = webAuthApplication.modifyOrigin(origin); + StringBuilder authUriBuilder = new StringBuilder(removeSideSlashes(finalOrigin)); + String serviceUriSegment = removeSideSlashes(webAuthApplication.getAuthServiceUriSegment()); + if (CommonUtils.isNotEmpty(serviceUriSegment)) { + authUriBuilder.append("/").append(serviceUriSegment); + } + authUriBuilder.append("/").append(serviceId).append("/"); + return authUriBuilder; } public static void addResponseCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, long maxSessionIdleTime) { @@ -272,12 +285,46 @@ public class ServletAppUtils { } @NotNull - public static String getFullServerUrl() { - ServletApplication application = ServletAppUtils.getServletApplication(); - return Stream.of(application.getServerURL(), application.getRootURI()) - .map(ServletAppUtils::removeSideSlashes) - .filter(CommonUtils::isNotEmpty) - .collect(Collectors.joining("/")); + public static String getOriginFromRequestOrThrow(HttpServletRequest request) throws DBWebException { + String origin = request.getHeader(HEADER_ORIGIN); + if (CommonUtils.isEmpty(origin)) { + origin = request.getHeader(HEADER_REFERER); + } + String forwardedScheme = request.getHeader(HEADER_FORWARDED_SCHEME); + String forwardedHost = request.getHeader(HEADER_FORWARDED_HOST); + if (CommonUtils.isNotEmpty(forwardedScheme) && CommonUtils.isNotEmpty(forwardedHost)) { + origin = forwardedHost + "://" + forwardedScheme; + } + if (CommonUtils.isEmpty(origin)) { + URI requestUrl = URI.create(request.getRequestURL().toString()); + origin = getRootUrlFromUri(requestUrl) + "/"; + } + origin = removeSideSlashes(origin); + var app = ServletAppUtils.getServletApplication(); + String rootUri = removeSideSlashes(app.getRootURI()); + if (!origin.endsWith(rootUri)) { + origin = origin + "/" + rootUri + "/"; + } + return removeSideSlashes(origin); } + public static String getRootUrlFromUri(@NotNull URI uri) { + var builder = new StringBuilder() + .append(uri.getScheme()) + .append("://") + .append(uri.getHost()); + if (uri.getPort() > 0) { + builder.append(":").append(uri.getPort()); + } + return removeSideSlashes(substringBeforeRootURI(builder.toString())); + } + + public static String substringBeforeRootURI(@NotNull String uri) { + String rootUri = removeSideSlashes(getServletApplication().getRootURI()); + if (CommonUtils.isEmpty(rootUri)) { + return uri; + } + String[] split = uri.split(rootUri); + return split[0]; + } } diff --git a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/model/config/CBServerConfig.java b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/model/config/CBServerConfig.java index a6e4065325..c3b9bc5a4c 100644 --- a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/model/config/CBServerConfig.java +++ b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/model/config/CBServerConfig.java @@ -31,6 +31,7 @@ public class CBServerConfig implements WebServerConfiguration { private static final Log log = Log.getLog(CBServerConfig.class); protected String serverURL; + protected boolean secureCookies; protected int serverPort = CBConstants.DEFAULT_SERVER_PORT; private String serverHost = null; private String serverName = null; @@ -181,4 +182,8 @@ public class CBServerConfig implements WebServerConfiguration { protected SMControllerConfiguration createSecurityManagerConfiguration() { return new SMControllerConfiguration(); } + + public boolean isSecureCookies() { + return secureCookies; + } } diff --git a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBApplication.java index 7f46c5d2b8..aa2f70690f 100644 --- a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBApplication.java +++ b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBApplication.java @@ -184,7 +184,7 @@ public abstract class CBApplication } @Override - public String getAuthServiceURL() { + public String getAuthServiceUriSegment() { return getServerConfigurationController().getAuthServiceURL(); } diff --git a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBServerConfigurationController.java b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBServerConfigurationController.java index 25008bef69..f6af12bf0b 100644 --- a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBServerConfigurationController.java @@ -74,12 +74,7 @@ public abstract class CBServerConfigurationController } public String getAuthServiceURL() { - return Stream.of(serverConfiguration.getServerURL(), - serverConfiguration.getRootURI(), - serverConfiguration.getServicesURI()) - .map(ServletAppUtils::removeSideSlashes) - .filter(CommonUtils::isNotEmpty) - .collect(Collectors.joining("/")); + return serverConfiguration.getServicesURI(); } @Override @@ -533,6 +528,12 @@ public abstract class CBServerConfigurationController CBConstants.PARAM_SESSION_EXPIRE_PERIOD, serverConfig.getMaxSessionIdleTime()); } + copyConfigValue( + originServerConfig, + serverConfigProperties, + CBConstants.PARAM_SECURE_COOKIES, + serverConfig.isSecureCookies() + ); var productConfigProperties = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); Map oldProductRuntimeConfig = JSONUtils.getObject(originServerConfig, CBConstants.PARAM_PRODUCT_SETTINGS); diff --git a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/jetty/CBJettyServer.java b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/jetty/CBJettyServer.java index cba73e94b0..4fba75734a 100644 --- a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/jetty/CBJettyServer.java +++ b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/jetty/CBJettyServer.java @@ -231,8 +231,7 @@ public class CBJettyServer { && servletContextHandler.getSessionHandler() instanceof CBSessionHandler cbSessionHandler ) { cbSessionHandler.setMaxCookieAge((int) (application.getMaxSessionIdleTime() / 1000)); - var serverUrl = this.application.getServerURL(); - cbSessionHandler.setSecureCookies(serverUrl != null && serverUrl.startsWith("https://")); + cbSessionHandler.setSecureCookies(application.getServerConfiguration().isSecureCookies()); } } } \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java index d928ba99f5..5b12b160fa 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java @@ -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. @@ -40,6 +40,9 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.eclipse.jetty.ee10.servlet.ServletApiRequest; +import org.eclipse.jetty.ee10.servlet.ServletContextHandler; +import org.eclipse.jetty.server.Request; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.data.json.JSONUtils; import org.jkiss.utils.CommonUtils; @@ -141,6 +144,13 @@ public class GraphQLEndpoint extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String contentType = request.getContentType(); + if (request instanceof ServletApiRequest apiRequest) { + ServletContextHandler.ServletRequestInfo info = apiRequest.getServletRequestInfo(); + if (info instanceof Request.Wrapper wrapper) { + System.out.println(wrapper); + } + } + System.out.println(request.toString()); if (CommonUtils.isEmpty(contentType) || !contentType.startsWith(HttpConstants.TYPE_JSON)) { String error = "Bad request," + (CommonUtils.isEmpty(contentType) ? " content type is missing" diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java index f23808efa2..9c0485487a 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java @@ -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. @@ -24,6 +24,7 @@ import io.cloudbeaver.model.WebPropertyInfo; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.registry.WebAuthProviderConfiguration; import io.cloudbeaver.service.DBWService; +import jakarta.servlet.http.HttpServletRequest; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings; @@ -119,10 +120,11 @@ public interface DBWServiceAdmin extends DBWService { @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) List listAuthProviderConfigurationParameters(@NotNull WebSession webSession, @NotNull String providerId) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) - List listAuthProviderConfigurations(@NotNull WebSession webSession, @Nullable String providerId) throws DBWebException; + List listAuthProviderConfigurations(@NotNull HttpServletRequest request, @NotNull WebSession webSession, @Nullable String providerId) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) WebAuthProviderConfiguration saveAuthProviderConfiguration( + @NotNull HttpServletRequest request, @NotNull WebSession webSession, @NotNull String providerId, @NotNull String id, diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java index 8a9bca7de0..fdcde4c503 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java @@ -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. @@ -19,6 +19,7 @@ package io.cloudbeaver.service.admin; import io.cloudbeaver.DBWebException; import io.cloudbeaver.WebServiceUtils; import io.cloudbeaver.server.CBApplication; +import io.cloudbeaver.server.graphql.GraphQLEndpoint; import io.cloudbeaver.service.DBWBindingContext; import io.cloudbeaver.service.DBWServiceBindingServlet; import io.cloudbeaver.service.DBWServletContext; @@ -152,17 +153,20 @@ public class WebServiceBindingAdmin extends WebServiceBindingBase getService(env).listAuthProviderConfigurationParameters(getWebSession(env), env.getArgument("providerId"))) .dataFetcher("listAuthProviderConfigurations", - env -> getService(env).listAuthProviderConfigurations(getWebSession(env), env.getArgument("providerId"))) + env -> getService(env).listAuthProviderConfigurations(GraphQLEndpoint.getServletRequest(env), + getWebSession(env), env.getArgument("providerId")) + ) .dataFetcher("saveAuthProviderConfiguration", env -> getService(env).saveAuthProviderConfiguration( + GraphQLEndpoint.getServletRequest(env), getWebSession(env), env.getArgument("providerId"), env.getArgument("id"), env.getArgument("displayName"), CommonUtils.toBoolean((Boolean)env.getArgument("disabled")), env.getArgument("iconURL"), - env.getArgument("description"), - env.getArgument("parameters"))) + env.getArgument("description"), env.getArgument("parameters") + )) .dataFetcher("deleteAuthProviderConfiguration", env -> getService(env).deleteAuthProviderConfiguration(getWebSession(env), env.getArgument("id"))) diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java index 7ee943724e..df5450be1d 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java @@ -35,6 +35,7 @@ import io.cloudbeaver.service.DBWServiceServerConfigurator; import io.cloudbeaver.service.admin.*; import io.cloudbeaver.service.security.SMUtils; import io.cloudbeaver.utils.ServletAppUtils; +import jakarta.servlet.http.HttpServletRequest; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; @@ -488,7 +489,12 @@ public class WebServiceAdmin implements DBWServiceAdmin { } @Override - public List listAuthProviderConfigurations(@NotNull WebSession webSession, @Nullable String providerId) throws DBWebException { + public List listAuthProviderConfigurations( + @NotNull HttpServletRequest request, + @NotNull WebSession webSession, + @Nullable String providerId + ) throws DBWebException { + String origin = ServletAppUtils.getOriginFromRequestOrThrow(request); List result = new ArrayList<>(); for (SMAuthProviderCustomConfiguration cfg : CBApplication.getInstance().getAppConfiguration().getAuthCustomConfigurations()) { if (providerId != null && !providerId.equals(cfg.getProvider())) { @@ -496,7 +502,7 @@ public class WebServiceAdmin implements DBWServiceAdmin { } WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(cfg.getProvider()); if (authProvider != null) { - result.add(new WebAuthProviderConfiguration(authProvider, cfg)); + result.add(new WebAuthProviderConfiguration(authProvider, cfg, origin)); } } return result; @@ -504,6 +510,7 @@ public class WebServiceAdmin implements DBWServiceAdmin { @Override public WebAuthProviderConfiguration saveAuthProviderConfiguration( + @NotNull HttpServletRequest request, @NotNull WebSession webSession, @NotNull String providerId, @NotNull String id, @@ -537,7 +544,7 @@ public class WebServiceAdmin implements DBWServiceAdmin { providerConfig.getProvider(), webSession.getUserId() )); - return new WebAuthProviderConfiguration(authProvider, providerConfig); + return new WebAuthProviderConfiguration(authProvider, providerConfig, ServletAppUtils.getOriginFromRequestOrThrow(request)); } @Override diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java index 4a843da817..400a344e39 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java @@ -22,6 +22,7 @@ import io.cloudbeaver.model.WebPropertyInfo; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.service.DBWService; import io.cloudbeaver.service.auth.model.user.WebAuthProviderInfo; +import jakarta.servlet.http.HttpServletRequest; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; @@ -44,6 +45,7 @@ public interface DBWServiceAuth extends DBWService { @WebAction(authRequired = false) WebAsyncAuthStatus federatedLogin( + @NotNull HttpServletRequest httpRequest, @NotNull WebSession webSession, @NotNull String providerId, @Nullable String providerConfigurationId, @@ -62,6 +64,7 @@ public interface DBWServiceAuth extends DBWService { @WebAction(authRequired = false) WebLogoutInfo authLogout( + @NotNull HttpServletRequest httpRequest, @NotNull WebSession webSession, @Nullable String providerId, @Nullable String configurationId @@ -71,7 +74,7 @@ public interface DBWServiceAuth extends DBWService { WebUserInfo activeUser(@NotNull WebSession webSession) throws DBWebException; @WebAction(authRequired = false) - WebAuthProviderInfo[] getAuthProviders(); + WebAuthProviderInfo[] getAuthProviders(@NotNull HttpServletRequest request) throws DBWebException; @WebAction() boolean changeLocalPassword(@NotNull WebSession webSession, @NotNull String oldPassword, @NotNull String newPassword) throws DBWebException; diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebServiceBindingAuth.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebServiceBindingAuth.java index e05f4d628a..e25760e50e 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebServiceBindingAuth.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebServiceBindingAuth.java @@ -17,6 +17,7 @@ package io.cloudbeaver.service.auth; import io.cloudbeaver.DBWebException; +import io.cloudbeaver.server.graphql.GraphQLEndpoint; import io.cloudbeaver.service.DBWBindingContext; import io.cloudbeaver.service.WebServiceBindingBase; import io.cloudbeaver.service.auth.impl.WebServiceAuthImpl; @@ -49,12 +50,15 @@ public class WebServiceBindingAuth extends WebServiceBindingBase env.getArgument("taskId") )) .dataFetcher("authLogoutExtended", env -> getService(env).authLogout( + GraphQLEndpoint.getServletRequest(env), getWebSession(env, false), env.getArgument("provider"), env.getArgument("configuration") )) .dataFetcher("authLogout", env -> { - getService(env).authLogout(getWebSession(env, false), + getService(env).authLogout( + GraphQLEndpoint.getServletRequest(env), + getWebSession(env, false), env.getArgument("provider"), env.getArgument("configuration")); return true; @@ -65,7 +69,7 @@ public class WebServiceBindingAuth extends WebServiceBindingBase CommonUtils.toBoolean(env.getArgument("linkUser")) )) .dataFetcher("activeUser", env -> getService(env).activeUser(getWebSession(env, false))) - .dataFetcher("authProviders", env -> getService(env).getAuthProviders()) + .dataFetcher("authProviders", env -> getService(env).getAuthProviders(GraphQLEndpoint.getServletRequest(env))) .dataFetcher("authChangeLocalPassword", env -> getService(env).changeLocalPassword( getWebSession(env), env.getArgument("oldPassword"), @@ -83,6 +87,7 @@ public class WebServiceBindingAuth extends WebServiceBindingBase env -> getService(env).setUserConfigurationParameters(getWebSession(env), env.getArgument("preferences"))) .dataFetcher("federatedLogin", env -> getService(env).federatedLogin( + GraphQLEndpoint.getServletRequest(env), getWebSession(env, false), env.getArgument("provider"), env.getArgument("configuration"), diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java index 9d4c2796eb..dfbae9e0ec 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java @@ -34,6 +34,8 @@ import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.service.auth.*; import io.cloudbeaver.service.auth.model.user.WebAuthProviderInfo; import io.cloudbeaver.service.security.SMUtils; +import io.cloudbeaver.utils.ServletAppUtils; +import jakarta.servlet.http.HttpServletRequest; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; @@ -42,6 +44,7 @@ import org.jkiss.dbeaver.model.auth.SMAuthInfo; import org.jkiss.dbeaver.model.auth.SMAuthStatus; import org.jkiss.dbeaver.model.auth.SMSessionExternal; import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor; +import org.jkiss.dbeaver.model.security.SMConstants; import org.jkiss.dbeaver.model.security.SMController; import org.jkiss.dbeaver.model.security.SMSubjectType; import org.jkiss.dbeaver.model.security.exception.SMTooManySessionsException; @@ -92,6 +95,7 @@ public class WebServiceAuthImpl implements DBWServiceAuth { @Override public WebAsyncAuthStatus federatedLogin( + @NotNull HttpServletRequest httpRequest, @NotNull WebSession webSession, @NotNull String providerId, @Nullable String providerConfigurationId, @@ -106,7 +110,10 @@ public class WebServiceAuthImpl implements DBWServiceAuth { throw new DBWebException("Provider '" + providerId + "' is not federated"); } try { - var smAuthInfo = initiateAuthentication(webSession, providerId, providerConfigurationId, Map.of(), forceSessionsLogout); + Map authParameters = new HashMap<>(); + authParameters.put(SMConstants.USER_ORIGIN, ServletAppUtils.getOriginFromRequestOrThrow(httpRequest)); + + var smAuthInfo = initiateAuthentication(webSession, providerId, providerConfigurationId, authParameters, forceSessionsLogout); if (smAuthInfo.getAuthStatus() != SMAuthStatus.IN_PROGRESS) { throw new DBWebException("Unexpected auth status: " + smAuthInfo.getAuthStatus()); } @@ -161,9 +168,7 @@ public class WebServiceAuthImpl implements DBWServiceAuth { if (authProviderDescriptor.isTrusted()) { throw new DBWebException(authProviderDescriptor.getLabel() + " not allowed for authorization via GQL API"); } - if (authParameters == null) { - authParameters = Map.of(); - } + SMController securityController = webSession.getSecurityController(); String currentSmSessionId = (webSession.getUser() == null || CBApplication.getInstance().isConfigurationMode()) ? null @@ -210,6 +215,7 @@ public class WebServiceAuthImpl implements DBWServiceAuth { @Override public WebLogoutInfo authLogout( + @NotNull HttpServletRequest httpRequest, @NotNull WebSession webSession, @Nullable String providerId, @Nullable String configurationId @@ -221,6 +227,7 @@ public class WebServiceAuthImpl implements DBWServiceAuth { List removedInfos = webSession.removeAuthInfo(providerId); List logoutUrls = new ArrayList<>(); var cbApp = CBApplication.getInstance(); + String origin = ServletAppUtils.getOriginFromRequestOrThrow(httpRequest); for (WebAuthInfo removedInfo : removedInfos) { if (removedInfo.getAuthProviderDescriptor() .getInstance() instanceof SMSignOutLinkProvider provider @@ -233,12 +240,15 @@ public class WebServiceAuthImpl implements DBWServiceAuth { continue; } String logoutUrl; + if (removedInfo.getAuthSession() instanceof SMSessionExternal externalSession) { logoutUrl = provider.getUserSignOutLink(providerConfig, - externalSession.getAuthParameters()); + externalSession.getAuthParameters(), origin + ); } else { logoutUrl = provider.getUserSignOutLink(providerConfig, - Map.of()); + Map.of(), origin + ); } if (CommonUtils.isNotEmpty(logoutUrl)) { logoutUrls.add(logoutUrl); @@ -286,9 +296,11 @@ public class WebServiceAuthImpl implements DBWServiceAuth { } @Override - public WebAuthProviderInfo[] getAuthProviders() { + public WebAuthProviderInfo[] getAuthProviders(@NotNull HttpServletRequest request) throws DBWebException { + String origin = ServletAppUtils.getOriginFromRequestOrThrow(request); return WebAuthProviderRegistry.getInstance().getAuthProviders() - .stream().map(WebAuthProviderInfo::new) + .stream() + .map(descriptor -> new WebAuthProviderInfo(descriptor, origin)) .toArray(WebAuthProviderInfo[]::new); } diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/model/user/WebAuthProviderInfo.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/model/user/WebAuthProviderInfo.java index 9b7a617075..1a8c503b7f 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/model/user/WebAuthProviderInfo.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/model/user/WebAuthProviderInfo.java @@ -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. @@ -42,9 +42,11 @@ public class WebAuthProviderInfo { @NotNull private final WebAuthProviderDescriptor descriptor; + private final String origin; - public WebAuthProviderInfo(@NotNull WebAuthProviderDescriptor descriptor) { + public WebAuthProviderInfo(@NotNull WebAuthProviderDescriptor descriptor, String origin) { this.descriptor = descriptor; + this.origin = origin; } public String getId() { @@ -109,7 +111,7 @@ public class WebAuthProviderInfo { List result = new ArrayList<>(); for (SMAuthProviderCustomConfiguration cfg : CBApplication.getInstance().getAppConfiguration().getAuthCustomConfigurations()) { if (!cfg.isDisabled() && getId().equals(cfg.getProvider())) { - result.add(new WebAuthProviderConfiguration(descriptor, cfg)); + result.add(new WebAuthProviderConfiguration(descriptor, cfg, origin)); } } return result; @@ -125,7 +127,7 @@ public class WebAuthProviderInfo { } public WebAuthProviderConfiguration getTemplateConfiguration() { - return new WebAuthProviderConfiguration(descriptor, TEMPLATE_CONFIG); + return new WebAuthProviderConfiguration(descriptor, TEMPLATE_CONFIG, "{origin}"); } @Override diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/rp/RPAuthProvider.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/rp/RPAuthProvider.java index 0c895857d8..dd62826fa0 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/rp/RPAuthProvider.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/rp/RPAuthProvider.java @@ -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. @@ -133,12 +133,20 @@ public class RPAuthProvider implements SMAuthProviderExternal, SMSign @NotNull @Override - public String getCommonSignOutLink(String id, @NotNull Map providerConfig) throws DBException { + public String getCommonSignOutLink( + @NotNull String providerId, + @NotNull Map providerConfig, + @NotNull String origin + ) throws DBException { return providerConfig.get(LOGOUT_URL) != null ? providerConfig.get(LOGOUT_URL).toString() : ""; } @Override - public String getUserSignOutLink(@NotNull SMAuthProviderCustomConfiguration providerConfig, @NotNull Map userCredentials) throws DBException { + public String getUserSignOutLink( + @NotNull SMAuthProviderCustomConfiguration providerConfig, + @NotNull Map userCredentials, + @NotNull String origin + ) throws DBException { return providerConfig.getParameters().get(LOGOUT_URL) != null ? providerConfig.getParameters().get(LOGOUT_URL).toString() : null; diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java index 6b8e7c3aa8..7f810ff612 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java @@ -39,6 +39,7 @@ import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.DBPConnectionInformation; import org.jkiss.dbeaver.model.DBPPage; import org.jkiss.dbeaver.model.auth.*; +import org.jkiss.dbeaver.model.data.json.JSONUtils; import org.jkiss.dbeaver.model.exec.DBCException; import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils; import org.jkiss.dbeaver.model.impl.jdbc.exec.JDBCTransaction; @@ -61,6 +62,7 @@ import org.jkiss.utils.CommonUtils; import org.jkiss.utils.SecurityUtils; import java.lang.reflect.Type; +import java.net.URI; import java.sql.*; import java.time.Instant; import java.time.LocalDateTime; @@ -1633,7 +1635,14 @@ public class CBEmbeddedSecurityController throw e; } } - + boolean isFederatedAuth = SMAuthProviderFederated.class.isAssignableFrom(authProviderInstance.getClass()); + if (isFederatedAuth) { + String userOrigin = JSONUtils.getString(userCredentials, SMConstants.USER_ORIGIN); + if (CommonUtils.isEmpty(userOrigin)) { + throw new SMException("User origin not found in authentication data"); + } + filteredUserCreds.put(SMConstants.USER_ORIGIN, modifyOrigin(userOrigin)); + } authAttemptId = createNewAuthAttempt( SMAuthStatus.IN_PROGRESS, authProviderId, @@ -1647,15 +1656,21 @@ public class CBEmbeddedSecurityController forceSessionsLogout ); - if (SMAuthProviderFederated.class.isAssignableFrom(authProviderInstance.getClass())) { + if (isFederatedAuth) { + String userOrigin = JSONUtils.getString(filteredUserCreds, SMConstants.USER_ORIGIN); //async auth var authProviderFederated = (SMAuthProviderFederated) authProviderInstance; - String signInLink = buildRedirectLink(authProviderFederated.getSignInLink(authProviderConfigurationId), - authAttemptId); + String signInLink = buildRedirectLink( + authProviderFederated.getSignInLink(authProviderConfigurationId, userOrigin), + authAttemptId + ); String signOutLink = authProviderFederated.getCommonSignOutLink(authProviderConfigurationId, - providerConfig.getParameters()); - Map authData = Map.of(new SMAuthConfigurationReference(authProviderId, - authProviderConfigurationId), filteredUserCreds); + providerConfig.getParameters(), userOrigin + ); + Map authData = Map.of( + new SMAuthConfigurationReference(authProviderId, authProviderConfigurationId), + filteredUserCreds + ); return SMAuthInfo.inProgress( authAttemptId, signInLink, @@ -1689,6 +1704,23 @@ public class CBEmbeddedSecurityController } } + @NotNull + protected String modifyOrigin(@NotNull String origin) { + StringBuilder finalOrigin = new StringBuilder(); + URI uri = URI.create(origin); + finalOrigin.append(uri.getScheme()) + .append("://") + .append(uri.getHost()); + if (uri.getPort() > 0 && application.getServerPort() != uri.getPort()) { + finalOrigin.append(":").append(application.getServerPort()); + } else { + return origin; + } + finalOrigin.append(uri.getPath()); + + return finalOrigin.toString(); + } + private Map filterSecuredUserData( Map userIdentifyingCredentials, WebAuthProviderDescriptor authProviderDescriptor @@ -1958,13 +1990,18 @@ public class CBEmbeddedSecurityController WebAuthProviderDescriptor authProviderDescriptor = getAuthProvider(authProviderId); var authProviderInstance = authProviderDescriptor.getInstance(); if (authProviderInstance instanceof SMAuthProviderFederated providerFederated) { - signInLink = buildRedirectLink(providerFederated.getRedirectLink( - authProviderConfiguration, - Map.of()), authId); - signOutLink = providerFederated.getUserSignOutLink( - application.getAuthConfiguration() - .getAuthProviderConfiguration(authProviderConfiguration), - authProviderData); + String userOrigin = JSONUtils.getString(authProviderData, SMConstants.USER_ORIGIN); + if(CommonUtils.isNotEmpty(userOrigin)){ + signInLink = buildRedirectLink( + providerFederated.getRedirectLink(authProviderConfiguration, Map.of(), userOrigin), + authId + ); + signOutLink = providerFederated.getUserSignOutLink( + application.getAuthConfiguration() + .getAuthProviderConfiguration(authProviderConfiguration), + authProviderData, userOrigin + ); + } } } @@ -3288,7 +3325,7 @@ public class CBEmbeddedSecurityController return authProvider; } - private String buildRedirectLink(String originalLink, String authId) { + private String buildRedirectLink(@NotNull String originalLink, @NotNull String authId) { return originalLink + "?authId=" + authId; }