Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CB-3834 secret controller redesign #2343

Merged
merged 5 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ public VoidSecretController() {

@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");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
);
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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);
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@
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();
Expand Down Expand Up @@ -147,7 +145,7 @@
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(?,?,?,?)"))
Expand Down Expand Up @@ -254,9 +252,10 @@
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()) {
Expand Down Expand Up @@ -300,15 +299,15 @@
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;
}
Expand Down Expand Up @@ -909,7 +908,9 @@
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);
Expand Down Expand Up @@ -966,7 +967,18 @@
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"))
);
}

Expand All @@ -980,7 +992,7 @@
}
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(?,?,?,?)"))) {
Expand Down Expand Up @@ -2794,15 +2806,31 @@
}
}

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) {

Check warning on line 2826 in server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java

View check run for this annotation

Jenkins-CI-integration / CheckStyle Java Report

server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java#L2826

Missing a Javadoc comment.
return value ? CHAR_BOOL_TRUE : CHAR_BOOL_FALSE;
}

public static boolean stringToBoolean(@Nullable String value) {

Check warning on line 2830 in server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java

View check run for this annotation

Jenkins-CI-integration / CheckStyle Java Report

server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java#L2830

Missing a Javadoc comment.
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=?"))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Loading