diff --git a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/SettingController.java b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/SettingController.java index 43b16ad3aa..c40d806449 100644 --- a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/SettingController.java +++ b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/SettingController.java @@ -44,6 +44,8 @@ public class SettingController { static { MASK_CONFIGURATION_SET.add(AmoroManagementConf.DB_PASSWORD.key()); MASK_CONFIGURATION_SET.add(AmoroManagementConf.ADMIN_PASSWORD.key()); + MASK_CONFIGURATION_SET.add( + AmoroManagementConf.AUTHORIZATION_LDAP_ROLE_MAPPING_BIND_PASSWORD.key()); } private final OptimizerManager optimizerManager; diff --git a/amoro-ams/src/main/java/org/apache/amoro/server/persistence/mapper/ApiTokensMapper.java b/amoro-ams/src/main/java/org/apache/amoro/server/persistence/mapper/ApiTokensMapper.java index e2f4b793a2..eff6a2f70f 100644 --- a/amoro-ams/src/main/java/org/apache/amoro/server/persistence/mapper/ApiTokensMapper.java +++ b/amoro-ams/src/main/java/org/apache/amoro/server/persistence/mapper/ApiTokensMapper.java @@ -32,7 +32,7 @@ public interface ApiTokensMapper { String TABLE_NAME = "api_tokens"; - @Select("SELECT id, apikey, apply_time FROM " + TABLE_NAME) + @Select("SELECT id, apikey, secret, apply_time FROM " + TABLE_NAME) @Results({ @Result(property = "id", column = "id"), @Result(property = "apikey", column = "apikey"), diff --git a/amoro-ams/src/test/java/org/apache/amoro/server/dashboard/controller/TestSettingController.java b/amoro-ams/src/test/java/org/apache/amoro/server/dashboard/controller/TestSettingController.java new file mode 100644 index 0000000000..913b6d30bc --- /dev/null +++ b/amoro-ams/src/test/java/org/apache/amoro/server/dashboard/controller/TestSettingController.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.amoro.server.dashboard.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.javalin.http.Context; +import org.apache.amoro.config.Configurations; +import org.apache.amoro.server.AmoroManagementConf; +import org.apache.amoro.server.dashboard.response.OkResponse; +import org.apache.amoro.server.resource.OptimizerManager; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +public class TestSettingController { + + private OptimizerManager optimizerManager; + private SettingController controller; + private Context ctx; + + @BeforeEach + void setUp() { + optimizerManager = mock(OptimizerManager.class); + controller = new SettingController(new Configurations(), optimizerManager); + ctx = mock(Context.class); + } + + @Test + @SuppressWarnings({"unchecked", "rawtypes"}) + void ldapBindPasswordIsMaskedInSystemSetting() { + Configurations configurations = new Configurations(); + configurations.set( + AmoroManagementConf.AUTHORIZATION_LDAP_ROLE_MAPPING_BIND_PASSWORD, "ldap-secret"); + controller = new SettingController(configurations, optimizerManager); + when(ctx.json(any())).thenReturn(ctx); + + controller.getSystemSetting(ctx); + + ArgumentCaptor captor = ArgumentCaptor.forClass(OkResponse.class); + verify(ctx).json(captor.capture()); + java.util.Map result = + (java.util.Map) captor.getValue().getResult(); + Assertions.assertEquals( + "******", + result.get(AmoroManagementConf.AUTHORIZATION_LDAP_ROLE_MAPPING_BIND_PASSWORD.key()), + "LDAP bind password must be masked in the system settings response"); + } +} diff --git a/amoro-ams/src/test/java/org/apache/amoro/server/persistence/TestApiTokensMapper.java b/amoro-ams/src/test/java/org/apache/amoro/server/persistence/TestApiTokensMapper.java new file mode 100644 index 0000000000..eafc3beadf --- /dev/null +++ b/amoro-ams/src/test/java/org/apache/amoro/server/persistence/TestApiTokensMapper.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.amoro.server.persistence; + +import org.apache.amoro.server.AMSManagerTestBase; +import org.apache.amoro.server.dashboard.model.ApiTokens; +import org.apache.amoro.server.persistence.mapper.ApiTokensMapper; +import org.apache.ibatis.session.SqlSession; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class TestApiTokensMapper extends AMSManagerTestBase { + + @Test + public void getApiTokensLoadsSecretColumn() { + // The @Results mapping declares the secret column; the SELECT list must fetch it, + // otherwise the token list endpoint fails for every request. + ApiTokens token = new ApiTokens("mapper-test-apikey", "mapper-test-secret"); + token.setApplyTime(System.currentTimeMillis()); + try (SqlSession session = SqlSessionFactoryProvider.getInstance().get().openSession(true)) { + session.getMapper(ApiTokensMapper.class).insert(token); + } + + List tokens; + try (SqlSession session = SqlSessionFactoryProvider.getInstance().get().openSession(true)) { + tokens = session.getMapper(ApiTokensMapper.class).getApiTokens(); + } + + Assertions.assertEquals( + "mapper-test-secret", + tokens.stream() + .filter(t -> "mapper-test-apikey".equals(t.getApikey())) + .findFirst() + .orElseThrow(() -> new AssertionError("inserted token not found")) + .getSecret()); + } +}