Merge commit '32c29149590022c335d8f64c6903a82619fd1bc9' into fix-1535-1

# Conflicts:
#	console/src/main/resources/static/js/main.js
This commit is contained in:
赵禹光 2019-07-31 18:40:39 +08:00
commit 0a54af1179
22 changed files with 8993 additions and 121 deletions

View File

@ -154,7 +154,7 @@ public @interface NacosProperties {
/**
* The placeholder of {@link NacosProperties#ENABLE_REMOTE_SYNC_CONFIG enableRemoteSyncConfig}, the value is <code>"${nacos.enableRemoteSyncConfig:}"</code>
*/
String ENABLE_REMOTE_SYNC_CONFIG_PLACEHOLDER = "${" + PREFIX + ENABLE_REMOTE_SYNC_CONFIG + "}";
String ENABLE_REMOTE_SYNC_CONFIG_PLACEHOLDER = "${" + PREFIX + ENABLE_REMOTE_SYNC_CONFIG + ":}";
/**
* The property of "endpoint"

View File

@ -32,6 +32,7 @@ import com.alibaba.nacos.client.config.impl.SpasAdapter;
import com.alibaba.nacos.client.monitor.MetricsMonitor;
import com.alibaba.nacos.client.naming.beat.BeatInfo;
import com.alibaba.nacos.client.naming.utils.*;
import com.alibaba.nacos.client.utils.AppNameUtils;
import com.alibaba.nacos.client.utils.StringUtils;
import com.alibaba.nacos.client.utils.TemplateUtils;
import com.alibaba.nacos.common.util.HttpMethod;
@ -481,18 +482,17 @@ public class NamingProxy {
private void checkSignature(Map<String, String> params) {
String ak = getAccessKey();
String sk = getSecretKey();
params.put("app", AppNameUtils.getAppName());
if (StringUtils.isEmpty(ak) && StringUtils.isEmpty(sk)) {
return;
}
try {
String app = System.getProperty("project.name");
String signData = getSignData(params.get("serviceName"));
String signature = SignUtil.sign(signData, sk);
params.put("signature", signature);
params.put("data", signData);
params.put("ak", ak);
params.put("app", app);
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -15,12 +15,14 @@
*/
package com.alibaba.nacos.client.naming.utils;
import com.alibaba.nacos.common.util.VersionUtils;
/**
* @author xuanyin.zy
*/
public class UtilAndComs {
public static final String VERSION = "Nacos-Java-Client:v1.1.1";
public static final String VERSION = "Nacos-Java-Client:v" + VersionUtils.VERSION;
public static String WEB_CONTEXT = "/nacos";

View File

@ -68,5 +68,14 @@
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>nacos-version.txt</include>
</includes>
</resource>
</resources>
</build>
</project>

View File

@ -36,6 +36,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@ -227,6 +228,32 @@ public class ConfigController {
return true;
}
/**
* @author klw
* @Description: delete configuration based on multiple config ids
* @Date 2019/7/5 10:26
* @Param [request, response, dataId, group, tenant, tag]
* @return java.lang.Boolean
*/
@RequestMapping(params = "delType=ids", method = RequestMethod.DELETE)
@ResponseBody
public RestResult<Boolean> deleteConfigs(HttpServletRequest request, HttpServletResponse response,
@RequestParam(value = "ids")List<Long> ids) {
String clientIp = RequestUtil.getRemoteIp(request);
final Timestamp time = TimeUtils.getCurrentTime();
List<ConfigInfo> configInfoList = persistService.removeConfigInfoByIds(ids, clientIp, null);
if(!CollectionUtils.isEmpty(configInfoList)){
for(ConfigInfo configInfo : configInfoList) {
ConfigTraceService.logPersistenceEvent(configInfo.getDataId(), configInfo.getGroup(),
configInfo.getTenant(), null, time.getTime(), clientIp,
ConfigTraceService.PERSISTENCE_EVENT_REMOVE, null);
EventDispatcher.fireEvent(new ConfigDataChangeEvent(false, configInfo.getDataId(),
configInfo.getGroup(), configInfo.getTenant(), time.getTime()));
}
}
return ResultBuilder.buildSuccessResult(true);
}
@RequestMapping(value = "/catalog", method = RequestMethod.GET)
@ResponseBody
public RestResult<ConfigAdvanceInfo> getConfigAdvanceInfo(HttpServletRequest request, HttpServletResponse response,

View File

@ -163,27 +163,27 @@ public class BasicDataSourceServiceImpl implements DataSourceService {
}
ds.setUrl(val.trim());
val = env.getProperty("db.user");
val = env.getProperty("db.user." + i, env.getProperty("db.user"));
if (null == val) {
fatalLog.error("db.user is null");
fatalLog.error("db.user." + i + " is null");
throw new IllegalArgumentException();
}
ds.setUsername(val.trim());
val = env.getProperty("db.password");
val = env.getProperty("db.password." + i, env.getProperty("db.password"));
if (null == val) {
fatalLog.error("db.password is null");
fatalLog.error("db.password." + i + " is null");
throw new IllegalArgumentException();
}
ds.setPassword(val.trim());
val = env.getProperty("db.initialSize");
val = env.getProperty("db.initialSize." + i, env.getProperty("db.initialSize"));
ds.setInitialSize(Integer.parseInt(defaultIfNull(val, "10")));
val = env.getProperty("db.maxActive");
val = env.getProperty("db.maxActive." + i, env.getProperty("db.maxActive"));
ds.setMaxActive(Integer.parseInt(defaultIfNull(val, "20")));
val = env.getProperty("db.maxIdle");
val = env.getProperty("db.maxIdle." + i, env.getProperty("db.maxIdle"));
ds.setMaxIdle(Integer.parseInt(defaultIfNull(val, "50")));
ds.setMaxWait(3000L);

View File

@ -23,6 +23,7 @@ import com.alibaba.nacos.config.server.utils.MD5;
import com.alibaba.nacos.config.server.utils.PaginationHelper;
import com.alibaba.nacos.config.server.utils.ParamUtils;
import com.alibaba.nacos.config.server.utils.event.EventDispatcher;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -75,6 +76,10 @@ public class PersistService {
private static final String SQL_TENANT_INFO_COUNT_BY_TENANT_ID = "select count(1) from tenant_info where tenant_id = ?";
private static final String SQL_FIND_CONFIG_INFO_BY_IDS = "SELECT ID,data_id,group_id,tenant_id,app_name,content,md5 FROM config_info WHERE ";
private static final String SQL_DELETE_CONFIG_INFO_BY_IDS = "DELETE FROM config_info WHERE ";
/**
* @author klw
* @Description: constant variables
@ -746,6 +751,42 @@ public class PersistService {
});
}
/**
* @author klw
* @Description: delete config info by ids
* @Date 2019/7/5 16:45
* @Param [ids, srcIp, srcUser]
* @return List<ConfigInfo> deleted configInfos
*/
public List<ConfigInfo> removeConfigInfoByIds(final List<Long> ids, final String srcIp, final String srcUser) {
if(CollectionUtils.isEmpty(ids)){
return null;
}
ids.removeAll(Collections.singleton(null));
return tjt.execute(new TransactionCallback<List<ConfigInfo>>() {
final Timestamp time = new Timestamp(System.currentTimeMillis());
@Override
public List<ConfigInfo> doInTransaction(TransactionStatus status) {
try {
String idsStr = Joiner.on(",").join(ids);
List<ConfigInfo> configInfoList = findConfigInfosByIds(idsStr);
if (!CollectionUtils.isEmpty(configInfoList)) {
removeConfigInfoByIdsAtomic(idsStr);
for(ConfigInfo configInfo : configInfoList){
removeTagByIdAtomic(configInfo.getId());
insertConfigHistoryAtomic(configInfo.getId(), configInfo, srcIp, srcUser, time, "D");
}
}
return configInfoList;
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
});
}
/**
* 删除beta配置信息, 物理删除
*/
@ -2787,6 +2828,37 @@ public class PersistService {
}
}
/**
* @author klw
* @Description: Delete configuration; database atomic operation, minimum SQL action, no business encapsulation
* @Date 2019/7/5 16:39
* @Param [id]
* @return void
*/
private void removeConfigInfoByIdsAtomic(final String ids) {
if(StringUtils.isBlank(ids)){
return;
}
StringBuilder sql = new StringBuilder(SQL_DELETE_CONFIG_INFO_BY_IDS);
sql.append("id in (");
List<Long> paramList = new ArrayList<>();
String[] tagArr = ids.split(",");
for (int i = 0; i < tagArr.length; i++) {
if (i != 0) {
sql.append(", ");
}
sql.append("?");
paramList.add(Long.valueOf(tagArr[i]));
}
sql.append(") ");
try {
jt.update(sql.toString(), paramList.toArray());
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
/**
* 删除配置数据库原子操作最小sql动作无业务封装
*
@ -2865,6 +2937,39 @@ public class PersistService {
}
}
/**
* @author klw
* @Description: find ConfigInfo by ids
* @Date 2019/7/5 16:37
* @Param [ids]
* @return java.util.List<com.alibaba.nacos.config.server.model.ConfigInfo>
*/
public List<ConfigInfo> findConfigInfosByIds(final String ids) {
if(StringUtils.isBlank(ids)){
return null;
}
StringBuilder sql = new StringBuilder(SQL_FIND_CONFIG_INFO_BY_IDS);
sql.append("id in (");
List<Long> paramList = new ArrayList<>();
String[] tagArr = ids.split(",");
for (int i = 0; i < tagArr.length; i++) {
if (i != 0) {
sql.append(", ");
}
sql.append("?");
paramList.add(Long.valueOf(tagArr[i]));
}
sql.append(") ");
try {
return this.jt.query(sql.toString(), paramList.toArray(), CONFIG_INFO_ROW_MAPPER);
} catch (EmptyResultDataAccessException e) { // 表明数据不存在, 返回null
return null;
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
/**
* 查询配置信息数据库原子操作最小sql动作无业务封装
*

View File

@ -93,13 +93,6 @@
<exclude>static/console-fe/.vscode/**</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>nacos-version.txt</include>
</includes>
</resource>
</resources>
</build>

View File

@ -292,12 +292,17 @@ const I18N_CONF = {
target: 'Target:',
selectNamespace: 'Select Namespace',
selectedEntry: '| Selected Entry',
cloneSelectedAlertTitle: 'Clone config',
cloneSelectedAlertContent: 'please select the configuration to clone',
delSelectedAlertTitle: 'Delete config',
delSelectedAlertContent: 'please select the configuration to delete',
delSuccessMsg: 'delete successful',
},
NewConfig: {
newListingMain: 'Create Configuration',
newListing: 'Create Configuration',
publishFailed: 'Publish failed. Make sure parameters are entered correctly.',
doNotEnte: 'Illegal characters not allowed',
doNotEnter: 'Illegal characters not allowed',
newConfig: 'Data ID cannot be empty.',
dataIdIsNotEmpty: 'Data ID cannot exceed 255 characters in length',
groupPlaceholder: 'Enter your group name',

View File

@ -290,12 +290,17 @@ const I18N_CONF = {
target: '目标空间',
selectNamespace: '请选择命名空间',
selectedEntry: '| 选中的条目',
cloneSelectedAlertTitle: '配置克隆',
cloneSelectedAlertContent: '请选择要克隆的配置',
delSelectedAlertTitle: '配置删除',
delSelectedAlertContent: '请选择要删除的配置',
delSuccessMsg: '删除成功',
},
NewConfig: {
newListingMain: '新建配置',
newListing: '新建配置',
publishFailed: '发布失败请检查参数是否正确',
doNotEnte: 'Illegal characters not allowed',
doNotEnter: '不允许非法字符',
newConfig: 'Data ID 不能为空',
dataIdIsNotEmpty: 'Data ID 长度不能超过255字符',
groupPlaceholder: '请输入Group名称',

View File

@ -262,12 +262,14 @@ class ConfigEditor extends React.Component {
stopBeta() {
const { locale } = this.props;
const { dataId, group } = this.state.form;
const tenant = getParams('namespace');
return request
.delete('v1/cs/configs', {
params: {
beta: true,
dataId,
group,
tenant,
},
})
.then(res => {

View File

@ -697,6 +697,52 @@ class ConfigurationManagement extends React.Component {
}
}
multipleSelectionDeletion() {
const { locale = {} } = this.props;
const self = this;
if (configsTableSelected.size === 0) {
Dialog.alert({
title: locale.delSelectedAlertTitle,
content: locale.delSelectedAlertContent,
});
} else {
let toShowDatas = [];
configsTableSelected.forEach((value, key, map) => {
let item = {};
item.dataId = value.dataId;
item.group = value.group;
toShowDatas.push(item);
});
Dialog.confirm({
title: locale.removeConfiguration,
content: (
<div style={{ marginTop: '-20px' }}>
<h3>{locale.sureDelete}</h3>
<Table dataSource={toShowDatas}>
<Table.Column title="Data Id" dataIndex="dataId" />
<Table.Column title="Group" dataIndex="group" />
</Table>
</div>
),
onOk: () => {
let idsStr = '';
configsTableSelected.forEach((value, key, map) => {
idsStr = `${idsStr + key},`;
});
const url = `v1/cs/configs?delType=ids&ids=${idsStr}`;
request({
url,
type: 'delete',
success(res) {
Message.success(locale.delSuccessMsg);
self.getData();
},
});
},
});
}
}
cloneSelectedDataConfirm() {
const { locale = {} } = this.props;
const self = this;
@ -704,8 +750,8 @@ class ConfigurationManagement extends React.Component {
self.field.setValue('cloneTargetSpace', undefined);
if (configsTableSelected.size === 0) {
Dialog.alert({
title: locale.exportSelectedAlertTitle,
content: locale.exportSelectedAlertContent,
title: locale.cloneSelectedAlertTitle,
content: locale.cloneSelectedAlertContent,
});
return;
}
@ -1258,7 +1304,16 @@ class ConfigurationManagement extends React.Component {
<div style={{ float: 'left' }}>
<Button
type={'primary'}
style={{ marginLeft: 60, marginRight: 10 }}
warning
style={{ marginRight: 10 }}
onClick={this.multipleSelectionDeletion.bind(this)}
data-spm-click={'gostr=/aliyun;locaid=configsDelete'}
>
{locale.deleteAction}
</Button>
<Button
type={'primary'}
style={{ marginRight: 10 }}
onClick={this.exportSelectedData.bind(this)}
data-spm-click={'gostr=/aliyun;locaid=configsExport'}
>

View File

@ -365,10 +365,10 @@ class NewConfig extends React.Component {
validateChart(rule, value, callback) {
const { locale = {} } = this.props;
const chartReg = /[@#\$%\^&\*]+/g;
const chartReg = /[@#\$%\^&\*\s]+/g;
if (chartReg.test(value)) {
callback(locale.doNotEnte);
callback(locale.doNotEnter);
} else {
callback();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -54,6 +54,8 @@ public class ServerListManager {
private Map<String, List<Server>> distroConfig = new ConcurrentHashMap<>();
private Map<String, Long> distroBeats = new ConcurrentHashMap<>(16);
private Set<String> liveSites = new HashSet<>();
private final static String LOCALHOST_SITE = UtilsAndCommons.UNKNOWN_SITE;
@ -196,11 +198,17 @@ public class ServerListManager {
throw new IllegalArgumentException("server: " + server.getKey() + " is not in serverlist");
}
Long lastBeat = distroBeats.get(server.getKey());
long now = System.currentTimeMillis();
if (null != lastBeat) {
server.setAlive(now - lastBeat < switchDomain.getDistroServerExpiredMillis());
}
distroBeats.put(server.getKey(), now);
Date date = new Date(Long.parseLong(params[2]));
server.setLastRefTimeStr(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
server.setWeight(params.length == 4 ? Integer.parseInt(params[3]) : 1);
server.setAlive(System.currentTimeMillis() - server.getLastRefTime() < switchDomain.getDistroServerExpiredMillis());
List<Server> list = distroConfig.get(server.getSite());
if (list == null || list.size() <= 0) {
list = new ArrayList<>();
@ -230,65 +238,6 @@ public class ServerListManager {
distroConfig.put(server.getSite(), tmpServerList);
}
liveSites.addAll(distroConfig.keySet());
List<Server> servers = distroConfig.get(LOCALHOST_SITE);
if (CollectionUtils.isEmpty(servers)) {
return;
}
//local site servers
List<String> allLocalSiteSrvs = new ArrayList<>();
for (Server server : servers) {
if (server.getKey().endsWith(":0")) {
continue;
}
server.setAdWeight(switchDomain.getAdWeight(server.getKey()) == null ? 0 : switchDomain.getAdWeight(server.getKey()));
for (int i = 0; i < server.getWeight() + server.getAdWeight(); i++) {
if (!allLocalSiteSrvs.contains(server.getKey())) {
allLocalSiteSrvs.add(server.getKey());
}
if (server.isAlive() && !newHealthyList.contains(server)) {
newHealthyList.add(server);
}
}
}
Collections.sort(newHealthyList);
float curRatio = (float) newHealthyList.size() / allLocalSiteSrvs.size();
if (autoDisabledHealthCheck
&& curRatio > switchDomain.getDistroThreshold()
&& System.currentTimeMillis() - lastHealthServerMillis > STABLE_PERIOD) {
Loggers.SRV_LOG.info("[NACOS-DISTRO] distro threshold restored and " +
"stable now, enable health check. current ratio: {}", curRatio);
switchDomain.setHealthCheckEnabled(true);
// we must set this variable, otherwise it will conflict with user's action
autoDisabledHealthCheck = false;
}
if (!CollectionUtils.isEqualCollection(healthyServers, newHealthyList)) {
// for every change disable healthy check for some while
if (switchDomain.isHealthCheckEnabled()) {
Loggers.SRV_LOG.info("[NACOS-DISTRO] healthy server list changed, " +
"disable health check for {} ms from now on, old: {}, new: {}", STABLE_PERIOD,
healthyServers, newHealthyList);
switchDomain.setHealthCheckEnabled(false);
autoDisabledHealthCheck = true;
lastHealthServerMillis = System.currentTimeMillis();
}
healthyServers = newHealthyList;
notifyListeners();
}
}
public void clean() {
@ -310,29 +259,14 @@ public class ServerListManager {
}
private void cleanInvalidServers() {
for (Map.Entry<String, List<Server>> entry : distroConfig.entrySet()) {
List<Server> tmpServers = null;
List<Server> currentServerList = entry.getValue();
for (Server server : entry.getValue()) {
if (!server.isAlive()) {
tmpServers = new ArrayList<>();
for (Server server1 : currentServerList) {
String serverKey1 = server1.getKey() + "_" + server1.getSite();
String serverKey = server.getKey() + "_" + server.getSite();
if (!serverKey.equals(serverKey1) && !tmpServers.contains(server1)) {
tmpServers.add(server1);
}
}
}
}
if (tmpServers != null) {
distroConfig.put(entry.getKey(), tmpServers);
List<Server> currentServers = entry.getValue();
if (null == currentServers) {
distroConfig.remove(entry.getKey());
continue;
}
currentServers.removeIf(server -> !server.isAlive());
}
}
@ -397,11 +331,7 @@ public class ServerListManager {
return;
}
for (String key : distroConfig.keySet()) {
for (Server server : distroConfig.get(key)) {
server.setAlive(System.currentTimeMillis() - server.getLastRefTime() < switchDomain.getDistroServerExpiredMillis());
}
}
checkDistroHeartbeat();
int weight = Runtime.getRuntime().availableProcessors() / 2;
if (weight <= 0) {
@ -442,4 +372,79 @@ public class ServerListManager {
}
}
private void checkDistroHeartbeat() {
Loggers.EPHEMERAL.debug("check distro heartbeat.");
List<Server> servers = distroConfig.get(LOCALHOST_SITE);
if (CollectionUtils.isEmpty(servers)) {
return;
}
List<Server> newHealthyList = new ArrayList<>(servers.size());
long now = System.currentTimeMillis();
for (Server s: servers) {
Long lastBeat = distroBeats.get(s.getKey());
if (null == lastBeat) {
continue;
}
s.setAlive(now - lastBeat < switchDomain.getDistroServerExpiredMillis());
}
//local site servers
List<String> allLocalSiteSrvs = new ArrayList<>();
for (Server server : servers) {
if (server.getKey().endsWith(":0")) {
continue;
}
server.setAdWeight(switchDomain.getAdWeight(server.getKey()) == null ? 0 : switchDomain.getAdWeight(server.getKey()));
for (int i = 0; i < server.getWeight() + server.getAdWeight(); i++) {
if (!allLocalSiteSrvs.contains(server.getKey())) {
allLocalSiteSrvs.add(server.getKey());
}
if (server.isAlive() && !newHealthyList.contains(server)) {
newHealthyList.add(server);
}
}
}
Collections.sort(newHealthyList);
float curRatio = (float) newHealthyList.size() / allLocalSiteSrvs.size();
if (autoDisabledHealthCheck
&& curRatio > switchDomain.getDistroThreshold()
&& System.currentTimeMillis() - lastHealthServerMillis > STABLE_PERIOD) {
Loggers.SRV_LOG.info("[NACOS-DISTRO] distro threshold restored and " +
"stable now, enable health check. current ratio: {}", curRatio);
switchDomain.setHealthCheckEnabled(true);
// we must set this variable, otherwise it will conflict with user's action
autoDisabledHealthCheck = false;
}
if (!CollectionUtils.isEqualCollection(healthyServers, newHealthyList)) {
// for every change disable healthy check for some while
if (switchDomain.isHealthCheckEnabled()) {
Loggers.SRV_LOG.info("[NACOS-DISTRO] healthy server list changed, " +
"disable health check for {} ms from now on, old: {}, new: {}", STABLE_PERIOD,
healthyServers, newHealthyList);
switchDomain.setHealthCheckEnabled(false);
autoDisabledHealthCheck = true;
lastHealthServerMillis = System.currentTimeMillis();
}
healthyServers = newHealthyList;
notifyListeners();
}
}
}

View File

@ -104,7 +104,7 @@ public class DistroConsistencyServiceImpl implements EphemeralConsistencyService
private Map<String, String> syncChecksumTasks = new ConcurrentHashMap<>(16);
@PostConstruct
public void init() throws Exception {
public void init() {
GlobalExecutor.submit(new Runnable() {
@Override
public void run() {
@ -154,6 +154,7 @@ public class DistroConsistencyServiceImpl implements EphemeralConsistencyService
@Override
public void remove(String key) throws NacosException {
onRemove(key);
listeners.remove(key);
}
@Override
@ -186,8 +187,6 @@ public class DistroConsistencyServiceImpl implements EphemeralConsistencyService
return;
}
listeners.remove(key);
notifier.addTask(key, ApplyAction.DELETE);
}
@ -322,6 +321,11 @@ public class DistroConsistencyServiceImpl implements EphemeralConsistencyService
if (!listeners.containsKey(key)) {
listeners.put(key, new CopyOnWriteArrayList<>());
}
if (listeners.get(key).contains(listener)) {
return;
}
listeners.get(key).add(listener);
}

View File

@ -143,6 +143,9 @@ public class ServiceManager implements RecordListener<Service> {
if (oldDom != null) {
oldDom.update(service);
// re-listen to handle the situation when the underlying listener is removed:
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), true), oldDom);
consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), false), oldDom);
} else {
putService(service);
service.init();

View File

@ -15,10 +15,12 @@
*/
package com.alibaba.nacos.naming.web;
import com.alibaba.nacos.api.naming.CommonParams;
import com.alibaba.nacos.naming.acl.AuthChecker;
import com.alibaba.nacos.naming.misc.SwitchDomain;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.*;
@ -34,6 +36,8 @@ import java.security.AccessControlException;
*/
public class AuthFilter implements Filter {
private static final String[] NAMESPACE_FORBIDDEN_STRINGS = new String[]{"..", "/"};
@Autowired
private AuthChecker authChecker;
@ -64,11 +68,16 @@ public class AuthFilter implements Filter {
}
if (method.isAnnotationPresent(NeedAuth.class) && !switchDomain.isEnableAuthentication()) {
// leave it empty.
}
if (path.contains(UtilsAndCommons.NACOS_NAMING_RAFT_CONTEXT)) {
authChecker.doRaftAuth(req);
} else {
authChecker.doAuth(req.getParameterMap(), req);
// Check namespace:
String namespaceId = req.getParameter(CommonParams.NAMESPACE_ID);
if (StringUtils.isNotBlank(namespaceId)) {
if (namespaceId.contains(NAMESPACE_FORBIDDEN_STRINGS[0]) || namespaceId.contains(NAMESPACE_FORBIDDEN_STRINGS[1])) {
throw new IllegalArgumentException("forbidden namespace: " + namespaceId);
}
}
@ -78,9 +87,12 @@ public class AuthFilter implements Filter {
} catch (NoSuchMethodException e) {
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "no such api");
return;
} catch (IllegalArgumentException e) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, UtilsAndCommons.getAllExceptionMsg(e));
return;
} catch (Exception e) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Server failed," + UtilsAndCommons.getAllExceptionMsg(e));
"Server failed," + UtilsAndCommons.getAllExceptionMsg(e));
return;
}
filterChain.doFilter(req, resp);

View File

@ -52,7 +52,7 @@ public class NamingConfig {
FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(authFilter());
registration.addUrlPatterns("/api/*", "/raft/*");
registration.addUrlPatterns("/v1/ns/*");
registration.setName("authFilter");
registration.setOrder(5);

View File

@ -232,6 +232,32 @@ public class RestAPI_ITCase {
namingServiceDelete(serviceName);
}
@Test
public void testInvalidNamespace() {
String serviceName = NamingBase.randomDomainName();
ResponseEntity<String> response = request(NamingBase.NAMING_CONTROLLER_PATH + "/service",
Params.newParams()
.appendParam("serviceName", serviceName)
.appendParam("protectThreshold", "0.6")
.appendParam("namespaceId", "..invalid-namespace")
.done(),
String.class,
HttpMethod.POST);
Assert.assertTrue(response.getStatusCode().is4xxClientError());
response = request(NamingBase.NAMING_CONTROLLER_PATH + "/service",
Params.newParams()
.appendParam("serviceName", serviceName)
.appendParam("protectThreshold", "0.6")
.appendParam("namespaceId", "/invalid-namespace")
.done(),
String.class,
HttpMethod.POST);
Assert.assertTrue(response.getStatusCode().is4xxClientError());
}
private void namingServiceDelete(String serviceName) {
//delete service
ResponseEntity<String> response = request(NamingBase.NAMING_CONTROLLER_PATH + "/service",