diff --git a/README.md b/README.md index 3e42e01cbb..95fbf24601 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,12 @@ You can see live demo of CloudBeaver here: https://demo.cloudbeaver.io ## Changelog +### CloudBeaver 22.2.3 - 2022-10-14 +- Users can specify the connection for the saved script in the Resource Manager. This connection will be selected by default when a user opens this script. +- The connection configuration through URL has been added for generic drivers. +- User access information can be stored in an SQL Server database. +- Different bugs have been fixed. + ### CloudBeaver 22.2.2 - 2022-10-10 - Administrators now: - have permission to create connections in both projects, Shared and Private, when it’s restricted for other users, diff --git a/config/core/initial-data.conf b/config/core/initial-data.conf index a33187160f..fe8f9db507 100644 --- a/config/core/initial-data.conf +++ b/config/core/initial-data.conf @@ -1,13 +1,13 @@ { teams: [ { - teamId: "admin", + subjectId: "admin", name: "Admin", description: "Administrative access. Has all permissions.", permissions: [ "public", "admin" ] }, { - teamId: "user", + subjectId: "user", name: "User", description: "Standard user", permissions: [ "public" ] diff --git a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF index d3f160a993..13faa28d65 100644 --- a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF @@ -18,7 +18,6 @@ Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport, Export-Package: io.cloudbeaver, io.cloudbeaver.auth, io.cloudbeaver.auth.provider, - io.cloudbeaver.auth.provider.fa, io.cloudbeaver.auth.provider.local, io.cloudbeaver.events, io.cloudbeaver.model, diff --git a/server/bundles/io.cloudbeaver.model/plugin.xml b/server/bundles/io.cloudbeaver.model/plugin.xml index 1bbc06fb18..96847f47d7 100644 --- a/server/bundles/io.cloudbeaver.model/plugin.xml +++ b/server/bundles/io.cloudbeaver.model/plugin.xml @@ -3,5 +3,8 @@ + + + diff --git a/server/bundles/io.cloudbeaver.server/schema/io.cloudbeaver.feature.exsd b/server/bundles/io.cloudbeaver.model/schema/io.cloudbeaver.feature.exsd similarity index 87% rename from server/bundles/io.cloudbeaver.server/schema/io.cloudbeaver.feature.exsd rename to server/bundles/io.cloudbeaver.model/schema/io.cloudbeaver.feature.exsd index 69cfc62e5c..c49cec3881 100644 --- a/server/bundles/io.cloudbeaver.server/schema/io.cloudbeaver.feature.exsd +++ b/server/bundles/io.cloudbeaver.model/schema/io.cloudbeaver.feature.exsd @@ -2,7 +2,7 @@ - + Web feature diff --git a/server/bundles/io.cloudbeaver.server/schema/io.cloudbeaver.valueSerializer.exsd b/server/bundles/io.cloudbeaver.model/schema/io.cloudbeaver.valueSerializer.exsd similarity index 100% rename from server/bundles/io.cloudbeaver.server/schema/io.cloudbeaver.valueSerializer.exsd rename to server/bundles/io.cloudbeaver.model/schema/io.cloudbeaver.valueSerializer.exsd diff --git a/server/bundles/io.cloudbeaver.model/schema/org.jkiss.dbeaver.authProvider.exsd b/server/bundles/io.cloudbeaver.model/schema/org.jkiss.dbeaver.authProvider.exsd new file mode 100644 index 0000000000..222af0fe9d --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/schema/org.jkiss.dbeaver.authProvider.exsd @@ -0,0 +1,47 @@ + + + + + + + + DBeaver auth provider + + + + + + + + + + + + + + + Data source auth model description + + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWUserIdentity.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWUserIdentity.java index de76364aeb..498b5fffbe 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWUserIdentity.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWUserIdentity.java @@ -17,8 +17,9 @@ package io.cloudbeaver; import org.jkiss.code.NotNull; +import org.jkiss.code.Nullable; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -30,13 +31,21 @@ public class DBWUserIdentity { @NotNull private final String displayName; - private final Map metaParameters = new HashMap<>(); + private final Map metaParameters = new LinkedHashMap<>(); + @Nullable + private String providedUserRole; + @Nullable + private String[] providedTeamIds; public DBWUserIdentity(@NotNull String id, @NotNull String displayName) { this(id, displayName, Map.of()); } - public DBWUserIdentity(@NotNull String id, @NotNull String displayName, @NotNull Map metaParameters) { + public DBWUserIdentity( + @NotNull String id, + @NotNull String displayName, + @NotNull Map metaParameters + ) { this.id = id; this.displayName = displayName; this.metaParameters.putAll(metaParameters); @@ -56,4 +65,30 @@ public class DBWUserIdentity { public Map getMetaParameters() { return Map.copyOf(metaParameters); } + + public void setMetaParameter(@NotNull String name, @Nullable String value) { + if (value == null) { + metaParameters.remove(name); + } else { + metaParameters.put(name, value); + } + } + + @Nullable + public String getProvidedUserRole() { + return providedUserRole; + } + + public void setProvidedUserRole(@Nullable String providedUserRole) { + this.providedUserRole = providedUserRole; + } + + @Nullable + public String[] getProvidedTeamIds() { + return providedTeamIds; + } + + public void setProvidedTeamIds(@Nullable String[] providedTeamIds) { + this.providedTeamIds = providedTeamIds; + } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebDataSourceRegistryProxy.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebDataSourceRegistryProxy.java index 2bc52588d3..7c781afdd2 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebDataSourceRegistryProxy.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/WebDataSourceRegistryProxy.java @@ -41,7 +41,7 @@ public class WebDataSourceRegistryProxy implements DBPDataSourceRegistry, DataSo @Override public DBPDataSourceContainer getDataSource(String id) { DBPDataSourceContainer dataSource = dataSourceRegistry.getDataSource(id); - if (dataSourceFilter != null && !dataSourceFilter.filter(dataSource)) { + if (dataSource == null || dataSourceFilter != null && !dataSourceFilter.filter(dataSource)) { return null; } return dataSource; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserCredentials.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderAssigner.java similarity index 54% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserCredentials.java rename to server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderAssigner.java index 9b769d2d85..6bd08092b8 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserCredentials.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderAssigner.java @@ -14,11 +14,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.cloudbeaver.model.user; +package io.cloudbeaver.auth; + +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; + +import java.util.Map; /** - * Web user. + * Auth + * Authenticates user using external user identity */ -public class WebUserCredentials { +public interface SMAuthProviderAssigner { + + @NotNull + SMAutoAssign detectAutoAssignments( + @NotNull DBRProgressMonitor monitor, + @NotNull Map providerConfig, + @NotNull Map authParameters + ) throws DBException; + + String getExternalTeamIdMetadataFieldName(); } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderExternal.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderExternal.java index 6bae9f9469..a68d5d7ac4 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderExternal.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderExternal.java @@ -50,7 +50,7 @@ public interface SMAuthProviderExternal extends DBWUserIdentity getUserIdentity( @NotNull DBRProgressMonitor monitor, @NotNull Map providerConfig, - @NotNull Map credentials) throws DBException; + @NotNull Map authParameters) throws DBException; /** * Get specified user details. diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMWAuthProviderFederated.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderFederated.java similarity index 97% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMWAuthProviderFederated.java rename to server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderFederated.java index f2a42ac129..c6d7044edb 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMWAuthProviderFederated.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAuthProviderFederated.java @@ -26,7 +26,7 @@ import java.util.Map; * Federated auth provider. * Provides links to external auth resource */ -public interface SMWAuthProviderFederated { +public interface SMAuthProviderFederated { /** * Returns new identifying credentials which can be used to find/create user in database diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAutoAssign.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAutoAssign.java new file mode 100644 index 0000000000..f697fae7ff --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/SMAutoAssign.java @@ -0,0 +1,50 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2022 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.auth; + +import java.util.ArrayList; +import java.util.List; + +public class SMAutoAssign { + private String authRole; + private List externalTeamIds = new ArrayList<>(); + + public SMAutoAssign() { + } + + public SMAutoAssign(String authRole, List externalRolesIds) { + this.authRole = authRole; + this.externalTeamIds = externalRolesIds; + } + + public String getAuthRole() { + return authRole; + } + + public void setAuthRole(String authRole) { + this.authRole = authRole; + } + + public List getExternalTeamIds() { + return externalTeamIds; + } + + public void addExternalTeamId(String externalRoleId) { + this.externalTeamIds.add(externalRoleId); + } +} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/provider/fa/AbstractSessionFederated.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/provider/fa/AbstractSessionFederated.java deleted file mode 100644 index fa81030504..0000000000 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/provider/fa/AbstractSessionFederated.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2022 DBeaver Corp - * - * All Rights Reserved. - * - * NOTICE: All information contained herein is, and remains - * the property of DBeaver Corp and its suppliers, if any. - * The intellectual and technical concepts contained - * herein are proprietary to DBeaver Corp and its suppliers - * and may be covered by U.S. and Foreign Patents, - * patents in process, and are protected by trade secret or copyright law. - * Dissemination of this information or reproduction of this material - * is strictly forbidden unless prior written permission is obtained - * from DBeaver Corp. - */ - -package io.cloudbeaver.auth.provider.fa; - -import org.jkiss.code.NotNull; -import org.jkiss.dbeaver.model.auth.*; - -import java.time.LocalDateTime; -import java.util.Map; - -public abstract class AbstractSessionFederated implements SMSessionFederated { - - @NotNull - protected final Map authParameters; - @NotNull - protected final SMSession parentSession; - @NotNull - protected final SMAuthSpace space; - - protected AbstractSessionFederated(@NotNull SMSession parentSession, @NotNull SMAuthSpace space, @NotNull Map authParameters) { - this.parentSession = parentSession; - this.space = space; - this.authParameters = authParameters; - } - - @NotNull - @Override - public SMAuthSpace getSessionSpace() { - return space; - } - - @NotNull - @Override - public SMSessionContext getSessionContext() { - return this.parentSession.getSessionContext(); - } - - @Override - public SMSessionPrincipal getSessionPrincipal() { - return parentSession.getSessionPrincipal(); - } - - @NotNull - @Override - public LocalDateTime getSessionStart() { - return parentSession.getSessionStart(); - } - - @Override - public void close() { - // do nothing - } - -} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/provider/fa/FederatedUserDetails.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/provider/fa/FederatedUserDetails.java deleted file mode 100644 index b45a2c398a..0000000000 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/auth/provider/fa/FederatedUserDetails.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2022 DBeaver Corp - * - * All Rights Reserved. - * - * NOTICE: All information contained herein is, and remains - * the property of DBeaver Corp and its suppliers, if any. - * The intellectual and technical concepts contained - * herein are proprietary to DBeaver Corp and its suppliers - * and may be covered by U.S. and Foreign Patents, - * patents in process, and are protected by trade secret or copyright law. - * Dissemination of this information or reproduction of this material - * is strictly forbidden unless prior written permission is obtained - * from DBeaver Corp. - */ - -package io.cloudbeaver.auth.provider.fa; - -import io.cloudbeaver.model.user.WebUser; -import org.jkiss.code.NotNull; -import org.jkiss.dbeaver.model.DBPObject; -import org.jkiss.dbeaver.model.meta.Property; - -public class FederatedUserDetails implements DBPObject { - - @NotNull - private AbstractSessionFederated session; - @NotNull - private WebUser user; - - public FederatedUserDetails(@NotNull AbstractSessionFederated session, @NotNull WebUser user) { - this.session = session; - this.user = user; - } - - @NotNull - public AbstractSessionFederated getSession() { - return session; - } - - @Property - public String getEmail() { - return user.getUserId(); - } - -} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseAuthWebAppConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseAuthWebAppConfiguration.java index ae5b7db8f2..567c05e7b8 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseAuthWebAppConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseAuthWebAppConfiguration.java @@ -19,11 +19,11 @@ package io.cloudbeaver.model.app; import com.google.gson.annotations.Expose; import io.cloudbeaver.auth.provider.local.LocalAuthProviderConstants; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; import org.jkiss.utils.ArrayUtils; import java.util.*; @@ -65,8 +65,8 @@ public abstract class BaseAuthWebAppConfiguration extends BaseWebAppConfiguratio public String[] getEnabledAuthProviders() { if (enabledAuthProviders == null) { // No config - enable all providers (+backward compatibility) - return AuthProviderRegistry.getInstance().getAuthProviders() - .stream().map(AuthProviderDescriptor::getId).toArray(String[]::new); + return WebAuthProviderRegistry.getInstance().getAuthProviders() + .stream().map(WebAuthProviderDescriptor::getId).toArray(String[]::new); } return enabledAuthProviders; } @@ -78,7 +78,7 @@ public abstract class BaseAuthWebAppConfiguration extends BaseWebAppConfiguratio @Override public boolean isAuthProviderEnabled(String id) { - var authProviderDescriptor = AuthProviderRegistry.getInstance().getAuthProvider(id); + var authProviderDescriptor = WebAuthProviderRegistry.getInstance().getAuthProvider(id); if (authProviderDescriptor == null) { return false; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java index 06663c190d..a651608295 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java @@ -17,16 +17,16 @@ package io.cloudbeaver.model.session; import io.cloudbeaver.DBWUserIdentity; -import io.cloudbeaver.model.user.WebAuthProviderConfiguration; import io.cloudbeaver.model.user.WebUser; import io.cloudbeaver.model.user.WebUserOriginInfo; +import io.cloudbeaver.registry.WebAuthProviderConfiguration; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.auth.SMAuthProvider; import org.jkiss.dbeaver.model.auth.SMSession; import org.jkiss.dbeaver.model.auth.SMSessionPrincipal; import org.jkiss.dbeaver.model.meta.Property; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; import java.time.OffsetDateTime; import java.util.Map; @@ -40,7 +40,7 @@ public class WebAuthInfo implements SMSessionPrincipal { private final WebSession session; private final WebUser user; - private final AuthProviderDescriptor authProvider; + private final WebAuthProviderDescriptor authProvider; private WebAuthProviderConfiguration authProviderConfiguration; private SMSession authSession; private final OffsetDateTime loginTime; @@ -52,7 +52,7 @@ public class WebAuthInfo implements SMSessionPrincipal { public WebAuthInfo( @NotNull WebSession session, @NotNull WebUser user, - @NotNull AuthProviderDescriptor authProvider, + @NotNull WebAuthProviderDescriptor authProvider, @NotNull DBWUserIdentity userIdentity, @NotNull SMSession authSession, @NotNull OffsetDateTime loginTime) { @@ -112,7 +112,7 @@ public class WebAuthInfo implements SMSessionPrincipal { return userIdentity; } - public AuthProviderDescriptor getAuthProviderDescriptor() { + public WebAuthProviderDescriptor getAuthProviderDescriptor() { return authProvider; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index 99f2d8d325..7d203fb14b 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -329,6 +329,10 @@ public class WebSession extends AbstractSessionPersistent private void loadProjects() { WebUser user = userContext.getUser(); + if (user == null && DBWorkbench.isDistributed()) { + // No anonymous mode in distributed apps + return; + } refreshAccessibleConnectionIds(); try { RMController controller = application.getResourceController(this, getSecurityController()); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionAuthProcessor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionAuthProcessor.java index d8eeedb840..d731b6bbdd 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionAuthProcessor.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionAuthProcessor.java @@ -23,6 +23,8 @@ import io.cloudbeaver.DBWebException; import io.cloudbeaver.auth.SMAuthProviderExternal; import io.cloudbeaver.model.app.WebAuthConfiguration; import io.cloudbeaver.model.user.WebUser; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import io.cloudbeaver.utils.WebAppUtils; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.DBException; @@ -31,8 +33,6 @@ import org.jkiss.dbeaver.model.auth.SMAuthInfo; import org.jkiss.dbeaver.model.auth.SMAuthProvider; import org.jkiss.dbeaver.model.auth.SMSession; import org.jkiss.dbeaver.model.exec.DBCException; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; import org.jkiss.utils.CommonUtils; import java.time.OffsetDateTime; @@ -192,8 +192,8 @@ public class WebSessionAuthProcessor { } } - private AuthProviderDescriptor getAuthProvider(String providerId) throws DBWebException { - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(providerId); + private WebAuthProviderDescriptor getAuthProvider(String providerId) throws DBWebException { + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(providerId); if (authProvider == null) { throw new DBWebException("Invalid auth provider '" + providerId + "'"); } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserConstants.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserConstants.java deleted file mode 100644 index a792f182b1..0000000000 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserConstants.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2022 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.user; - -public interface WebUserConstants { - String META_FIRST_NAME = "firstName"; - String META_LAST_NAME = "lastName"; -} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserOriginInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserOriginInfo.java index 333066c37b..ef02b350e3 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserOriginInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserOriginInfo.java @@ -22,6 +22,7 @@ import io.cloudbeaver.model.WebObjectOrigin; import io.cloudbeaver.model.WebPropertyInfo; import io.cloudbeaver.model.session.WebAuthInfo; import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; import io.cloudbeaver.utils.WebCommonUtils; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; @@ -31,7 +32,6 @@ import org.jkiss.dbeaver.model.DBPObject; import org.jkiss.dbeaver.model.auth.SMAuthProvider; import org.jkiss.dbeaver.model.auth.SMSession; import org.jkiss.dbeaver.model.meta.Property; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -48,10 +48,10 @@ public class WebUserOriginInfo implements WebObjectOrigin { private final WebSession session; private final WebUser user; @NotNull - private final AuthProviderDescriptor authProvider; + private final WebAuthProviderDescriptor authProvider; private boolean selfIdentity; - public WebUserOriginInfo(WebSession session, WebUser user, @NotNull AuthProviderDescriptor authProvider, boolean selfIdentity) { + public WebUserOriginInfo(WebSession session, WebUser user, @NotNull WebAuthProviderDescriptor authProvider, boolean selfIdentity) { this.session = session; this.user = user; this.authProvider = authProvider; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebAuthProviderConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderConfiguration.java similarity index 72% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebAuthProviderConfiguration.java rename to server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderConfiguration.java index 411dc322fd..6e49b819cb 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebAuthProviderConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderConfiguration.java @@ -14,29 +14,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.cloudbeaver.model.user; +package io.cloudbeaver.registry; -import io.cloudbeaver.auth.SMWAuthProviderFederated; +import io.cloudbeaver.auth.SMAuthProviderFederated; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.auth.SMAuthProvider; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; import java.util.Map; /** - * WebAuthProviderInfo. + * WebAuthProviderConfiguration. */ public class WebAuthProviderConfiguration { private static final Log log = Log.getLog(WebAuthProviderConfiguration.class); - private final AuthProviderDescriptor providerDescriptor; + private final WebAuthProviderDescriptor providerDescriptor; private final SMAuthProviderCustomConfiguration config; - public WebAuthProviderConfiguration(AuthProviderDescriptor providerDescriptor, SMAuthProviderCustomConfiguration config) { + public WebAuthProviderConfiguration(WebAuthProviderDescriptor providerDescriptor, SMAuthProviderCustomConfiguration config) { this.providerDescriptor = providerDescriptor; this.config = config; } @@ -72,25 +71,25 @@ public class WebAuthProviderConfiguration { @Property public String getSignInLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); - return instance instanceof SMWAuthProviderFederated ? ((SMWAuthProviderFederated) instance).getSignInLink(getId(), config.getParameters()) : null; + return instance instanceof SMAuthProviderFederated ? ((SMAuthProviderFederated) instance).getSignInLink(getId(), config.getParameters()) : null; } @Property public String getSignOutLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); - return instance instanceof SMWAuthProviderFederated ? ((SMWAuthProviderFederated) instance).getSignOutLink(getId(), config.getParameters()) : null; + return instance instanceof SMAuthProviderFederated ? ((SMAuthProviderFederated) instance).getSignOutLink(getId(), config.getParameters()) : null; } @Property public String getRedirectLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); - return instance instanceof SMWAuthProviderFederated ? ((SMWAuthProviderFederated) instance).getRedirectLink(getId(), config.getParameters()) : null; + return instance instanceof SMAuthProviderFederated ? ((SMAuthProviderFederated) instance).getRedirectLink(getId(), config.getParameters()) : null; } @Property public String getMetadataLink() throws DBException { SMAuthProvider instance = providerDescriptor.getInstance(); - return instance instanceof SMWAuthProviderFederated ? ((SMWAuthProviderFederated) instance).getMetadataLink(getId(), config.getParameters()) : null; + return instance instanceof SMAuthProviderFederated ? ((SMAuthProviderFederated) instance).getMetadataLink(getId(), config.getParameters()) : null; } @Override diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java new file mode 100644 index 0000000000..a6c46bebc1 --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java @@ -0,0 +1,189 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2022 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.registry; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.jkiss.code.NotNull; +import org.jkiss.code.Nullable; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.DBPImage; +import org.jkiss.dbeaver.model.auth.AuthPropertyDescriptor; +import org.jkiss.dbeaver.model.auth.SMAuthProvider; +import org.jkiss.dbeaver.model.impl.AbstractDescriptor; +import org.jkiss.dbeaver.model.impl.PropertyDescriptor; +import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor; +import org.jkiss.dbeaver.model.security.SMAuthCredentialsProfile; +import org.jkiss.dbeaver.model.security.SMAuthProviderDescriptor; +import org.jkiss.dbeaver.model.security.SMSubjectType; +import org.jkiss.utils.ArrayUtils; +import org.jkiss.utils.CommonUtils; + +import java.util.*; + +/** + * Auth provider descriptor + */ +public class WebAuthProviderDescriptor extends AbstractDescriptor { + + public static final String EXTENSION_ID = "org.jkiss.dbeaver.auth.provider"; //$NON-NLS-1$ + private static final Log log = Log.getLog(WebAuthProviderDescriptor.class); + + private final IConfigurationElement cfg; + + private final ObjectType implType; + private final Map> metaProperties = new HashMap<>(); + private SMAuthProvider instance; + private final DBPImage icon; + private final Map configurationParameters = new LinkedHashMap<>(); + private final List credentialProfiles = new ArrayList<>(); + private final boolean configurable; + private final boolean trusted; + private final String[] requiredFeatures; + + public WebAuthProviderDescriptor(IConfigurationElement cfg) { + super(cfg); + this.cfg = cfg; + this.implType = new ObjectType(cfg, "class"); + this.icon = iconToImage(cfg.getAttribute("icon")); + this.configurable = CommonUtils.toBoolean(cfg.getAttribute("configurable")); + this.trusted = CommonUtils.toBoolean(cfg.getAttribute("trusted")); + + for (IConfigurationElement cfgElement : cfg.getChildren("configuration")) { + for (IConfigurationElement propGroup : ArrayUtils.safeArray(cfgElement.getChildren(PropertyDescriptor.TAG_PROPERTY_GROUP))) { + String category = propGroup.getAttribute(PropertyDescriptor.ATTR_LABEL); + IConfigurationElement[] propElements = propGroup.getChildren(PropertyDescriptor.TAG_PROPERTY); + for (IConfigurationElement prop : propElements) { + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(category, prop); + configurationParameters.put(CommonUtils.toString(propertyDescriptor.getId()), propertyDescriptor); + } + } + } + for (IConfigurationElement credElement : cfg.getChildren("credentials")) { + credentialProfiles.add(new SMAuthCredentialsProfile(credElement)); + } + for (IConfigurationElement mpElement : cfg.getChildren("metaProperties")) { + SMSubjectType subjectType = CommonUtils.valueOf(SMSubjectType.class, mpElement.getAttribute("type"), SMSubjectType.user); + List metaProps = new ArrayList<>(); + for (IConfigurationElement propGroup : ArrayUtils.safeArray(mpElement.getChildren(PropertyDescriptor.TAG_PROPERTY_GROUP))) { + metaProps.addAll(PropertyDescriptor.extractProperties(propGroup)); + } + metaProperties.put(subjectType, metaProps); + } + + String rfList = cfg.getAttribute("requiredFeatures"); + if (!CommonUtils.isEmpty(rfList)) { + requiredFeatures = rfList.split(","); + } else { + requiredFeatures = null; + } + } + + @NotNull + public String getId() { + return cfg.getAttribute("id"); + } + + public String getLabel() { + return cfg.getAttribute("label"); + } + + public String getDescription() { + return cfg.getAttribute("description"); + } + + public DBPImage getIcon() { + return icon; + } + + public boolean isConfigurable() { + return configurable; + } + + public boolean isTrusted() { + return trusted; + } + + public List getConfigurationParameters() { + return new ArrayList<>(configurationParameters.values()); + } + + public List getCredentialProfiles() { + return new ArrayList<>(credentialProfiles); + } + + public List getCredentialParameters(String[] propNames) { + if (credentialProfiles.size() > 1) { + for (SMAuthCredentialsProfile profile : credentialProfiles) { + if (profile.getCredentialParameters().size() == propNames.length) { + boolean matches = true; + for (String paramName : propNames) { + if (profile.getCredentialParameter(paramName) == null) { + matches = false; + break; + } + } + if (matches) { + return profile.getCredentialParameters(); + } + } + } + } + return credentialProfiles.get(0).getCredentialParameters(); + } + + @NotNull + public SMAuthProvider getInstance() { + if (instance == null) { + try { + instance = implType.createInstance(SMAuthProvider.class); + } catch (DBException e) { + throw new IllegalStateException("Can not instantiate auth provider '" + implType.getImplName() + "'", e); + } + } + return instance; + } + + public String[] getRequiredFeatures() { + return requiredFeatures; + } + + @Override + public String toString() { + return getId(); + } + + public SMAuthProviderDescriptor createDescriptorBean() { + SMAuthProviderDescriptor smInfo = new SMAuthProviderDescriptor(); + smInfo.setId(this.getId()); + smInfo.setLabel(this.getLabel()); + smInfo.setDescription(this.getDescription()); + smInfo.setCredentialProfiles(this.getCredentialProfiles()); + + if (this.icon != null) { + smInfo.setIcon(icon.getLocation()); + } + + return smInfo; + } + + @Nullable + public List getMetaProperties(SMSubjectType subjectType) { + return metaProperties.get(subjectType); + } + +} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderRegistry.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderRegistry.java new file mode 100644 index 0000000000..3aba8bcfc0 --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderRegistry.java @@ -0,0 +1,85 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2022 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.registry; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.Platform; +import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.registry.RegistryConstants; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class WebAuthProviderRegistry { + + private static final Log log = Log.getLog(WebAuthProviderRegistry.class); + + private static final String TAG_AUTH_PROVIDER = "authProvider"; //$NON-NLS-1$ + private static final String TAG_AUTH_PROVIDER_DISABLE = "authProviderDisable"; //$NON-NLS-1$ + + private static WebAuthProviderRegistry instance = null; + + public synchronized static WebAuthProviderRegistry getInstance() { + if (instance == null) { + instance = new WebAuthProviderRegistry(); + instance.loadExtensions(Platform.getExtensionRegistry()); + } + return instance; + } + + private final Map authProviders = new LinkedHashMap<>(); + + private WebAuthProviderRegistry() { + } + + private void loadExtensions(IExtensionRegistry registry) { + { + IConfigurationElement[] extConfigs = registry.getConfigurationElementsFor(WebAuthProviderDescriptor.EXTENSION_ID); + for (IConfigurationElement ext : extConfigs) { + // Load webServices + if (TAG_AUTH_PROVIDER.equals(ext.getName())) { + WebAuthProviderDescriptor providerDescriptor = new WebAuthProviderDescriptor(ext); + this.authProviders.put(providerDescriptor.getId(), providerDescriptor); + } + } + + for (IConfigurationElement ext : extConfigs) { + // Disable auth providers + if (TAG_AUTH_PROVIDER_DISABLE.equals(ext.getName())) { + String providerId = ext.getAttribute(RegistryConstants.ATTR_ID); + if (!this.authProviders.containsKey(providerId)) { + log.warn("Can't disable auth provider '" + providerId + "' - no such provider found"); + } else { + this.authProviders.remove(providerId); + } + } + } + } + } + + public List getAuthProviders() { + return new ArrayList<>(authProviders.values()); + } + + public WebAuthProviderDescriptor getAuthProvider(String id) { + return authProviders.get(id); + } + +} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebServiceRegistry.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebServiceRegistry.java index e8009cf16f..26cb24dab0 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebServiceRegistry.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebServiceRegistry.java @@ -23,7 +23,6 @@ import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; import java.util.*; @@ -46,7 +45,7 @@ public class WebServiceRegistry { private final List webServices = new ArrayList<>(); private DBWServiceBinding[] webServiceInstances; - private final Map authProviders = new LinkedHashMap<>(); + private final Map authProviders = new LinkedHashMap<>(); private final Map valueSerializers = new HashMap<>(); private WebServiceRegistry() { diff --git a/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle.properties b/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle.properties index 61e0f48e8c..bd1c38a678 100644 --- a/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle.properties +++ b/server/bundles/io.cloudbeaver.server/OSGI-INF/l10n/bundle.properties @@ -1,4 +1,3 @@ Bundle-Vendor = DBeaver Corp Bundle-Name = Cloudbeaver Web Server -meta.io.cloudbeaver.auth.provider.fa.FederatedUserDetails.email.name = E-Mail diff --git a/server/bundles/io.cloudbeaver.server/plugin.xml b/server/bundles/io.cloudbeaver.server/plugin.xml index 7e5a924ae6..ec3704d572 100644 --- a/server/bundles/io.cloudbeaver.server/plugin.xml +++ b/server/bundles/io.cloudbeaver.server/plugin.xml @@ -3,9 +3,7 @@ - - diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java index 8dee743f17..6f2a43060c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java @@ -24,6 +24,9 @@ import io.cloudbeaver.model.WebConnectionFolderInfo; import io.cloudbeaver.model.WebNetworkHandlerConfigInput; import io.cloudbeaver.model.session.WebActionParameters; import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; +import io.cloudbeaver.server.CBAppConfig; import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.utils.WebAppUtils; import io.cloudbeaver.utils.WebCommonUtils; @@ -55,9 +58,7 @@ import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry; import org.jkiss.utils.CommonUtils; import java.io.InputStream; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; /** * Various constants @@ -338,5 +339,17 @@ public class WebServiceUtils extends WebCommonUtils { return project.getId().equals(RMProjectType.GLOBAL.getPrefix() + "_" + CBApplication.getInstance().getDefaultProjectName()); } + public static List getEnabledAuthProviders() { + List result = new ArrayList<>(); + CBAppConfig appConfig = CBApplication.getInstance().getAppConfiguration(); + String[] authProviders = appConfig.getEnabledAuthProviders(); + for (String apId : authProviders) { + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(apId); + if (authProvider != null) { + result.add(authProvider); + } + } + return result; + } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/user/WebAuthProviderInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/user/WebAuthProviderInfo.java index 9d6ccfd0e3..cb94bcbe3a 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/user/WebAuthProviderInfo.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/user/WebAuthProviderInfo.java @@ -17,12 +17,13 @@ package io.cloudbeaver.model.user; import io.cloudbeaver.WebServiceUtils; +import io.cloudbeaver.registry.WebAuthProviderConfiguration; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.server.CBPlatform; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.security.SMAuthCredentialsProfile; import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; import java.util.ArrayList; import java.util.List; @@ -34,13 +35,13 @@ public class WebAuthProviderInfo { private static final Log log = Log.getLog(WebAuthProviderInfo.class); - private final AuthProviderDescriptor descriptor; + private final WebAuthProviderDescriptor descriptor; - public WebAuthProviderInfo(AuthProviderDescriptor descriptor) { + public WebAuthProviderInfo(WebAuthProviderDescriptor descriptor) { this.descriptor = descriptor; } - AuthProviderDescriptor getDescriptor() { + WebAuthProviderDescriptor getDescriptor() { return descriptor; } 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 7682ae1a2f..a907666c4b 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 @@ -20,12 +20,12 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import io.cloudbeaver.model.app.BaseAuthWebAppConfiguration; import io.cloudbeaver.model.app.WebAuthConfiguration; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings; import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; import org.jkiss.utils.CommonUtils; import java.util.LinkedHashMap; @@ -171,8 +171,8 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC } public String[] getAllAuthProviders() { - return AuthProviderRegistry.getInstance().getAuthProviders() - .stream().map(AuthProviderDescriptor::getId).toArray(String[]::new); + return WebAuthProviderRegistry.getInstance().getAuthProviders() + .stream().map(WebAuthProviderDescriptor::getId).toArray(String[]::new); } public DBNBrowseSettings getDefaultNavigatorSettings() { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java index ee23e45c5d..1b80c95528 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java @@ -2,9 +2,11 @@ package io.cloudbeaver.server.servlets; import io.cloudbeaver.DBWConstants; import io.cloudbeaver.DBWebException; -import io.cloudbeaver.auth.SMWAuthProviderFederated; +import io.cloudbeaver.auth.SMAuthProviderFederated; import io.cloudbeaver.model.session.WebActionParameters; import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import io.cloudbeaver.registry.WebHandlerRegistry; import io.cloudbeaver.registry.WebServletHandlerDescriptor; import io.cloudbeaver.server.CBAppConfig; @@ -21,8 +23,6 @@ import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.auth.SMAuthInfo; import org.jkiss.dbeaver.model.auth.SMAuthProvider; import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; import org.jkiss.utils.CommonUtils; import org.jkiss.utils.IOUtils; @@ -86,7 +86,7 @@ public class CBStaticServlet extends DefaultServlet { String[] authProviders = appConfig.getEnabledAuthProviders(); if (authProviders.length == 1) { String authProviderId = authProviders[0]; - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(authProviderId); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(authProviderId); if (authProvider != null && authProvider.isConfigurable()) { SMAuthProviderCustomConfiguration activeAuthConfig = null; for (SMAuthProviderCustomConfiguration cfg : appConfig.getAuthCustomConfigurations()) { @@ -105,7 +105,7 @@ public class CBStaticServlet extends DefaultServlet { // We have the only provider // Forward to signon URL SMAuthProvider authProviderInstance = authProvider.getInstance(); - if (authProviderInstance instanceof SMWAuthProviderFederated) { + if (authProviderInstance instanceof SMAuthProviderFederated) { if (webSession.getUser() == null) { var securityController = webSession.getSecurityController(); SMAuthInfo authInfo = securityController.authenticate( diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java index ab8dae7a28..15d68683fc 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java @@ -20,13 +20,13 @@ import io.cloudbeaver.DBWebException; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.model.user.WebUser; import io.cloudbeaver.model.user.WebUserOriginInfo; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.security.SMDataSourceGrant; import org.jkiss.dbeaver.model.security.SMObjects; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; import java.util.ArrayList; import java.util.List; @@ -96,7 +96,7 @@ public class AdminUserInfo { public WebUserOriginInfo[] getOrigins() throws DBWebException { List result = new ArrayList<>(); for (String provider : getUserLinkedProviders()) { - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(provider); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(provider); if (authProvider == null) { log.error("Auth provider '" + provider + "' not found"); } else { 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 249090e947..0e9f3e548c 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 @@ -24,7 +24,7 @@ import io.cloudbeaver.model.WebConnectionConfig; import io.cloudbeaver.model.WebConnectionInfo; import io.cloudbeaver.model.WebPropertyInfo; import io.cloudbeaver.model.session.WebSession; -import io.cloudbeaver.model.user.WebAuthProviderConfiguration; +import io.cloudbeaver.registry.WebAuthProviderConfiguration; import io.cloudbeaver.service.DBWService; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; @@ -189,8 +189,7 @@ public interface DBWServiceAdmin extends DBWService { Boolean deleteUserMetaParameter(WebSession webSession, String id) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) - Boolean setUserMetaParameterValues(WebSession webSession, String userId, Map parameters) throws DBWebException; - + Boolean setUserMetaParameterValues(WebSession webSession, String userId, Map parameters) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) Boolean enableUser(WebSession webSession, String userId, Boolean enabled) throws DBWebException; 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 0071eacfa3..493af768e4 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 @@ -25,11 +25,8 @@ import io.cloudbeaver.model.WebConnectionInfo; import io.cloudbeaver.model.WebPropertyInfo; import io.cloudbeaver.model.session.WebAuthInfo; import io.cloudbeaver.model.session.WebSession; -import io.cloudbeaver.model.user.WebAuthProviderConfiguration; import io.cloudbeaver.model.user.WebUser; -import io.cloudbeaver.registry.WebFeatureRegistry; -import io.cloudbeaver.registry.WebPermissionDescriptor; -import io.cloudbeaver.registry.WebServiceRegistry; +import io.cloudbeaver.registry.*; import io.cloudbeaver.server.CBAppConfig; import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.server.CBConstants; @@ -56,8 +53,6 @@ import org.jkiss.dbeaver.model.security.SMObjects; import org.jkiss.dbeaver.model.security.user.SMTeam; import org.jkiss.dbeaver.model.security.user.SMUser; import org.jkiss.dbeaver.registry.DataSourceDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; import org.jkiss.utils.CommonUtils; import java.text.MessageFormat; @@ -293,7 +288,7 @@ public class WebServiceAdmin implements DBWServiceAdmin { @Override public boolean setUserCredentials(@NotNull WebSession webSession, @NotNull String userID, @NotNull String providerId, @NotNull Map credentials) throws DBWebException { - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(providerId); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(providerId); if (authProvider == null) { throw new DBWebException("Invalid auth provider '" + providerId + "'"); } @@ -492,11 +487,16 @@ public class WebServiceAdmin implements DBWServiceAdmin { @Override public List listAuthProviderConfigurationParameters(@NotNull WebSession webSession, @NotNull String providerId) throws DBWebException { - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(providerId); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(providerId); if (authProvider == null) { throw new DBWebException("Invalid provider ID " + providerId); } - return authProvider.getConfigurationParameters().stream().map(p -> new WebPropertyInfo(webSession, p)).collect(Collectors.toList()); + return authProvider.getConfigurationParameters().stream().filter(p -> { + if (p.hasFeature("distributed")) { + return CBApplication.getInstance().isDistributed(); + } + return true; + }).map(p -> new WebPropertyInfo(webSession, p)).collect(Collectors.toList()); } @Override @@ -506,7 +506,7 @@ public class WebServiceAdmin implements DBWServiceAdmin { if (providerId != null && !providerId.equals(cfg.getProvider())) { continue; } - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(cfg.getProvider()); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(cfg.getProvider()); if (authProvider != null) { result.add(new WebAuthProviderConfiguration(authProvider, cfg)); } @@ -524,7 +524,7 @@ public class WebServiceAdmin implements DBWServiceAdmin { @Nullable String iconURL, @Nullable String description, @Nullable Map parameters) throws DBWebException { - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(providerId); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(providerId); if (authProvider == null) { throw new DBWebException("Auth provider '" + providerId + "' not found"); } @@ -779,9 +779,9 @@ public class WebServiceAdmin implements DBWServiceAdmin { } @Override - public Boolean setUserMetaParameterValues(WebSession webSession, String userId, Map parameters) throws DBWebException { + public Boolean setUserMetaParameterValues(WebSession webSession, String userId, Map parameters) throws DBWebException { try { - webSession.getAdminSecurityController().setUserMeta(userId, parameters); + webSession.getAdminSecurityController().setSubjectMetas(userId, parameters); return true; } catch (DBException e) { throw new DBWebException("Error changing user '" + userId + "' meta parameters", e); 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 index 93b1ada087..0bcec0ee52 100644 --- 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 @@ -22,6 +22,8 @@ import io.cloudbeaver.auth.provider.rp.RPAuthProvider; import io.cloudbeaver.model.app.WebAuthConfiguration; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.model.session.WebSessionAuthProcessor; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.service.DBWSessionHandler; import io.cloudbeaver.utils.WebAppUtils; @@ -32,8 +34,6 @@ import org.jkiss.dbeaver.model.auth.SMAuthInfo; import org.jkiss.dbeaver.model.security.SMConstants; import org.jkiss.dbeaver.model.security.SMController; import org.jkiss.dbeaver.model.security.exception.SMException; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -61,7 +61,7 @@ public class RPSessionHandler implements DBWSessionHandler { public void reverseProxyAuthentication(@NotNull HttpServletRequest request, @NotNull WebSession webSession) throws DBWebException { SMController securityController = webSession.getSecurityController(); - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(RPAuthProvider.AUTH_PROVIDER); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(RPAuthProvider.AUTH_PROVIDER); if (authProvider == null) { throw new DBWebException("Auth provider " + RPAuthProvider.AUTH_PROVIDER + " not found"); } 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 e937043663..c764e472a5 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 @@ -17,6 +17,7 @@ package io.cloudbeaver.service.auth.impl; import io.cloudbeaver.DBWebException; +import io.cloudbeaver.WebServiceUtils; import io.cloudbeaver.auth.provider.local.LocalAuthProvider; import io.cloudbeaver.model.WebPropertyInfo; import io.cloudbeaver.model.session.WebAuthInfo; @@ -24,6 +25,8 @@ import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.model.session.WebSessionAuthProcessor; import io.cloudbeaver.model.user.WebAuthProviderInfo; import io.cloudbeaver.model.user.WebUser; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import io.cloudbeaver.registry.WebUserProfileRegistry; import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.service.auth.DBWServiceAuth; @@ -35,11 +38,13 @@ import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.auth.SMAuthInfo; import org.jkiss.dbeaver.model.auth.SMAuthStatus; +import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor; import org.jkiss.dbeaver.model.security.SMController; +import org.jkiss.dbeaver.model.security.SMSubjectType; import org.jkiss.dbeaver.model.security.user.SMUser; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; import org.jkiss.utils.CommonUtils; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -158,7 +163,7 @@ public class WebServiceAuthImpl implements DBWServiceAuth { @Override public WebAuthProviderInfo[] getAuthProviders() { - return AuthProviderRegistry.getInstance().getAuthProviders() + return WebAuthProviderRegistry.getInstance().getAuthProviders() .stream().map(WebAuthProviderInfo::new) .toArray(WebAuthProviderInfo[]::new); } @@ -177,7 +182,20 @@ public class WebServiceAuthImpl implements DBWServiceAuth { @Override public WebPropertyInfo[] listUserProfileProperties(@NotNull WebSession webSession) { - return WebUserProfileRegistry.getInstance().getProperties().stream() + List props = new ArrayList<>(); + + // First add user profile properties + props.addAll(WebUserProfileRegistry.getInstance().getProperties()); + + // Add metas from enabled auth providers + for (WebAuthProviderDescriptor ap : WebServiceUtils.getEnabledAuthProviders()) { + List metaProps = ap.getMetaProperties(SMSubjectType.user); + if (!CommonUtils.isEmpty(metaProps)) { + props.addAll(metaProps); + } + } + + return props.stream() .map(p -> new WebPropertyInfo(webSession, p, null)) .toArray(WebPropertyInfo[]::new); } diff --git a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_create.sql b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_create.sql index e5fb68c092..58e841360b 100644 --- a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_create.sql +++ b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_create.sql @@ -66,6 +66,18 @@ CREATE TABLE CB_AUTH_SUBJECT PRIMARY KEY (SUBJECT_ID) ); +CREATE TABLE CB_SUBJECT_META +( + SUBJECT_ID VARCHAR(128) NOT NULL, + META_ID VARCHAR(32) NOT NULL, + META_VALUE VARCHAR(1024), + + UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + + PRIMARY KEY (SUBJECT_ID, META_ID), + FOREIGN KEY (SUBJECT_ID) REFERENCES CB_AUTH_SUBJECT(SUBJECT_ID) ON DELETE CASCADE +); + CREATE TABLE CB_AUTH_PERMISSIONS ( SUBJECT_ID VARCHAR(128) NOT NULL, @@ -106,15 +118,6 @@ CREATE TABLE CB_USER ); -- Additional user properties (profile) -CREATE TABLE CB_USER_META -( - USER_ID VARCHAR(128) NOT NULL, - META_ID VARCHAR(32) NOT NULL, - META_VALUE VARCHAR(1024), - - PRIMARY KEY (USER_ID, META_ID), - FOREIGN KEY (USER_ID) REFERENCES CB_USER (USER_ID) ON DELETE CASCADE -); CREATE TABLE CB_USER_PARAMETERS ( @@ -299,9 +302,9 @@ CREATE INDEX CB_SESSION_LOG_INDEX ON CB_SESSION_LOG (SESSION_ID, LOG_TIME); CREATE TABLE CB_USER_SECRETS ( - USER_ID VARCHAR(128) NOT NULL, - SECRET_ID VARCHAR(512) NOT NULL, - SECRET_VALUE TEXT NOT NULL, + USER_ID VARCHAR(128) NOT NULL, + SECRET_ID VARCHAR(512) NOT NULL, + SECRET_VALUE TEXT NOT NULL, SECRET_LABEL VARCHAR(128), SECRET_DESCRIPTION VARCHAR(1024), diff --git a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_12.sql b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_12.sql new file mode 100644 index 0000000000..b0b70fc32b --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_12.sql @@ -0,0 +1,16 @@ +CREATE TABLE CB_SUBJECT_META +( + SUBJECT_ID VARCHAR(128) NOT NULL, + META_ID VARCHAR(32) NOT NULL, + META_VALUE VARCHAR(1024), + + UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + + PRIMARY KEY (SUBJECT_ID, META_ID), + FOREIGN KEY (SUBJECT_ID) REFERENCES CB_AUTH_SUBJECT(SUBJECT_ID) ON DELETE CASCADE +); + +INSERT INTO CB_SUBJECT_META (SUBJECT_ID, META_ID, META_VALUE) +SELECT USER_ID, META_ID, META_VALUE FROM CB_USER_META; + +DROP TABLE CB_USER_META; diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/local/LocalAuthProvider.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/local/LocalAuthProvider.java index 4896f14621..40a6b19080 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/local/LocalAuthProvider.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/local/LocalAuthProvider.java @@ -17,6 +17,8 @@ package io.cloudbeaver.auth.provider.local; import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; @@ -25,8 +27,6 @@ import org.jkiss.dbeaver.model.auth.SMAuthProvider; import org.jkiss.dbeaver.model.auth.SMSession; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; 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 java.util.Map; @@ -51,7 +51,7 @@ public class LocalAuthProvider implements SMAuthProvider { String userName = CommonUtils.toString(userCredentials.get(CRED_USER), null); - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(PROVIDER_ID); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(PROVIDER_ID); Map storedCredentials = securityController.getUserCredentials(userName, authProvider.getId()); if (storedCredentials == null) { throw new DBException("Invalid user name or password"); @@ -95,7 +95,7 @@ public class LocalAuthProvider implements SMAuthProvider { public static boolean changeUserPassword(@NotNull WebSession webSession, @NotNull String oldPassword, @NotNull String newPassword) throws DBException { String userName = webSession.getUser().getUserId(); - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(PROVIDER_ID); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(PROVIDER_ID); Map storedCredentials = webSession.getSecurityController().getUserCredentials(userName, authProvider.getId()); if (storedCredentials == null) { throw new DBException("Invalid user name or password"); 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 b652caa400..bfadbd672f 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 @@ -65,8 +65,8 @@ public class RPAuthProvider implements SMAuthProviderExternal { @NotNull @Override - public DBWUserIdentity getUserIdentity(@NotNull DBRProgressMonitor monitor, @NotNull Map providerConfig, @NotNull Map credentials) throws DBException { - String userName = String.valueOf(credentials.get("user")); + public DBWUserIdentity getUserIdentity(@NotNull DBRProgressMonitor monitor, @NotNull Map providerConfig, @NotNull Map authParameters) throws DBException { + String userName = String.valueOf(authParameters.get("user")); return new DBWUserIdentity(userName, userName); } 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 ca075801bd..9ad8f041b8 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 @@ -20,12 +20,16 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import io.cloudbeaver.DBWConstants; +import io.cloudbeaver.auth.SMAuthProviderAssigner; import io.cloudbeaver.auth.SMAuthProviderExternal; -import io.cloudbeaver.auth.SMWAuthProviderFederated; +import io.cloudbeaver.auth.SMAuthProviderFederated; +import io.cloudbeaver.auth.SMAutoAssign; import io.cloudbeaver.model.app.WebApplication; import io.cloudbeaver.model.app.WebAuthApplication; import io.cloudbeaver.model.app.WebAuthConfiguration; import io.cloudbeaver.model.session.WebAuthInfo; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import io.cloudbeaver.service.security.db.CBDatabase; import io.cloudbeaver.service.security.internal.AuthAttemptSessionInfo; import io.cloudbeaver.service.security.internal.SMTokenInfo; @@ -40,17 +44,11 @@ import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils; import org.jkiss.dbeaver.model.impl.jdbc.exec.JDBCTransaction; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.runtime.LoggingProgressMonitor; -import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor; import org.jkiss.dbeaver.model.security.*; import org.jkiss.dbeaver.model.security.exception.SMAccessTokenExpiredException; import org.jkiss.dbeaver.model.security.exception.SMException; import org.jkiss.dbeaver.model.security.exception.SMRefreshTokenExpiredException; -import org.jkiss.dbeaver.model.security.user.SMAuthPermissions; -import org.jkiss.dbeaver.model.security.user.SMObjectPermissions; -import org.jkiss.dbeaver.model.security.user.SMTeam; -import org.jkiss.dbeaver.model.security.user.SMUser; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; +import org.jkiss.dbeaver.model.security.user.*; import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; @@ -139,16 +137,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } dbStat.execute(); } - if (!CommonUtils.isEmpty(metaParameters)) { - try (PreparedStatement dbStat = dbCon.prepareStatement("INSERT INTO CB_USER_META(USER_ID,META_ID,META_VALUE) VALUES(?,?,?)")) { - dbStat.setString(1, userId); - for (Map.Entry mp : metaParameters.entrySet()) { - dbStat.setString(2, mp.getKey()); - dbStat.setString(3, mp.getValue()); - dbStat.execute(); - } - } - } + saveSubjectMetas(dbCon, userId, metaParameters); txn.commit(); } } catch (SQLException e) { @@ -158,6 +147,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen @Override public void deleteUser(String userId) throws DBCException { + invalidateAllUserTokens(userId); try (Connection dbCon = database.openConnection()) { try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { deleteAuthSubject(dbCon, userId); @@ -232,18 +222,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } } - // Metas - try (PreparedStatement dbStat = dbCon.prepareStatement("SELECT META_ID,META_VALUE FROM CB_USER_META WHERE USER_ID=?")) { - dbStat.setString(1, userId); - try (ResultSet dbResult = dbStat.executeQuery()) { - while (dbResult.next()) { - user.setMetaParameter( - dbResult.getString(1), - dbResult.getString(2) - ); - } - } - } + readSubjectMetas(dbCon, user); // Teams try (PreparedStatement dbStat = dbCon.prepareStatement("SELECT TEAM_ID FROM CB_USER_TEAM WHERE USER_ID=?")) { dbStat.setString(1, userId); @@ -282,25 +261,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } } - // Read metas - try (PreparedStatement dbStat = dbCon.prepareStatement("SELECT USER_ID,META_ID,META_VALUE FROM CB_USER_META" + - (CommonUtils.isEmpty(userNameMask) ? "" : " WHERE USER_ID=?"))) { - if (!CommonUtils.isEmpty(userNameMask)) { - dbStat.setString(1, userNameMask); - } - try (ResultSet dbResult = dbStat.executeQuery()) { - while (dbResult.next()) { - String userId = dbResult.getString(1); - SMUser user = result.get(userId); - if (user != null) { - user.setMetaParameter( - dbResult.getString(2), - dbResult.getString(3) - ); - } - } - } - } + readSubjectsMetas(dbCon, SMSubjectType.user, userNameMask, result); // Read teams try (PreparedStatement dbStat = dbCon.prepareStatement("SELECT USER_ID,TEAM_ID FROM CB_USER_TEAM" + (CommonUtils.isEmpty(userNameMask) ? "" : " WHERE USER_ID=?"))) { @@ -325,30 +286,67 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } - @Override - public void setUserMeta(String userId, Map metaParameters) throws DBCException { - try (Connection dbCon = database.openConnection()) { - try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { - // Delete old metas - try (PreparedStatement dbStat = dbCon.prepareStatement("DELETE FROM CB_USER_META WHERE USER_ID=?")) { - dbStat.setString(1, userId); - dbStat.execute(); + private void cleanupSubjectMeta(Connection dbCon, String subjectId) throws SQLException { + // Delete old metas + try (PreparedStatement dbStat = dbCon.prepareStatement( + "DELETE FROM CB_SUBJECT_META WHERE SUBJECT_ID=?")) { + dbStat.setString(1, subjectId); + dbStat.execute(); + } + } + + private void readSubjectMetas(Connection dbCon, SMSubject subject) throws SQLException { + // Metas + try (PreparedStatement dbStat = dbCon.prepareStatement( + "SELECT META_ID,META_VALUE FROM CB_SUBJECT_META WHERE SUBJECT_ID=?")) { + dbStat.setString(1, subject.getSubjectId()); + try (ResultSet dbResult = dbStat.executeQuery()) { + while (dbResult.next()) { + subject.setMetaParameter( + dbResult.getString(1), + dbResult.getString(2) + ); } - if (!metaParameters.isEmpty()) { - // Insert new metas - try (PreparedStatement dbStat = dbCon.prepareStatement("INSERT INTO CB_USER_META(USER_ID,META_ID,META_VALUE) VALUES(?,?,?)")) { - dbStat.setString(1, userId); - for (Map.Entry mpe : metaParameters.entrySet()) { - dbStat.setString(2, mpe.getKey()); - dbStat.setString(3, CommonUtils.toString(mpe.getValue())); - dbStat.execute(); - } + } + } + } + + private void readSubjectsMetas(Connection dbCon, SMSubjectType subjectType, String nameMask, Map result) throws SQLException { + // Read metas + try (PreparedStatement dbStat = dbCon.prepareStatement( + "SELECT m.SUBJECT_ID,m.META_ID,m.META_VALUE FROM CB_AUTH_SUBJECT s, CB_SUBJECT_META m\n" + + "WHERE s.SUBJECT_TYPE=? AND s.SUBJECT_ID=m.SUBJECT_ID" + + (CommonUtils.isEmpty(nameMask) ? "" : " AND s.SUBJECT_ID=?"))) { + dbStat.setString(1, subjectType.getCode()); + if (!CommonUtils.isEmpty(nameMask)) { + dbStat.setString(2, nameMask); + } + try (ResultSet dbResult = dbStat.executeQuery()) { + while (dbResult.next()) { + String subjectId = dbResult.getString(1); + SMSubject subject = result.get(subjectId); + if (subject != null) { + subject.setMetaParameter( + dbResult.getString(2), + dbResult.getString(3) + ); } } - txn.commit(); } - } catch (SQLException e) { - throw new DBCException("Error while loading users", e); + } + } + + private void saveSubjectMetas(Connection dbCon, String subjectId, Map metaParameters) throws SQLException { + if (!CommonUtils.isEmpty(metaParameters)) { + try (PreparedStatement dbStat = dbCon.prepareStatement( + "INSERT INTO CB_SUBJECT_META(SUBJECT_ID,META_ID,META_VALUE) VALUES(?,?,?)")) { + dbStat.setString(1, subjectId); + for (Map.Entry mp : metaParameters.entrySet()) { + dbStat.setString(2, mp.getKey()); + dbStat.setString(3, mp.getValue()); + dbStat.execute(); + } + } } } @@ -439,7 +437,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen /////////////////////////////////////////// // Credentials - private static SMAuthCredentialsProfile getCredentialProfileByParameters(AuthProviderDescriptor authProvider, Set keySet) { + private static SMAuthCredentialsProfile getCredentialProfileByParameters(WebAuthProviderDescriptor authProvider, Set keySet) { List credentialProfiles = authProvider.getCredentialProfiles(); if (credentialProfiles.size() > 1) { for (SMAuthCredentialsProfile profile : credentialProfiles) { @@ -462,12 +460,12 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen @Override public void setUserCredentials(@NotNull String userId, @NotNull String authProviderId, @NotNull Map credentials) throws DBException { - var existUserByCredentials = findUserByCredentials(authProviderId, credentials); + var existUserByCredentials = findUserByCredentials(getAuthProvider(authProviderId), credentials); if (existUserByCredentials != null && !existUserByCredentials.equals(userId)) { throw new DBException("Another user is already linked to the specified credentials"); } List transformedCredentials; - AuthProviderDescriptor authProvider = getAuthProvider(authProviderId); + WebAuthProviderDescriptor authProvider = getAuthProvider(authProviderId); try { SMAuthCredentialsProfile credProfile = getCredentialProfileByParameters(authProvider, credentials.keySet()); transformedCredentials = credentials.entrySet().stream().map(cred -> { @@ -508,10 +506,10 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } @Nullable - private String findUserByCredentials(String authProviderId, Map authParameters) throws DBCException { - AuthProviderDescriptor authProvider = getAuthProvider(authProviderId); + private String findUserByCredentials(WebAuthProviderDescriptor authProvider, Map authParameters) throws DBCException { Map identCredentials = new LinkedHashMap<>(); - for (AuthPropertyDescriptor prop : authProvider.getCredentialParameters(authParameters.keySet())) { + String[] propNames = authParameters.keySet().toArray(new String[0]); + for (AuthPropertyDescriptor prop : authProvider.getCredentialParameters(propNames)) { if (prop.isIdentifying()) { String propId = CommonUtils.toString(prop.getId()); Object paramValue = authParameters.get(propId); @@ -577,7 +575,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen @Override public Map getUserCredentials(String userId, String authProviderId) throws DBCException { - AuthProviderDescriptor authProvider = getAuthProvider(authProviderId); + WebAuthProviderDescriptor authProvider = getAuthProvider(authProviderId); try (Connection dbCon = database.openConnection()) { try (PreparedStatement dbStat = dbCon.prepareStatement( "SELECT CRED_ID,CRED_VALUE FROM CB_USER_CREDENTIALS\n" + @@ -650,6 +648,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } } + readSubjectsMetas(dbCon, SMSubjectType.team,null, teams); return teams.values().toArray(new SMTeam[0]); } catch (SQLException e) { throw new DBCException("Error reading teams from database", e); @@ -773,7 +772,22 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } /////////////////////////////////////////// - // Permissions + // Subject functions + + @Override + public void setSubjectMetas(String userId, Map metaParameters) throws DBCException { + try (Connection dbCon = database.openConnection()) { + try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { + cleanupSubjectMeta(dbCon, userId); + if (!metaParameters.isEmpty()) { + saveSubjectMetas(dbCon, userId, metaParameters); + } + txn.commit(); + } + } catch (SQLException e) { + throw new DBCException("Error while loading users", e); + } + } @Override public void setSubjectPermissions(String subjectId, List permissionIds, String grantorId) throws DBException { @@ -920,7 +934,8 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen smTokens.getSmAccessToken(), smTokens.getSmRefreshToken(), new SMAuthPermissions(null, smSessionId, permissions), - Map.of() + Map.of(), + smConfig.getDefaultAuthRole() ); } } catch (SQLException e) { @@ -943,11 +958,11 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen @Nullable String authProviderConfigurationId, @NotNull Map userCredentials ) throws DBException { - var authProgressMonitor = new VoidProgressMonitor(); + var authProgressMonitor = new LoggingProgressMonitor(log); try (Connection dbCon = database.openConnection()) { try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { Map securedUserIdentifyingCredentials = userCredentials; - AuthProviderDescriptor authProviderDescriptor = getAuthProvider(authProviderId); + WebAuthProviderDescriptor authProviderDescriptor = getAuthProvider(authProviderId); var authProviderInstance = authProviderDescriptor.getInstance(); if (SMAuthProviderExternal.class.isAssignableFrom(authProviderInstance.getClass())) { var authProviderExternal = (SMAuthProviderExternal) authProviderInstance; @@ -970,9 +985,9 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen sessionParameters ); - if (SMWAuthProviderFederated.class.isAssignableFrom(authProviderInstance.getClass())) { + if (SMAuthProviderFederated.class.isAssignableFrom(authProviderInstance.getClass())) { //async auth - var authProviderFederated = (SMWAuthProviderFederated) authProviderInstance; + var authProviderFederated = (SMAuthProviderFederated) authProviderInstance; var redirectUrl = buildRedirectLink( authProviderFederated.getSignInLink(authProviderConfigurationId, Map.of()), authAttemptId); @@ -980,7 +995,11 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } txn.commit(); return finishAuthentication( - SMAuthInfo.inProgress(authAttemptId, null, Map.of(authProviderId, securedUserIdentifyingCredentials)), + SMAuthInfo.inProgress( + authAttemptId, + null, + Map.of(authProviderId, securedUserIdentifyingCredentials) + ), true, false ); @@ -992,7 +1011,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen private Map filterSecuredUserData( Map userIdentifyingCredentials, - AuthProviderDescriptor authProviderDescriptor + WebAuthProviderDescriptor authProviderDescriptor ) { SMAuthCredentialsProfile credProfile = getCredentialProfileByParameters(authProviderDescriptor, userIdentifyingCredentials.keySet()); return userIdentifyingCredentials.entrySet() @@ -1133,8 +1152,10 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } Map authData = new LinkedHashMap<>(); String redirectUrl = null; + try (PreparedStatement dbStat = dbCon.prepareStatement( - "SELECT AUTH_PROVIDER_ID,AUTH_PROVIDER_CONFIGURATION_ID,AUTH_STATE FROM CB_AUTH_ATTEMPT_INFO " + "SELECT AUTH_PROVIDER_ID,AUTH_PROVIDER_CONFIGURATION_ID,AUTH_STATE " + + "FROM CB_AUTH_ATTEMPT_INFO " + "WHERE AUTH_ID=? ORDER BY CREATE_TIME" )) { dbStat.setString(1, authId); @@ -1144,13 +1165,15 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen String authProviderConfiguration = dbResult.getString(2); Map authProviderData = gson.fromJson(dbResult.getString(3), MAP_STRING_OBJECT_TYPE); if (authProviderConfiguration != null) { - var authProviderInstance = getAuthProvider(authProviderId).getInstance(); - if (SMWAuthProviderFederated.class.isAssignableFrom(authProviderInstance.getClass())) { + WebAuthProviderDescriptor authProviderDescriptor = getAuthProvider(authProviderId); + var authProviderInstance = authProviderDescriptor.getInstance(); + if (SMAuthProviderFederated.class.isAssignableFrom(authProviderInstance.getClass())) { redirectUrl = buildRedirectLink( - ((SMWAuthProviderFederated) authProviderInstance).getRedirectLink(authProviderConfiguration, Map.of()), + ((SMAuthProviderFederated) authProviderInstance).getRedirectLink(authProviderConfiguration, Map.of()), authId ); } + } authData.put(authProviderId, authProviderData); } @@ -1172,12 +1195,15 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen SMTokens smTokens = findTokenBySmSession(smSessionId); SMAuthPermissions authPermissions = getTokenPermissions(smTokens.getSmAccessToken()); + String userId = authPermissions.getUserId(); + String authRole = readTokenAuthRole(smTokens.getSmAccessToken()); var successAuthStatus = SMAuthInfo.success( authId, smTokens.getSmAccessToken(), smTokens.getSmRefreshToken(), authPermissions, - authData + authData, + authRole ); updateAuthStatus(authId, SMAuthStatus.EXPIRED, authData, null, authPermissions.getSessionId()); return successAuthStatus; @@ -1221,6 +1247,14 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } + private void invalidateAllUserTokens(String userId) throws DBCException { + try (Connection dbCon = database.openConnection()) { + JDBCUtils.executeStatement(dbCon, "DELETE FROM CB_AUTH_TOKEN WHERE USER_ID=?", userId); + } catch (SQLException e) { + throw new DBCException("Session invalidation failed", e); + } + } + private SMCredentials getCurrentUserCreds() throws SMException { var currentUserCreds = credentialsProvider.getActiveUserCredentials(); if (currentUserCreds == null) { @@ -1305,16 +1339,24 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen String activeUserId = permissions == null ? null : permissions.getUserId(); Map storedUserData = new LinkedHashMap<>(); + SMTeam[] allTeams = null; + String detectedAuthRole = null; for (String authProviderId : authProviderIds) { + WebAuthProviderDescriptor authProvider = getAuthProvider(authProviderId); var userAuthData = (Map) authInfo.getAuthData().get(authProviderId); + SMAutoAssign autoAssign = getAutoAssignUserData(authId, authProvider, userAuthData, finishAuthMonitor); + if (autoAssign != null) { + detectedAuthRole = autoAssign.getAuthRole(); + } + var userIdFromCreds = findOrCreateExternalUserByCredentials( - authProviderId, + authProvider, authAttemptSessionInfo.getSessionParams(), userAuthData, finishAuthMonitor, activeUserId, activeUserId == null, - authInfo.getAuthRole() + detectedAuthRole ); if (userIdFromCreds == null) { @@ -1322,6 +1364,14 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen updateAuthStatus(authId, SMAuthStatus.ERROR, storedUserData, error); return SMAuthInfo.error(authId, error); } + + if (autoAssign != null && !CommonUtils.isEmpty(autoAssign.getExternalTeamIds())) { + if (allTeams == null) { + allTeams = readAllTeams(); + } + autoUpdateUserTeams(authProvider, autoAssign, userIdFromCreds, allTeams); + } + if (activeUserId == null) { activeUserId = userIdFromCreds; } @@ -1331,7 +1381,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen ); } - String tokenAuthRole = updateUserAuthRoleIfNeeded(activeUserId, authInfo.getAuthRole()); + String tokenAuthRole = updateUserAuthRoleIfNeeded(activeUserId, detectedAuthRole); if (smTokens == null && permissions == null) { try (Connection dbCon = database.openConnection()) { try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { @@ -1368,10 +1418,101 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen //refresh token must be sent only once isMainAuthSession ? smTokens.getSmRefreshToken() : null, permissions, - authInfo.getAuthData() + authInfo.getAuthData(), + tokenAuthRole ); } + private void autoUpdateUserTeams( + WebAuthProviderDescriptor authProvider, + SMAutoAssign autoAssign, + String userId, + SMTeam[] allTeams + ) throws DBCException { + if (!(authProvider.getInstance() instanceof SMAuthProviderAssigner)) { + return; + } + SMAuthProviderAssigner authProviderAssigner = (SMAuthProviderAssigner) authProvider.getInstance(); + + String[] newTeamIds = autoAssign.getExternalTeamIds() + .stream() + .map(externalTeamId -> findTeamByExternalTeamId( + allTeams, + authProviderAssigner.getExternalTeamIdMetadataFieldName(), + externalTeamId + )) + .filter(Objects::nonNull) + .map(SMTeam::getTeamId) + .toArray(String[]::new); + if (!ArrayUtils.isEmpty(newTeamIds)) { + setUserTeams( + userId, + newTeamIds, + userId + ); + } + } + + @Nullable + private SMAutoAssign getAutoAssignUserData( + String authAttemptId, + WebAuthProviderDescriptor authProvider, + Map userData, + DBRProgressMonitor monitor + ) throws DBException { + var authProviderInstance = authProvider.getInstance(); + if (!(authProviderInstance instanceof SMAuthProviderAssigner)) { + return null; + } + var authProviderAssigner = (SMAuthProviderAssigner) authProviderInstance; + String providerConfigId = readProviderConfigId(authAttemptId, authProvider.getId()); + if (providerConfigId == null) { + return null; + } + var providerConfig = + application.getAuthConfiguration().getAuthProviderConfiguration(providerConfigId); + return authProviderAssigner.detectAutoAssignments( + monitor, + providerConfig == null ? Map.of() : providerConfig.getParameters(), + userData + ); + } + + @Nullable + private SMTeam findTeamByExternalTeamId(SMTeam[] allTeams, String externalGroupParameterName, String groupId) { + for (SMTeam team : allTeams) { + String teamGroupId = team.getMetaParameters().get(externalGroupParameterName); + if (CommonUtils.equalObjects(teamGroupId, groupId)) { + return team; + } + } + return null; + } + + + private String readProviderConfigId(String authAttemptId, String authProviderId) throws DBException { + try (Connection dbCon = database.openConnection()) { + try (PreparedStatement dbStat = dbCon.prepareStatement( + "SELECT AUTH_PROVIDER_CONFIGURATION_ID " + + "FROM CB_AUTH_ATTEMPT_INFO " + + "WHERE AUTH_ID=? AND AUTH_PROVIDER_ID=?" + )) { + dbStat.setString(1, authAttemptId); + dbStat.setString(2, authProviderId); + try (ResultSet dbResult = dbStat.executeQuery()) { + if (!dbResult.next()) { + return null; + } + return dbResult.getString(1); + + } + } + } catch (SQLException e) { + throw new DBException("Failed to read auth provider configuration", e); + } + } + + @Nullable protected String readUserAuthRole(String userId) throws DBException { try (Connection dbCon = database.openConnection()) { @@ -1430,7 +1571,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } private String findOrCreateExternalUserByCredentials( - @NotNull String authProviderId, + @NotNull WebAuthProviderDescriptor authProvider, @NotNull Map sessionParameters, @NotNull Map userCredentials, @NotNull DBRProgressMonitor progressMonitor, @@ -1438,9 +1579,8 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen boolean createNewUserIfNotExist, String authRole ) throws DBException { - AuthProviderDescriptor authProvider = getAuthProvider(authProviderId); SMAuthProvider smAuthProviderInstance = authProvider.getInstance(); - String userId = findUserByCredentials(authProviderId, userCredentials); + String userId = findUserByCredentials(authProvider, userCredentials); String userIdFromCredentials; try { userIdFromCredentials = smAuthProviderInstance.validateLocalAuth(progressMonitor, this, Map.of(), userCredentials, null); @@ -1450,7 +1590,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } if (activeUserId != null && userId != null && !activeUserId.equals(userId)) { log.debug("User '" + activeUserId + "' is authenticated in '" - + authProviderId + "' auth provider with credentials of user '" + + authProvider.getId() + "' auth provider with credentials of user '" + userIdFromCredentials + "'"); } if (userId == null && createNewUserIfNotExist) { @@ -1470,7 +1610,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen setUserTeams(userId, new String[]{defaultTeamName}, userId); } } - setUserCredentials(userId, authProviderId, userCredentials); + setUserCredentials(userId, authProvider.getId(), userCredentials); } else if (userId == null) { userId = userIdFromCredentials; } @@ -1564,12 +1704,12 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } WebAuthConfiguration appConfiguration = (WebAuthConfiguration) application.getAppConfiguration(); Set customConfigurations = appConfiguration.getAuthCustomConfigurations(); - List providers = AuthProviderRegistry.getInstance().getAuthProviders().stream() + List providers = WebAuthProviderRegistry.getInstance().getAuthProviders().stream() .filter(ap -> !ap.isTrusted() && appConfiguration.isAuthProviderEnabled(ap.getId()) && (!ap.isConfigurable() || hasProviderConfiguration(ap, customConfigurations))) - .map(AuthProviderDescriptor::createDescriptorBean).collect(Collectors.toList()); + .map(WebAuthProviderDescriptor::createDescriptorBean).collect(Collectors.toList()); if (!CommonUtils.isEmpty(customConfigurations)) { // Attach custom configs to providers @@ -1587,7 +1727,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen return providers.toArray(new SMAuthProviderDescriptor[0]); } - private static boolean hasProviderConfiguration(AuthProviderDescriptor ap, Set customConfigurations) { + private static boolean hasProviderConfiguration(WebAuthProviderDescriptor ap, Set customConfigurations) { for (SMAuthProviderCustomConfiguration cc : customConfigurations) { if (!cc.isDisabled() && cc.getProvider().equals(ap.getId())) { return true; @@ -1895,7 +2035,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } try (PreparedStatement dbStat = dbCon.prepareStatement( "INSERT INTO CB_AUTH_PROVIDER(PROVIDER_ID,IS_ENABLED) VALUES(?,'Y')")) { - for (AuthProviderDescriptor authProvider : AuthProviderRegistry.getInstance().getAuthProviders()) { + for (WebAuthProviderDescriptor authProvider : WebAuthProviderRegistry.getInstance().getAuthProviders()) { if (!registeredProviders.contains(authProvider.getId())) { dbStat.setString(1, authProvider.getId()); dbStat.executeUpdate(); @@ -1925,8 +2065,8 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen } } - private AuthProviderDescriptor getAuthProvider(String authProviderId) throws DBCException { - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(authProviderId); + private WebAuthProviderDescriptor getAuthProvider(String authProviderId) throws DBCException { + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(authProviderId); if (authProvider == null) { throw new DBCException("Auth provider not found: " + authProviderId); } diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java index 6459df0f9f..64c97112c9 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java @@ -21,6 +21,8 @@ import com.google.gson.GsonBuilder; import io.cloudbeaver.auth.provider.local.LocalAuthProviderConstants; import io.cloudbeaver.model.app.WebApplication; import io.cloudbeaver.model.session.WebAuthInfo; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import io.cloudbeaver.registry.WebAuthProviderRegistry; import io.cloudbeaver.utils.WebAppUtils; import org.apache.commons.dbcp2.*; import org.apache.commons.pool2.impl.GenericObjectPool; @@ -42,8 +44,6 @@ import org.jkiss.dbeaver.model.sql.schema.ClassLoaderScriptSource; import org.jkiss.dbeaver.model.sql.schema.SQLSchemaManager; import org.jkiss.dbeaver.model.sql.schema.SQLSchemaVersionManager; import org.jkiss.dbeaver.registry.DataSourceProviderRegistry; -import org.jkiss.dbeaver.registry.auth.AuthProviderDescriptor; -import org.jkiss.dbeaver.registry.auth.AuthProviderRegistry; import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.dbeaver.utils.GeneralUtils; import org.jkiss.dbeaver.utils.RuntimeUtils; @@ -68,7 +68,7 @@ public class CBDatabase { public static final String SCHEMA_UPDATE_SQL_PATH = "db/cb_schema_update_"; private static final int LEGACY_SCHEMA_VERSION = 1; - private static final int CURRENT_SCHEMA_VERSION = 11; + private static final int CURRENT_SCHEMA_VERSION = 12; private static final String DEFAULT_DB_USER_NAME = "cb-data"; private static final String DEFAULT_DB_PWD_FILE = ".database-credentials.dat"; @@ -219,7 +219,7 @@ public class CBDatabase { // Associate all auth credentials with admin user for (WebAuthInfo ai : authInfoList) { if (!ai.getAuthProvider().equals(LocalAuthProviderConstants.PROVIDER_ID)) { - AuthProviderDescriptor authProvider = ai.getAuthProviderDescriptor(); + WebAuthProviderDescriptor authProvider = ai.getAuthProviderDescriptor(); Map userCredentials = ai.getUserCredentials(); if (!CommonUtils.isEmpty(userCredentials)) { adminSecurityController.setUserCredentials(adminName, authProvider.getId(), userCredentials); @@ -266,7 +266,7 @@ public class CBDatabase { credentials.put(LocalAuthProviderConstants.CRED_USER, adminUser.getUserId()); credentials.put(LocalAuthProviderConstants.CRED_PASSWORD, clientPassword); - AuthProviderDescriptor authProvider = AuthProviderRegistry.getInstance().getAuthProvider(LocalAuthProviderConstants.PROVIDER_ID); + WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(LocalAuthProviderConstants.PROVIDER_ID); if (authProvider != null) { adminSecurityController.setUserCredentials(adminUser.getUserId(), authProvider.getId(), credentials); } diff --git a/server/test/io.cloudbeaver.test.platform/workspace/conf/initial-data.conf b/server/test/io.cloudbeaver.test.platform/workspace/conf/initial-data.conf index 718fa039bc..1aa23bdcc3 100644 --- a/server/test/io.cloudbeaver.test.platform/workspace/conf/initial-data.conf +++ b/server/test/io.cloudbeaver.test.platform/workspace/conf/initial-data.conf @@ -3,13 +3,13 @@ adminPassword: "test", teams: [ { - teamId: "admin", + subjectId: "admin", name: "Admin", description: "Administrative access. Has all permissions.", permissions: [ "public", "admin" ] }, { - teamId: "user", + subjectId: "user", name: "User", description: "Standard user", permissions: [ "public" ]