From b0d323914a84b17717d6f53c1c6c8f3000289e93 Mon Sep 17 00:00:00 2001 From: Ainur <59531286+yagudin10@users.noreply.github.com> Date: Tue, 15 Mar 2022 12:20:55 +0300 Subject: [PATCH] CB-1546 reverse proxy header auth (#709) --- .../auth/provider/local/LocalAuthSession.java | 2 +- .../io/cloudbeaver/server/CBAppConfig.java | 10 ++ .../io.cloudbeaver.service.auth/plugin.xml | 3 + .../service/auth/RPSessionHandler.java | 101 ++++++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/RPSessionHandler.java diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/auth/provider/local/LocalAuthSession.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/auth/provider/local/LocalAuthSession.java index 266f0b5278..a88bc75403 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/auth/provider/local/LocalAuthSession.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/auth/provider/local/LocalAuthSession.java @@ -33,7 +33,7 @@ public class LocalAuthSession implements SMSession { private final SMSession webSession; private final String userId; - LocalAuthSession(SMSession webSession, String userId) { + public LocalAuthSession(SMSession webSession, String userId) { this.webSession = webSession; this.userId = userId; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java index 475dd6c94d..ee9553eb4f 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java @@ -49,6 +49,7 @@ public class CBAppConfig implements WebAppConfiguration { private boolean supportsCustomConnections; private boolean supportsConnectionBrowser; private boolean supportsUserWorkspaces; + private boolean supportsReverseProxyAuth; private boolean publicCredentialsSaveEnabled; private boolean adminCredentialsSaveEnabled; @@ -84,6 +85,7 @@ public class CBAppConfig implements WebAppConfiguration { this.plugins = new LinkedHashMap<>(); this.authConfiguration = new LinkedHashMap<>(); this.resourceQuotas = new LinkedHashMap<>(); + this.supportsReverseProxyAuth = false; } public CBAppConfig(CBAppConfig src) { @@ -105,6 +107,7 @@ public class CBAppConfig implements WebAppConfiguration { this.plugins = new LinkedHashMap<>(src.plugins); this.authConfiguration = new LinkedHashMap<>(src.authConfiguration); this.resourceQuotas = new LinkedHashMap<>(src.resourceQuotas); + this.supportsReverseProxyAuth = src.supportsReverseProxyAuth; } public boolean isAnonymousAccessEnabled() { @@ -328,4 +331,11 @@ public class CBAppConfig implements WebAppConfiguration { } } + //////////////////////////////////////////// + // Reverse proxy auth + + public boolean isSupportsReverseProxyAuth() { + return supportsReverseProxyAuth; + } + } diff --git a/server/bundles/io.cloudbeaver.service.auth/plugin.xml b/server/bundles/io.cloudbeaver.service.auth/plugin.xml index 88c2b42c37..2c07a5ec6e 100644 --- a/server/bundles/io.cloudbeaver.service.auth/plugin.xml +++ b/server/bundles/io.cloudbeaver.service.auth/plugin.xml @@ -19,6 +19,9 @@ + + + diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/RPSessionHandler.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/RPSessionHandler.java new file mode 100644 index 0000000000..f970099a5c --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/RPSessionHandler.java @@ -0,0 +1,101 @@ +package io.cloudbeaver.service.auth; + +import io.cloudbeaver.DBWUserIdentity; +import io.cloudbeaver.DBWebException; +import io.cloudbeaver.auth.provider.local.LocalAuthSession; +import io.cloudbeaver.model.session.WebAuthInfo; +import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.model.user.WebUser; +import io.cloudbeaver.server.CBApplication; +import io.cloudbeaver.server.CBPlatform; +import io.cloudbeaver.service.DBWSessionHandler; +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.model.auth.SMSession; +import org.jkiss.dbeaver.model.security.SMController; +import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; +import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; +import org.jkiss.utils.CommonUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.Map; + +public class RPSessionHandler implements DBWSessionHandler { + + public static final String X_USER = "X-User"; + public static final String X_ROLE = "X-Role"; + public static final String AUTH_PROVIDER = "local"; + + @Override + public boolean handleSessionOpen(WebSession webSession, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException { + boolean configMode = CBApplication.getInstance().isConfigurationMode(); + //checks if the app is not in configuration mode and reverse proxy auth is enabled in the config file + if (!configMode && CBApplication.getInstance().getAppConfiguration().isSupportsReverseProxyAuth()) { + reverseProxyAuthentication(request, webSession); + } + return false; + } + public boolean reverseProxyAuthentication(@NotNull HttpServletRequest request, @NotNull WebSession webSession) throws DBWebException { + SMController securityController = CBPlatform.getInstance().getApplication().getSecurityController(); + AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(AUTH_PROVIDER); + + String userName = request.getHeader(X_USER); + String roles = request.getHeader(X_ROLE); + String[] userRoles = roles.split("\\|"); + WebUser curUser = webSession.getUser(); + SMSession authSession; + if (userName != null) { + try { + WebUser user = securityController.getUserById(userName); + Map credentials = new HashMap<>(); + credentials.put("user", userName); + var adminSecurityController = CBPlatform.getInstance().getApplication().getAdminSecurityController(); + if (user == null) { + // User doesn't exist. We can create new user automatically + // Create new user + curUser = new WebUser(userName); + adminSecurityController.createUser(curUser); + + String defaultRoleName = CBPlatform.getInstance().getApplication().getAppConfiguration().getDefaultUserRole(); + if (userRoles.length == 0) { + userRoles = new String[]{defaultRoleName}; + } + // We need to associate new credentials with active user + securityController.setUserCredentials(userName, authProvider, credentials); + } + adminSecurityController.setUserRoles(userName, userRoles, userName); + user = curUser; + if (user == null) { + user = new WebUser(userName); + } + DBWUserIdentity userIdentity = new DBWUserIdentity(userName, userName); + + if (CommonUtils.isEmpty(user.getDisplayName())) { + user.setDisplayName(userIdentity.getDisplayName()); + } + authSession = new LocalAuthSession(webSession, userName); + + WebAuthInfo authInfo = new WebAuthInfo( + webSession, + user, + authProvider, + userIdentity, + authSession, + OffsetDateTime.now()); + authInfo.setMessage("Authenticated with " + authProvider.getLabel() + " provider"); + webSession.addAuthInfo(authInfo); + } catch (Exception e) { + throw new DBWebException("Error", e); + } + } + return false; + } + @Override + public boolean handleSessionClose(WebSession webSession) throws DBException, IOException { + return false; + } +}