mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
CB-3834 secret controller redesign (#2343)
* CB-3834 Secret manager database schema * CB-3834 add credentials storage flat to teams * CB-3834 subject based secrets --------- Co-authored-by: Serge Rider <serge@jkiss.org> Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
This commit is contained in:
co-authored by
Serge Rider
kseniaguzeeva
parent
71a61047e2
commit
a2094a4d90
+2
-2
@@ -37,12 +37,12 @@ public class VoidSecretController implements DBSSecretController, DBSSecretContr
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSecretValue(@NotNull String secretId) {
|
||||
public String getPrivateSecretValue(@NotNull String secretId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecretValue(@NotNull String secretId, @Nullable String secretValue) throws DBException {
|
||||
public void setPrivateSecretValue(@NotNull String secretId, @Nullable String secretValue) throws DBException {
|
||||
throw new DBException("Secret controller is read-only");
|
||||
}
|
||||
|
||||
|
||||
@@ -60,8 +60,9 @@ CREATE TABLE {table_prefix}CB_WORKSPACE
|
||||
|
||||
CREATE TABLE {table_prefix}CB_AUTH_SUBJECT
|
||||
(
|
||||
SUBJECT_ID VARCHAR(128) NOT NULL,
|
||||
SUBJECT_TYPE VARCHAR(8) NOT NULL,
|
||||
SUBJECT_ID VARCHAR(128) NOT NULL,
|
||||
SUBJECT_TYPE VARCHAR(8) NOT NULL,
|
||||
IS_SECRET_STORAGE CHAR(1) DEFAULT 'Y' NOT NULL,
|
||||
|
||||
PRIMARY KEY (SUBJECT_ID)
|
||||
);
|
||||
@@ -105,16 +106,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)
|
||||
@@ -131,11 +146,10 @@ CREATE TABLE {table_prefix}CB_USER_PARAMETERS
|
||||
|
||||
CREATE TABLE {table_prefix}CB_TEAM
|
||||
(
|
||||
TEAM_ID VARCHAR(128) NOT NULL,
|
||||
TEAM_NAME VARCHAR(100) NOT NULL,
|
||||
TEAM_DESCRIPTION VARCHAR(255) NOT NULL,
|
||||
|
||||
CREATE_TIME TIMESTAMP NOT NULL,
|
||||
TEAM_ID VARCHAR(128) NOT NULL,
|
||||
TEAM_NAME VARCHAR(100) NOT NULL,
|
||||
TEAM_DESCRIPTION VARCHAR(255) NOT NULL,
|
||||
CREATE_TIME TIMESTAMP NOT NULL,
|
||||
|
||||
PRIMARY KEY (TEAM_ID),
|
||||
FOREIGN KEY (TEAM_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE
|
||||
@@ -315,3 +329,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_AUTH_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);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
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_AUTH_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;
|
||||
|
||||
ALTER TABLE {table_prefix}CB_AUTH_SUBJECT
|
||||
ADD COLUMN IS_SECRET_STORAGE CHAR(1) DEFAULT 'Y' NOT NULL;
|
||||
+45
-17
@@ -74,8 +74,6 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
protected static final String CHAR_BOOL_TRUE = "Y";
|
||||
protected static final String CHAR_BOOL_FALSE = "N";
|
||||
|
||||
private static final String SUBJECT_USER = "U";
|
||||
private static final String SUBJECT_TEAM = "R";
|
||||
private static final Type MAP_STRING_OBJECT_TYPE = new TypeToken<Map<String, Object>>() {
|
||||
}.getType();
|
||||
private static final Gson gson = new GsonBuilder().create();
|
||||
@@ -147,7 +145,7 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
boolean enabled,
|
||||
@Nullable String defaultAuthRole
|
||||
) throws DBException, SQLException {
|
||||
createAuthSubject(dbCon, userId, SUBJECT_USER);
|
||||
createAuthSubject(dbCon, userId, SMSubjectType.user, true);
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("INSERT INTO {table_prefix}CB_USER" +
|
||||
"(USER_ID,IS_ACTIVE,CREATE_TIME,DEFAULT_AUTH_ROLE) VALUES(?,?,?,?)"))
|
||||
@@ -254,9 +252,10 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
public SMTeam[] getUserTeams(String userId) throws DBException {
|
||||
Map<String, SMTeam> teams = new LinkedHashMap<>();
|
||||
try (Connection dbCon = database.openConnection()) {
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("SELECT R.* FROM {table_prefix}CB_USER_TEAM UR, {table_prefix}CB_TEAM R " +
|
||||
"WHERE UR.USER_ID=? AND UR.TEAM_ID=R.TEAM_ID"))
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(database.normalizeTableNames(
|
||||
"SELECT R.*,S.IS_SECRET_STORAGE FROM {table_prefix}CB_USER_TEAM UR, {table_prefix}CB_TEAM R, " +
|
||||
"{table_prefix}CB_AUTH_SUBJECT S " +
|
||||
"WHERE UR.USER_ID=? AND UR.TEAM_ID=R.TEAM_ID AND S.SUBJECT_ID=R.TEAM_ID"))
|
||||
) {
|
||||
dbStat.setString(1, userId);
|
||||
try (ResultSet dbResult = dbStat.executeQuery()) {
|
||||
@@ -300,15 +299,15 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
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 U.USER_ID,U.IS_ACTIVE,U.DEFAULT_AUTH_ROLE,S.IS_SECRET_STORAGE FROM " +
|
||||
"{table_prefix}CB_USER U, {table_prefix}CB_AUTH_SUBJECT S " +
|
||||
"WHERE U.USER_ID=? AND U.USER_ID=S.SUBJECT_ID")
|
||||
)) {
|
||||
dbStat.setString(1, userId);
|
||||
try (ResultSet dbResult = dbStat.executeQuery()) {
|
||||
if (dbResult.next()) {
|
||||
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);
|
||||
user = fetchUser(dbResult);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -909,7 +908,9 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
Map<String, SMTeam> teams = new LinkedHashMap<>();
|
||||
try (Statement dbStat = dbCon.createStatement()) {
|
||||
try (ResultSet dbResult = dbStat.executeQuery(
|
||||
database.normalizeTableNames("SELECT * FROM {table_prefix}CB_TEAM ORDER BY TEAM_ID"))) {
|
||||
database.normalizeTableNames("SELECT T.*,S.IS_SECRET_STORAGE FROM {table_prefix}CB_TEAM T," +
|
||||
"{table_prefix}CB_AUTH_SUBJECT S " +
|
||||
"WHERE T.TEAM_ID=S.SUBJECT_ID ORDER BY TEAM_ID"))) {
|
||||
while (dbResult.next()) {
|
||||
SMTeam team = fetchTeam(dbResult);
|
||||
teams.put(team.getTeamId(), team);
|
||||
@@ -966,7 +967,18 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
return new SMTeam(
|
||||
dbResult.getString("TEAM_ID"),
|
||||
dbResult.getString("TEAM_NAME"),
|
||||
dbResult.getString("TEAM_DESCRIPTION")
|
||||
dbResult.getString("TEAM_DESCRIPTION"),
|
||||
stringToBoolean(dbResult.getString("IS_SECRET_STORAGE"))
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private SMUser fetchUser(ResultSet dbResult) throws SQLException {
|
||||
return new SMUser(
|
||||
dbResult.getString("USER_ID"),
|
||||
stringToBoolean(dbResult.getString("IS_ACTIVE")),
|
||||
dbResult.getString("DEFAULT_AUTH_ROLE"),
|
||||
stringToBoolean(dbResult.getString("IS_SECRET_STORAGE"))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -980,7 +992,7 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
}
|
||||
try (Connection dbCon = database.openConnection()) {
|
||||
try (JDBCTransaction txn = new JDBCTransaction(dbCon)) {
|
||||
createAuthSubject(dbCon, teamId, SUBJECT_TEAM);
|
||||
createAuthSubject(dbCon, teamId, SMSubjectType.team, true);
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("INSERT INTO {table_prefix}CB_TEAM" +
|
||||
"(TEAM_ID,TEAM_NAME,TEAM_DESCRIPTION,CREATE_TIME) VALUES(?,?,?,?)"))) {
|
||||
@@ -2794,15 +2806,31 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
}
|
||||
}
|
||||
|
||||
private void createAuthSubject(Connection dbCon, String subjectId, String subjectType) throws SQLException {
|
||||
private void createAuthSubject(
|
||||
Connection dbCon,
|
||||
String subjectId,
|
||||
SMSubjectType subjectType,
|
||||
boolean secretStorage
|
||||
) throws SQLException {
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("INSERT INTO {table_prefix}CB_AUTH_SUBJECT(SUBJECT_ID,SUBJECT_TYPE) VALUES(?,?)"))) {
|
||||
database.normalizeTableNames(
|
||||
"INSERT INTO {table_prefix}CB_AUTH_SUBJECT(SUBJECT_ID,SUBJECT_TYPE,IS_SECRET_STORAGE) " +
|
||||
"VALUES (?,?,?)"))) {
|
||||
dbStat.setString(1, subjectId);
|
||||
dbStat.setString(2, subjectType);
|
||||
dbStat.setString(2, subjectType.getCode());
|
||||
dbStat.setString(3, booleanToString(secretStorage));
|
||||
dbStat.execute();
|
||||
}
|
||||
}
|
||||
|
||||
public static String booleanToString(boolean value) {
|
||||
return value ? CHAR_BOOL_TRUE : CHAR_BOOL_FALSE;
|
||||
}
|
||||
|
||||
public static boolean stringToBoolean(@Nullable String value) {
|
||||
return CHAR_BOOL_TRUE.equals(value);
|
||||
}
|
||||
|
||||
private void deleteAuthSubject(Connection dbCon, String subjectId) throws SQLException {
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("DELETE FROM {table_prefix}CB_AUTH_SUBJECT WHERE SUBJECT_ID=?"))) {
|
||||
|
||||
+1
-1
@@ -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 = 17;
|
||||
|
||||
private static final String DEFAULT_DB_USER_NAME = "cb-data";
|
||||
private static final String DEFAULT_DB_PWD_FILE = ".database-credentials.dat";
|
||||
|
||||
Reference in New Issue
Block a user