Skip to content

Commit

Permalink
CB-3834 secret controller redesign (#2343)
Browse files Browse the repository at this point in the history
* CB-3834 Secret manager database schema

* CB-3834 add credentials storage flat to teams

* CB-3834 subject based secrets

---------

Co-authored-by: Serge Rider <[email protected]>
Co-authored-by: kseniaguzeeva <[email protected]>
  • Loading branch information
3 people authored Jan 31, 2024
1 parent 71a6104 commit a2094a4
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 29 deletions.
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 @@ 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();
Expand Down Expand Up @@ -147,7 +145,7 @@ public void createUser(
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 void setUserTeams(@NotNull Connection dbCon, String userId, String[] team
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 @@ 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 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 @@ public SMTeam[] readAllTeams() throws DBCException {
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 @@ private SMTeam fetchTeam(ResultSet dbResult) throws SQLException {
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 @@ public void createTeam(String teamId, String name, String description, String gr
}
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 @@ public void initializeMetaInformation() throws DBCException {
}
}

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=?"))) {
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

0 comments on commit a2094a4

Please sign in to comment.