diff --git a/server/integration-test/src/test/java/com/oceanbase/odc/metadb/connection/ConnectionConfigRepositoryTest.java b/server/integration-test/src/test/java/com/oceanbase/odc/metadb/connection/ConnectionConfigRepositoryTest.java index 1cadd25370..611676b96b 100644 --- a/server/integration-test/src/test/java/com/oceanbase/odc/metadb/connection/ConnectionConfigRepositoryTest.java +++ b/server/integration-test/src/test/java/com/oceanbase/odc/metadb/connection/ConnectionConfigRepositoryTest.java @@ -44,6 +44,7 @@ public class ConnectionConfigRepositoryTest extends ServiceTestEnv { private static final String NAME = "TEST_C1"; private static final String CLUSTER_NAME = "C1"; private static final String TENANT_NAME = "T1"; + private static final String USERNAME = "odcTest"; @Autowired private ConnectionConfigRepository repository; @@ -148,7 +149,8 @@ public void findAll_BySpecsMatch_Found() { .and(ConnectionSpecs.idLike(saved.getId().toString())) .and(ConnectionSpecs.hostLike(connection.getHost())) .and(ConnectionSpecs.portLike(connection.getPort().toString())) - .and(ConnectionSpecs.isNotTemp()); + .and(ConnectionSpecs.isNotTemp()) + .and(ConnectionSpecs.usernameEqual(USERNAME)); List all = repository.findAll(spec); @@ -280,6 +282,7 @@ private ConnectionEntity createEntity(ConnectionVisibleScope visibleScope) { entity.setCreateTime(null); entity.setUpdateTime(null); entity.setTemp(false); + entity.setUsername(USERNAME); if (visibleScope == ConnectionVisibleScope.PRIVATE) { entity.setOwnerId(CREATOR_ID); } else { diff --git a/server/integration-test/src/test/java/com/oceanbase/odc/service/connection/ConnectionStatusManagerTest.java b/server/integration-test/src/test/java/com/oceanbase/odc/service/connection/ConnectionStatusManagerTest.java index fd872eab6a..c664e3309c 100644 --- a/server/integration-test/src/test/java/com/oceanbase/odc/service/connection/ConnectionStatusManagerTest.java +++ b/server/integration-test/src/test/java/com/oceanbase/odc/service/connection/ConnectionStatusManagerTest.java @@ -71,14 +71,6 @@ public void setUp() throws Exception { statusManager.clear(); } - @Test - public void getAndRefreshStatus_PasswordSavedFalse_Return_NONPASSWORD() { - ConnectionConfig connection = newConnection(); - connection.setPasswordSaved(false); - CheckState checkState = statusManager.getAndRefreshStatus(connection); - Assert.assertEquals(ConnectionStatus.NOPASSWORD, checkState.getStatus()); - } - @Test public void getAndRefreshStatus_EnabledFalse_Return_DISABLED() { ConnectionConfig connection = newConnection(); diff --git a/server/integration-test/src/test/java/com/oceanbase/odc/service/connection/ConnectionTestingTest.java b/server/integration-test/src/test/java/com/oceanbase/odc/service/connection/ConnectionTestingTest.java index ec6b726312..f1d02b2bd0 100644 --- a/server/integration-test/src/test/java/com/oceanbase/odc/service/connection/ConnectionTestingTest.java +++ b/server/integration-test/src/test/java/com/oceanbase/odc/service/connection/ConnectionTestingTest.java @@ -46,7 +46,7 @@ public class ConnectionTestingTest { @Mock private ConnectionSSLAdaptor sslAdaptor; @Mock - private ConnectionEnvironmentAdapter environmentAdapter; + private DefaultConnectionAdapter environmentAdapter; @Before public void setUp() throws Exception { diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/shared/constant/ConnectionStatus.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/shared/constant/ConnectionStatus.java index 4228b77a1d..5bca4fbca3 100644 --- a/server/odc-core/src/main/java/com/oceanbase/odc/core/shared/constant/ConnectionStatus.java +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/shared/constant/ConnectionStatus.java @@ -31,10 +31,6 @@ public enum ConnectionStatus { * 检测中 */ TESTING, - /** - * 密码未保存,不进行检测 - */ - NOPASSWORD, /** * 连接已禁用,不进行检测 */ diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/metadb/connection/ConnectionSpecs.java b/server/odc-service/src/main/java/com/oceanbase/odc/metadb/connection/ConnectionSpecs.java index fb08aa6cb4..cfa90d86a2 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/metadb/connection/ConnectionSpecs.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/metadb/connection/ConnectionSpecs.java @@ -117,6 +117,10 @@ public static Specification userIdEqual(Long userId) { return columnEqual("visibleScope", ConnectionVisibleScope.PRIVATE).and(columnEqual("ownerId", userId)); } + public static Specification usernameEqual(String username) { + return columnEqual("username", username); + } + public static Specification dialectTypeIn(List dialectTypes) { return in("dialectType", dialectTypes, DialectType.class); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionAdapter.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionAdapter.java new file mode 100644 index 0000000000..7b8d7b1ba0 --- /dev/null +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionAdapter.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.oceanbase.odc.service.connection; + +import com.oceanbase.odc.service.connection.model.CloudConnectionConfig; + +/** + * @author jingtian + * @date 2024/4/2 + */ +public interface ConnectionAdapter { + public T adaptConfig(T connectionConfig); +} diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionEncryption.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionEncryption.java index 67e479ddd0..38f0c298eb 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionEncryption.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionEncryption.java @@ -40,7 +40,7 @@ public class ConnectionEncryption { @Autowired private EncryptionFacade encryptionFacade; - ConnectionConfig encryptPasswords(ConnectionConfig connection) { + public ConnectionConfig encryptPasswords(ConnectionConfig connection) { if (Objects.isNull(connection.getCipher())) { connection.setCipher(Cipher.AES256SALT); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionService.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionService.java index 586a4b2420..9404331b54 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionService.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionService.java @@ -167,7 +167,7 @@ public class ConnectionService { private ConnectProperties connectProperties; @Autowired - private ConnectionEnvironmentAdapter environmentAdapter; + private DefaultConnectionAdapter environmentAdapter; @Autowired private ConnectionSSLAdaptor connectionSSLAdaptor; @@ -294,6 +294,7 @@ public ConnectionConfig innerCreate(@NotNull @Valid ConnectionConfig connection, PreConditions.notNull(connection.getPassword(), "connection.password"); } else { connection.setPassword(null); + connection.setPasswordEncrypted(null); } connectionEncryption.encryptPasswords(connection); @@ -588,6 +589,9 @@ public ConnectionConfig update(@NotNull Long id, @NotNull @Valid ConnectionConfi new Object[] {connection.getName()}, "same datasource name exists"); } }); + if (Boolean.FALSE.equals(connection.getPasswordSaved())) { + connection.setPassword(null); + } connectionEncryption.encryptPasswords(connection); connection.fillEncryptedPasswordFromSavedIfNull(saved); @@ -748,6 +752,9 @@ private Page innerList(@NotNull QueryConnectionParams params, if (CollectionUtils.isNotEmpty(params.getIds())) { spec = spec.and(ConnectionSpecs.idIn(params.getIds())); } + if (Objects.nonNull(params.getUsername())) { + spec = spec.and(ConnectionSpecs.usernameEqual(params.getUsername())); + } spec = spec.and(ConnectionSpecs.sort(pageable.getSort())); Pageable page = pageable.equals(Pageable.unpaged()) ? pageable : PageRequest.of(pageable.getPageNumber(), pageable.getPageSize()); diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionStatusManager.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionStatusManager.java index e5a0c7b37f..ed3f29befa 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionStatusManager.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionStatusManager.java @@ -88,9 +88,6 @@ public class ConnectionStatusManager { CheckState getAndRefreshStatus(ConnectionConfig connection) { PreConditions.notNull(connection, "connection"); - if (Objects.nonNull(connection.getPasswordSaved()) && !connection.getPasswordSaved()) { - return CheckState.of(ConnectionStatus.NOPASSWORD); - } if (Objects.nonNull(connection.getEnabled()) && !connection.getEnabled()) { return CheckState.of(ConnectionStatus.DISABLED); } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionTesting.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionTesting.java index 578680172d..def37a74d7 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionTesting.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionTesting.java @@ -72,7 +72,7 @@ public class ConnectionTesting { @Autowired private ConnectProperties connectProperties; @Autowired - private ConnectionEnvironmentAdapter environmentAdapter; + private DefaultConnectionAdapter environmentAdapter; @Autowired private ConnectionSSLAdaptor connectionSSLAdaptor; @Autowired @@ -82,10 +82,9 @@ public class ConnectionTesting { public ConnectionTestResult test(@NotNull @Valid TestConnectionReq req) { PreConditions.notNull(req, "req"); + environmentAdapter.adaptConfig(req); PreConditions.validArgumentState(Objects.nonNull(req.getPassword()), ErrorCodes.ConnectionPasswordMissed, null, "password required for connection without password saved"); - - environmentAdapter.adaptConfig(req); cloudMetadataClient.checkPermission(OBTenant.of(req.getClusterName(), req.getTenantName()), req.getInstanceType(), false, CloudPermissionAction.READONLY); connectionSSLAdaptor.adapt(req); @@ -232,7 +231,6 @@ private ConnectionConfig reqToConnectionConfig(TestConnectionReq req) { OBTenantEndpoint endpoint = req.getEndpoint(); if (Objects.nonNull(endpoint) && OceanBaseAccessMode.IC_PROXY == endpoint.getAccessMode()) { - config.setClusterName(null); config.setEndpoint(endpoint); } if (StringUtils.isNotBlank(req.getOBTenantName())) { diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionEnvironmentAdapter.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/DefaultConnectionAdapter.java similarity index 98% rename from server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionEnvironmentAdapter.java rename to server/odc-service/src/main/java/com/oceanbase/odc/service/connection/DefaultConnectionAdapter.java index 29f61553b9..09c52d1bd0 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/ConnectionEnvironmentAdapter.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/DefaultConnectionAdapter.java @@ -26,7 +26,7 @@ import com.oceanbase.odc.service.connection.model.OBTenantEndpoint; @Component -public class ConnectionEnvironmentAdapter { +public class DefaultConnectionAdapter implements ConnectionAdapter { @Autowired private CloudMetadataClient cloudMetadataClient; @@ -71,5 +71,4 @@ public T adaptConfig(T connectionConfig) { connectionConfig.setEndpoint(endpoint); return connectionConfig; } - } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/database/DatabaseSyncManager.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/database/DatabaseSyncManager.java index 18430e78ea..a36c447a0d 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/database/DatabaseSyncManager.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/database/DatabaseSyncManager.java @@ -16,16 +16,23 @@ package com.oceanbase.odc.service.connection.database; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.oceanbase.odc.core.authority.util.SkipAuthorize; import com.oceanbase.odc.core.shared.exception.BadRequestException; +import com.oceanbase.odc.metadb.iam.UserEntity; import com.oceanbase.odc.service.connection.model.ConnectionConfig; +import com.oceanbase.odc.service.iam.UserService; import com.oceanbase.odc.service.iam.util.SecurityContextUtils; import lombok.NonNull; @@ -41,15 +48,27 @@ public class DatabaseSyncManager { @Autowired private DatabaseService databaseService; + @Autowired + private UserService userService; @Autowired @Qualifier("syncDatabaseTaskExecutor") private ThreadPoolTaskExecutor executor; + LoadingCache id2UserEntity = CacheBuilder.newBuilder().maximumSize(100) + .expireAfterWrite(10, TimeUnit.MINUTES) + .build(new CacheLoader() { + @Override + public UserEntity load(Long creatorId) { + return userService.nullSafeGet(creatorId); + } + }); + @SkipAuthorize("internal usage") public Future submitSyncDataSourceTask(@NonNull ConnectionConfig connection) { return doExecute(() -> executor.submit(() -> { - SecurityContextUtils.setCurrentUser(connection.getCreatorId(), connection.getOrganizationId(), null); + Long creatorId = connection.getCreatorId(); + SecurityContextUtils.setCurrentUser(creatorId, connection.getOrganizationId(), getAccountName(creatorId)); return databaseService.internalSyncDataSourceSchemas(connection.getId()); })); } @@ -61,4 +80,15 @@ private Future doExecute(Supplier> supplier) { throw new BadRequestException("sync database failed"); } } + + private String getAccountName(@NonNull Long creatorId) { + try { + UserEntity userEntity = id2UserEntity.get(creatorId); + Validate.notNull(userEntity, "UserEntity not found by id:" + creatorId); + return userEntity.getAccountName(); + } catch (Exception e) { + log.warn("Failed to get user entity from cache, message:{}", e.getMessage()); + return null; + } + } } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/ConnectionConfig.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/ConnectionConfig.java index 7947370c86..e608d6b700 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/ConnectionConfig.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/ConnectionConfig.java @@ -381,6 +381,9 @@ public void fillPasswordFromSavedIfNull(ConnectionConfig saved) { } public void fillEncryptedPasswordFromSavedIfNull(ConnectionConfig saved) { + if (Boolean.FALSE.equals(this.getPasswordSaved())) { + return; + } PreConditions.notNull(saved, "saved"); if (Objects.isNull(this.passwordEncrypted)) { setPasswordEncrypted(saved.getPasswordEncrypted()); diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/OBInstanceStatus.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/OBInstanceStatus.java index 7f8f2ac807..de0ec2081b 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/OBInstanceStatus.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/OBInstanceStatus.java @@ -36,7 +36,13 @@ public enum OBInstanceStatus { ABNORMAL("ABNORMAL"), - OFFLINE("OFFLINE"); + OFFLINE("OFFLINE"), + + PENDING_STOP("PENDING_STOP"), + + STOPPED("STOPPED"), + + PENDING_START("PENDING_START"); private String name; diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/OBInstanceType.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/OBInstanceType.java index fc6b062bc0..8f2535a10a 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/OBInstanceType.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/OBInstanceType.java @@ -32,7 +32,8 @@ public enum OBInstanceType implements Translatable { MYSQL_TENANT("mtenant"), ORACLE_TENANT("otenant"), MYSQL_SERVERLESS("mtenant_serverless"), - ORACLE_SERVERLESS("otenant_serverless"); + ORACLE_SERVERLESS("otenant_serverless"), + DEDICATED("DEDICATED"); @Getter private String value; diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/QueryConnectionParams.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/QueryConnectionParams.java index a7cc48bd5e..0fafaea2ac 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/QueryConnectionParams.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/connection/model/QueryConnectionParams.java @@ -55,5 +55,9 @@ public class QueryConnectionParams { private List permittedActions; private String hostPort; private String name; + /** + * Database username + */ + private String username; } diff --git a/server/odc-service/src/main/java/com/oceanbase/odc/service/session/ConnectSessionService.java b/server/odc-service/src/main/java/com/oceanbase/odc/service/session/ConnectSessionService.java index 58d1ee72af..42b35b3605 100644 --- a/server/odc-service/src/main/java/com/oceanbase/odc/service/session/ConnectSessionService.java +++ b/server/odc-service/src/main/java/com/oceanbase/odc/service/session/ConnectSessionService.java @@ -60,7 +60,6 @@ import com.oceanbase.odc.core.shared.exception.InternalServerError; import com.oceanbase.odc.core.shared.exception.NotFoundException; import com.oceanbase.odc.core.shared.exception.OverLimitException; -import com.oceanbase.odc.core.shared.exception.VerifyException; import com.oceanbase.odc.core.sql.execute.task.SqlExecuteTaskManagerFactory; import com.oceanbase.odc.core.sql.split.SqlCommentProcessor; import com.oceanbase.odc.core.task.DefaultTaskManager; @@ -77,7 +76,6 @@ import com.oceanbase.odc.service.connection.database.model.Database; import com.oceanbase.odc.service.connection.model.ConnectProperties; import com.oceanbase.odc.service.connection.model.ConnectionConfig; -import com.oceanbase.odc.service.connection.model.ConnectionTestResult; import com.oceanbase.odc.service.connection.model.CreateSessionReq; import com.oceanbase.odc.service.connection.model.CreateSessionResp; import com.oceanbase.odc.service.connection.model.DBSessionResp; @@ -257,6 +255,8 @@ public ConnectionSession create(@NotNull CreateSessionReq req) { ConnectionConfig connection = connectionService.getForConnectionSkipPermissionCheck(dataSourceId); cloudMetadataClient.checkPermission(OBTenant.of(connection.getClusterName(), connection.getTenantName()), connection.getInstanceType(), false, CloudPermissionAction.READONLY); + PreConditions.validArgumentState(Objects.nonNull(connection.getPassword()), + ErrorCodes.ConnectionPasswordMissed, null, "password required for connection without password saved"); if (StringUtils.isNotBlank(schemaName) && connection.getDialectType().isOracle()) { schemaName = com.oceanbase.odc.common.util.StringUtils.quoteOracleIdentifier(schemaName); } @@ -265,10 +265,6 @@ public ConnectionSession create(@NotNull CreateSessionReq req) { Set actions = authorizationFacade.getAllPermittedActions(authenticationFacade.currentUser(), ResourceType.ODC_CONNECTION, "" + dataSourceId); connection.setPermittedActions(actions); - ConnectionTestResult result = connectionTesting.test(connection); - if (!result.isActive() && result.getErrorCode() != ErrorCodes.ConnectionInitScriptFailed) { - throw new VerifyException(result.getErrorMessage()); - } SqlExecuteTaskManagerFactory factory = new SqlExecuteTaskManagerFactory(this.monitorTaskManager, "console", 1); if (StringUtils.isNotEmpty(schemaName)) { diff --git a/server/starters/web-starter/src/main/java/com/oceanbase/odc/migrate/WebModeMultiOrganizationMetaDB.java b/server/starters/web-starter/src/main/java/com/oceanbase/odc/migrate/WebModeMultiOrganizationMetaDB.java index de980a8ce7..64c2d9baea 100644 --- a/server/starters/web-starter/src/main/java/com/oceanbase/odc/migrate/WebModeMultiOrganizationMetaDB.java +++ b/server/starters/web-starter/src/main/java/com/oceanbase/odc/migrate/WebModeMultiOrganizationMetaDB.java @@ -46,7 +46,7 @@ @DependsOn({"localObjectStorageFacade", "springContextUtil"}) // can't remove ,cause migrate is after environment properties set. @ConditionalOnProperty(value = "odc.iam.auth.type", - havingValues = {"buc", "oauth2", "obcloud"}, collectionProperty = true) + havingValues = {"buc", "oauth2"}, collectionProperty = true) public class WebModeMultiOrganizationMetaDB extends AbstractWebModeMetaDB { @Override