diff --git a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java b/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java index ff2b06c2..e97055cf 100644 --- a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java +++ b/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java @@ -98,6 +98,26 @@ public class WebConfig implements WebMvcConfigurer { return false; } + // 检查是否使用默认密码,如果是则仅允许改密和登出操作 + User validUser = (User) httpServletRequest.getAttribute("user"); + if (validUser != null && validUser.isDefaultPassword()) { + String uri = httpServletRequest.getRequestURI(); + String method = httpServletRequest.getMethod(); + boolean isPasswordChange = "PUT".equals(method) && uri.matches("/api/[^/]+/user"); + boolean isLogout = uri.contains("/user/logout"); + if (!isPasswordChange && !isLogout) { + BaseModel baseModel = BaseModel.getInstance(null); + baseModel.setCode(50015); + baseModel.setMessage("Default password must be changed before proceeding"); + ObjectMapper mapper = new ObjectMapper(); + String json = mapper.writeValueAsString(baseModel); + httpServletResponse.setContentType("application/json;charset=UTF-8"); + PrintWriter out = httpServletResponse.getWriter(); + out.print(json); + return false; + } + } + return true; } }) diff --git a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/UserController.java b/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/UserController.java index 3d57a661..22f7cceb 100644 --- a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/UserController.java +++ b/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/controller/UserController.java @@ -56,6 +56,9 @@ public class UserController { String token = UUID.randomUUID().toString(); loginUsers.put(token, loginUser); tokenResp.put("token", token); + if (loginUser.isDefaultPassword()) { + tokenResp.put("needPasswordChange", "true"); + } return BaseModel.getInstance(tokenResp); } else { BaseModel> model = BaseModel.getInstance(null); @@ -98,6 +101,7 @@ public class UserController { HttpServletRequest httpServletRequest) { userService.update(user); String token = (String) httpServletRequest.getAttribute("token"); + user.setDefaultPassword(false); loginUsers.put(token, user); return BaseModel.getInstance("success"); } diff --git a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/User.java b/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/User.java index a93df5b0..959b55d9 100644 --- a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/User.java +++ b/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/model/User.java @@ -44,6 +44,9 @@ public class User extends Model { @Transient private String oldPassword; + @Transient + private boolean defaultPassword; + public Long getId() { return id; } @@ -115,4 +118,12 @@ public class User extends Model { public void setOldPassword(String oldPassword) { this.oldPassword = oldPassword; } + + public boolean isDefaultPassword() { + return defaultPassword; + } + + public void setDefaultPassword(boolean defaultPassword) { + this.defaultPassword = defaultPassword; + } } diff --git a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/UserServiceImpl.java b/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/UserServiceImpl.java index 5aaf5543..6dd26f7d 100644 --- a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/UserServiceImpl.java +++ b/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/UserServiceImpl.java @@ -3,6 +3,8 @@ package com.alibaba.otter.canal.admin.service.impl; import java.security.NoSuchAlgorithmException; import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import com.alibaba.otter.canal.admin.common.exception.ServiceException; @@ -19,7 +21,11 @@ import com.alibaba.otter.canal.protocol.SecurityUtil; @Service public class UserServiceImpl implements UserService { - private static byte[] seeds = "canal is best!".getBytes(); + private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); + + private static final String DEFAULT_PASSWORD_HASH = "6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9"; + + private static byte[] seeds = "canal is best!".getBytes(); private static final Integer PASSWORD_LENGTH = 5; @@ -40,6 +46,11 @@ public class UserServiceImpl implements UserService { throw new ServiceException("user:" + user.getName() + " auth failed!"); } + if (DEFAULT_PASSWORD_HASH.equalsIgnoreCase(user.getPassword())) { + user.setDefaultPassword(true); + logger.warn("Default admin password detected for user: {}. Please change immediately.", username); + } + user.setPassword(""); return user; } diff --git a/client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/ApplicationConfigMonitor.java b/client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/ApplicationConfigMonitor.java index f7f86f11..547b8714 100644 --- a/client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/ApplicationConfigMonitor.java +++ b/client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/monitor/ApplicationConfigMonitor.java @@ -18,7 +18,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.context.refresh.ContextRefresher; import org.springframework.stereotype.Component; +import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; import com.alibaba.otter.canal.adapter.launcher.loader.CanalAdapterService; import com.alibaba.otter.canal.client.adapter.support.Util; @@ -70,7 +72,7 @@ public class ApplicationConfigMonitor { super.onFileChange(file); try { // 检查yml格式 - new Yaml().loadAs(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8), Map.class); + new Yaml(new SafeConstructor(new LoaderOptions())).loadAs(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8), Map.class); canalAdapterService.destroy();