Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion db/init/mysql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ CREATE TABLE `dashboard_user` (
-- ----------------------------
-- Records of dashboard_user
-- ----------------------------
INSERT INTO `dashboard_user` VALUES ('1', 'admin', 'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413', 1, 1, null, '2022-05-25 18:02:52', '2022-05-25 18:02:52');
INSERT INTO `dashboard_user` VALUES ('1', 'admin', '$2b$12$VRoSQ/.z8C/ldOO9TBfclesgVQ8BxyQK/4Rg/e.DNCisEd.gSyCBG', 1, 1, null, '2022-05-25 18:02:52', '2022-05-25 18:02:52');

-- ----------------------------
-- Table structure for data_permission
Expand Down
2 changes: 1 addition & 1 deletion db/init/ob/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ CREATE TABLE `dashboard_user` (
-- ----------------------------
-- Records of dashboard_user
-- ----------------------------
INSERT INTO `dashboard_user` VALUES ('1', 'admin', 'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413', 1, 1, null, '2022-05-25 18:02:52', '2022-05-25 18:02:52');
INSERT INTO `dashboard_user` VALUES ('1', 'admin', '$2b$12$VRoSQ/.z8C/ldOO9TBfclesgVQ8BxyQK/4Rg/e.DNCisEd.gSyCBG', 1, 1, null, '2022-05-25 18:02:52', '2022-05-25 18:02:52');

-- ----------------------------
-- Table structure for data_permission
Expand Down
2 changes: 1 addition & 1 deletion db/init/og/create-table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ COMMENT ON COLUMN "public"."dashboard_user"."date_updated" IS 'update time';
-- ----------------------------
-- Records of dashboard_user
-- ----------------------------
INSERT INTO "public"."dashboard_user" VALUES ('1', 'admin', 'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413', 1, 1, null, '2022-05-25 18:08:01', '2022-05-25 18:08:01');
INSERT INTO "public"."dashboard_user" VALUES ('1', 'admin', '$2b$12$VRoSQ/.z8C/ldOO9TBfclesgVQ8BxyQK/4Rg/e.DNCisEd.gSyCBG', 1, 1, null, '2022-05-25 18:08:01', '2022-05-25 18:08:01');

-- ----------------------------
-- Table structure for data_permission
Expand Down
4 changes: 2 additions & 2 deletions db/init/oracle/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ comment on column FIELD.date_updated
is 'update time';

/**default admin user**/
INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(dashboard_user(id)) */ INTO dashboard_user (id, user_name, password, role, enabled) VALUES ('1','admin','ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413', '1', '1');
INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(dashboard_user(id)) */ INTO dashboard_user (id, user_name, password, role, enabled) VALUES ('1','admin','$2b$12$VRoSQ/.z8C/ldOO9TBfclesgVQ8BxyQK/4Rg/e.DNCisEd.gSyCBG', '1', '1');

/** insert admin role */
INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(user_role(id)) */ INTO user_role (id, user_id, role_id) VALUES ('1351007709096976384', '1', '1346358560427216896');
Expand Down Expand Up @@ -3813,4 +3813,4 @@ INSERT INTO permission (id, object_id, resource_id, date_created, date_updated)
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303902', '1346358560427216896', '1953048313980116901', sysdate, sysdate);
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303903', '1346358560427216896', '1953048313980116902', sysdate, sysdate);
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303904', '1346358560427216896', '1953048313980116903', sysdate, sysdate);
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303905', '1346358560427216896', '1953048313980116904', sysdate, sysdate);
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303905', '1346358560427216896', '1953048313980116904', sysdate, sysdate);
2 changes: 1 addition & 1 deletion db/init/pg/create-table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ COMMENT ON COLUMN "public"."dashboard_user"."date_updated" IS 'update time';
-- ----------------------------
-- Records of dashboard_user
-- ----------------------------
INSERT INTO "public"."dashboard_user" VALUES ('1', 'admin', 'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413', 1, 1, null, '2022-05-25 18:08:01', '2022-05-25 18:08:01');
INSERT INTO "public"."dashboard_user" VALUES ('1', 'admin', '$2b$12$VRoSQ/.z8C/ldOO9TBfclesgVQ8BxyQK/4Rg/e.DNCisEd.gSyCBG', 1, 1, null, '2022-05-25 18:08:01', '2022-05-25 18:08:01');

-- ----------------------------
-- Table structure for data_permission
Expand Down
5 changes: 5 additions & 0 deletions shenyu-admin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@
import org.apache.shenyu.admin.model.vo.DashboardUserEditVO;
import org.apache.shenyu.admin.model.vo.DashboardUserVO;
import org.apache.shenyu.admin.service.DashboardUserService;
import org.apache.shenyu.admin.service.PasswordHashService;
import org.apache.shenyu.admin.utils.Assert;
import org.apache.shenyu.admin.utils.ResultUtil;
import org.apache.shenyu.admin.utils.SessionUtil;
import org.apache.shenyu.admin.utils.ShenyuResultMessage;
import org.apache.shenyu.admin.validation.annotation.Existed;
import org.apache.shenyu.common.utils.DigestUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand All @@ -65,9 +65,13 @@
public class DashboardUserController {

private final DashboardUserService dashboardUserService;

private final PasswordHashService passwordHashService;

public DashboardUserController(final DashboardUserService dashboardUserService) {
public DashboardUserController(final DashboardUserService dashboardUserService,
final PasswordHashService passwordHashService) {
this.dashboardUserService = dashboardUserService;
this.passwordHashService = passwordHashService;
}

/**
Expand Down Expand Up @@ -119,7 +123,7 @@ public ShenyuAdminResult detailDashboardUser(@PathVariable("id") final String id
public ShenyuAdminResult createDashboardUser(@Valid @RequestBody final DashboardUserDTO dashboardUserDTO) {
return Optional.ofNullable(dashboardUserDTO)
.map(item -> {
item.setPassword(DigestUtils.sha512Hex(item.getPassword()));
item.setPassword(passwordHashService.encode(item.getPassword()));
Integer createCount = dashboardUserService.createOrUpdate(item);
return ShenyuAdminResult.success(ShenyuResultMessage.CREATE_SUCCESS, createCount);
})
Expand All @@ -141,7 +145,7 @@ public ShenyuAdminResult updateDashboardUser(@PathVariable("id")
@Valid @RequestBody final DashboardUserDTO dashboardUserDTO) {
dashboardUserDTO.setId(id);
if (StringUtils.isNotBlank(dashboardUserDTO.getPassword())) {
dashboardUserDTO.setPassword(DigestUtils.sha512Hex(dashboardUserDTO.getPassword()));
dashboardUserDTO.setPassword(passwordHashService.encode(dashboardUserDTO.getPassword()));
}
Integer updateCount = dashboardUserService.createOrUpdate(dashboardUserDTO);
return ShenyuAdminResult.success(ShenyuResultMessage.UPDATE_SUCCESS, updateCount);
Expand All @@ -167,8 +171,6 @@ public ShenyuAdminResult modifyPassword(@PathVariable("id")
if (!userInfo.getUserId().equals(id) && !userInfo.getUserName().equals(dashboardUserModifyPasswordDTO.getUserName())) {
return ShenyuAdminResult.error(ShenyuResultMessage.DASHBOARD_MODIFY_PASSWORD_ERROR);
}
dashboardUserModifyPasswordDTO.setPassword(DigestUtils.sha512Hex(dashboardUserModifyPasswordDTO.getPassword()));
dashboardUserModifyPasswordDTO.setOldPassword(DigestUtils.sha512Hex(dashboardUserModifyPasswordDTO.getOldPassword()));
return ShenyuAdminResult.success(ShenyuResultMessage.UPDATE_SUCCESS, dashboardUserService.modifyPassword(dashboardUserModifyPasswordDTO));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ public interface DashboardUserMapper extends ExistProvider {
* find dashboard user by query.
*
* @param userName user name
* @param password user password
* @param password exact stored password value
* @return {@linkplain DashboardUserDO}
* @deprecated do not use this method for authentication with raw passwords.
*/
@Deprecated
DashboardUserDO findByQuery(@Param("userName") String userName, @Param("password") String password);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,11 @@ public interface DashboardUserService {
* find dashboard user by query.
*
* @param userName user name
* @param password user password
* @param password exact stored password value
* @return {@linkplain DashboardUserVO}
* @deprecated use {@link #findByUserName(String)} and {@link PasswordHashService} for authentication.
*/
@Deprecated
DashboardUserVO findByQuery(String userName, String password);

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* 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.shenyu.admin.service;

import org.apache.commons.lang3.StringUtils;
import org.apache.shenyu.common.utils.DigestUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.regex.Pattern;

/**
* Central password storage policy for dashboard users.
*/
@Service
public class PasswordHashService {

private static final Pattern BCRYPT_PATTERN = Pattern.compile("^\\$2[aby]\\$\\d{2}\\$[./A-Za-z0-9]{53}$");

private static final Pattern LEGACY_SHA512_PATTERN = Pattern.compile("^[A-Fa-f0-9]{128}$");

private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The seed hash uses cost 12 ($2b$12$...), but the runtime encoder new BCryptPasswordEncoder() defaults to cost 10 ($2a$10$). This means the built-in admin account has strength 12 while all newly created/modified user passwords get strength 10.

Fix: Either use new BCryptPasswordEncoder(12) in PasswordHashService, or regenerate the seed hash at cost 10 for consistency.


/**
* Encode a raw dashboard user password for storage.
* Returns the input unchanged if it is blank.
*
* @param requestPassword raw password
* @return bcrypt encoded password
*/
public String encode(final String requestPassword) {
if (StringUtils.isBlank(requestPassword)) {
return requestPassword;
}
return passwordEncoder.encode(requestPassword);
}

/**
* Verify a raw password against a bcrypt hash.
*
* @param requestPassword raw password
* @param storedPasswordHash stored password hash
* @return true when the password matches
*/
public boolean matches(final String requestPassword, final String storedPasswordHash) {
if (!isBcryptHash(storedPasswordHash)) {
return false;
}
return passwordEncoder.matches(requestPassword, storedPasswordHash);
}

/**
* Determine whether a stored password uses bcrypt format.
*
* @param storedPasswordHash stored password hash
* @return true when the stored password is bcrypt
*/
public boolean isBcryptHash(final String storedPasswordHash) {
return StringUtils.isNotBlank(storedPasswordHash) && BCRYPT_PATTERN.matcher(storedPasswordHash).matches();
}

/**
* Verify a raw password against the legacy SHA-512 hex format.
*
* @param requestPassword raw password
* @param storedPasswordHash stored password hash
* @return true when the password matches the legacy hash
*/
public boolean matchesLegacySha512(final String requestPassword, final String storedPasswordHash) {
return isLegacySha512Hash(storedPasswordHash)
&& StringUtils.equals(DigestUtils.sha512Hex(requestPassword), storedPasswordHash);
}

/**
* Determine whether a stored password uses the legacy SHA-512 hex format.
*
* @param storedPasswordHash stored password hash
* @return true when the stored password is a legacy SHA-512 hex hash
*/
public boolean isLegacySha512Hash(final String storedPasswordHash) {
return StringUtils.isNotBlank(storedPasswordHash) && LEGACY_SHA512_PATTERN.matcher(storedPasswordHash).matches();
}
}
Loading
Loading