From f934853107868ecac48a32c920b0c0599c4cae3f Mon Sep 17 00:00:00 2001 From: Aleksandr Skoblikov Date: Fri, 3 Nov 2023 13:32:40 +0100 Subject: [PATCH] CB-3971 validate main session --- .../db/cb_schema_create.sql | 2 +- .../db/cb_schema_update_14.sql | 2 + .../CBEmbeddedSecurityController.java | 70 ++++++++++++------- .../service/security/db/CBDatabase.java | 2 +- .../internal/AuthAttemptSessionInfo.java | 9 ++- 5 files changed, 57 insertions(+), 28 deletions(-) create mode 100644 server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_14.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 febb3482c3..300af38bdb 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 @@ -276,7 +276,7 @@ CREATE TABLE {table_prefix}CB_AUTH_ATTEMPT SESSION_ID VARCHAR(64), SESSION_TYPE VARCHAR(64) NOT NULL, APP_SESSION_STATE TEXT NOT NULL, - + IS_MAIN_AUTH CHAR(1) DEFAULT 'Y' NOT NULL, CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (AUTH_ID), diff --git a/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_14.sql b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_14.sql new file mode 100644 index 0000000000..39927e4dd4 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.security/db/cb_schema_update_14.sql @@ -0,0 +1,2 @@ +ALTER TABLE {table_prefix}CB_AUTH_ATTEMPT + ADD COLUMN IS_MAIN_AUTH CHAR(1) DEFAULT 'Y' NOT NULL; \ No newline at end of file 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 b96cb165e3..47dd7cf7c5 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 @@ -1289,9 +1289,9 @@ public SMAuthInfo authenticate( throw new SMException("Unsupported authentication provider: " + authProviderId); } var authProgressMonitor = new LoggingProgressMonitor(log); + boolean isMainSession = previousSmSessionId == null; try (Connection dbCon = database.openConnection()) { try (JDBCTransaction txn = new JDBCTransaction(dbCon)) { - boolean isMainSession = previousSmSessionId == null; Map securedUserIdentifyingCredentials = userCredentials; WebAuthProviderDescriptor authProviderDescriptor = getAuthProvider(authProviderId); var authProviderInstance = authProviderDescriptor.getInstance(); @@ -1334,7 +1334,7 @@ public SMAuthInfo authenticate( String signOutLink = authProviderFederated.getSignOutLink(authProviderConfigurationId, Map.of()); Map authData = Map.of(new SMAuthConfigurationReference(authProviderId, authProviderConfigurationId), filteredUserCreds); - return SMAuthInfo.inProgress(authAttemptId, signInLink, signOutLink, authData); + return SMAuthInfo.inProgress(authAttemptId, signInLink, signOutLink, authData, isMainSession); } txn.commit(); return finishAuthentication( @@ -1342,7 +1342,9 @@ public SMAuthInfo authenticate( authAttemptId, null, null, - Map.of(new SMAuthConfigurationReference(authProviderId, authProviderConfigurationId), securedUserIdentifyingCredentials) + Map.of(new SMAuthConfigurationReference(authProviderId, authProviderConfigurationId), + securedUserIdentifyingCredentials), + isMainSession ), true, false @@ -1385,8 +1387,9 @@ private String createNewAuthAttempt( try (PreparedStatement dbStat = dbCon.prepareStatement( database.normalizeTableNames( "INSERT INTO {table_prefix}CB_AUTH_ATTEMPT" + - "(AUTH_ID,AUTH_STATUS,APP_SESSION_ID,SESSION_TYPE,APP_SESSION_STATE,SESSION_ID) " + - "VALUES(?,?,?,?,?,?)" + "(AUTH_ID,AUTH_STATUS,APP_SESSION_ID,SESSION_TYPE,APP_SESSION_STATE," + + "SESSION_ID,IS_MAIN_AUTH) " + + "VALUES(?,?,?,?,?,?,?)" ) )) { dbStat.setString(1, authAttemptId); @@ -1399,6 +1402,7 @@ private String createNewAuthAttempt( } else { dbStat.setNull(6, Types.VARCHAR); } + dbStat.setString(7, isMainSession ? CHAR_BOOL_TRUE : CHAR_BOOL_FALSE); dbStat.execute(); } @@ -1518,9 +1522,11 @@ private SMAuthInfo getAuthStatus(@NotNull String authId, boolean readExpiredData SMAuthStatus smAuthStatus; String authError; String smSessionId; + boolean isMainAuth; try (PreparedStatement dbStat = dbCon.prepareStatement( database.normalizeTableNames( - "SELECT AUTH_STATUS,AUTH_ERROR,SESSION_ID FROM {table_prefix}CB_AUTH_ATTEMPT WHERE AUTH_ID=?" + "SELECT AUTH_STATUS,AUTH_ERROR,SESSION_ID,IS_MAIN_AUTH FROM {table_prefix}CB_AUTH_ATTEMPT WHERE " + + "AUTH_ID=?" ) )) { dbStat.setString(1, authId); @@ -1531,6 +1537,7 @@ private SMAuthInfo getAuthStatus(@NotNull String authId, boolean readExpiredData smAuthStatus = SMAuthStatus.valueOf(dbResult.getString(1)); authError = dbResult.getString(2); smSessionId = dbResult.getString(3); + isMainAuth = CHAR_BOOL_TRUE.equals(dbResult.getString(4)); } } Map authData = new LinkedHashMap<>(); @@ -1571,11 +1578,11 @@ private SMAuthInfo getAuthStatus(@NotNull String authId, boolean readExpiredData if (smAuthStatus != SMAuthStatus.SUCCESS) { switch (smAuthStatus) { case IN_PROGRESS: - return SMAuthInfo.inProgress(authId, signInLink, signOutLink, authData); + return SMAuthInfo.inProgress(authId, signInLink, signOutLink, authData, isMainAuth); case ERROR: - return SMAuthInfo.error(authId, authError); + return SMAuthInfo.error(authId, authError, isMainAuth); case EXPIRED: - return SMAuthInfo.expired(authId, readExpiredData ? authData : Map.of()); + return SMAuthInfo.expired(authId, readExpiredData ? authData : Map.of(), isMainAuth); default: throw new SMException("Unknown auth status:" + smAuthStatus); } @@ -1583,16 +1590,21 @@ private SMAuthInfo getAuthStatus(@NotNull String authId, boolean readExpiredData SMTokens smTokens = findTokenBySmSession(smSessionId); SMAuthPermissions authPermissions = getTokenPermissions(smTokens.getSmAccessToken()); - String authRole = readTokenAuthRole(smTokens.getSmAccessToken()); - var successAuthStatus = SMAuthInfo.successMainSession( - authId, - smTokens.getSmAccessToken(), - smTokens.getSmRefreshToken(), - authPermissions, - authData, - authRole - ); - return successAuthStatus; + + if (isMainAuth) { + String authRole = readTokenAuthRole(smTokens.getSmAccessToken()); + return SMAuthInfo.successMainSession( + authId, + smTokens.getSmAccessToken(), + smTokens.getSmRefreshToken(), + authPermissions, + authData, + authRole + ); + } else { + //TODO remove permissions from child session + return SMAuthInfo.successChildSession(authId, authPermissions, authData); + } } catch (SQLException e) { throw new DBException("Error while read auth info", e); } @@ -1792,7 +1804,7 @@ private SMAuthInfo finishAuthentication( DBRProgressMonitor finishAuthMonitor = new LoggingProgressMonitor(log); AuthAttemptSessionInfo authAttemptSessionInfo = readAuthAttemptSessionInfo(authId); - boolean isMainAuthSession = authAttemptSessionInfo.getSmSessionId() == null; + boolean isMainAuthSession = authAttemptSessionInfo.isMainAuth(); SMTokens smTokens = null; SMAuthPermissions permissions = null; @@ -1850,7 +1862,7 @@ private SMAuthInfo finishAuthentication( if (userIdFromCreds == null) { var error = "Invalid user credentials"; updateAuthStatus(authId, SMAuthStatus.ERROR, storedUserData, error); - return SMAuthInfo.error(authId, error); + return SMAuthInfo.error(authId, error, isMainAuthSession); } if (autoAssign != null && !CommonUtils.isEmpty(autoAssign.getExternalTeamIds())) { @@ -2036,8 +2048,9 @@ protected String updateUserAuthRoleIfNeeded(@Nullable String userId, @Nullable S private AuthAttemptSessionInfo readAuthAttemptSessionInfo(@NotNull String authId) throws DBException { try (Connection dbCon = database.openConnection()) { try (PreparedStatement dbStat = dbCon.prepareStatement( - database.normalizeTableNames("SELECT APP_SESSION_ID,SESSION_TYPE,APP_SESSION_STATE,SESSION_ID FROM " + - "{table_prefix}CB_AUTH_ATTEMPT WHERE AUTH_ID=?") + database.normalizeTableNames( + "SELECT APP_SESSION_ID,SESSION_TYPE,APP_SESSION_STATE,SESSION_ID,IS_MAIN_AUTH " + + "FROM {table_prefix}CB_AUTH_ATTEMPT WHERE AUTH_ID=?") )) { dbStat.setString(1, authId); try (ResultSet dbResult = dbStat.executeQuery()) { @@ -2050,8 +2063,15 @@ private AuthAttemptSessionInfo readAuthAttemptSessionInfo(@NotNull String authId dbResult.getString(3), MAP_STRING_OBJECT_TYPE ); String smSessionId = dbResult.getString(4); - - return new AuthAttemptSessionInfo(appSessionId, smSessionId, sessionType, sessionParams); + boolean isMainAuth = CHAR_BOOL_TRUE.equals(dbResult.getString(5)); + + return new AuthAttemptSessionInfo( + appSessionId, + smSessionId, + sessionType, + sessionParams, + isMainAuth + ); } } } catch (SQLException e) { 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 5ce47a1c59..ff14ecb78a 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 @@ -72,7 +72,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 = 13; + private static final int CURRENT_SCHEMA_VERSION = 14; private static final String DEFAULT_DB_USER_NAME = "cb-data"; private static final String DEFAULT_DB_PWD_FILE = ".database-credentials.dat"; diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/AuthAttemptSessionInfo.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/AuthAttemptSessionInfo.java index 24c7803483..7354896a78 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/AuthAttemptSessionInfo.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/AuthAttemptSessionInfo.java @@ -33,17 +33,20 @@ public class AuthAttemptSessionInfo { private final SMSessionType sessionType; @NotNull private final Map sessionParams; + private final boolean mainAuth; public AuthAttemptSessionInfo( @NotNull String appSessionId, @Nullable String smSessionId, @NotNull SMSessionType sessionType, - @NotNull Map sessionParams + @NotNull Map sessionParams, + boolean mainAuth ) { this.appSessionId = appSessionId; this.smSessionId = smSessionId; this.sessionType = sessionType; this.sessionParams = sessionParams; + this.mainAuth = mainAuth; } @NotNull @@ -65,4 +68,8 @@ public Map getSessionParams() { public String getSmSessionId() { return smSessionId; } + + public boolean isMainAuth() { + return mainAuth; + } }