Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI登录密码改采用更安全的加密策略及可通过-Dbistoury.ui.register_disabled=true来禁用帐号注册功能 #72

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
49 changes: 48 additions & 1 deletion bistoury-ui-service-impl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,43 @@
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.64</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.2.13.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
Expand All @@ -50,4 +87,14 @@
</plugins>
</build>

</project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package qunar.tc.bistoury.ui.security;

import qunar.tc.bistoury.ui.service.impl.UserServiceImpl;

public class PasswordEncoderMain {

public static void main(String[] args) {
String rawPassword = args == null || args.length < 1 ? "admin" : args[0];
String encodePwd = UserServiceImpl.encodePwd(rawPassword);
System.out.println("rawPassword: " + rawPassword + " encodePwd: " + encodePwd);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package qunar.tc.bistoury.ui.service.impl;

import org.springframework.security.crypto.password.PasswordEncoder;

/**
* 此旧为实现,仅为兼容而存在 建议采用默认更安全的加密加密策略,实现需要
* 实在需要,请在SPI定义文件META-INF\services\org.springframework.security.crypto.password.PasswordEncoder中配置此实现类
*
* @author qxo
* @date 2020/01/01
*/
public class PasswordEncoderForOldAESCryptImpl implements PasswordEncoder {

private final AESCryptServiceImpl aesCryptService = new AESCryptServiceImpl();

@Override
public String encode(CharSequence rawPassword) {
return rawPassword == null ? null : aesCryptService.encrypt(rawPassword.toString());
}

@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword == null ? false : aesCryptService.encrypt(rawPassword.toString()).equals(encodedPassword);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,27 @@

package qunar.tc.bistoury.ui.service.impl;

import java.util.List;
import java.util.ServiceLoader;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.stereotype.Service;

import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import qunar.tc.bistoury.serverside.configuration.DynamicConfig;
import qunar.tc.bistoury.serverside.configuration.DynamicConfigLoader;
import qunar.tc.bistoury.serverside.configuration.local.LocalDynamicConfig;
import qunar.tc.bistoury.ui.dao.UserDao;
import qunar.tc.bistoury.ui.model.User;
import qunar.tc.bistoury.ui.service.AESCryptService;
import qunar.tc.bistoury.ui.service.UserService;

import javax.annotation.PostConstruct;
import java.util.List;

/**
* @author leix.xie
* @date 2019/7/4 11:00
Expand All @@ -44,11 +48,42 @@ public class UserServiceImpl implements UserService {

private static final Splitter SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();

@Autowired
private UserDao userDao;
/**
* 密码加密器,可通过环境变理BISTOURY_UI_PASSWORD_ENCODER来指定实现类,
* 也可用new表示采用推存的加密实现类:Pbkdf2PasswordEncoder
* 用old表示旧实现PasswordEncoderForOldAESCryptImpl
* 如未指定默认采用SPI方式,且SPI默认实现为旧的PasswordEncoderForOldAESCryptImpl
*/
private static final PasswordEncoder PASSWORD_ENCODER;
static {
String cls = System.getenv("BISTOURY_UI_PASSWORD_ENCODER");
if ("new".equals(cls)) {
PASSWORD_ENCODER = new Pbkdf2PasswordEncoder();
} else if ("old".equals(cls)) {
PASSWORD_ENCODER = new PasswordEncoderForOldAESCryptImpl();
} else if (cls != null) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
PASSWORD_ENCODER = (PasswordEncoder)classLoader.loadClass(cls).newInstance();
} catch (InstantiationException e) {
throw new IllegalStateException(e);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
} else {
ServiceLoader<PasswordEncoder> sloader = ServiceLoader.load(PasswordEncoder.class);
PASSWORD_ENCODER = sloader.iterator().next();
}
}

public static String encodePwd(String rawPassword) {
return PASSWORD_ENCODER.encode(rawPassword);
}

@Autowired
private AESCryptService aesCryptService;
private UserDao userDao;

private List<String> admins;

Expand All @@ -61,22 +96,30 @@ public void init() {
@Override
public boolean login(User user) {
User checkUser = this.userDao.getUserByUserCode(user.getUserCode());
if (checkUser == null || !this.aesCryptService.encrypt(user.getPassword()).equals(checkUser.getPassword())) {
if (checkUser == null || !PASSWORD_ENCODER.matches(user.getPassword(), checkUser.getPassword())) {
return false;
}
return true;
}

/**
* 为true表示禁止帐号注册功能
*/
private final boolean disableRegister = Boolean.getBoolean("bistoury.ui.register_disabled");

@Override
public int register(User user) {
if (disableRegister) {
throw new IllegalAccessError("User register is disabled!");
}
Preconditions.checkNotNull(user, "user cannot be null");
Preconditions.checkArgument(!Strings.isNullOrEmpty(user.getUserCode()), "user code cannot be null or empty");
Preconditions.checkArgument(!Strings.isNullOrEmpty(user.getPassword()), "password cannot be null or empty");
User checkUser = this.userDao.getUserByUserCode(user.getUserCode());
if (checkUser != null) {
return -1;
}
user.setPassword(this.aesCryptService.encrypt(user.getPassword()));
user.setPassword(PASSWORD_ENCODER.encode(user.getPassword()));
return this.userDao.registerUser(user);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
qunar.tc.bistoury.ui.service.impl.PasswordEncoderForOldAESCryptImpl
#org.springframework.security.crypto.password.Pbkdf2PasswordEncoder
#org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
#org.springframework.security.crypto.scrypt.SCryptPasswordEncoder
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package qunar.tc.bistoury.ui.security;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;

public class PasswordEncoderTest {

@Test
public void test() {
PasswordEncoder[] passwordEncoders = new PasswordEncoder[] {
new Pbkdf2PasswordEncoder(),
new BCryptPasswordEncoder(),
new SCryptPasswordEncoder()
};
final String rawPassword = "password";
for (PasswordEncoder passwordEncoder : passwordEncoders) {
final String encoded = passwordEncoder.encode(rawPassword);
System.out.println(passwordEncoder.getClass()+" src: "+rawPassword + " => "+encoded);
Assert.assertTrue(passwordEncoder.matches(rawPassword, encoded));
}
}
}
6 changes: 3 additions & 3 deletions bistoury-ui/src/bin/bistoury-ui-env.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
set -euo pipefail

JAVA_HOME="/tmp/bistoury/java"
JAVA_OPTS="-Dbistoury.conf=$BISTOURY_COF_DIR -Dbistoury.cache=$BISTOURY_CACHE_DIR"
set +o nounset
test -z "$JAVA_HOME" && JAVA_HOME="/tmp/bistoury/java"
JAVA_OPTS="$JAVA_OPTS -Dbistoury.conf=$BISTOURY_COF_DIR -Dbistoury.cache=$BISTOURY_CACHE_DIR"
2 changes: 1 addition & 1 deletion script/h2/data.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
insert into bistoury_user (user_code, password) values ('admin','q1mHvT20zskSnIHSF27d/A==');
insert into bistoury_user (user_code, password) values ('admin','${admin_pwd}');
insert into bistoury_app(code, name, group_code, status, creator) values ('bistoury_demo_app','测试应用','tcdev',1,'admin');
insert into bistoury_user_app (app_code, user_code) values ('bistoury_demo_app','admin');
insert into bistoury_server (server_id, ip, port, host, log_dir, room, app_code, auto_jstack_enable, auto_jmap_histo_enable) values ('bade8ba7d59b4ca0b91a044739a670aa','${local_ip}',8080,'${local_host}','${log_dir}','al','bistoury_demo_app',1,0);
14 changes: 7 additions & 7 deletions script/h2/h2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
H2_DIR=`pwd`
H2_LOG_FILE=$H2_DIR/h2.log
H2_PID_FILE=$H2_DIR/h2.pid
BISTOURY_TMP_DIR="/tmp/bistoury"
test -z "$BISTOURY_TMP_DIR" && BISTOURY_TMP_DIR="/tmp/bistoury"
H2_PORT_FILE="$BISTOURY_TMP_DIR/h2port.conf"

H2_DATA_BASE_URL="/tmp/bistoury/h2/bistoury;MODE=MYSQL;TRACE_LEVEL_SYSTEM_OUT=2;AUTO_SERVER=TRUE;"
H2_DATA_BASE_URL="${BISTOURY_TMP_DIR}/h2/bistoury;MODE=MYSQL;TRACE_LEVEL_SYSTEM_OUT=2;AUTO_SERVER=TRUE;"
APP_LOG_DIR="\/tmp"

LOCAL_IP=`/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"|tail -1`

H2_PORT=9092;
echo "$H2_PORT">$H2_PORT_FILE

Expand All @@ -36,18 +34,20 @@ else
fi

start(){

echo "Init tables"
$JAVA -cp h2-1.4.199.jar org.h2.tools.RunScript -url "jdbc:h2:file:$H2_DATA_BASE_URL" -script ./schema.sql

echo "Init datas"
#替换数据库初始化文件中的sql
local_host=`hostname`
APP_LOG_DIR=` echo $APP_LOG_DIR | sed 's#\/#\\\/#g'`
sed 's/${local_ip}/'$LOCAL_IP'/g' data.sql | sed 's/${local_host}/'$local_host'/g'|sed 's/${log_dir}/'$APP_LOG_DIR'/g' >newdata.sql

test -z "$LOCAL_IP" && LOCAL_IP=`/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"|tail -1`
test -z "$BISTOURY_ADMIN_PWD" && export BISTOURY_ADMIN_PWD="q1mHvT20zskSnIHSF27d/A=="
sed 's@${local_ip}@'$LOCAL_IP'@g' data.sql | sed 's@${admin_pwd}@'$BISTOURY_ADMIN_PWD'@g' | \
sed 's/${local_host}/'$local_host'/g'|sed 's@${log_dir}@'$APP_LOG_DIR'@g' >newdata.sql
$JAVA -cp h2-1.4.199.jar org.h2.tools.RunScript -url "jdbc:h2:file:$H2_DATA_BASE_URL" -script ./newdata.sql

unset BISTOURY_ADMIN_PWD
rm -rf newdata.sql

echo "Start h2 database"
Expand Down
12 changes: 10 additions & 2 deletions script/quick_start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@ BISTOURY_AGENT_APP_LIB_CLASS="";
BISTOURY_TMP_DIR="/tmp/bistoury"
BISTOURY_PROXY_CONF_FILE="$BISTOURY_TMP_DIR/proxy.conf"

LOCAL_IP=`/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"|tail -1`

start(){

test -z "$LOCAL_IP" && LOCAL_IP=`/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"|tail -1`
export JAVA_OPTS="$JAVA_OPTS -Dbistoury.ui.register_disabled=true"
test -z "$BISTOURY_ADMIN_PWD" && BISTOURY_ADMIN_PWD=admin
cd $BISTOURY_UI_BIN_DIR
echo "BISTOURY_ADMIN_PWD=$BISTOURY_ADMIN_PWD"
export BISTOURY_ADMIN_PWD=$(java -cp '../lib/*' qunar.tc.bistoury.ui.security.PasswordEncoderMain "$BISTOURY_ADMIN_PWD" | awk '/encodePwd:/{print $4}')
#echo "BISTOURY_ADMIN_PWD=$BISTOURY_ADMIN_PWD"
export BISTOURY_UI_PASSWORD_ENCODER=new

cd $H2_DATABASE_DIR
./h2.sh -j $2 -i $LOCAL_IP -l $APP_LOG_DIR start
unset BISTOURY_ADMIN_PWD
sleep 5

cd $BISTOURY_PROXY_BIN_DIR
Expand Down