From b6feb13958f55f62fe144360182e5be6aed3e253 Mon Sep 17 00:00:00 2001 From: Serge Rider Date: Thu, 18 Jan 2024 15:27:12 +0100 Subject: [PATCH 1/3] CB-3834 Secret manager database schema --- .../db/cb_schema_create.sql | 22 ++++++++++++++++ .../db/cb_schema_update_16.sql | 26 +++++++++++++++++++ .../service/security/db/CBDatabase.java | 2 +- 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_16.sql 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 03c7a6b5bb..4114b0e7e2 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 @@ -315,3 +315,25 @@ CREATE TABLE {table_prefix}CB_USER_SECRETS PRIMARY KEY (USER_ID, SECRET_ID), FOREIGN KEY (USER_ID) REFERENCES {table_prefix}CB_USER (USER_ID) ON DELETE CASCADE ); + +CREATE TABLE {table_prefix}CB_SUBJECT_SECRETS +( + SUBJECT_ID VARCHAR(128) NOT NULL, + SECRET_ID VARCHAR(255) NOT NULL, + + PROJECT_ID VARCHAR(128), + OBJECT_TYPE VARCHAR(32), + OBJECT_ID VARCHAR(128), + + SECRET_VALUE TEXT NOT NULL, + + ENCODING_TYPE VARCHAR(32) DEFAULT 'PLAINTEXT' NOT NULL, + CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + + PRIMARY KEY (SUBJECT_ID, SECRET_ID), + FOREIGN KEY (SUBJECT_ID) REFERENCES {table_prefix}CB_SUBJECT (SUBJECT_ID) ON DELETE CASCADE +); + +CREATE INDEX IDX_SUBJECT_SECRETS_PROJECT ON {table_prefix}CB_SUBJECT_SECRETS (PROJECT_ID,SUBJECT_ID); +CREATE INDEX IDX_SUBJECT_SECRETS_OBJECT ON {table_prefix}CB_SUBJECT_SECRETS (PROJECT_ID,OBJECT_TYPE,OBJECT_ID); diff --git a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_16.sql b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_16.sql new file mode 100644 index 0000000000..2dc1d65553 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_16.sql @@ -0,0 +1,26 @@ +CREATE TABLE {table_prefix}CB_SUBJECT_SECRETS +( + SUBJECT_ID VARCHAR(128) NOT NULL, + SECRET_ID VARCHAR(255) NOT NULL, + + PROJECT_ID VARCHAR(128), + OBJECT_TYPE VARCHAR(32), + OBJECT_ID VARCHAR(128), + + SECRET_VALUE TEXT NOT NULL, + + ENCODING_TYPE VARCHAR(32) DEFAULT 'PLAINTEXT' NOT NULL, + CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + + PRIMARY KEY (SUBJECT_ID, SECRET_ID), + FOREIGN KEY (SUBJECT_ID) REFERENCES {table_prefix}CB_SUBJECT (SUBJECT_ID) ON DELETE CASCADE + ); + +CREATE INDEX IDX_SUBJECT_SECRETS_PROJECT ON {table_prefix}CB_SUBJECT_SECRETS (PROJECT_ID,SUBJECT_ID); +CREATE INDEX IDX_SUBJECT_SECRETS_OBJECT ON {table_prefix}CB_SUBJECT_SECRETS (PROJECT_ID,OBJECT_TYPE,OBJECT_ID); + +INSERT INTO {table_prefix}CB_SUBJECT_SECRETS (SUBJECT_ID, SECRET_ID, SECRET_VALUE, ENCODING_TYPE, CREATE_TIME, UPDATE_TIME) +SELECT USER_ID, SECRET_ID, SECRET_VALUE, ENCODING_TYPE, UPDATE_TIME, UPDATE_TIME FROM {table_prefix}CB_USER_SECRETS; + +DROP TABLE {table_prefix}CB_USER_SECRETS; 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 8dfe25b61a..b1255969d6 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 @@ -73,7 +73,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 = 15; + private static final int CURRENT_SCHEMA_VERSION = 16; private static final String DEFAULT_DB_USER_NAME = "cb-data"; private static final String DEFAULT_DB_PWD_FILE = ".database-credentials.dat"; From 938033df4aab9f6912b5263f4c385a5eac86a0d6 Mon Sep 17 00:00:00 2001 From: Aleksandr Skoblikov Date: Wed, 24 Jan 2024 20:21:51 +0400 Subject: [PATCH 2/3] CB-3834 credentials profile migration --- .../db/cb_schema_create.sql | 20 ++++++++++++++++--- .../db/cb_schema_update_16.sql | 2 +- .../db/cb_schema_update_17.sql | 16 +++++++++++++++ .../service/security/db/CBDatabase.java | 2 +- 4 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_17.sql 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 4114b0e7e2..843f30f8f4 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 @@ -105,16 +105,30 @@ CREATE TABLE {table_prefix}CB_OBJECT_PERMISSIONS FOREIGN KEY (SUBJECT_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE ); +CREATE TABLE {table_prefix}CB_CREDENTIALS_PROFILE +( + PROFILE_ID VARCHAR(128) NOT NULL, + PROFILE_NAME VARCHAR(100) NOT NULL, + PROFILE_DESCRIPTION VARCHAR(255) NOT NULL, + PARENT_PROFILE_ID VARCHAR(128) NULL, + CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + + PRIMARY KEY (PROFILE_ID), + FOREIGN KEY (PROFILE_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE, + FOREIGN KEY (PARENT_PROFILE_ID) REFERENCES {table_prefix}CB_CREDENTIALS_PROFILE(PROFILE_ID) ON DELETE NO ACTION +); + CREATE TABLE {table_prefix}CB_USER ( USER_ID VARCHAR(128) NOT NULL, - IS_ACTIVE CHAR(1) NOT NULL, CREATE_TIME TIMESTAMP NOT NULL, DEFAULT_AUTH_ROLE VARCHAR(32) NULL, + CREDENTIALS_PROFILE_ID VARCHAR(128) NULL, PRIMARY KEY (USER_ID), - FOREIGN KEY (USER_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE + FOREIGN KEY (USER_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE, + FOREIGN KEY (CREDENTIALS_PROFILE_ID) REFERENCES {table_prefix}CB_CREDENTIALS_PROFILE(PROFILE_ID) ON DELETE NO ACTION ); -- Additional user properties (profile) @@ -332,7 +346,7 @@ CREATE TABLE {table_prefix}CB_SUBJECT_SECRETS UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (SUBJECT_ID, SECRET_ID), - FOREIGN KEY (SUBJECT_ID) REFERENCES {table_prefix}CB_SUBJECT (SUBJECT_ID) ON DELETE CASCADE + FOREIGN KEY (SUBJECT_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE ); CREATE INDEX IDX_SUBJECT_SECRETS_PROJECT ON {table_prefix}CB_SUBJECT_SECRETS (PROJECT_ID,SUBJECT_ID); diff --git a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_16.sql b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_16.sql index 2dc1d65553..298030ea58 100644 --- a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_16.sql +++ b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_16.sql @@ -14,7 +14,7 @@ CREATE TABLE {table_prefix}CB_SUBJECT_SECRETS UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (SUBJECT_ID, SECRET_ID), - FOREIGN KEY (SUBJECT_ID) REFERENCES {table_prefix}CB_SUBJECT (SUBJECT_ID) ON DELETE CASCADE + FOREIGN KEY (SUBJECT_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE ); CREATE INDEX IDX_SUBJECT_SECRETS_PROJECT ON {table_prefix}CB_SUBJECT_SECRETS (PROJECT_ID,SUBJECT_ID); diff --git a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_17.sql b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_17.sql new file mode 100644 index 0000000000..5a3f382caa --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_17.sql @@ -0,0 +1,16 @@ +CREATE TABLE {table_prefix}CB_CREDENTIALS_PROFILE +( + PROFILE_ID VARCHAR(128) NOT NULL, + PROFILE_NAME VARCHAR(100) NOT NULL, + PROFILE_DESCRIPTION VARCHAR(255) NOT NULL, + PARENT_PROFILE_ID VARCHAR(255) NULL, + + CREATE_TIME TIMESTAMP NOT NULL, + + PRIMARY KEY (PROFILE_ID), + FOREIGN KEY (PROFILE_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE, + FOREIGN KEY (PARENT_PROFILE_ID) REFERENCES {table_prefix}CB_CREDENTIALS_PROFILE(PROFILE_ID) ON DELETE NO ACTION +); + +ALTER TABLE {table_prefix}CB_USER ADD COLUMN CREDENTIALS_PROFILE_ID VARCHAR(128) NULL; +ALTER TABLE {table_prefix}CB_USER ADD FOREIGN KEY(CREDENTIALS_PROFILE_ID) REFERENCES {table_prefix}CB_CREDENTIALS_PROFILE(PROFILE_ID) ON DELETE NO ACTION; 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 b1255969d6..5cddbba56a 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 @@ -73,7 +73,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 = 16; + private static final int CURRENT_SCHEMA_VERSION = 17; private static final String DEFAULT_DB_USER_NAME = "cb-data"; private static final String DEFAULT_DB_PWD_FILE = ".database-credentials.dat"; From 5fe9ad41f830f73c53104f2d9c940c14ffe551be Mon Sep 17 00:00:00 2001 From: Aleksandr Skoblikov Date: Thu, 25 Jan 2024 18:27:07 +0400 Subject: [PATCH 3/3] CB-3834 profile management api --- .../model/app/BaseWebAppConfiguration.java | 6 + .../model/app/WebAppConfiguration.java | 4 + .../io/cloudbeaver/model/user/WebUser.java | 5 + .../schema/service.admin.graphqls | 1 + .../service/admin/AdminUserInfo.java | 6 + .../CBEmbeddedSecurityController.java | 120 +++++++++++++++++- .../service/security/db/CBDatabase.java | 2 +- .../security/db/CBDatabaseInitialData.java | 6 + 8 files changed, 143 insertions(+), 7 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java index 719feb4ed3..25b1a23733 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java @@ -30,6 +30,7 @@ public abstract class BaseWebAppConfiguration implements WebAppConfiguration { protected final Map plugins; protected String defaultUserTeam; + protected String defaultUserCredentialsProfile; protected boolean resourceManagerEnabled; protected boolean showReadOnlyConnectionInfo; protected String[] enabledFeatures; @@ -105,4 +106,9 @@ public void setEnabledFeatures(String[] enabledFeatures) { public boolean isShowReadOnlyConnectionInfo() { return showReadOnlyConnectionInfo; } + + + public String getDefaultUserCredentialsProfile() { + return defaultUserCredentialsProfile; + } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebAppConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebAppConfiguration.java index 92c2388921..adc0afb372 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebAppConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebAppConfiguration.java @@ -17,6 +17,7 @@ package io.cloudbeaver.model.app; import org.jkiss.code.NotNull; +import org.jkiss.code.Nullable; import java.util.Map; @@ -32,6 +33,9 @@ public interface WebAppConfiguration { String getDefaultUserTeam(); + @Nullable + String getDefaultUserCredentialsProfile(); + T getPluginOption(@NotNull String pluginId, @NotNull String option); Map getPluginConfig(@NotNull String pluginId, boolean create); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java index bfc843edb4..e547e5109c 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java @@ -92,4 +92,9 @@ public String toString() { public String getAuthRole() { return user.getAuthRole(); } + + public String getCredentialsProfileId() { + return user.getCredentialsProfileId(); + } + } diff --git a/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls b/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls index fa77fb0dd7..155a99446c 100644 --- a/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls +++ b/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls @@ -43,6 +43,7 @@ type AdminUserInfo { linkedAuthProviders: [String!]! enabled: Boolean! authRole: String + credentialsProfileId: String @since(version: "23.3.4") } type AdminTeamInfo { 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 6f057c253a..6b789f14b4 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 @@ -59,6 +59,12 @@ public String getAuthRole() { return user.getAuthRole(); } + @Property + public String getCredentialsProfileId() { + return user.getCredentialsProfileId(); + } + + @Property public Map getMetaParameters() { return user.getMetaParameters(); 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 d9c223c900..65faa34ef3 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 @@ -76,6 +76,7 @@ public class CBEmbeddedSecurityController private static final String SUBJECT_USER = "U"; private static final String SUBJECT_TEAM = "R"; + private static final String SUBJECT_PROFILE = "P"; private static final Type MAP_STRING_OBJECT_TYPE = new TypeToken>() { }.getType(); private static final Gson gson = new GsonBuilder().create(); @@ -300,7 +301,9 @@ public SMUser getUserById(String userId) throws DBException { try (Connection dbCon = database.openConnection()) { SMUser user; try (PreparedStatement dbStat = dbCon.prepareStatement( - database.normalizeTableNames("SELECT USER_ID,IS_ACTIVE,DEFAULT_AUTH_ROLE FROM {table_prefix}CB_USER WHERE USER_ID=?") + database.normalizeTableNames( + "SELECT USER_ID,IS_ACTIVE,DEFAULT_AUTH_ROLE,CREDENTIALS_PROFILE_ID FROM {table_prefix}CB_USER " + + "WHERE USER_ID=?") )) { dbStat.setString(1, userId); try (ResultSet dbResult = dbStat.executeQuery()) { @@ -308,7 +311,8 @@ public SMUser getUserById(String userId) throws DBException { String userName = dbResult.getString(1); String active = dbResult.getString(2); String authRole = dbResult.getString(3); - user = new SMUser(userName, CHAR_BOOL_TRUE.equals(active), authRole); + String credentialsProfileId = dbResult.getString(4); + user = new SMUser(userName, CHAR_BOOL_TRUE.equals(active), authRole, credentialsProfileId); } else { return null; } @@ -373,7 +377,8 @@ public SMUser[] findUsers(@NotNull SMUserFilter filter) Map result = new LinkedHashMap<>(); // Read users try (PreparedStatement dbStat = dbCon.prepareStatement( - database.normalizeTableNames("SELECT USER_ID,IS_ACTIVE,DEFAULT_AUTH_ROLE FROM {table_prefix}CB_USER" + database.normalizeTableNames("SELECT USER_ID,IS_ACTIVE,DEFAULT_AUTH_ROLE,CREDENTIALS_PROFILE_ID FROM " + + "{table_prefix}CB_USER" + buildUsersFilter(filter) + "\nORDER BY USER_ID " + getOffsetLimitPart(filter)))) { int parameterIndex = setUsersFilterValues(dbStat, filter, 1); @@ -382,7 +387,9 @@ public SMUser[] findUsers(@NotNull SMUserFilter filter) String userId = dbResult.getString(1); String active = dbResult.getString(2); String authRole = dbResult.getString(3); - result.put(userId, new SMUser(userId, CHAR_BOOL_TRUE.equals(active), authRole)); + String credentialsProfileId = dbResult.getString(4); + result.put(userId, + new SMUser(userId, CHAR_BOOL_TRUE.equals(active), authRole, credentialsProfileId)); } } } @@ -971,7 +978,10 @@ private SMTeam fetchTeam(ResultSet dbResult) throws SQLException { } @Override - public void createTeam(String teamId, String name, String description, String grantor) throws DBCException { + public void createTeam( + @NotNull String teamId, @Nullable String name, @Nullable String description, + @NotNull String grantor + ) throws DBCException { if (CommonUtils.isEmpty(teamId)) { throw new DBCException("Empty team name is not allowed"); } @@ -1000,7 +1010,7 @@ public void createTeam(String teamId, String name, String description, String gr txn.commit(); } } catch (SQLException e) { - throw new DBCException("Error saving tem in database", e); + throw new DBCException("Error saving team in database", e); } } @@ -1078,6 +1088,104 @@ public void deleteTeam(String teamId, boolean force) throws DBCException { } } + @Override + @NotNull + public SMCredentialsProfile[] readAllCredentialsProfiles() throws DBCException { + List profiles = new ArrayList<>(); + try (var dbCon = database.openConnection(); + var dbStat = dbCon.prepareStatement(database.normalizeTableNames( + "SELECT PROFILE_ID, PROFILE_NAME, PROFILE_DESCRIPTION, PARENT_PROFILE_ID FROM " + + "{table_prefix}CB_CREDENTIALS_PROFILE ORDER BY PROFILE_ID" + )); + var dbResult = dbStat.executeQuery(); + ) { + while (dbResult.next()) { + String profileId = dbResult.getString(1); + String name = dbResult.getString(2); + String description = dbResult.getString(3); + String parentProfile = dbResult.getString(4); + profiles.add(new SMCredentialsProfile(profileId, name, description, parentProfile)); + } + return profiles.toArray(SMCredentialsProfile[]::new); + } catch (SQLException e) { + throw new DBCException("Error reading credentials profiles from database", e); + } + } + + @Override + public void createCredentialsProfile(@NotNull SMCredentialsProfile credentialsProfile) throws DBCException { + if (isSubjectExists(credentialsProfile.getCredentialsProfileId())) { + throw new DBCException("User, team or credentials profile '" + credentialsProfile.getCredentialsProfileId() + "' already " + + "exists"); + } + + try (var dbCon = database.openConnection(); + var txn = new JDBCTransaction(dbCon)) { + createAuthSubject(dbCon, credentialsProfile.getCredentialsProfileId(), SUBJECT_TEAM); + try (PreparedStatement dbStat = dbCon.prepareStatement( + database.normalizeTableNames("INSERT INTO {table_prefix}CB_CREDENTIALS_PROFILE" + + "(PROFILE_ID,PROFILE_NAME,PROFILE_DESCRIPTION,PARENT_PROFILE_ID) VALUES(?,?,?,?)"))) { + dbStat.setString(1, credentialsProfile.getCredentialsProfileId()); + dbStat.setString(2, CommonUtils.notEmpty(credentialsProfile.getName())); + dbStat.setString(3, CommonUtils.notEmpty(credentialsProfile.getProfileDescription())); + if (CommonUtils.isNotEmpty(credentialsProfile.getParentProfileId())) { + dbStat.setString(4, credentialsProfile.getParentProfileId()); + } else { + dbStat.setNull(4, Types.VARCHAR); + } + dbStat.execute(); + } + txn.commit(); + } catch (SQLException e) { + throw new DBCException("Error saving credentials profile in database", e); + } + } + + @Override + public void deleteCredentialsProfile(@NotNull String credentialsProfileId) throws DBCException { + String defaultUserCredentialsProfile = application.getAppConfiguration().getDefaultUserCredentialsProfile(); + if (CommonUtils.isNotEmpty(defaultUserCredentialsProfile) + && defaultUserCredentialsProfile.equals(credentialsProfileId)) { + throw new DBCException("Default credentials profile cannot be deleted"); + } + + try (var dbCon = database.openConnection(); + var txn = new JDBCTransaction(dbCon)) { + deleteAuthSubject(dbCon, credentialsProfileId); + JDBCUtils.executeStatement( + dbCon, + database.normalizeTableNames("DELETE FROM {table_prefix}CB_CREDENTIALS_PROFILE WHERE PROFILE_ID=?"), + credentialsProfileId + ); + txn.commit(); + } catch (SQLException e) { + throw new DBCException("Error deleting credentials profile from database", e); + } + } + + @Override + public void setUserCredentialsProfile(@NotNull String userId, @Nullable String credentialsProfileId) + throws DBCException { + try (var dbCon = database.openConnection(); + PreparedStatement dbStat = dbCon.prepareStatement( + database.normalizeTableNames( + "UPDATE {table_prefix}CB_USER SET CREDENTIALS_PROFILE_ID=? WHERE USER_ID=?")) + ) { + if (CommonUtils.isEmpty(credentialsProfileId)) { + String defaultCredentialsProfile = application.getAppConfiguration().getDefaultUserCredentialsProfile(); + if (defaultCredentialsProfile == null) { + dbStat.setNull(1, Types.VARCHAR); + } else { + dbStat.setString(1, defaultCredentialsProfile); + } + } else { + dbStat.setString(1, credentialsProfileId); + } + } catch (SQLException e) { + throw new DBCException("Error saving credentials profile for user", e); + } + } + /////////////////////////////////////////// // Subject functions 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 5cddbba56a..4837704288 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 @@ -301,7 +301,7 @@ private SMUser createAdminUser( SMUser adminUser = adminSecurityController.getUserById(adminName); if (adminUser == null) { - adminUser = new SMUser(adminName, true, "ADMINISTRATOR"); + adminUser = new SMUser(adminName, true, "ADMINISTRATOR", null); adminSecurityController.createUser(adminUser.getUserId(), adminUser.getMetaParameters(), true, adminUser.getAuthRole()); } diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java index 17c42babb2..6dd6bf94df 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java @@ -16,6 +16,7 @@ */ package io.cloudbeaver.service.security.db; +import org.jkiss.dbeaver.model.security.user.SMCredentialsProfile; import org.jkiss.dbeaver.model.security.user.SMTeam; import java.util.List; @@ -24,6 +25,7 @@ class CBDatabaseInitialData { private String adminName; private String adminPassword; private List teams; + private List credentialsProfiles; public String getAdminName() { return adminName; @@ -37,6 +39,10 @@ public List getTeams() { return teams; } + public List getCredentialsProfiles() { + return credentialsProfiles; + } + public void setTeams(List teams) { this.teams = teams; }