diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/LoginController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/LoginController.java index 059a696b1e59..c76c10a2dbf5 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/LoginController.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/LoginController.java @@ -296,8 +296,8 @@ public void loginByAuth2(@RequestParam String code, @RequestParam String provide } Session session = sessionService.createSessionIfAbsent(user); response.setStatus(HttpStatus.SC_MOVED_TEMPORARILY); - response.sendRedirect(String.format("%s?sessionId=%s&authType=%s", oAuth2ClientProperties.getCallbackUrl(), - session.getId(), "oauth2")); + response.sendRedirect(String.format("%s?sessionId=%s&authType=%s&securityConfigType=%s", + oAuth2ClientProperties.getCallbackUrl(), session.getId(), "oauth2", "OAUTH2")); } catch (Exception ex) { log.error(ex.getMessage(), ex); response.setStatus(HttpStatus.SC_MOVED_TEMPORARILY); @@ -361,8 +361,8 @@ public void handleOidcCallback(@PathVariable String providerId, Session session = sessionService.createSessionIfAbsent(user); response.setStatus(HttpStatus.SC_MOVED_TEMPORARILY); - response.sendRedirect(String.format("%s/login?sessionId=%s&authType=%s", - apiConfig.getUiUrl(), session.getId(), "oidc")); + response.sendRedirect(String.format("%s/login?sessionId=%s&authType=%s&securityConfigType=%s", + apiConfig.getUiUrl(), session.getId(), "oidc", "OIDC")); } catch (Exception ex) { log.error("A critical error occurred during the OIDC callback process.", ex); try { diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java index b47a9b108921..544094b189d8 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java @@ -118,6 +118,8 @@ public enum Status { DELETE_USER_BY_ID_ERROR(10093, "delete user by id error", "删除用户错误"), GRANT_PROJECT_ERROR(10094, "grant project error", "授权项目错误"), GRANT_RESOURCE_ERROR(10095, "grant resource error", "授权资源错误"), + OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE(10096, "operation not allowed in non-password authentication mode", + "非密码认证模式下不允许此操作"), GRANT_DATASOURCE_ERROR(10097, "grant datasource error", "授权数据源错误"), GET_USER_INFO_ERROR(10098, "get user info error", "获取用户信息错误"), USER_LIST_ERROR(10099, "user list error", "查询用户列表错误"), diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java index a22a287b815b..519240fec3f5 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java @@ -21,6 +21,7 @@ import org.apache.dolphinscheduler.api.enums.Status; import org.apache.dolphinscheduler.api.exceptions.ServiceException; +import org.apache.dolphinscheduler.api.security.AuthenticationType; import org.apache.dolphinscheduler.api.service.SessionService; import org.apache.dolphinscheduler.api.service.UsersService; import org.apache.dolphinscheduler.api.utils.CheckUtils; @@ -64,6 +65,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -101,6 +103,20 @@ public class UsersServiceImpl extends BaseServiceImpl implements UsersService { @Autowired private SessionService sessionService; + @Value("${security.authentication.type:PASSWORD}") + private String securityAuthenticationType = AuthenticationType.PASSWORD.name(); + + @Value("${security.authentication.oauth2.enable:false}") + private boolean oauth2Enabled; + + private boolean isPasswordManagementDisabled() { + if (oauth2Enabled) { + return true; + } + return StringUtils.isNotBlank(securityAuthenticationType) + && !AuthenticationType.PASSWORD.name().equals(securityAuthenticationType); + } + /** * create user, only system admin have permission * @@ -128,6 +144,10 @@ public User createUser(User loginUser, throw new ServiceException(Status.USER_NO_OPERATION_PERM); } + if (isPasswordManagementDisabled()) { + throw new ServiceException(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE); + } + // check all user params String msg = this.checkUserParams(userName, userPassword, email, phone); if (!StringUtils.isEmpty(msg)) { @@ -356,7 +376,11 @@ public User updateUser(User loginUser, } } - if (StringUtils.isNotEmpty(userName)) { + if (StringUtils.isNotEmpty(userName) && !StringUtils.equals(userName, user.getUserName())) { + + if (isPasswordManagementDisabled()) { + throw new ServiceException(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE); + } if (!CheckUtils.checkUserName(userName)) { throw new ServiceException(Status.REQUEST_PARAMS_NOT_VALID_ERROR, userName); @@ -371,6 +395,11 @@ public User updateUser(User loginUser, } if (StringUtils.isNotEmpty(userPassword)) { + + if (isPasswordManagementDisabled()) { + throw new ServiceException(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE); + } + if (!CheckUtils.checkPasswordLength(userPassword)) { throw new ServiceException(Status.USER_PASSWORD_LENGTH_ERROR); } @@ -872,6 +901,11 @@ private String checkUserParams(String userName, String password, String email, S @Override @Transactional public User registerUser(String userName, String userPassword, String repeatPassword, String email) { + + if (isPasswordManagementDisabled()) { + throw new ServiceException(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE); + } + // check user params String msg = this.checkUserParams(userName, userPassword, email, ""); if (!StringUtils.isEmpty(msg)) { diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerOidcTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerOidcTest.java index a113ee6ebf16..d93bb3fdeb34 100644 --- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerOidcTest.java +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerOidcTest.java @@ -194,7 +194,8 @@ public void testHandleOidcCallback_withSuccess() throws Exception { when(oidcAuthenticator.login(state, code)).thenReturn(user); when(sessionService.createSessionIfAbsent(user)).thenReturn(session); - String expectedRedirectUrl = String.format("%s/login?sessionId=%s&authType=%s", uiUrl, sessionId, "oidc"); + String expectedRedirectUrl = String.format("%s/login?sessionId=%s&authType=%s&securityConfigType=%s", + uiUrl, sessionId, "oidc", "OIDC"); performOidcCallback(code, null, state) .andExpect(status().isFound()) diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerTest.java index 57fb1076df58..2c90a6317ad1 100644 --- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerTest.java +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/LoginControllerTest.java @@ -280,6 +280,7 @@ public User getAuthUser(HttpServletRequest request) { Assertions.assertEquals(302, ((MockHttpServletResponse) response).getStatus()); String redirect = ((MockHttpServletResponse) response).getRedirectedUrl(); Assertions.assertTrue(redirect.startsWith("http://ui/callback?sessionId=sid-1")); + Assertions.assertTrue(redirect.contains("securityConfigType=OAUTH2")); } } diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/UsersControllerPasswordModeTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/UsersControllerPasswordModeTest.java new file mode 100644 index 000000000000..161f85956c59 --- /dev/null +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/UsersControllerPasswordModeTest.java @@ -0,0 +1,154 @@ +/* + * 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.dolphinscheduler.api.controller; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.apache.dolphinscheduler.api.enums.Status; +import org.apache.dolphinscheduler.api.service.UsersService; +import org.apache.dolphinscheduler.api.utils.Result; +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.dao.entity.User; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +@TestPropertySource(properties = { + "security.authentication.type=PASSWORD", + "security.authentication.oauth2.enable=false" +}) +public class UsersControllerPasswordModeTest extends AbstractControllerTest { + + @Autowired + private UsersService usersService; + + @Test + public void testCreateUserSuccess() throws Exception { + String userName = uniqueUserName("create_success"); + + MultiValueMap paramsMap = new LinkedMultiValueMap<>(); + paramsMap.add("userName", userName); + paramsMap.add("userPassword", "123456qwe?"); + paramsMap.add("tenantId", "-1"); + paramsMap.add("queue", ""); + paramsMap.add("email", userName + "@example.com"); + paramsMap.add("phone", "15800000000"); + paramsMap.add("state", "1"); + + MvcResult mvcResult = mockMvc.perform(post("/users/create") + .header(SESSION_ID, sessionId) + .params(paramsMap)) + .andExpect(status().isCreated()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); + Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue()); + } + + @Test + public void testUpdateUserSuccess() throws Exception { + String userName = uniqueUserName("update_success"); + createUser(userName); + User user = usersService.getUserByUserName(userName); + + MultiValueMap paramsMap = new LinkedMultiValueMap<>(); + paramsMap.add("id", String.valueOf(user.getId())); + paramsMap.add("userName", userName + "_new"); + paramsMap.add("userPassword", ""); + paramsMap.add("tenantId", "-1"); + paramsMap.add("queue", ""); + paramsMap.add("email", "updated-" + userName + "@example.com"); + paramsMap.add("phone", "15800000001"); + paramsMap.add("state", "1"); + paramsMap.add("timeZone", "Asia/Shanghai"); + + MvcResult mvcResult = mockMvc.perform(post("/users/update") + .header(SESSION_ID, sessionId) + .params(paramsMap)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); + Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue()); + } + + @Test + public void testUpdateUserPasswordSuccess() throws Exception { + String userName = uniqueUserName("password_success"); + createUser(userName); + User user = usersService.getUserByUserName(userName); + + MultiValueMap paramsMap = new LinkedMultiValueMap<>(); + paramsMap.add("id", String.valueOf(user.getId())); + paramsMap.add("userName", userName); + paramsMap.add("userPassword", "updated123?"); + paramsMap.add("tenantId", "-1"); + paramsMap.add("queue", ""); + paramsMap.add("email", userName + "@example.com"); + paramsMap.add("phone", "15800000002"); + paramsMap.add("state", "1"); + paramsMap.add("timeZone", "Asia/Shanghai"); + + MvcResult mvcResult = mockMvc.perform(post("/users/update") + .header(SESSION_ID, sessionId) + .params(paramsMap)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); + Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue()); + } + + @Test + public void testRegisterUserSuccess() throws Exception { + MultiValueMap paramsMap = new LinkedMultiValueMap<>(); + String userName = uniqueUserName("register_success"); + paramsMap.add("userName", userName); + paramsMap.add("userPassword", "123456qwe?"); + paramsMap.add("repeatPassword", "123456qwe?"); + paramsMap.add("email", userName + "@example.com"); + + MvcResult mvcResult = mockMvc.perform(post("/users/register") + .params(paramsMap)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); + Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue()); + } + + private User createUser(String userName) { + return usersService.createUser(userName, "123456qwe?", userName + "@example.com", -1, "15800000000", "", 1); + } + + private String uniqueUserName(String prefix) { + return prefix + "_" + System.nanoTime(); + } +} diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/UsersControllerTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/UsersControllerTest.java index efc2d4cfd5e8..30ec919ec72e 100644 --- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/UsersControllerTest.java +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/UsersControllerTest.java @@ -65,6 +65,30 @@ public void testCreateUser() throws Exception { logger.info(mvcResult.getResponse().getContentAsString()); } + @Test + public void testCreateUserNotAllowedWhenOAuth2Enabled() throws Exception { + MultiValueMap paramsMap = new LinkedMultiValueMap<>(); + paramsMap.add("userName", "user_test_with_oauth2"); + paramsMap.add("userPassword", "123456qwe?"); + paramsMap.add("tenantId", "109"); + paramsMap.add("queue", "1"); + paramsMap.add("email", "12343534@qq.com"); + paramsMap.add("phone", "15800000000"); + paramsMap.add("state", "1"); + + MvcResult mvcResult = mockMvc.perform(post("/users/create") + .header(SESSION_ID, sessionId) + .params(paramsMap)) + .andExpect(status().isCreated()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); + Assertions.assertEquals(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE.getCode(), + result.getCode().intValue()); + logger.info(mvcResult.getResponse().getContentAsString()); + } + @Test public void testUpdateUser() throws Exception { MultiValueMap paramsMap = new LinkedMultiValueMap<>(); @@ -87,6 +111,56 @@ public void testUpdateUser() throws Exception { Assertions.assertEquals(Status.UPDATE_USER_ERROR.getCode(), result.getCode().intValue()); } + @Test + public void testUpdateUserAllowsNonCredentialChangesWhenOAuth2Enabled() throws Exception { + MultiValueMap paramsMap = buildUpdateUserParams(user.getUserName(), ""); + paramsMap.set("email", "updated-user-with-oauth2@example.com"); + paramsMap.set("phone", "15800000001"); + + MvcResult mvcResult = mockMvc.perform(post("/users/update") + .header(SESSION_ID, sessionId) + .params(paramsMap)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); + Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue()); + logger.info(mvcResult.getResponse().getContentAsString()); + } + + @Test + public void testUpdateUserNameNotAllowedWhenOAuth2Enabled() throws Exception { + MultiValueMap paramsMap = buildUpdateUserParams("user_test_with_oauth2", ""); + + MvcResult mvcResult = mockMvc.perform(post("/users/update") + .header(SESSION_ID, sessionId) + .params(paramsMap)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); + Assertions.assertEquals(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE.getCode(), + result.getCode().intValue()); + } + + @Test + public void testUpdateUserPasswordNotAllowedWhenOAuth2Enabled() throws Exception { + MultiValueMap paramsMap = buildUpdateUserParams(user.getUserName(), "123456qwe?"); + + MvcResult mvcResult = mockMvc.perform(post("/users/update") + .header(SESSION_ID, sessionId) + .params(paramsMap)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); + Assertions.assertEquals(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE.getCode(), + result.getCode().intValue()); + } + @Test public void testGrantProject() throws Exception { MultiValueMap paramsMap = new LinkedMultiValueMap<>(); @@ -253,7 +327,8 @@ public void testRegisterUser() throws Exception { .andReturn(); Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); - Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue()); + Assertions.assertEquals(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE.getCode(), + result.getCode().intValue()); } @Test @@ -290,4 +365,18 @@ public void testBatchActivateUser() throws Exception { Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class); Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue()); } + + private MultiValueMap buildUpdateUserParams(String userName, String userPassword) { + MultiValueMap paramsMap = new LinkedMultiValueMap<>(); + paramsMap.add("id", String.valueOf(user.getId())); + paramsMap.add("userName", userName); + paramsMap.add("userPassword", userPassword); + paramsMap.add("tenantId", "-1"); + paramsMap.add("queue", ""); + paramsMap.add("email", "user-with-oauth2@example.com"); + paramsMap.add("phone", "15800000000"); + paramsMap.add("state", "1"); + paramsMap.add("timeZone", "Asia/Shanghai"); + return paramsMap; + } } diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java index d7434488794f..c417380777f7 100644 --- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java @@ -62,6 +62,7 @@ import org.mockito.quality.Strictness; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.test.util.ReflectionTestUtils; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -308,6 +309,92 @@ public void testUpdateUser() { "Asia/Shanghai")); } + @Test + public void testUpdateUserAllowsNonCredentialChangesInNonPasswordMode() { + ReflectionTestUtils.setField(usersService, "securityAuthenticationType", "OIDC"); + when(userDao.queryById(any())).thenReturn(getUser()); + when(userDao.updateById(any())).thenReturn(true); + + assertDoesNotThrow(() -> usersService.updateUser(getLoginUser(), + 1, + "userTest0001", + null, + "user@example.com", + 1, + "13457864543", + "queue", + 1, + "Asia/Shanghai")); + + assertThrowsServiceException(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE, + () -> usersService.updateUser(getLoginUser(), + 1, + "updatedUser", + null, + "user@example.com", + 1, + "13457864543", + "queue", + 1, + "Asia/Shanghai")); + } + + @Test + public void testUserPasswordManagementRejectedWhenOAuth2EnabledWithPasswordAuthentication() { + ReflectionTestUtils.setField(usersService, "securityAuthenticationType", "PASSWORD"); + ReflectionTestUtils.setField(usersService, "oauth2Enabled", true); + when(userDao.queryById(any())).thenReturn(getUser()); + when(userDao.updateById(any())).thenReturn(true); + + assertThrowsServiceException(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE, + () -> usersService.createUser(getLoginUser(), + "newUser", + "userTest0001", + "new-user@example.com", + 1, + "13457864543", + "queue", + 1)); + + assertThrowsServiceException(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE, + () -> usersService.registerUser("newUser", "userTest0001", "userTest0001", "new-user@example.com")); + + assertDoesNotThrow(() -> usersService.updateUser(getLoginUser(), + 1, + "userTest0001", + null, + "user@example.com", + 1, + "13457864543", + "queue", + 1, + "Asia/Shanghai")); + + assertThrowsServiceException(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE, + () -> usersService.updateUser(getLoginUser(), + 1, + "updatedUser", + null, + "user@example.com", + 1, + "13457864543", + "queue", + 1, + "Asia/Shanghai")); + + assertThrowsServiceException(Status.OPERATION_NOT_ALLOWED_IN_NON_PASSWORD_MODE, + () -> usersService.updateUser(getLoginUser(), + 1, + "userTest0001", + "updatedPassword", + "user@example.com", + 1, + "13457864543", + "queue", + 1, + "Asia/Shanghai")); + } + @Test public void testUpdateUserSimple() { // null user -> USER_NOT_EXIST diff --git a/dolphinscheduler-ui/src/locales/en_US/password.ts b/dolphinscheduler-ui/src/locales/en_US/password.ts index a9cde2c18c9a..ae3e35252c93 100644 --- a/dolphinscheduler-ui/src/locales/en_US/password.ts +++ b/dolphinscheduler-ui/src/locales/en_US/password.ts @@ -23,5 +23,7 @@ export default { confirm_password_tips: 'Please enter your confirm password', two_password_entries_are_inconsistent: 'Two password entries are inconsistent', - submit: 'Submit' + submit: 'Submit', + not_supported_in_non_password_mode: + 'Password modification is not supported in the current authentication mode, please modify it in the authentication system' } diff --git a/dolphinscheduler-ui/src/locales/zh_CN/password.ts b/dolphinscheduler-ui/src/locales/zh_CN/password.ts index ceff17fd728f..ed2460a7694c 100644 --- a/dolphinscheduler-ui/src/locales/zh_CN/password.ts +++ b/dolphinscheduler-ui/src/locales/zh_CN/password.ts @@ -22,5 +22,7 @@ export default { password_tips: '请输入密码', confirm_password_tips: '请输入确认密码', two_password_entries_are_inconsistent: '两次密码输入不一致', - submit: '提交' + submit: '提交', + not_supported_in_non_password_mode: + '当前认证模式下不支持修改密码,请在认证系统中修改' } diff --git a/dolphinscheduler-ui/src/views/login/use-login.ts b/dolphinscheduler-ui/src/views/login/use-login.ts index 204f88ba5c55..faa0b8e02c84 100644 --- a/dolphinscheduler-ui/src/views/login/use-login.ts +++ b/dolphinscheduler-ui/src/views/login/use-login.ts @@ -97,7 +97,12 @@ export function useLogin(state: any) { if (authType === 'oauth2' || authType === 'oidc') { const sessionId = route.query.sessionId if (sessionId) { - cookies.set('sessionId', String(sessionId), { path: '/' }) + const currentSessionId = String(sessionId) + await userStore.setSessionId(currentSessionId) + cookies.set('sessionId', currentSessionId, { path: '/' }) + await userStore.setSecurityConfigType( + String(route.query.securityConfigType || authType).toUpperCase() + ) const userInfoRes: UserInfoRes = await getUserInfo() await userStore.setUserInfo(userInfoRes) const timezone = userInfoRes.timeZone ? userInfoRes.timeZone : 'UTC' diff --git a/dolphinscheduler-ui/src/views/password/index.tsx b/dolphinscheduler-ui/src/views/password/index.tsx index 9135ba18ad0f..64c74a017d6f 100644 --- a/dolphinscheduler-ui/src/views/password/index.tsx +++ b/dolphinscheduler-ui/src/views/password/index.tsx @@ -16,10 +16,11 @@ */ import { defineComponent, getCurrentInstance, toRefs } from 'vue' -import { NForm, NFormItem, NButton, NInput } from 'naive-ui' +import { NForm, NFormItem, NButton, NInput, NEmpty } from 'naive-ui' import { useForm } from './use-form' import { useUpdate } from './use-update' import Card from '@/components/card' +import { useUserStore } from '@/store/user/user' const password = defineComponent({ name: 'password', @@ -27,12 +28,23 @@ const password = defineComponent({ const { state, rules, t } = useForm() const { handleUpdate } = useUpdate(state) const trim = getCurrentInstance()?.appContext.config.globalProperties.trim + const userStore = useUserStore() - return { ...toRefs(state), t, handleUpdate, rules, trim } + return { ...toRefs(state), t, handleUpdate, rules, trim, userStore } }, render() { const { t } = this + if (this.userStore.getSecurityConfigType !== 'PASSWORD') { + return ( + + + + ) + } + return ( {{ diff --git a/dolphinscheduler-ui/src/views/security/user-manage/components/user-detail-modal.tsx b/dolphinscheduler-ui/src/views/security/user-manage/components/user-detail-modal.tsx index 751bd3c009d5..5ed239b09649 100644 --- a/dolphinscheduler-ui/src/views/security/user-manage/components/user-detail-modal.tsx +++ b/dolphinscheduler-ui/src/views/security/user-manage/components/user-detail-modal.tsx @@ -35,6 +35,7 @@ import { import { useUserDetail } from './use-user-detail' import Modal from '@/components/modal' import type { IRecord } from '../types' +import { useUserStore } from '@/store/user/user' const props = { show: { @@ -55,6 +56,7 @@ export const UserModal = defineComponent({ const { t } = useI18n() const { state, IS_ADMIN, formRules, onReset, onSave, onSetValues } = useUserDetail() + const userStore = useUserStore() const onCancel = () => { onReset() ctx.emit('cancel') @@ -84,7 +86,8 @@ export const UserModal = defineComponent({ formRules, onCancel, onConfirm, - trim + trim, + userStore } }, render(props: { currentRecord: IRecord }) { @@ -120,6 +123,10 @@ export const UserModal = defineComponent({ minlength={3} maxlength={39} placeholder={t('security.user.username_tips')} + disabled={ + !!currentRecord?.id && + this.userStore.getSecurityConfigType !== 'PASSWORD' + } /> {!this.currentRecord?.id && ( diff --git a/dolphinscheduler-ui/src/views/security/user-manage/index.tsx b/dolphinscheduler-ui/src/views/security/user-manage/index.tsx index 980cc8884e47..9760700adb5a 100644 --- a/dolphinscheduler-ui/src/views/security/user-manage/index.tsx +++ b/dolphinscheduler-ui/src/views/security/user-manage/index.tsx @@ -26,6 +26,7 @@ import AuthorizeModal from './components/authorize-modal' import PasswordModal from './components/password-modal' import Card from '@/components/card' import Search from '@/components/input-search' +import { useUserStore } from '@/store/user/user' const UsersManage = defineComponent({ name: 'user-manage', @@ -34,6 +35,7 @@ const UsersManage = defineComponent({ const { state, changePage, changePageSize, updateList, onOperationClick } = useTable() const { columnsRef } = useColumns(onOperationClick) + const userStore = useUserStore() const onAddUser = () => { state.detailModalShow = true @@ -62,7 +64,8 @@ const UsersManage = defineComponent({ onDetailModalCancel, onAuthorizeModalCancel, onPasswordModalCancel, - trim + trim, + userStore } }, render() { @@ -75,6 +78,7 @@ const UsersManage = defineComponent({ type='primary' class='btn-create-user' size='small' + disabled={this.userStore.getSecurityConfigType !== 'PASSWORD'} > {this.t('security.user.create_user')} diff --git a/dolphinscheduler-ui/src/views/security/user-manage/use-columns.ts b/dolphinscheduler-ui/src/views/security/user-manage/use-columns.ts index 3efc2c167039..f15e87424e6e 100644 --- a/dolphinscheduler-ui/src/views/security/user-manage/use-columns.ts +++ b/dolphinscheduler-ui/src/views/security/user-manage/use-columns.ts @@ -208,6 +208,8 @@ export function useColumns(onCallback: Function) { type: 'error', size: 'small', class: 'edit', + disabled: + userStore.getSecurityConfigType !== 'PASSWORD', onClick: () => void onCallback({ rowData }, 'resetPassword') },