chore: import upstream snapshot with attribution
This commit is contained in:
+147
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 1999-2025 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.common.JustForTest;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.lifecycle.Closeable;
|
||||
import com.alibaba.nacos.common.remote.client.ServerListFactory;
|
||||
import com.alibaba.nacos.common.spi.NacosServiceLoader;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Server list Manager.
|
||||
*
|
||||
* @author totalo
|
||||
*/
|
||||
public abstract class AbstractServerListManager implements ServerListFactory, Closeable {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractServerListManager.class);
|
||||
|
||||
protected ServerListProvider serverListProvider;
|
||||
|
||||
protected NacosClientProperties properties;
|
||||
|
||||
public AbstractServerListManager(NacosClientProperties properties) {
|
||||
this(properties, null);
|
||||
}
|
||||
|
||||
public AbstractServerListManager(NacosClientProperties properties, String namespace) {
|
||||
// To avoid set operation affect the original properties.
|
||||
NacosClientProperties tmpProperties = properties.derive();
|
||||
if (StringUtils.isNotBlank(namespace)) {
|
||||
tmpProperties.setProperty(PropertyKeyConst.NAMESPACE, namespace);
|
||||
}
|
||||
tmpProperties.setProperty(Constants.CLIENT_MODULE_TYPE, getModuleName());
|
||||
this.properties = tmpProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getServerList() {
|
||||
return serverListProvider.getServerList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
String className = this.getClass().getName();
|
||||
LOGGER.info("{} do shutdown begin", className);
|
||||
if (null != serverListProvider) {
|
||||
serverListProvider.shutdown();
|
||||
}
|
||||
serverListProvider = null;
|
||||
LOGGER.info("{} do shutdown stop", className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start server list manager.
|
||||
*
|
||||
* @throws NacosException during start and initialize.
|
||||
*/
|
||||
public void start() throws NacosException {
|
||||
Collection<ServerListProvider> serverListProviders =
|
||||
NacosServiceLoader.load(ServerListProvider.class);
|
||||
Collection<ServerListProvider> sorted = serverListProviders.stream()
|
||||
.sorted((a, b) -> b.getOrder() - a.getOrder()).collect(Collectors.toList());
|
||||
for (ServerListProvider each : sorted) {
|
||||
boolean matchResult = each.match(properties);
|
||||
LOGGER.info("Load and match ServerListProvider {}, match result: {}",
|
||||
each.getClass().getCanonicalName(),
|
||||
matchResult);
|
||||
if (matchResult) {
|
||||
this.serverListProvider = each;
|
||||
LOGGER.info("Will use {} as ServerListProvider",
|
||||
this.serverListProvider.getClass().getCanonicalName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (null == serverListProvider) {
|
||||
LOGGER.error("No server list provider found, SPI load size: {}", sorted.size());
|
||||
throw new NacosException(NacosException.CLIENT_INVALID_PARAM,
|
||||
"No server list provider found.");
|
||||
}
|
||||
this.serverListProvider.init(properties, getNacosRestTemplate());
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return getModuleName() + "-" + serverListProvider.getServerName();
|
||||
}
|
||||
|
||||
public String getContextPath() {
|
||||
return serverListProvider.getContextPath();
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return serverListProvider.getNamespace();
|
||||
}
|
||||
|
||||
public String getAddressSource() {
|
||||
return serverListProvider.getAddressSource();
|
||||
}
|
||||
|
||||
public boolean isFixed() {
|
||||
return serverListProvider.isFixed();
|
||||
}
|
||||
|
||||
/**
|
||||
* get module name.
|
||||
*
|
||||
* @return module name
|
||||
*/
|
||||
protected abstract String getModuleName();
|
||||
|
||||
/**
|
||||
* get nacos rest template.
|
||||
*
|
||||
* @return nacos rest template
|
||||
*/
|
||||
protected abstract NacosRestTemplate getNacosRestTemplate();
|
||||
|
||||
@JustForTest
|
||||
NacosClientProperties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.client.utils.ClientBasicParamUtil;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Address server list provider.
|
||||
*
|
||||
* @author totalo
|
||||
*/
|
||||
public abstract class AbstractServerListProvider implements ServerListProvider {
|
||||
|
||||
protected String contextPath = ClientBasicParamUtil.getDefaultContextPath();
|
||||
|
||||
protected String namespace = "";
|
||||
|
||||
@Override
|
||||
public void init(final NacosClientProperties properties,
|
||||
final NacosRestTemplate nacosRestTemplate) throws NacosException {
|
||||
if (null == properties) {
|
||||
throw new NacosException(NacosException.INVALID_PARAM, "properties is null");
|
||||
}
|
||||
initContextPath(properties);
|
||||
initNameSpace(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server list.
|
||||
* @return server list
|
||||
*/
|
||||
@Override
|
||||
public abstract List<String> getServerList();
|
||||
|
||||
/**
|
||||
* Get server name.
|
||||
* @return server name
|
||||
*/
|
||||
@Override
|
||||
public abstract String getServerName();
|
||||
|
||||
/**
|
||||
* Get order.
|
||||
* @return order
|
||||
*/
|
||||
@Override
|
||||
public abstract int getOrder();
|
||||
|
||||
public String getContextPath() {
|
||||
return contextPath;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
private void initContextPath(NacosClientProperties properties) {
|
||||
String contentPathTmp = properties.getProperty(PropertyKeyConst.CONTEXT_PATH);
|
||||
if (!StringUtils.isBlank(contentPathTmp)) {
|
||||
this.contextPath = contentPathTmp;
|
||||
}
|
||||
}
|
||||
|
||||
private void initNameSpace(NacosClientProperties properties) {
|
||||
String namespace = properties.getProperty(PropertyKeyConst.NAMESPACE);
|
||||
if (StringUtils.isNotBlank(namespace)) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
}
|
||||
}
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright 1999-2025 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.SystemPropertyKeyConst;
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.constant.Constants.Address;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.client.utils.ClientBasicParamUtil;
|
||||
import com.alibaba.nacos.client.utils.ContextPathUtil;
|
||||
import com.alibaba.nacos.client.utils.TemplateUtils;
|
||||
import com.alibaba.nacos.common.executor.NameThreadFactory;
|
||||
import com.alibaba.nacos.common.http.HttpRestResult;
|
||||
import com.alibaba.nacos.common.http.HttpUtils;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.http.param.Query;
|
||||
import com.alibaba.nacos.common.notify.NotifyCenter;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.common.utils.InternetAddressUtil;
|
||||
import com.alibaba.nacos.common.utils.IoUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Endpoint server list provider.
|
||||
*
|
||||
* @author totalo
|
||||
*/
|
||||
public class EndpointServerListProvider extends AbstractServerListProvider {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(EndpointServerListProvider.class);
|
||||
|
||||
private static final boolean USE_ENDPOINT_PARSING_RULE_DEFAULT_VALUE = true;
|
||||
|
||||
private NacosRestTemplate nacosRestTemplate;
|
||||
|
||||
private static final String CUSTOM_NAME = "custom";
|
||||
|
||||
private final long refreshServerListInternal = TimeUnit.SECONDS.toMillis(30);
|
||||
|
||||
private final int initServerListRetryTimes = 5;
|
||||
|
||||
private long lastServerListRefreshTime = 0L;
|
||||
|
||||
private ScheduledExecutorService refreshServerListExecutor;
|
||||
|
||||
private String endpoint;
|
||||
|
||||
private int endpointPort = 8080;
|
||||
|
||||
private String endpointContextPath;
|
||||
|
||||
private String serverListName = ClientBasicParamUtil.getDefaultNodesPath();
|
||||
|
||||
private volatile List<String> serversFromEndpoint = new ArrayList<>();
|
||||
|
||||
private String addressServerUrl;
|
||||
|
||||
private String moduleName = "default";
|
||||
|
||||
@Override
|
||||
public void init(final NacosClientProperties properties,
|
||||
final NacosRestTemplate nacosRestTemplate)
|
||||
throws NacosException {
|
||||
super.init(properties, nacosRestTemplate);
|
||||
this.nacosRestTemplate = nacosRestTemplate;
|
||||
initEndpoint(properties);
|
||||
initEndpointPort(properties);
|
||||
initEndpointContextPath(properties);
|
||||
initServerListName(properties);
|
||||
initAddressServerUrl(properties);
|
||||
initModuleName(properties);
|
||||
startRefreshServerListTask(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getServerList() {
|
||||
return serversFromEndpoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
String contextPathTmp =
|
||||
StringUtils.isNotBlank(this.endpointContextPath) ? this.endpointContextPath
|
||||
: this.contextPath;
|
||||
return CUSTOM_NAME + "-"
|
||||
+ String.join("_", endpoint, String.valueOf(endpointPort), contextPathTmp,
|
||||
serverListName)
|
||||
+ (StringUtils.isNotBlank(namespace) ? ("_" + StringUtils.trim(namespace)) : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Address.ENDPOINT_SERVER_LIST_PROVIDER_ORDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(final NacosClientProperties properties) {
|
||||
String endpointTmp = getEndPointTmp(properties);
|
||||
return StringUtils.isNotBlank(endpointTmp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAddressSource() {
|
||||
return this.addressServerUrl;
|
||||
}
|
||||
|
||||
private String getEndPointTmp(NacosClientProperties properties) {
|
||||
String endpointTmp = properties.getProperty(PropertyKeyConst.ENDPOINT);
|
||||
String isUseEndpointRuleParsing =
|
||||
properties.getProperty(PropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
|
||||
properties.getProperty(SystemPropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
|
||||
String.valueOf(USE_ENDPOINT_PARSING_RULE_DEFAULT_VALUE)));
|
||||
if (Boolean.parseBoolean(isUseEndpointRuleParsing)) {
|
||||
endpointTmp = ClientBasicParamUtil.parsingEndpointRule(endpointTmp);
|
||||
}
|
||||
return endpointTmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start refresh server list task.
|
||||
*
|
||||
* @throws NacosException nacos exception
|
||||
*/
|
||||
public void startRefreshServerListTask(NacosClientProperties properties) throws NacosException {
|
||||
for (int i = 0; i < initServerListRetryTimes && getServerList().isEmpty(); ++i) {
|
||||
refreshServerListIfNeed();
|
||||
if (!serversFromEndpoint.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
this.wait((i + 1) * 100L);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("get serverlist fail,url: {}", addressServerUrl);
|
||||
}
|
||||
}
|
||||
|
||||
if (serversFromEndpoint.isEmpty()) {
|
||||
LOGGER.error("[init-serverlist] fail to get NACOS-server serverlist! url: {}",
|
||||
addressServerUrl);
|
||||
throw new NacosException(NacosException.SERVER_ERROR,
|
||||
"fail to get NACOS-server serverlist! not connnect url:" + addressServerUrl);
|
||||
}
|
||||
|
||||
refreshServerListExecutor = new ScheduledThreadPoolExecutor(1,
|
||||
new NameThreadFactory(
|
||||
"com.alibaba.nacos.client.address.EndpointServerListProvider.refreshServerList"));
|
||||
// executor schedules the timer task
|
||||
long refreshInterval = Long.parseLong(
|
||||
properties.getProperty(PropertyKeyConst.ENDPOINT_REFRESH_INTERVAL_SECONDS, "30"));
|
||||
refreshServerListExecutor.scheduleWithFixedDelay(this::refreshServerListIfNeed, 0L,
|
||||
refreshInterval,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void refreshServerListIfNeed() {
|
||||
try {
|
||||
if (System.currentTimeMillis()
|
||||
- lastServerListRefreshTime < refreshServerListInternal) {
|
||||
return;
|
||||
}
|
||||
List<String> list = getServerListFromEndpoint();
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
throw new Exception("Can not acquire Nacos list");
|
||||
}
|
||||
list.sort(String::compareTo);
|
||||
if (!CollectionUtils.isEqualCollection(list, serversFromEndpoint)) {
|
||||
LOGGER.info("[SERVER-LIST] server list is updated: {}", list);
|
||||
serversFromEndpoint = list;
|
||||
lastServerListRefreshTime = System.currentTimeMillis();
|
||||
NotifyCenter.publishEvent(new ServerListChangeEvent());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.warn("failed to update server list", e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getServerListFromEndpoint() {
|
||||
try {
|
||||
HttpRestResult<String> httpResult = nacosRestTemplate.get(addressServerUrl,
|
||||
HttpUtils.builderHeader(moduleName), Query.EMPTY, String.class);
|
||||
|
||||
if (!httpResult.ok()) {
|
||||
LOGGER.error("[check-serverlist] error. addressServerUrl: {}, code: {}",
|
||||
addressServerUrl,
|
||||
httpResult.getCode());
|
||||
return null;
|
||||
}
|
||||
List<String> lines = IoUtils.readLines(new StringReader(httpResult.getData()));
|
||||
List<String> result = new ArrayList<>(lines.size());
|
||||
for (String serverAddr : lines) {
|
||||
String[] ipPort = InternetAddressUtil.splitIpPortStr(serverAddr);
|
||||
String ip = ipPort[0].trim();
|
||||
if (ipPort.length == 1) {
|
||||
result.add(ip + InternetAddressUtil.IP_PORT_SPLITER
|
||||
+ ClientBasicParamUtil.getDefaultServerPort());
|
||||
} else {
|
||||
result.add(serverAddr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("[check-serverlist] exception. url: {}", addressServerUrl, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void initEndpoint(NacosClientProperties properties) {
|
||||
// Endpoint should not be null or empty, because the match has return `true`.
|
||||
this.endpoint = getEndPointTmp(properties);
|
||||
}
|
||||
|
||||
private void initEndpointPort(NacosClientProperties properties) {
|
||||
String endpointPortTmp = TemplateUtils.stringEmptyAndThenExecute(
|
||||
properties.getProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_PORT),
|
||||
() -> properties.getProperty(PropertyKeyConst.ENDPOINT_PORT));
|
||||
if (StringUtils.isNotBlank(endpointPortTmp)) {
|
||||
this.endpointPort = Integer.parseInt(endpointPortTmp);
|
||||
}
|
||||
}
|
||||
|
||||
private void initEndpointContextPath(NacosClientProperties properties) {
|
||||
String endpointContextPathTmp = TemplateUtils.stringEmptyAndThenExecute(
|
||||
properties.getProperty(
|
||||
PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_CONTEXT_PATH),
|
||||
() -> properties.getProperty(PropertyKeyConst.ENDPOINT_CONTEXT_PATH));
|
||||
if (StringUtils.isNotBlank(endpointContextPathTmp)) {
|
||||
this.endpointContextPath = endpointContextPathTmp;
|
||||
}
|
||||
}
|
||||
|
||||
private void initServerListName(NacosClientProperties properties) {
|
||||
String serverListNameTmp = properties.getProperty(PropertyKeyConst.ENDPOINT_CLUSTER_NAME);
|
||||
boolean isUseClusterName = Boolean.parseBoolean(
|
||||
properties.getProperty(PropertyKeyConst.IS_ADAPT_CLUSTER_NAME_USAGE));
|
||||
if (StringUtils.isBlank(serverListNameTmp) && isUseClusterName) {
|
||||
serverListNameTmp = properties.getProperty(PropertyKeyConst.CLUSTER_NAME);
|
||||
}
|
||||
if (!StringUtils.isBlank(serverListNameTmp)) {
|
||||
this.serverListName = serverListNameTmp;
|
||||
}
|
||||
}
|
||||
|
||||
private void initAddressServerUrl(NacosClientProperties properties) {
|
||||
String contextPathTmp = StringUtils.isNotBlank(this.endpointContextPath)
|
||||
? ContextPathUtil.normalizeContextPath(
|
||||
this.endpointContextPath)
|
||||
: ContextPathUtil.normalizeContextPath(this.contextPath);
|
||||
StringBuilder addressServerUrlTem = new StringBuilder(
|
||||
String.format("http://%s:%d%s/%s", this.endpoint, this.endpointPort, contextPathTmp,
|
||||
this.serverListName));
|
||||
boolean hasQueryString = false;
|
||||
if (StringUtils.isNotBlank(namespace)) {
|
||||
addressServerUrlTem.append("?namespace=").append(namespace);
|
||||
hasQueryString = true;
|
||||
}
|
||||
if (properties.containsKey(PropertyKeyConst.ENDPOINT_QUERY_PARAMS)) {
|
||||
addressServerUrlTem.append(hasQueryString ? "&" : "?");
|
||||
addressServerUrlTem
|
||||
.append(properties.getProperty(PropertyKeyConst.ENDPOINT_QUERY_PARAMS));
|
||||
}
|
||||
this.addressServerUrl = addressServerUrlTem.toString();
|
||||
LOGGER.info("address server url = {}", this.addressServerUrl);
|
||||
}
|
||||
|
||||
private void initModuleName(NacosClientProperties properties) {
|
||||
String moduleNameTmp = properties.getProperty(Constants.CLIENT_MODULE_TYPE);
|
||||
if (StringUtils.isNotBlank(moduleNameTmp)) {
|
||||
this.moduleName = moduleNameTmp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
if (null != refreshServerListExecutor) {
|
||||
refreshServerListExecutor.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.constant.Constants.Address;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.client.utils.ClientBasicParamUtil;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.utils.InternetAddressUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import static com.alibaba.nacos.common.constant.RequestUrlConstants.HTTPS_PREFIX;
|
||||
import static com.alibaba.nacos.common.constant.RequestUrlConstants.HTTP_PREFIX;
|
||||
|
||||
/**
|
||||
* Properties server list provider.
|
||||
*
|
||||
* @author totalo
|
||||
*/
|
||||
public class PropertiesListProvider extends AbstractServerListProvider {
|
||||
|
||||
private static final String FIXED_NAME = "fixed";
|
||||
|
||||
private List<String> serverList;
|
||||
|
||||
@Override
|
||||
public void init(final NacosClientProperties properties,
|
||||
final NacosRestTemplate nacosRestTemplate) throws NacosException {
|
||||
super.init(properties, nacosRestTemplate);
|
||||
serverList = new ArrayList<>();
|
||||
String serverAddrsStr = properties.getProperty(PropertyKeyConst.SERVER_ADDR);
|
||||
StringTokenizer serverAddrsTokens = new StringTokenizer(serverAddrsStr, ",;");
|
||||
while (serverAddrsTokens.hasMoreTokens()) {
|
||||
String serverAddr = serverAddrsTokens.nextToken().trim();
|
||||
if (serverAddr.startsWith(HTTP_PREFIX) || serverAddr.startsWith(HTTPS_PREFIX)) {
|
||||
this.serverList.add(serverAddr);
|
||||
} else {
|
||||
String[] serverAddrArr = InternetAddressUtil.splitIpPortStr(serverAddr);
|
||||
if (serverAddrArr.length == 1) {
|
||||
this.serverList
|
||||
.add(serverAddrArr[0] + InternetAddressUtil.IP_PORT_SPLITER
|
||||
+ ClientBasicParamUtil.getDefaultServerPort());
|
||||
} else {
|
||||
this.serverList.add(serverAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getServerList() {
|
||||
return serverList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
return FIXED_NAME + "-"
|
||||
+ (StringUtils.isNotBlank(namespace) ? (StringUtils.trim(namespace) + "-")
|
||||
: "")
|
||||
+ ClientBasicParamUtil.getNameSuffixByServerIps(serverList.toArray(new String[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Address.ADDRESS_SERVER_LIST_PROVIDER_ORDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(final NacosClientProperties properties) {
|
||||
return StringUtils.isNotBlank(properties.getProperty(PropertyKeyConst.SERVER_ADDR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFixed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address;
|
||||
|
||||
import com.alibaba.nacos.common.notify.SlowEvent;
|
||||
|
||||
/**
|
||||
* Server List Change Event.
|
||||
*
|
||||
* @author zongtanghu
|
||||
*/
|
||||
public class ServerListChangeEvent extends SlowEvent {
|
||||
|
||||
private static final long serialVersionUID = -1655577508567092395L;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 1999-2025 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.client.utils.ClientBasicParamUtil;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.lifecycle.Closeable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Server list provider.
|
||||
*
|
||||
* @author totalo
|
||||
*/
|
||||
public interface ServerListProvider extends Closeable {
|
||||
|
||||
/**
|
||||
* Init.
|
||||
* @param properties nacos client properties
|
||||
* @param nacosRestTemplate nacos rest template
|
||||
* @throws NacosException nacos exception
|
||||
*/
|
||||
void init(final NacosClientProperties properties, final NacosRestTemplate nacosRestTemplate)
|
||||
throws NacosException;
|
||||
|
||||
/**
|
||||
* Get server list.
|
||||
* @return server list
|
||||
*/
|
||||
List<String> getServerList();
|
||||
|
||||
/**
|
||||
* Get server name.
|
||||
* @return server name
|
||||
*/
|
||||
default String getServerName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get namespace.
|
||||
* @return namespace
|
||||
*/
|
||||
default String getNamespace() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get context path.
|
||||
* @return context path
|
||||
*/
|
||||
default String getContextPath() {
|
||||
return ClientBasicParamUtil.getDefaultContextPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order.
|
||||
* @return order
|
||||
*/
|
||||
int getOrder();
|
||||
|
||||
/**
|
||||
* Match.
|
||||
* @param properties nacos client properties
|
||||
* @return match
|
||||
*/
|
||||
boolean match(final NacosClientProperties properties);
|
||||
|
||||
/**
|
||||
* check the server list is fixed or not.
|
||||
* @return true if the server list is fixed
|
||||
*/
|
||||
default boolean isFixed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get address source.
|
||||
* @return address source
|
||||
*/
|
||||
default String getAddressSource() {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.impl;
|
||||
|
||||
/**
|
||||
* Nacos auth login constants.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class NacosAuthLoginConstant {
|
||||
|
||||
public static final String ACCESSTOKEN = "accessToken";
|
||||
|
||||
public static final String TOKENTTL = "tokenTtl";
|
||||
|
||||
public static final String TOKENREFRESHWINDOW = "tokenRefreshWindow";
|
||||
|
||||
public static final String USERNAME = "username";
|
||||
|
||||
public static final String PASSWORD = "password";
|
||||
|
||||
public static final String COLON = ":";
|
||||
|
||||
public static final String SERVER = "server";
|
||||
|
||||
public static final String RELOGINFLAG = "reLoginFlag";
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.impl;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.auth.impl.process.HttpLoginProcessor;
|
||||
import com.alibaba.nacos.common.utils.RandomUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import com.alibaba.nacos.plugin.auth.spi.client.AbstractClientAuthService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* a ClientAuthService implement.
|
||||
*
|
||||
* @author wuyfee
|
||||
*/
|
||||
|
||||
@SuppressWarnings("checkstyle:SummaryJavadoc")
|
||||
public class NacosClientAuthServiceImpl extends AbstractClientAuthService {
|
||||
|
||||
private static final Logger SECURITY_LOGGER =
|
||||
LoggerFactory.getLogger(NacosClientAuthServiceImpl.class);
|
||||
|
||||
/**
|
||||
* TTL of token in seconds.
|
||||
*/
|
||||
private long tokenTtl;
|
||||
|
||||
/**
|
||||
* Last timestamp refresh security info from server.
|
||||
*/
|
||||
private long lastRefreshTime;
|
||||
|
||||
/**
|
||||
* time window to refresh security info in seconds.
|
||||
*/
|
||||
private long tokenRefreshWindow;
|
||||
|
||||
/**
|
||||
* A context to take with when sending request to Nacos server.
|
||||
*/
|
||||
private volatile LoginIdentityContext loginIdentityContext = new LoginIdentityContext();
|
||||
|
||||
/**
|
||||
* Re-login window in milliseconds.
|
||||
*/
|
||||
private final long reLoginWindow = 60000;
|
||||
|
||||
/**
|
||||
* Login to servers.
|
||||
*
|
||||
* @return true if login successfully
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Boolean login(Properties properties) {
|
||||
try {
|
||||
boolean reLoginFlag = Boolean.parseBoolean(
|
||||
loginIdentityContext.getParameter(NacosAuthLoginConstant.RELOGINFLAG, "false"));
|
||||
if (reLoginFlag) {
|
||||
if ((System.currentTimeMillis() - lastRefreshTime) < reLoginWindow) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ((System.currentTimeMillis() - lastRefreshTime) < TimeUnit.SECONDS
|
||||
.toMillis(tokenTtl - tokenRefreshWindow)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(properties.getProperty(PropertyKeyConst.USERNAME))) {
|
||||
lastRefreshTime = System.currentTimeMillis();
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String server : this.serverList) {
|
||||
HttpLoginProcessor httpLoginProcessor = new HttpLoginProcessor(nacosRestTemplate);
|
||||
properties.setProperty(NacosAuthLoginConstant.SERVER, server);
|
||||
LoginIdentityContext identityContext = httpLoginProcessor.getResponse(properties);
|
||||
if (identityContext != null) {
|
||||
if (identityContext.getAllKey().contains(NacosAuthLoginConstant.ACCESSTOKEN)) {
|
||||
tokenTtl = Long.parseLong(
|
||||
identityContext.getParameter(NacosAuthLoginConstant.TOKENTTL));
|
||||
tokenRefreshWindow = generateTokenRefreshWindow(tokenTtl);
|
||||
lastRefreshTime = System.currentTimeMillis();
|
||||
|
||||
LoginIdentityContext newCtx = new LoginIdentityContext();
|
||||
newCtx.setParameter(NacosAuthLoginConstant.ACCESSTOKEN,
|
||||
identityContext.getParameter(NacosAuthLoginConstant.ACCESSTOKEN));
|
||||
this.loginIdentityContext = newCtx;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
SECURITY_LOGGER.warn("[SecurityProxy] login failed, error: ", throwable);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginIdentityContext getLoginIdentityContext(RequestResource resource) {
|
||||
return this.loginIdentityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly generate TokenRefreshWindow, Avoid a large number of logins causing pressure on the Nacos server.
|
||||
* @param tokenTtl TTL of token in seconds.
|
||||
* @return tokenRefreshWindow, numerical range [tokenTtl/15 ~ tokenTtl/10]
|
||||
*/
|
||||
public long generateTokenRefreshWindow(long tokenTtl) {
|
||||
long startNumber = tokenTtl / 15;
|
||||
long endNumber = tokenTtl / 10;
|
||||
return RandomUtils.nextLong(startNumber, endNumber);
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.impl.process;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.auth.impl.NacosAuthLoginConstant;
|
||||
import com.alibaba.nacos.client.utils.ClientBasicParamUtil;
|
||||
import com.alibaba.nacos.client.utils.ContextPathUtil;
|
||||
import com.alibaba.nacos.common.http.HttpRestResult;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.http.param.Header;
|
||||
import com.alibaba.nacos.common.http.param.Query;
|
||||
import com.alibaba.nacos.common.tls.TlsSystemConfig;
|
||||
import com.alibaba.nacos.common.utils.InternetAddressUtil;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static com.alibaba.nacos.common.constant.RequestUrlConstants.HTTPS_PREFIX;
|
||||
import static com.alibaba.nacos.common.constant.RequestUrlConstants.HTTP_PREFIX;
|
||||
|
||||
/**
|
||||
* Login processor for Http.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class HttpLoginProcessor implements LoginProcessor {
|
||||
|
||||
private static final Logger SECURITY_LOGGER = LoggerFactory.getLogger(HttpLoginProcessor.class);
|
||||
|
||||
private static final String LOGIN_V1_URL = "/v1/auth/users/login";
|
||||
|
||||
private static final String LOGIN_V3_URL = "/v3/auth/user/login";
|
||||
|
||||
public static final String DEFAULT_NACOS_WEB_CONTEXT = "/nacos";
|
||||
|
||||
private final NacosRestTemplate nacosRestTemplate;
|
||||
|
||||
public HttpLoginProcessor(NacosRestTemplate nacosRestTemplate) {
|
||||
this.nacosRestTemplate = nacosRestTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginIdentityContext getResponse(Properties properties) {
|
||||
|
||||
String contextPath = ContextPathUtil.normalizeContextPath(
|
||||
properties.getProperty(PropertyKeyConst.CONTEXT_PATH, DEFAULT_NACOS_WEB_CONTEXT));
|
||||
String server = properties.getProperty(NacosAuthLoginConstant.SERVER, StringUtils.EMPTY);
|
||||
|
||||
if (!server.startsWith(HTTPS_PREFIX) && !server.startsWith(HTTP_PREFIX)) {
|
||||
if (!InternetAddressUtil.containsPort(server)) {
|
||||
server = server + InternetAddressUtil.IP_PORT_SPLITER
|
||||
+ ClientBasicParamUtil.getDefaultServerPort();
|
||||
}
|
||||
server = getProtocolPrefix() + server;
|
||||
}
|
||||
|
||||
String url = server + contextPath + LOGIN_V3_URL;
|
||||
|
||||
Map<String, String> params = new HashMap<>(2);
|
||||
Map<String, String> bodyMap = new HashMap<>(2);
|
||||
params.put(PropertyKeyConst.USERNAME,
|
||||
properties.getProperty(PropertyKeyConst.USERNAME, StringUtils.EMPTY));
|
||||
bodyMap.put(PropertyKeyConst.PASSWORD,
|
||||
properties.getProperty(PropertyKeyConst.PASSWORD, StringUtils.EMPTY));
|
||||
try {
|
||||
HttpRestResult<String> restResult = nacosRestTemplate.postForm(url, Header.EMPTY,
|
||||
Query.newInstance().initParams(params), bodyMap, String.class);
|
||||
int code = restResult.getCode();
|
||||
if (code == NacosException.NOT_FOUND || code == NacosException.SERVER_NOT_IMPLEMENTED) {
|
||||
url = server + contextPath + LOGIN_V1_URL;
|
||||
restResult = nacosRestTemplate.postForm(url, Header.EMPTY,
|
||||
Query.newInstance().initParams(params),
|
||||
bodyMap, String.class);
|
||||
}
|
||||
if (!restResult.ok()) {
|
||||
SECURITY_LOGGER.error("login failed: {}", JacksonUtils.toJson(restResult));
|
||||
return null;
|
||||
}
|
||||
JsonNode obj = JacksonUtils.toObj(restResult.getData());
|
||||
|
||||
LoginIdentityContext loginIdentityContext = new LoginIdentityContext();
|
||||
|
||||
if (obj.has(Constants.ACCESS_TOKEN)) {
|
||||
loginIdentityContext.setParameter(NacosAuthLoginConstant.ACCESSTOKEN,
|
||||
obj.get(Constants.ACCESS_TOKEN).asText());
|
||||
loginIdentityContext.setParameter(NacosAuthLoginConstant.TOKENTTL,
|
||||
obj.get(Constants.TOKEN_TTL).asText());
|
||||
} else {
|
||||
SECURITY_LOGGER
|
||||
.info("[NacosClientAuthServiceImpl] ACCESS_TOKEN is empty from response");
|
||||
}
|
||||
return loginIdentityContext;
|
||||
} catch (Exception e) {
|
||||
Map<String, String> newBodyMap = new HashMap<>(bodyMap);
|
||||
newBodyMap.put(PropertyKeyConst.PASSWORD,
|
||||
ClientBasicParamUtil
|
||||
.desensitiseParameter(bodyMap.get(PropertyKeyConst.PASSWORD)));
|
||||
SECURITY_LOGGER.error("[NacosClientAuthServiceImpl] login http request failed"
|
||||
+ " url: {}, params: {}, bodyMap: {}, errorMsg: {}", url, params, newBodyMap,
|
||||
e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getProtocolPrefix() {
|
||||
return Boolean.getBoolean(TlsSystemConfig.TLS_ENABLE) ? HTTPS_PREFIX : HTTP_PREFIX;
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.impl.process;
|
||||
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Nacos login processor.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public interface LoginProcessor {
|
||||
|
||||
/**
|
||||
* send request to server and get result.
|
||||
*
|
||||
* @param properties request properties.
|
||||
* @return login identity context.
|
||||
*/
|
||||
LoginIdentityContext getResponse(Properties properties);
|
||||
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.oidc;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import com.alibaba.nacos.plugin.auth.constant.OidcProtocolConstants;
|
||||
import com.alibaba.nacos.plugin.auth.spi.client.AbstractClientAuthService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* OIDC Client Authentication Service implementation.
|
||||
*
|
||||
* <p>Implements the {@link AbstractClientAuthService} SPI to provide OIDC-based
|
||||
* authentication for Nacos clients. Uses the OAuth2 Client Credentials Grant
|
||||
* to obtain access tokens from the Identity Provider.
|
||||
*
|
||||
* <p>Flow:
|
||||
* <ol>
|
||||
* <li>{@link #login(Properties)} is called periodically by the framework</li>
|
||||
* <li>On first call with OIDC configured: performs OIDC Discovery and obtains access token</li>
|
||||
* <li>On subsequent calls: checks if token needs refresh and refreshes if needed</li>
|
||||
* <li>{@link #getLoginIdentityContext(RequestResource)} returns the context with accessToken</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author wangzji
|
||||
*/
|
||||
public class OidcClientAuthServiceImpl extends AbstractClientAuthService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OidcClientAuthServiceImpl.class);
|
||||
|
||||
private final Object refreshLock = new Object();
|
||||
|
||||
private volatile OidcClientContext context;
|
||||
|
||||
private volatile OidcTokenHolder tokenHolder;
|
||||
|
||||
private volatile LoginIdentityContext loginIdentityContext = new LoginIdentityContext();
|
||||
|
||||
/**
|
||||
* Whether OIDC has been determined to be unconfigured.
|
||||
* Once set to true, subsequent login() calls skip OIDC processing.
|
||||
*/
|
||||
private volatile boolean oidcNotConfigured = false;
|
||||
|
||||
@Override
|
||||
public Boolean login(Properties properties) {
|
||||
try {
|
||||
// Fast path: if OIDC is already known to be unconfigured, skip
|
||||
if (oidcNotConfigured) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 1: Initialize context on first call (double-check locking)
|
||||
if (context == null) {
|
||||
synchronized (refreshLock) {
|
||||
if (context == null) {
|
||||
OidcClientContext newContext = new OidcClientContext();
|
||||
boolean configured = newContext.init(properties);
|
||||
if (!configured) {
|
||||
oidcNotConfigured = true;
|
||||
LOGGER.debug(
|
||||
"[OIDC-CLIENT] OIDC not configured (missing client-id/client-secret), skipping");
|
||||
return true;
|
||||
}
|
||||
this.tokenHolder = new OidcTokenHolder();
|
||||
this.context = newContext;
|
||||
LOGGER.info("[OIDC-CLIENT] OIDC client configured, client-id: {}",
|
||||
context.getClientId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Perform OIDC Discovery if not yet done
|
||||
if (!context.isDiscovered()) {
|
||||
boolean discoveryResult = context.discover();
|
||||
if (!discoveryResult) {
|
||||
LOGGER.warn(
|
||||
"[OIDC-CLIENT] OIDC Discovery failed, will retry on next login cycle");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Fetch or refresh token if needed (double-check locking)
|
||||
if (tokenHolder.isExpiredOrNeedRefresh()) {
|
||||
synchronized (refreshLock) {
|
||||
if (tokenHolder.isExpiredOrNeedRefresh()) {
|
||||
boolean tokenResult = tokenHolder.fetchToken(context);
|
||||
if (!tokenResult) {
|
||||
LOGGER.warn(
|
||||
"[OIDC-CLIENT] Token fetch failed, will retry on next login cycle");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 4: Update LoginIdentityContext with new access token (dual header)
|
||||
LoginIdentityContext newCtx = new LoginIdentityContext();
|
||||
String token = tokenHolder.getAccessToken();
|
||||
newCtx.setParameter(OidcProtocolConstants.AUTHORIZATION_HEADER,
|
||||
OidcProtocolConstants.BEARER_PREFIX + token);
|
||||
newCtx.setParameter(OidcProtocolConstants.ACCESS_TOKEN_PARAM, token);
|
||||
this.loginIdentityContext = newCtx;
|
||||
|
||||
LOGGER.debug(
|
||||
"[OIDC-CLIENT] LoginIdentityContext updated with new access token");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Throwable throwable) {
|
||||
LOGGER.warn("[OIDC-CLIENT] login failed, error: ", throwable);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginIdentityContext getLoginIdentityContext(RequestResource resource) {
|
||||
return this.loginIdentityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
LOGGER.info("[OIDC-CLIENT] Shutting down OIDC client auth service");
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.oidc;
|
||||
|
||||
/**
|
||||
* Client-specific constants for OIDC client authentication.
|
||||
*
|
||||
* <p>Protocol-level constants (Discovery fields, OAuth2 parameters, HTTP headers, etc.)
|
||||
* are defined in {@link com.alibaba.nacos.plugin.auth.constant.OidcProtocolConstants}.
|
||||
*
|
||||
* @author wangzji
|
||||
*/
|
||||
public final class OidcClientConstants {
|
||||
|
||||
private OidcClientConstants() {
|
||||
}
|
||||
|
||||
// ----- Properties configuration keys (client-specific) -----
|
||||
|
||||
/**
|
||||
* OIDC Issuer URI, used for OIDC Discovery.
|
||||
*/
|
||||
public static final String PROP_ISSUER_URI = "nacos.client.auth.oidc.issuer-uri";
|
||||
|
||||
/**
|
||||
* OAuth2 Client ID for Client Credentials Grant.
|
||||
*/
|
||||
public static final String PROP_CLIENT_ID = "nacos.client.auth.oidc.client-id";
|
||||
|
||||
/**
|
||||
* OAuth2 Client Secret for Client Credentials Grant.
|
||||
*/
|
||||
public static final String PROP_CLIENT_SECRET = "nacos.client.auth.oidc.client-secret";
|
||||
|
||||
/**
|
||||
* OAuth2 scopes, defaults to "openid".
|
||||
*/
|
||||
public static final String PROP_SCOPE = "nacos.client.auth.oidc.scope";
|
||||
|
||||
/**
|
||||
* Token endpoint override. If set, OIDC Discovery is skipped.
|
||||
*/
|
||||
public static final String PROP_TOKEN_ENDPOINT = "nacos.client.auth.oidc.token-endpoint";
|
||||
|
||||
// ----- Default values -----
|
||||
|
||||
public static final String DEFAULT_SCOPE = "openid";
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.oidc;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.constant.OidcProtocolConstants;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* OIDC client context that holds configuration and performs OIDC Discovery.
|
||||
*
|
||||
* <p>Reads OIDC configuration from {@link Properties} and optionally performs
|
||||
* OIDC Discovery to resolve the token endpoint from the issuer's
|
||||
* {@code .well-known/openid-configuration}.
|
||||
*
|
||||
* @author wangzji
|
||||
*/
|
||||
public class OidcClientContext {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OidcClientContext.class);
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private String issuerUri;
|
||||
|
||||
private String clientId;
|
||||
|
||||
private String clientSecret;
|
||||
|
||||
private String scope;
|
||||
|
||||
private volatile String tokenEndpoint;
|
||||
|
||||
private volatile boolean discovered;
|
||||
|
||||
/**
|
||||
* Initialize context from properties.
|
||||
*
|
||||
* @param properties the client properties
|
||||
* @return true if OIDC is configured (client-id and client-secret are present)
|
||||
*/
|
||||
public boolean init(Properties properties) {
|
||||
this.issuerUri = properties.getProperty(OidcClientConstants.PROP_ISSUER_URI);
|
||||
this.clientId = properties.getProperty(OidcClientConstants.PROP_CLIENT_ID);
|
||||
this.clientSecret = properties.getProperty(OidcClientConstants.PROP_CLIENT_SECRET);
|
||||
this.scope = properties.getProperty(OidcClientConstants.PROP_SCOPE,
|
||||
OidcClientConstants.DEFAULT_SCOPE);
|
||||
|
||||
// Allow direct token endpoint override, skipping discovery
|
||||
String directTokenEndpoint =
|
||||
properties.getProperty(OidcClientConstants.PROP_TOKEN_ENDPOINT);
|
||||
if (StringUtils.isNotBlank(directTokenEndpoint)) {
|
||||
this.tokenEndpoint = directTokenEndpoint;
|
||||
this.discovered = true;
|
||||
}
|
||||
|
||||
return isConfigured();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if OIDC is configured with sufficient credentials.
|
||||
*
|
||||
* @return true if client-id, client-secret and (issuer-uri or token-endpoint) are present
|
||||
*/
|
||||
public boolean isConfigured() {
|
||||
return StringUtils.isNotBlank(clientId) && StringUtils.isNotBlank(clientSecret)
|
||||
&& (StringUtils.isNotBlank(issuerUri) || StringUtils.isNotBlank(tokenEndpoint));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform OIDC Discovery to retrieve the token endpoint.
|
||||
*
|
||||
* <p>Fetches {@code {issuer-uri}/.well-known/openid-configuration} and
|
||||
* extracts the {@code token_endpoint} field.
|
||||
*
|
||||
* @return true if discovery succeeds
|
||||
*/
|
||||
public boolean discover() {
|
||||
if (discovered) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(issuerUri)) {
|
||||
LOGGER.warn(
|
||||
"[OIDC-CLIENT] issuer-uri is not configured, cannot perform OIDC Discovery");
|
||||
return false;
|
||||
}
|
||||
|
||||
String discoveryUrl = issuerUri.endsWith("/")
|
||||
? issuerUri + ".well-known/openid-configuration"
|
||||
: issuerUri + OidcProtocolConstants.WELL_KNOWN_PATH;
|
||||
|
||||
LOGGER.info("[OIDC-CLIENT] Performing OIDC Discovery from: {}", discoveryUrl);
|
||||
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
connection = (HttpURLConnection) new URL(discoveryUrl).openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setConnectTimeout(OidcProtocolConstants.DEFAULT_CONNECT_TIMEOUT_MS);
|
||||
connection.setReadTimeout(OidcProtocolConstants.DEFAULT_READ_TIMEOUT_MS);
|
||||
connection.setRequestProperty("Accept", OidcProtocolConstants.CONTENT_TYPE_JSON);
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode != OidcProtocolConstants.HTTP_STATUS_OK) {
|
||||
LOGGER.error("[OIDC-CLIENT] OIDC Discovery failed, HTTP status: {}", responseCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
String responseBody;
|
||||
try (InputStream responseStream = connection.getInputStream()) {
|
||||
responseBody = readInputStreamAsString(responseStream);
|
||||
}
|
||||
|
||||
JsonNode root = OBJECT_MAPPER.readTree(responseBody);
|
||||
JsonNode tokenEndpointNode = root.get(OidcProtocolConstants.DISCOVERY_TOKEN_ENDPOINT);
|
||||
|
||||
if (tokenEndpointNode == null || tokenEndpointNode.isNull()) {
|
||||
LOGGER.error("[OIDC-CLIENT] OIDC Discovery response missing 'token_endpoint'");
|
||||
return false;
|
||||
}
|
||||
|
||||
this.tokenEndpoint = tokenEndpointNode.asText();
|
||||
this.discovered = true;
|
||||
LOGGER.info("[OIDC-CLIENT] OIDC Discovery success, token_endpoint: {}",
|
||||
this.tokenEndpoint);
|
||||
return true;
|
||||
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("[OIDC-CLIENT] OIDC Discovery failed", e);
|
||||
return false;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getIssuerUri() {
|
||||
return issuerUri;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public String getTokenEndpoint() {
|
||||
return tokenEndpoint;
|
||||
}
|
||||
|
||||
public boolean isDiscovered() {
|
||||
return discovered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an InputStream fully into a String (Java 8 compatible).
|
||||
*
|
||||
* @param inputStream the input stream to read
|
||||
* @return the string content
|
||||
* @throws IOException if reading fails
|
||||
*/
|
||||
static String readInputStreamAsString(InputStream inputStream) throws IOException {
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int length;
|
||||
while ((length = inputStream.read(buffer)) != -1) {
|
||||
result.write(buffer, 0, length);
|
||||
}
|
||||
return result.toString(StandardCharsets.UTF_8.name());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.oidc;
|
||||
|
||||
import com.alibaba.nacos.common.utils.RandomUtils;
|
||||
import com.alibaba.nacos.plugin.auth.constant.OidcProtocolConstants;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* Manages the OIDC Access Token lifecycle using the Client Credentials Grant.
|
||||
*
|
||||
* <p>Responsible for:
|
||||
* <ul>
|
||||
* <li>Fetching access tokens from the IdP token endpoint</li>
|
||||
* <li>Tracking token expiration</li>
|
||||
* <li>Determining when a proactive refresh is needed (within 6.7%-10% of expiry window)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author wangzji
|
||||
*/
|
||||
public class OidcTokenHolder {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OidcTokenHolder.class);
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private volatile String accessToken;
|
||||
|
||||
private volatile long expiresInSeconds;
|
||||
|
||||
private volatile long obtainedAtMs;
|
||||
|
||||
/**
|
||||
* Fetch a new access token using Client Credentials Grant.
|
||||
*
|
||||
* @param context the OIDC client context with configuration
|
||||
* @return true if the token was fetched successfully
|
||||
*/
|
||||
public boolean fetchToken(OidcClientContext context) {
|
||||
String tokenEndpoint = context.getTokenEndpoint();
|
||||
if (tokenEndpoint == null) {
|
||||
LOGGER.error("[OIDC-CLIENT] Token endpoint is not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGGER.debug("[OIDC-CLIENT] Requesting access token from: {}", tokenEndpoint);
|
||||
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
// Build form-encoded request body
|
||||
String requestBody = buildTokenRequestBody(context);
|
||||
|
||||
connection = (HttpURLConnection) new URL(tokenEndpoint).openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoOutput(true);
|
||||
connection.setConnectTimeout(OidcProtocolConstants.DEFAULT_CONNECT_TIMEOUT_MS);
|
||||
connection.setReadTimeout(OidcProtocolConstants.DEFAULT_READ_TIMEOUT_MS);
|
||||
connection.setRequestProperty("Content-Type", OidcProtocolConstants.CONTENT_TYPE_FORM);
|
||||
connection.setRequestProperty("Accept", OidcProtocolConstants.CONTENT_TYPE_JSON);
|
||||
|
||||
byte[] bodyBytes = requestBody.getBytes(StandardCharsets.UTF_8);
|
||||
connection.setRequestProperty("Content-Length", String.valueOf(bodyBytes.length));
|
||||
|
||||
try (OutputStream os = connection.getOutputStream()) {
|
||||
os.write(bodyBytes);
|
||||
os.flush();
|
||||
}
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode != OidcProtocolConstants.HTTP_STATUS_OK) {
|
||||
String errorBody = "";
|
||||
try (InputStream errorStream = connection.getErrorStream()) {
|
||||
if (errorStream != null) {
|
||||
errorBody = OidcClientContext.readInputStreamAsString(errorStream);
|
||||
}
|
||||
}
|
||||
LOGGER.error("[OIDC-CLIENT] Token request failed, HTTP status: {}, body: {}",
|
||||
responseCode, errorBody);
|
||||
return false;
|
||||
}
|
||||
|
||||
String responseBody;
|
||||
try (InputStream responseStream = connection.getInputStream()) {
|
||||
responseBody = OidcClientContext.readInputStreamAsString(responseStream);
|
||||
}
|
||||
|
||||
return parseTokenResponse(responseBody);
|
||||
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("[OIDC-CLIENT] Token request failed", e);
|
||||
return false;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the token response JSON and update internal state.
|
||||
*
|
||||
* @param responseBody the JSON response body
|
||||
* @return true if parsing succeeds
|
||||
*/
|
||||
private boolean parseTokenResponse(String responseBody) {
|
||||
try {
|
||||
JsonNode root = OBJECT_MAPPER.readTree(responseBody);
|
||||
|
||||
JsonNode accessTokenNode = root.get(OidcProtocolConstants.TOKEN_RESPONSE_ACCESS_TOKEN);
|
||||
if (accessTokenNode == null || accessTokenNode.isNull()) {
|
||||
LOGGER.error("[OIDC-CLIENT] Token response missing 'access_token'");
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonNode expiresInNode = root.get(OidcProtocolConstants.TOKEN_RESPONSE_EXPIRES_IN);
|
||||
long newExpiresIn = 300; // default 5 minutes if not provided
|
||||
if (expiresInNode != null && !expiresInNode.isNull()) {
|
||||
newExpiresIn = expiresInNode.asLong(300);
|
||||
}
|
||||
|
||||
this.accessToken = accessTokenNode.asText();
|
||||
this.expiresInSeconds = newExpiresIn;
|
||||
this.obtainedAtMs = System.currentTimeMillis();
|
||||
|
||||
LOGGER.info("[OIDC-CLIENT] Access token obtained successfully, expires_in: {}s",
|
||||
newExpiresIn);
|
||||
return true;
|
||||
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("[OIDC-CLIENT] Failed to parse token response", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the form-encoded request body for Client Credentials Grant.
|
||||
*
|
||||
* @param context the OIDC client context
|
||||
* @return the URL-encoded form body
|
||||
*/
|
||||
private String buildTokenRequestBody(OidcClientContext context) {
|
||||
try {
|
||||
String charsetName = StandardCharsets.UTF_8.name();
|
||||
StringJoiner joiner = new StringJoiner("&");
|
||||
joiner.add(OidcProtocolConstants.GRANT_TYPE + "="
|
||||
+ OidcProtocolConstants.GRANT_TYPE_CLIENT_CREDENTIALS);
|
||||
joiner.add(OidcProtocolConstants.PARAM_CLIENT_ID + "="
|
||||
+ URLEncoder.encode(context.getClientId(), charsetName));
|
||||
joiner.add(OidcProtocolConstants.PARAM_CLIENT_SECRET + "="
|
||||
+ URLEncoder.encode(context.getClientSecret(), charsetName));
|
||||
if (context.getScope() != null && !context.getScope().isEmpty()) {
|
||||
joiner.add(OidcProtocolConstants.PARAM_SCOPE + "="
|
||||
+ URLEncoder.encode(context.getScope(), charsetName));
|
||||
}
|
||||
return joiner.toString();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Should never happen since UTF-8 is always supported
|
||||
throw new IllegalStateException("UTF-8 encoding not supported", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the token is expired or needs proactive refresh.
|
||||
*
|
||||
* <p>Proactive refresh occurs within a random window of [tokenTtl/15, tokenTtl/10]
|
||||
* before expiration (i.e., approximately 6.7%-10% of the token TTL before expiry).
|
||||
* This is consistent with the refresh strategy used by {@code NacosClientAuthServiceImpl}.
|
||||
*
|
||||
* @return true if the token should be refreshed
|
||||
*/
|
||||
public boolean isExpiredOrNeedRefresh() {
|
||||
if (accessToken == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
long elapsedMs = System.currentTimeMillis() - obtainedAtMs;
|
||||
long elapsedSeconds = elapsedMs / 1000;
|
||||
long refreshWindow = generateTokenRefreshWindow(expiresInSeconds);
|
||||
|
||||
return elapsedSeconds >= (expiresInSeconds - refreshWindow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random refresh window, consistent with NacosClientAuthServiceImpl.
|
||||
*
|
||||
* @param tokenTtl the token TTL in seconds
|
||||
* @return the refresh window in seconds, range [tokenTtl/15, tokenTtl/10]
|
||||
*/
|
||||
long generateTokenRefreshWindow(long tokenTtl) {
|
||||
if (tokenTtl <= 0) {
|
||||
return 0;
|
||||
}
|
||||
long startNumber = tokenTtl / 15;
|
||||
long endNumber = tokenTtl / 10;
|
||||
if (startNumber >= endNumber) {
|
||||
return startNumber;
|
||||
}
|
||||
return RandomUtils.nextLong(startNumber, endNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current access token.
|
||||
*
|
||||
* @return the access token, or null if not yet obtained
|
||||
*/
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token TTL in seconds.
|
||||
*
|
||||
* @return expires_in value from the token response
|
||||
*/
|
||||
public long getExpiresInSeconds() {
|
||||
return expiresInSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp when the token was obtained.
|
||||
*
|
||||
* @return time in milliseconds
|
||||
*/
|
||||
public long getObtainedAtMs() {
|
||||
return obtainedAtMs;
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsConfig;
|
||||
import com.alibaba.nacos.client.auth.ram.injector.AbstractResourceInjector;
|
||||
import com.alibaba.nacos.client.auth.ram.injector.AiResourceInjector;
|
||||
import com.alibaba.nacos.client.auth.ram.injector.ConfigResourceInjector;
|
||||
import com.alibaba.nacos.client.auth.ram.injector.LockResourceInjector;
|
||||
import com.alibaba.nacos.client.auth.ram.injector.NamingResourceInjector;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.RamUtil;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.SpasAdapter;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import com.alibaba.nacos.plugin.auth.constant.SignType;
|
||||
import com.alibaba.nacos.plugin.auth.spi.client.AbstractClientAuthService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Client Auth service implementation for aliyun RAM.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class RamClientAuthServiceImpl extends AbstractClientAuthService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RamClientAuthServiceImpl.class);
|
||||
|
||||
private final RamContext ramContext;
|
||||
|
||||
private final Map<String, AbstractResourceInjector> resourceInjectors;
|
||||
|
||||
public RamClientAuthServiceImpl() {
|
||||
ramContext = new RamContext();
|
||||
resourceInjectors = new HashMap<>();
|
||||
resourceInjectors.put(SignType.NAMING, new NamingResourceInjector());
|
||||
resourceInjectors.put(SignType.CONFIG, new ConfigResourceInjector());
|
||||
resourceInjectors.put(SignType.LOCK, new LockResourceInjector());
|
||||
resourceInjectors.put(SignType.AI, new AiResourceInjector());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean login(Properties properties) {
|
||||
if (ramContext.validate()) {
|
||||
return true;
|
||||
}
|
||||
loadRoleName(properties);
|
||||
loadAccessKey(properties);
|
||||
loadSecretKey(properties);
|
||||
loadRegionId(properties);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void loadRoleName(Properties properties) {
|
||||
String ramRoleName = properties.getProperty(PropertyKeyConst.RAM_ROLE_NAME);
|
||||
if (!StringUtils.isBlank(ramRoleName)) {
|
||||
StsConfig.getInstance().setRamRoleName(ramRoleName);
|
||||
ramContext.setRamRoleName(ramRoleName);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadAccessKey(Properties properties) {
|
||||
ramContext.setAccessKey(RamUtil.getAccessKey(properties));
|
||||
}
|
||||
|
||||
private void loadSecretKey(Properties properties) {
|
||||
ramContext.setSecretKey(RamUtil.getSecretKey(properties));
|
||||
}
|
||||
|
||||
private void loadRegionId(Properties properties) {
|
||||
String regionId = properties.getProperty(PropertyKeyConst.SIGNATURE_REGION_ID);
|
||||
ramContext.setRegionId(regionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginIdentityContext getLoginIdentityContext(RequestResource resource) {
|
||||
LoginIdentityContext result = new LoginIdentityContext();
|
||||
if (!ramContext.validate() || notFountInjector(resource.getType())) {
|
||||
return result;
|
||||
}
|
||||
resourceInjectors.get(resource.getType()).doInject(resource, ramContext, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean notFountInjector(String type) {
|
||||
if (!resourceInjectors.containsKey(type)) {
|
||||
LOGGER.warn("Injector for type {} not found, will use default ram identity context.",
|
||||
type);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
SpasAdapter.freeCredentialInstance();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram;
|
||||
|
||||
/**
|
||||
* Ram auth plugin constants.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class RamConstants {
|
||||
|
||||
public static final String SIGNATURE_VERSION = "signatureVersion";
|
||||
|
||||
public static final String V4 = "v4";
|
||||
|
||||
public static final String SIGNATURE_V4_METHOD = "HmacSHA256";
|
||||
|
||||
public static final String SIGNATURE_V4_PRODUCE = "mse-nacos";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* Aliyun RAM context.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class RamContext {
|
||||
|
||||
private String accessKey;
|
||||
|
||||
private String secretKey;
|
||||
|
||||
private String ramRoleName;
|
||||
|
||||
private String regionId;
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getRamRoleName() {
|
||||
return ramRoleName;
|
||||
}
|
||||
|
||||
public void setRamRoleName(String ramRoleName) {
|
||||
this.ramRoleName = ramRoleName;
|
||||
}
|
||||
|
||||
public String getRegionId() {
|
||||
return regionId;
|
||||
}
|
||||
|
||||
public void setRegionId(String regionId) {
|
||||
this.regionId = regionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the RAM context.
|
||||
*
|
||||
* @return true if the context is valid
|
||||
*/
|
||||
public boolean validate() {
|
||||
return StringUtils.isNotBlank(ramRoleName)
|
||||
|| StringUtils.isNotBlank(accessKey) && StringUtils
|
||||
.isNotBlank(secretKey);
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
/**
|
||||
* Credential Listener.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public interface CredentialListener {
|
||||
|
||||
/**
|
||||
* update Credential.
|
||||
*/
|
||||
void onUpdateCredential();
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Credential Service.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public final class CredentialService implements SpasCredentialLoader {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CredentialService.class);
|
||||
|
||||
private static final ConcurrentHashMap<String, CredentialService> INSTANCES =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
private final String appName;
|
||||
|
||||
private Credentials credentials = new Credentials();
|
||||
|
||||
private final CredentialWatcher watcher;
|
||||
|
||||
private CredentialListener listener;
|
||||
|
||||
private CredentialService(String appName) {
|
||||
if (appName == null) {
|
||||
String value = NacosClientProperties.PROTOTYPE
|
||||
.getProperty(IdentifyConstants.PROJECT_NAME_PROPERTY);
|
||||
if (StringUtils.isNotEmpty(value)) {
|
||||
appName = value;
|
||||
}
|
||||
}
|
||||
this.appName = appName;
|
||||
watcher = new CredentialWatcher(appName, this);
|
||||
}
|
||||
|
||||
public static CredentialService getInstance() {
|
||||
return getInstance(null);
|
||||
}
|
||||
|
||||
public static CredentialService getInstance(String appName) {
|
||||
String key = appName != null ? appName : IdentifyConstants.NO_APP_NAME;
|
||||
return INSTANCES.computeIfAbsent(key, k -> new CredentialService(appName));
|
||||
}
|
||||
|
||||
public static CredentialService freeInstance() {
|
||||
return freeInstance(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free instance.
|
||||
*
|
||||
* @param appName app name
|
||||
* @return {@link CredentialService}
|
||||
*/
|
||||
public static CredentialService freeInstance(String appName) {
|
||||
String key = appName != null ? appName : IdentifyConstants.NO_APP_NAME;
|
||||
CredentialService instance = INSTANCES.remove(key);
|
||||
if (instance != null) {
|
||||
instance.free();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free service.
|
||||
*/
|
||||
public void free() {
|
||||
if (watcher != null) {
|
||||
watcher.stop();
|
||||
}
|
||||
LOGGER.info("[{}] {} is freed", appName, this.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credentials getCredential() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
public void setCredential(Credentials credential) {
|
||||
boolean changed = !(credentials == credential
|
||||
|| (credentials != null && credentials.identical(credential)));
|
||||
credentials = credential;
|
||||
if (changed && listener != null) {
|
||||
listener.onUpdateCredential();
|
||||
}
|
||||
}
|
||||
|
||||
public void setStaticCredential(Credentials credential) {
|
||||
if (watcher != null) {
|
||||
watcher.stop();
|
||||
}
|
||||
setCredential(credential);
|
||||
}
|
||||
|
||||
public void registerCredentialListener(CredentialListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
}
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.common.executor.ExecutorFactory;
|
||||
import com.alibaba.nacos.common.executor.NameThreadFactory;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Credential Watcher.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class CredentialWatcher {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CredentialWatcher.class);
|
||||
|
||||
private static final long REFRESH_INTERVAL = 10 * 1000L;
|
||||
|
||||
private final CredentialService serviceInstance;
|
||||
|
||||
private final String appName;
|
||||
|
||||
private String propertyPath;
|
||||
|
||||
private boolean stopped;
|
||||
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
public CredentialWatcher(String appName, CredentialService serviceInstance) {
|
||||
this.appName = appName;
|
||||
this.serviceInstance = serviceInstance;
|
||||
loadCredential(true);
|
||||
|
||||
executor = ExecutorFactory.newSingleScheduledExecutorService(
|
||||
new NameThreadFactory("com.alibaba.nacos.client.auth.ram.identify.watcher"));
|
||||
|
||||
executor.scheduleWithFixedDelay(new Runnable() {
|
||||
|
||||
private long modified = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (this) {
|
||||
if (stopped) {
|
||||
return;
|
||||
}
|
||||
boolean reload = false;
|
||||
if (propertyPath == null) {
|
||||
reload = true;
|
||||
} else {
|
||||
File file = new File(propertyPath);
|
||||
long lastModified = file.lastModified();
|
||||
if (modified != lastModified) {
|
||||
reload = true;
|
||||
modified = lastModified;
|
||||
}
|
||||
}
|
||||
if (reload) {
|
||||
loadCredential(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, REFRESH_INTERVAL, REFRESH_INTERVAL, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop watcher.
|
||||
*/
|
||||
public void stop() {
|
||||
if (stopped) {
|
||||
return;
|
||||
}
|
||||
if (executor != null) {
|
||||
synchronized (executor) {
|
||||
stopped = true;
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
LOGGER.info("[{}] {} is stopped", appName, this.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
private void loadCredential(boolean init) {
|
||||
loadPropertyPath(init);
|
||||
InputStream propertiesIs = loadPropertyPathToStream();
|
||||
Credentials credentials = new Credentials();
|
||||
boolean loadResult = Objects.isNull(propertiesIs) ? loadCredentialFromEnv(init, credentials)
|
||||
: loadCredentialFromProperties(propertiesIs, init, credentials);
|
||||
if (!loadResult) {
|
||||
return;
|
||||
}
|
||||
if (!credentials.valid()) {
|
||||
LOGGER
|
||||
.warn(
|
||||
"[1] Credential file missing required property {} Credential file missing {} or {}",
|
||||
appName,
|
||||
IdentifyConstants.ACCESS_KEY, IdentifyConstants.SECRET_KEY);
|
||||
propertyPath = null;
|
||||
// return;
|
||||
}
|
||||
serviceInstance.setCredential(credentials);
|
||||
}
|
||||
|
||||
private boolean loadCredentialFromProperties(InputStream propertiesIs, boolean init,
|
||||
Credentials credentials) {
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
properties.load(propertiesIs);
|
||||
} catch (IOException e) {
|
||||
LOGGER
|
||||
.error("[26] Unable to load credential file, appName:" + appName
|
||||
+ "Unable to load credential file "
|
||||
+ propertyPath, e);
|
||||
propertyPath = null;
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
propertiesIs.close();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("[27] Unable to close credential file, appName:" + appName
|
||||
+ "Unable to close credential file " + propertyPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (init) {
|
||||
LOGGER.info("[{}] Load credential file {}", appName, propertyPath);
|
||||
}
|
||||
|
||||
String accessKey = null;
|
||||
String secretKey = null;
|
||||
String tenantId = null;
|
||||
if (!IdentifyConstants.DOCKER_CREDENTIAL_PATH.equals(propertyPath)) {
|
||||
if (properties.containsKey(IdentifyConstants.ACCESS_KEY)) {
|
||||
accessKey = properties.getProperty(IdentifyConstants.ACCESS_KEY);
|
||||
}
|
||||
if (properties.containsKey(IdentifyConstants.SECRET_KEY)) {
|
||||
secretKey = properties.getProperty(IdentifyConstants.SECRET_KEY);
|
||||
}
|
||||
if (properties.containsKey(IdentifyConstants.TENANT_ID)) {
|
||||
tenantId = properties.getProperty(IdentifyConstants.TENANT_ID);
|
||||
}
|
||||
} else {
|
||||
if (properties.containsKey(IdentifyConstants.DOCKER_ACCESS_KEY)) {
|
||||
accessKey = properties.getProperty(IdentifyConstants.DOCKER_ACCESS_KEY);
|
||||
}
|
||||
if (properties.containsKey(IdentifyConstants.DOCKER_SECRET_KEY)) {
|
||||
secretKey = properties.getProperty(IdentifyConstants.DOCKER_SECRET_KEY);
|
||||
}
|
||||
|
||||
if (properties.containsKey(IdentifyConstants.DOCKER_TENANT_ID)) {
|
||||
tenantId = properties.getProperty(IdentifyConstants.DOCKER_TENANT_ID);
|
||||
}
|
||||
}
|
||||
setAccessKey(credentials, accessKey);
|
||||
setSecretKey(credentials, secretKey);
|
||||
setTenantId(credentials, tenantId);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean loadCredentialFromEnv(boolean init, Credentials credentials) {
|
||||
propertyPath = null;
|
||||
String accessKey =
|
||||
NacosClientProperties.PROTOTYPE.getProperty(IdentifyConstants.ENV_ACCESS_KEY);
|
||||
String secretKey =
|
||||
NacosClientProperties.PROTOTYPE.getProperty(IdentifyConstants.ENV_SECRET_KEY);
|
||||
if (accessKey == null && secretKey == null) {
|
||||
if (init) {
|
||||
LOGGER.info("{} No credential found", appName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
setAccessKey(credentials, accessKey);
|
||||
setSecretKey(credentials, secretKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void loadPropertyPath(boolean init) {
|
||||
if (propertyPath == null) {
|
||||
URL url = ClassLoader.getSystemResource(IdentifyConstants.PROPERTIES_FILENAME);
|
||||
if (url != null) {
|
||||
propertyPath = url.getPath();
|
||||
}
|
||||
if (propertyPath == null || propertyPath.isEmpty()) {
|
||||
|
||||
String value = NacosClientProperties.PROTOTYPE.getProperty("spas.identity");
|
||||
if (StringUtils.isNotEmpty(value)) {
|
||||
propertyPath = value;
|
||||
}
|
||||
if (propertyPath == null || propertyPath.isEmpty()) {
|
||||
propertyPath =
|
||||
IdentifyConstants.CREDENTIAL_PATH
|
||||
+ (appName == null ? IdentifyConstants.CREDENTIAL_DEFAULT
|
||||
: appName);
|
||||
} else {
|
||||
if (init) {
|
||||
LOGGER.info("[{}] Defined credential file: -Dspas.identity={}", appName,
|
||||
propertyPath);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (init) {
|
||||
LOGGER.info("[{}] Load credential file from classpath: {}", appName,
|
||||
IdentifyConstants.PROPERTIES_FILENAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream loadPropertyPathToStream() {
|
||||
InputStream propertiesIs = null;
|
||||
do {
|
||||
try {
|
||||
propertiesIs = new FileInputStream(propertyPath);
|
||||
} catch (FileNotFoundException e) {
|
||||
if (appName != null && !appName.equals(IdentifyConstants.CREDENTIAL_DEFAULT)
|
||||
&& propertyPath
|
||||
.equals(IdentifyConstants.CREDENTIAL_PATH + appName)) {
|
||||
propertyPath = IdentifyConstants.CREDENTIAL_PATH
|
||||
+ IdentifyConstants.CREDENTIAL_DEFAULT;
|
||||
continue;
|
||||
}
|
||||
if (!IdentifyConstants.DOCKER_CREDENTIAL_PATH.equals(propertyPath)) {
|
||||
propertyPath = IdentifyConstants.DOCKER_CREDENTIAL_PATH;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} while (true);
|
||||
return propertiesIs;
|
||||
}
|
||||
|
||||
private void setAccessKey(Credentials credentials, String accessKey) {
|
||||
if (!Objects.isNull(accessKey)) {
|
||||
credentials.setAccessKey(accessKey.trim());
|
||||
}
|
||||
}
|
||||
|
||||
private void setSecretKey(Credentials credentials, String secretKey) {
|
||||
if (!Objects.isNull(secretKey)) {
|
||||
credentials.setSecretKey(secretKey.trim());
|
||||
}
|
||||
}
|
||||
|
||||
private void setTenantId(Credentials credentials, String tenantId) {
|
||||
if (!Objects.isNull(tenantId)) {
|
||||
credentials.setTenantId(tenantId.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
/**
|
||||
* Credentials.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class Credentials implements SpasCredential {
|
||||
|
||||
private volatile String accessKey;
|
||||
|
||||
private volatile String secretKey;
|
||||
|
||||
private volatile String tenantId;
|
||||
|
||||
public Credentials() {
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
public Credentials(String accessKey, String secretKey, String tenantId) {
|
||||
this.accessKey = accessKey;
|
||||
this.secretKey = secretKey;
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getTenantId() {
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
public void setTenantId(String tenantId) {
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
|
||||
public boolean valid() {
|
||||
return accessKey != null && !accessKey.isEmpty() && secretKey != null
|
||||
&& !secretKey.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Identical.
|
||||
*
|
||||
* @param other other
|
||||
* @return true if identical
|
||||
*/
|
||||
public boolean identical(Credentials other) {
|
||||
return this == other || (other != null && (accessKey == null && other.accessKey == null
|
||||
|| accessKey != null && accessKey.equals(other.accessKey))
|
||||
&& (secretKey == null && other.secretKey == null || secretKey != null && secretKey
|
||||
.equals(other.secretKey)));
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
/**
|
||||
* Identify Constants.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class IdentifyConstants {
|
||||
|
||||
public static final String ACCESS_KEY = "accessKey";
|
||||
|
||||
public static final String SECRET_KEY = "secretKey";
|
||||
|
||||
public static final String SECURITY_TOKEN_HEADER = "Spas-SecurityToken";
|
||||
|
||||
public static final String TENANT_ID = "tenantId";
|
||||
|
||||
public static final String PROPERTIES_FILENAME = "spas.properties";
|
||||
|
||||
public static final String CREDENTIAL_PATH = "/home/admin/.spas_key/";
|
||||
|
||||
public static final String CREDENTIAL_DEFAULT = "default";
|
||||
|
||||
public static final String DOCKER_CREDENTIAL_PATH = "/etc/instanceInfo";
|
||||
|
||||
public static final String DOCKER_ACCESS_KEY = "env_spas_accessKey";
|
||||
|
||||
public static final String DOCKER_SECRET_KEY = "env_spas_secretKey";
|
||||
|
||||
public static final String DOCKER_TENANT_ID = "ebv_spas_tenantId";
|
||||
|
||||
public static final String ENV_ACCESS_KEY = "spas_accessKey";
|
||||
|
||||
public static final String ENV_SECRET_KEY = "spas_secretKey";
|
||||
|
||||
public static final String ENV_TENANT_ID = "tenant.id";
|
||||
|
||||
public static final String NO_APP_NAME = "";
|
||||
|
||||
public static final String PROJECT_NAME_PROPERTY = "project.name";
|
||||
|
||||
public static final String RAM_ROLE_NAME_PROPERTY = "ram.role.name";
|
||||
|
||||
public static final String REFRESH_TIME_PROPERTY = "time.to.refresh.in.millisecond";
|
||||
|
||||
public static final String SECURITY_PROPERTY = "security.credentials";
|
||||
|
||||
public static final String SECURITY_URL_PROPERTY = "security.credentials.url";
|
||||
|
||||
public static final String SECURITY_CACHE_PROPERTY = "cache.security.credentials";
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
/**
|
||||
* Spas Credential Interface.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public interface SpasCredential {
|
||||
|
||||
/**
|
||||
* get AccessKey.
|
||||
*
|
||||
* @return AccessKey
|
||||
*/
|
||||
String getAccessKey();
|
||||
|
||||
/**
|
||||
* get SecretKey.
|
||||
*
|
||||
* @return SecretKey
|
||||
*/
|
||||
String getSecretKey();
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
/**
|
||||
* Spas Credential Loader.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public interface SpasCredentialLoader {
|
||||
|
||||
/**
|
||||
* get Credential.
|
||||
*
|
||||
* @return Credential
|
||||
*/
|
||||
SpasCredential getCredential();
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* Sts config.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class StsConfig {
|
||||
|
||||
private static final String RAM_SECURITY_CREDENTIALS_URL =
|
||||
"http://100.100.100.200/latest/meta-data/ram/security-credentials/";
|
||||
|
||||
private String ramRoleName;
|
||||
|
||||
/**
|
||||
* The STS temporary certificate will be refreshed when the validity period of
|
||||
* the temporary certificate is left (allow the local time to be at most slower than the STS service time).
|
||||
*/
|
||||
private int timeToRefreshInMillisecond = 3 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* Metadata interface for obtaining STS temporary credentials (including role name).
|
||||
*/
|
||||
private String securityCredentialsUrl;
|
||||
|
||||
/**
|
||||
* Set the STS temporary certificate and no longer obtain it through the metadata interface.
|
||||
*/
|
||||
private String securityCredentials;
|
||||
|
||||
/**
|
||||
* Whether to cache.
|
||||
*/
|
||||
private boolean cacheSecurityCredentials = true;
|
||||
|
||||
private static class Singleton {
|
||||
|
||||
private static final StsConfig INSTANCE = new StsConfig();
|
||||
}
|
||||
|
||||
private StsConfig() {
|
||||
String ramRoleName = NacosClientProperties.PROTOTYPE
|
||||
.getProperty(IdentifyConstants.RAM_ROLE_NAME_PROPERTY);
|
||||
if (!StringUtils.isBlank(ramRoleName)) {
|
||||
setRamRoleName(ramRoleName);
|
||||
}
|
||||
|
||||
String timeToRefreshInMillisecond = NacosClientProperties.PROTOTYPE
|
||||
.getProperty(IdentifyConstants.REFRESH_TIME_PROPERTY);
|
||||
if (!StringUtils.isBlank(timeToRefreshInMillisecond)) {
|
||||
setTimeToRefreshInMillisecond(Integer.parseInt(timeToRefreshInMillisecond));
|
||||
}
|
||||
|
||||
String securityCredentials =
|
||||
NacosClientProperties.PROTOTYPE.getProperty(IdentifyConstants.SECURITY_PROPERTY);
|
||||
if (!StringUtils.isBlank(securityCredentials)) {
|
||||
setSecurityCredentials(securityCredentials);
|
||||
}
|
||||
|
||||
String securityCredentialsUrl = NacosClientProperties.PROTOTYPE
|
||||
.getProperty(IdentifyConstants.SECURITY_URL_PROPERTY);
|
||||
if (!StringUtils.isBlank(securityCredentialsUrl)) {
|
||||
setSecurityCredentialsUrl(securityCredentialsUrl);
|
||||
}
|
||||
|
||||
String cacheSecurityCredentials = NacosClientProperties.PROTOTYPE
|
||||
.getProperty(IdentifyConstants.SECURITY_CACHE_PROPERTY);
|
||||
if (!StringUtils.isBlank(cacheSecurityCredentials)) {
|
||||
setCacheSecurityCredentials(Boolean.parseBoolean(cacheSecurityCredentials));
|
||||
}
|
||||
}
|
||||
|
||||
public static StsConfig getInstance() {
|
||||
return Singleton.INSTANCE;
|
||||
}
|
||||
|
||||
public String getRamRoleName() {
|
||||
return ramRoleName;
|
||||
}
|
||||
|
||||
public void setRamRoleName(String ramRoleName) {
|
||||
this.ramRoleName = ramRoleName;
|
||||
}
|
||||
|
||||
public int getTimeToRefreshInMillisecond() {
|
||||
return timeToRefreshInMillisecond;
|
||||
}
|
||||
|
||||
public void setTimeToRefreshInMillisecond(int timeToRefreshInMillisecond) {
|
||||
this.timeToRefreshInMillisecond = timeToRefreshInMillisecond;
|
||||
}
|
||||
|
||||
public String getSecurityCredentialsUrl() {
|
||||
if (securityCredentialsUrl == null && ramRoleName != null) {
|
||||
return RAM_SECURITY_CREDENTIALS_URL + ramRoleName;
|
||||
}
|
||||
return securityCredentialsUrl;
|
||||
}
|
||||
|
||||
public void setSecurityCredentialsUrl(String securityCredentialsUrl) {
|
||||
this.securityCredentialsUrl = securityCredentialsUrl;
|
||||
}
|
||||
|
||||
public String getSecurityCredentials() {
|
||||
return securityCredentials;
|
||||
}
|
||||
|
||||
public void setSecurityCredentials(String securityCredentials) {
|
||||
this.securityCredentials = securityCredentials;
|
||||
}
|
||||
|
||||
public boolean isStsOn() {
|
||||
return StringUtils.isNotEmpty(getSecurityCredentials())
|
||||
|| StringUtils.isNotEmpty(getSecurityCredentialsUrl());
|
||||
}
|
||||
|
||||
public boolean isCacheSecurityCredentials() {
|
||||
return cacheSecurityCredentials;
|
||||
}
|
||||
|
||||
public void setCacheSecurityCredentials(boolean cacheSecurityCredentials) {
|
||||
this.cacheSecurityCredentials = cacheSecurityCredentials;
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Sts credential for aliyun RAM.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class StsCredential {
|
||||
|
||||
@JsonProperty(value = "AccessKeyId")
|
||||
private String accessKeyId;
|
||||
|
||||
@JsonProperty(value = "AccessKeySecret")
|
||||
private String accessKeySecret;
|
||||
|
||||
@JsonProperty(value = "Expiration")
|
||||
private Date expiration;
|
||||
|
||||
@JsonProperty(value = "SecurityToken")
|
||||
private String securityToken;
|
||||
|
||||
@JsonProperty(value = "LastUpdated")
|
||||
private Date lastUpdated;
|
||||
|
||||
@JsonProperty(value = "Code")
|
||||
private String code;
|
||||
|
||||
public String getAccessKeyId() {
|
||||
return accessKeyId;
|
||||
}
|
||||
|
||||
public void setAccessKeyId(String accessKeyId) {
|
||||
this.accessKeyId = accessKeyId;
|
||||
}
|
||||
|
||||
public String getAccessKeySecret() {
|
||||
return accessKeySecret;
|
||||
}
|
||||
|
||||
public void setAccessKeySecret(String accessKeySecret) {
|
||||
this.accessKeySecret = accessKeySecret;
|
||||
}
|
||||
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Date expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
public String getSecurityToken() {
|
||||
return securityToken;
|
||||
}
|
||||
|
||||
public void setSecurityToken(String securityToken) {
|
||||
this.securityToken = securityToken;
|
||||
}
|
||||
|
||||
public Date getLastUpdated() {
|
||||
return lastUpdated;
|
||||
}
|
||||
|
||||
public void setLastUpdated(Date lastUpdated) {
|
||||
this.lastUpdated = lastUpdated;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "STSCredential{" + "accessKeyId='" + accessKeyId + '\'' + ", accessKeySecret='"
|
||||
+ accessKeySecret
|
||||
+ '\'' + ", expiration=" + expiration + ", securityToken='" + securityToken + '\''
|
||||
+ ", lastUpdated=" + lastUpdated + ", code='" + code + '\'' + '}';
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
|
||||
import com.alibaba.nacos.client.remote.HttpClientManager;
|
||||
import com.alibaba.nacos.common.http.HttpRestResult;
|
||||
import com.alibaba.nacos.common.http.param.Header;
|
||||
import com.alibaba.nacos.common.http.param.Query;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Sts credential holder.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class StsCredentialHolder {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(StsCredentialHolder.class);
|
||||
|
||||
private static final StsCredentialHolder INSTANCE = new StsCredentialHolder();
|
||||
|
||||
private StsCredential stsCredential;
|
||||
|
||||
private StsCredentialHolder() {
|
||||
}
|
||||
|
||||
public static StsCredentialHolder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Sts Credential.
|
||||
*
|
||||
* @return StsCredential
|
||||
*/
|
||||
public StsCredential getStsCredential() {
|
||||
boolean cacheSecurityCredentials = StsConfig.getInstance().isCacheSecurityCredentials();
|
||||
if (cacheSecurityCredentials && stsCredential != null) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long expirationTime = stsCredential.getExpiration().getTime();
|
||||
int timeToRefreshInMillisecond =
|
||||
StsConfig.getInstance().getTimeToRefreshInMillisecond();
|
||||
if (expirationTime - currentTime > timeToRefreshInMillisecond) {
|
||||
return stsCredential;
|
||||
}
|
||||
}
|
||||
String stsResponse = getStsResponse();
|
||||
stsCredential = JacksonUtils.toObj(stsResponse, new TypeReference<StsCredential>() {
|
||||
});
|
||||
LOGGER.info("[getSTSCredential] code:{}, accessKeyId:{}, lastUpdated:{}, expiration:{}",
|
||||
stsCredential.getCode(), stsCredential.getAccessKeyId(),
|
||||
stsCredential.getLastUpdated(),
|
||||
stsCredential.getExpiration());
|
||||
return stsCredential;
|
||||
}
|
||||
|
||||
private static String getStsResponse() {
|
||||
String securityCredentials = StsConfig.getInstance().getSecurityCredentials();
|
||||
if (securityCredentials != null) {
|
||||
return securityCredentials;
|
||||
}
|
||||
String securityCredentialsUrl = StsConfig.getInstance().getSecurityCredentialsUrl();
|
||||
try {
|
||||
HttpRestResult<String> result = HttpClientManager.getInstance().getNacosRestTemplate()
|
||||
.get(securityCredentialsUrl, Header.EMPTY, Query.EMPTY, String.class);
|
||||
|
||||
if (!result.ok()) {
|
||||
LOGGER.error(
|
||||
"can not get security credentials, securityCredentialsUrl: {}, responseCode: {}, response: {}",
|
||||
securityCredentialsUrl, result.getCode(), result.getMessage());
|
||||
throw new NacosRuntimeException(NacosException.SERVER_ERROR,
|
||||
"can not get security credentials, responseCode: " + result.getCode()
|
||||
+ ", response: " + result
|
||||
.getMessage());
|
||||
}
|
||||
return result.getData();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("can not get security credentials", e);
|
||||
throw new NacosRuntimeException(NacosException.SERVER_ERROR, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
|
||||
/**
|
||||
* Abstract aliyun RAM resource injector.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public abstract class AbstractResourceInjector {
|
||||
|
||||
/**
|
||||
* Generate and inject resource into context. Default impl will do nothing.
|
||||
*
|
||||
* @param resource request resource
|
||||
* @param context ram context
|
||||
* @param result the result identity context
|
||||
*/
|
||||
public void doInject(RequestResource resource, RamContext context,
|
||||
LoginIdentityContext result) {
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 1999-2025 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import com.alibaba.nacos.client.auth.ram.RamConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.IdentifyConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsConfig;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredential;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredentialHolder;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.CalculateV4SigningKeyUtil;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.SpasAdapter;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AI module aliyun ram reousce injector.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class AiResourceInjector extends AbstractResourceInjector {
|
||||
|
||||
private static final String ACCESS_KEY_HEADER = "Spas-AccessKey";
|
||||
|
||||
@Override
|
||||
public void doInject(RequestResource resource, RamContext context,
|
||||
LoginIdentityContext result) {
|
||||
if (!context.validate()) {
|
||||
return;
|
||||
}
|
||||
String accessKey = context.getAccessKey();
|
||||
String secretKey = context.getSecretKey();
|
||||
if (StsConfig.getInstance().isStsOn()) {
|
||||
StsCredential stsCredential = StsCredentialHolder.getInstance().getStsCredential();
|
||||
accessKey = stsCredential.getAccessKeyId();
|
||||
secretKey = stsCredential.getAccessKeySecret();
|
||||
result.setParameter(IdentifyConstants.SECURITY_TOKEN_HEADER,
|
||||
stsCredential.getSecurityToken());
|
||||
}
|
||||
result.setParameter(ACCESS_KEY_HEADER, accessKey);
|
||||
String signatureKey = secretKey;
|
||||
if (StringUtils.isNotEmpty(context.getRegionId())) {
|
||||
signatureKey = CalculateV4SigningKeyUtil.finalSigningKeyStringWithDefaultInfo(secretKey,
|
||||
context.getRegionId());
|
||||
result.setParameter(RamConstants.SIGNATURE_VERSION, RamConstants.V4);
|
||||
}
|
||||
Map<String, String> signHeaders =
|
||||
SpasAdapter.getSignHeaders(buildResourceString(resource), signatureKey);
|
||||
result.setParameters(signHeaders);
|
||||
}
|
||||
|
||||
private String buildResourceString(RequestResource resource) {
|
||||
return resource.getNamespace() + "+" + resource.getGroup();
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import com.alibaba.nacos.client.auth.ram.RamConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.IdentifyConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsConfig;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredential;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredentialHolder;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.CalculateV4SigningKeyUtil;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.SpasAdapter;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Resource Injector for naming module.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class ConfigResourceInjector extends AbstractResourceInjector {
|
||||
|
||||
private static final String ACCESS_KEY_HEADER = "Spas-AccessKey";
|
||||
|
||||
private static final String DEFAULT_RESOURCE = "";
|
||||
|
||||
@Override
|
||||
public void doInject(RequestResource resource, RamContext context,
|
||||
LoginIdentityContext result) {
|
||||
String accessKey = context.getAccessKey();
|
||||
String secretKey = context.getSecretKey();
|
||||
// STS 临时凭证鉴权的优先级高于 AK/SK 鉴权
|
||||
if (StsConfig.getInstance().isStsOn()) {
|
||||
StsCredential stsCredential = StsCredentialHolder.getInstance().getStsCredential();
|
||||
accessKey = stsCredential.getAccessKeyId();
|
||||
secretKey = stsCredential.getAccessKeySecret();
|
||||
result.setParameter(IdentifyConstants.SECURITY_TOKEN_HEADER,
|
||||
stsCredential.getSecurityToken());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(accessKey) && StringUtils.isNotBlank(secretKey)) {
|
||||
result.setParameter(ACCESS_KEY_HEADER, accessKey);
|
||||
}
|
||||
String signatureKey = secretKey;
|
||||
if (StringUtils.isNotEmpty(context.getRegionId())) {
|
||||
signatureKey = CalculateV4SigningKeyUtil
|
||||
.finalSigningKeyStringWithDefaultInfo(secretKey, context.getRegionId());
|
||||
result.setParameter(RamConstants.SIGNATURE_VERSION, RamConstants.V4);
|
||||
}
|
||||
Map<String, String> signHeaders = SpasAdapter
|
||||
.getSignHeaders(getResource(resource.getNamespace(), resource.getGroup()),
|
||||
signatureKey);
|
||||
result.setParameters(signHeaders);
|
||||
}
|
||||
|
||||
private String getResource(String tenant, String group) {
|
||||
if (StringUtils.isBlank(tenant)) {
|
||||
if (StringUtils.isBlank(group)) {
|
||||
return DEFAULT_RESOURCE;
|
||||
} else {
|
||||
return group;
|
||||
}
|
||||
} else {
|
||||
return tenant + "+" + group;
|
||||
}
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.IdentifyConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsConfig;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredential;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredentialHolder;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
|
||||
/**
|
||||
* lock resource injector.
|
||||
*
|
||||
* @author 985492783@qq.com
|
||||
* @date 2023/9/17 1:10
|
||||
*/
|
||||
public class LockResourceInjector extends AbstractResourceInjector {
|
||||
|
||||
private static final String AK_FIELD = "ak";
|
||||
|
||||
@Override
|
||||
public void doInject(RequestResource resource, RamContext context,
|
||||
LoginIdentityContext result) {
|
||||
String accessKey = context.getAccessKey();
|
||||
String secretKey = context.getSecretKey();
|
||||
// STS 临时凭证鉴权的优先级高于 AK/SK 鉴权
|
||||
if (StsConfig.getInstance().isStsOn()) {
|
||||
StsCredential stsCredential = StsCredentialHolder.getInstance().getStsCredential();
|
||||
accessKey = stsCredential.getAccessKeyId();
|
||||
secretKey = stsCredential.getAccessKeySecret();
|
||||
result.setParameter(IdentifyConstants.SECURITY_TOKEN_HEADER,
|
||||
stsCredential.getSecurityToken());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(accessKey) && StringUtils.isNotBlank(secretKey)) {
|
||||
result.setParameter(AK_FIELD, accessKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
||||
import com.alibaba.nacos.client.auth.ram.RamConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.IdentifyConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsConfig;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredential;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredentialHolder;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.CalculateV4SigningKeyUtil;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.SignUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Resource Injector for naming module.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class NamingResourceInjector extends AbstractResourceInjector {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(NamingResourceInjector.class);
|
||||
|
||||
private static final String SIGNATURE_FILED = "signature";
|
||||
|
||||
private static final String DATA_FILED = "data";
|
||||
|
||||
private static final String AK_FILED = "ak";
|
||||
|
||||
@Override
|
||||
public void doInject(RequestResource resource, RamContext context,
|
||||
LoginIdentityContext result) {
|
||||
if (context.validate()) {
|
||||
try {
|
||||
String accessKey = context.getAccessKey();
|
||||
String secretKey = context.getSecretKey();
|
||||
// STS 临时凭证鉴权的优先级高于 AK/SK 鉴权
|
||||
if (StsConfig.getInstance().isStsOn()) {
|
||||
StsCredential stsCredential =
|
||||
StsCredentialHolder.getInstance().getStsCredential();
|
||||
accessKey = stsCredential.getAccessKeyId();
|
||||
secretKey = stsCredential.getAccessKeySecret();
|
||||
result.setParameter(IdentifyConstants.SECURITY_TOKEN_HEADER,
|
||||
stsCredential.getSecurityToken());
|
||||
}
|
||||
String signatureKey = secretKey;
|
||||
if (StringUtils.isNotEmpty(context.getRegionId())) {
|
||||
signatureKey = CalculateV4SigningKeyUtil
|
||||
.finalSigningKeyStringWithDefaultInfo(secretKey, context.getRegionId());
|
||||
result.setParameter(RamConstants.SIGNATURE_VERSION, RamConstants.V4);
|
||||
}
|
||||
String signData = getSignData(getGroupedServiceName(resource));
|
||||
String signature = SignUtil.sign(signData, signatureKey);
|
||||
result.setParameter(SIGNATURE_FILED, signature);
|
||||
result.setParameter(DATA_FILED, signData);
|
||||
result.setParameter(AK_FILED, accessKey);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("inject ak/sk failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getGroupedServiceName(RequestResource resource) {
|
||||
if (resource.getResource().contains(Constants.SERVICE_INFO_SPLITER) || StringUtils
|
||||
.isBlank(resource.getGroup())) {
|
||||
return resource.getResource();
|
||||
}
|
||||
return NamingUtils.getGroupedNameOptional(resource.getResource(), resource.getGroup());
|
||||
}
|
||||
|
||||
private String getSignData(String serviceName) {
|
||||
return StringUtils.isNotEmpty(serviceName)
|
||||
? System.currentTimeMillis() + Constants.SERVICE_INFO_SPLITER
|
||||
+ serviceName
|
||||
: String.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.utils;
|
||||
|
||||
import com.alibaba.nacos.client.auth.ram.RamConstants;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* CalculateV4SigningKeyUtil.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class CalculateV4SigningKeyUtil {
|
||||
|
||||
private static final String PREFIX = "aliyun_v4";
|
||||
|
||||
private static final String CONSTANT = "aliyun_v4_request";
|
||||
|
||||
private static final DateTimeFormatter V4_SIGN_DATE_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private static final ZoneId UTC_0 = ZoneId.of("GMT+00:00");
|
||||
|
||||
private static byte[] firstSigningKey(String secret, String date, String signMethod)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
Mac mac = Mac.getInstance(signMethod);
|
||||
mac.init(new SecretKeySpec((PREFIX + secret).getBytes(StandardCharsets.UTF_8), signMethod));
|
||||
return mac.doFinal(date.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private static byte[] regionSigningKey(String secret, String date, String region,
|
||||
String signMethod)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
byte[] firstSignkey = firstSigningKey(secret, date, signMethod);
|
||||
Mac mac = Mac.getInstance(signMethod);
|
||||
mac.init(new SecretKeySpec(firstSignkey, signMethod));
|
||||
return mac.doFinal(region.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private static byte[] finalSigningKey(String secret, String date, String region,
|
||||
String productCode,
|
||||
String signMethod) {
|
||||
try {
|
||||
byte[] secondSignkey = regionSigningKey(secret, date, region, signMethod);
|
||||
Mac mac = Mac.getInstance(signMethod);
|
||||
mac.init(new SecretKeySpec(secondSignkey, signMethod));
|
||||
byte[] thirdSigningKey = mac.doFinal(productCode.getBytes(StandardCharsets.UTF_8));
|
||||
// 计算最终派生秘钥
|
||||
mac = Mac.getInstance(signMethod);
|
||||
mac.init(new SecretKeySpec(thirdSigningKey, signMethod));
|
||||
return mac.doFinal(CONSTANT.getBytes(StandardCharsets.UTF_8));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("unsupported Algorithm:" + signMethod);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new RuntimeException("InvalidKey");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return V4 signature key with base64 encode.
|
||||
*
|
||||
* @param secret secret key
|
||||
* @param date date with utc format, like 20211222
|
||||
* @param region region id
|
||||
* @param productCode cloud product code
|
||||
* @param signMethod sign method
|
||||
* @return V4 signature key with base64 encode
|
||||
*/
|
||||
public static String finalSigningKeyString(String secret, String date, String region,
|
||||
String productCode,
|
||||
String signMethod) {
|
||||
return Base64.getEncoder()
|
||||
.encodeToString(finalSigningKey(secret, date, region, productCode, signMethod));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return V4 signature key with base64 encode for some default information.
|
||||
*
|
||||
* <li>
|
||||
* <ul>date = current date</ul>
|
||||
* <ul>produceCode = mse</ul>
|
||||
* <ul>signMethod = HMAC-SHA256</ul>
|
||||
* </li>
|
||||
*
|
||||
* @param secret secret key
|
||||
* @param region region id
|
||||
* @return V4 signature key with base64 encode
|
||||
*/
|
||||
public static String finalSigningKeyStringWithDefaultInfo(String secret, String region) {
|
||||
String signDate = LocalDateTime.now(UTC_0).format(V4_SIGN_DATE_FORMATTER);
|
||||
return finalSigningKeyString(secret, signDate, region, RamConstants.SIGNATURE_V4_PRODUCE,
|
||||
RamConstants.SIGNATURE_V4_METHOD);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.utils;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.SystemPropertyKeyConst;
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Util to get ram info, such as AK, SK and RAM role.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class RamUtil {
|
||||
|
||||
public static String getAccessKey(Properties properties) {
|
||||
boolean isUseRamInfoParsing = Boolean.parseBoolean(properties
|
||||
.getProperty(PropertyKeyConst.IS_USE_RAM_INFO_PARSING,
|
||||
System.getProperty(SystemPropertyKeyConst.IS_USE_RAM_INFO_PARSING,
|
||||
Constants.DEFAULT_USE_RAM_INFO_PARSING)));
|
||||
|
||||
String result = properties.getProperty(PropertyKeyConst.ACCESS_KEY);
|
||||
if (isUseRamInfoParsing && StringUtils.isBlank(result)) {
|
||||
result = SpasAdapter.getAk();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getSecretKey(Properties properties) {
|
||||
boolean isUseRamInfoParsing = Boolean.parseBoolean(properties
|
||||
.getProperty(PropertyKeyConst.IS_USE_RAM_INFO_PARSING,
|
||||
System.getProperty(SystemPropertyKeyConst.IS_USE_RAM_INFO_PARSING,
|
||||
Constants.DEFAULT_USE_RAM_INFO_PARSING)));
|
||||
|
||||
String result = properties.getProperty(PropertyKeyConst.SECRET_KEY);
|
||||
if (isUseRamInfoParsing && StringUtils.isBlank(result)) {
|
||||
result = SpasAdapter.getSk();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.utils;
|
||||
|
||||
import com.alibaba.nacos.common.codec.Base64;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Sign util.
|
||||
*
|
||||
* @author pbting
|
||||
* @date 2019-01-22 10:20 PM
|
||||
*/
|
||||
public class SignUtil {
|
||||
|
||||
private static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Sign.
|
||||
*
|
||||
* @param data data
|
||||
* @param key key
|
||||
* @return signature
|
||||
* @throws Exception exception
|
||||
*/
|
||||
public static String sign(String data, String key) throws Exception {
|
||||
try {
|
||||
byte[] signature = sign(data.getBytes(UTF8), key.getBytes(UTF8),
|
||||
SignUtil.SigningAlgorithm.HmacSHA1);
|
||||
return new String(Base64.encodeBase64(signature), UTF8);
|
||||
} catch (Exception ex) {
|
||||
throw new Exception("Unable to calculate a request signature: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] sign(byte[] data, byte[] key, SignUtil.SigningAlgorithm algorithm)
|
||||
throws Exception {
|
||||
try {
|
||||
Mac mac = Mac.getInstance(algorithm.toString());
|
||||
mac.init(new SecretKeySpec(key, algorithm.toString()));
|
||||
return mac.doFinal(data);
|
||||
} catch (Exception ex) {
|
||||
throw new Exception("Unable to calculate a request signature: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public enum SigningAlgorithm {
|
||||
|
||||
// Hmac SHA1 algorithm
|
||||
HmacSHA1;
|
||||
|
||||
SigningAlgorithm() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.utils;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.CredentialService;
|
||||
import com.alibaba.nacos.common.codec.Base64;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* adapt spas interface.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class SpasAdapter {
|
||||
|
||||
private static final String TIMESTAMP_HEADER = "Timestamp";
|
||||
|
||||
private static final String SIGNATURE_HEADER = "Spas-Signature";
|
||||
|
||||
private static final String GROUP_KEY = "group";
|
||||
|
||||
public static final String TENANT_KEY = "tenant";
|
||||
|
||||
private static final String SHA_ENCRYPT = "HmacSHA1";
|
||||
|
||||
public static Map<String, String> getSignHeaders(String resource, String secretKey) {
|
||||
Map<String, String> header = new HashMap<>(2);
|
||||
String timeStamp = String.valueOf(System.currentTimeMillis());
|
||||
header.put(TIMESTAMP_HEADER, timeStamp);
|
||||
if (secretKey != null) {
|
||||
String signature;
|
||||
if (StringUtils.isBlank(resource)) {
|
||||
signature = signWithHmacSha1Encrypt(timeStamp, secretKey);
|
||||
} else {
|
||||
signature = signWithHmacSha1Encrypt(resource + "+" + timeStamp, secretKey);
|
||||
}
|
||||
header.put(SIGNATURE_HEADER, signature);
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
public static Map<String, String> getSignHeaders(String groupKey, String tenant,
|
||||
String secretKey) {
|
||||
if (StringUtils.isBlank(groupKey) && StringUtils.isBlank(tenant)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String resource = "";
|
||||
if (StringUtils.isNotBlank(groupKey) && StringUtils.isNotBlank(tenant)) {
|
||||
resource = tenant + "+" + groupKey;
|
||||
} else {
|
||||
if (!StringUtils.isBlank(groupKey)) {
|
||||
resource = groupKey;
|
||||
}
|
||||
}
|
||||
return getSignHeaders(resource, secretKey);
|
||||
}
|
||||
|
||||
public static Map<String, String> getSignHeaders(Map<String, String> paramValues,
|
||||
String secretKey) {
|
||||
if (null == paramValues) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String resource = "";
|
||||
if (paramValues.containsKey(TENANT_KEY) && paramValues.containsKey(GROUP_KEY)) {
|
||||
resource = paramValues.get(TENANT_KEY) + "+" + paramValues.get(GROUP_KEY);
|
||||
} else {
|
||||
if (!StringUtils.isBlank(paramValues.get(GROUP_KEY))) {
|
||||
resource = paramValues.get(GROUP_KEY);
|
||||
}
|
||||
}
|
||||
return getSignHeaders(resource, secretKey);
|
||||
}
|
||||
|
||||
public static String getSk() {
|
||||
return CredentialService.getInstance().getCredential().getSecretKey();
|
||||
}
|
||||
|
||||
public static String getAk() {
|
||||
return CredentialService.getInstance().getCredential().getAccessKey();
|
||||
}
|
||||
|
||||
public static void freeCredentialInstance() {
|
||||
CredentialService.freeInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign with hmac SHA1 encrtpt.
|
||||
*
|
||||
* @param encryptText encrypt text
|
||||
* @param encryptKey encrypt key
|
||||
* @return base64 string
|
||||
*/
|
||||
public static String signWithHmacSha1Encrypt(String encryptText, String encryptKey) {
|
||||
try {
|
||||
byte[] data = encryptKey.getBytes(Constants.ENCODE);
|
||||
// Construct a key according to the given byte array, and the second parameter specifies the name of a key algorithm
|
||||
SecretKey secretKey = new SecretKeySpec(data, SHA_ENCRYPT);
|
||||
// Generate a Mac object specifying Mac algorithm
|
||||
Mac mac = Mac.getInstance(SHA_ENCRYPT);
|
||||
// Initialize the Mac object with the given key
|
||||
mac.init(secretKey);
|
||||
byte[] text = encryptText.getBytes(Constants.ENCODE);
|
||||
byte[] textFinal = mac.doFinal(text);
|
||||
// Complete Mac operation, base64 encoding, convert byte array to string
|
||||
return new String(Base64.encodeBase64(textFinal), Constants.ENCODE);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("signWithhmacSHA1Encrypt fail", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.constant;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* All the constants.
|
||||
*
|
||||
* @author onew
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
public static class SysEnv {
|
||||
|
||||
public static final String USER_HOME = "user.home";
|
||||
|
||||
public static final String PROJECT_NAME = "project.name";
|
||||
|
||||
public static final String JM_LOG_PATH = "JM.LOG.PATH";
|
||||
|
||||
public static final String JM_SNAPSHOT_PATH = "JM.SNAPSHOT.PATH";
|
||||
|
||||
public static final String NACOS_ENV_FIRST = "nacos.env.first";
|
||||
|
||||
}
|
||||
|
||||
public static class Security {
|
||||
|
||||
public static final long SECURITY_INFO_REFRESH_INTERVAL_MILLS =
|
||||
TimeUnit.SECONDS.toMillis(5);
|
||||
|
||||
}
|
||||
|
||||
public static class Address {
|
||||
|
||||
public static final int ENDPOINT_SERVER_LIST_PROVIDER_ORDER = 500;
|
||||
|
||||
public static final int ADDRESS_SERVER_LIST_PROVIDER_ORDER = 499;
|
||||
}
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
abstract class AbstractPropertySource {
|
||||
|
||||
/**
|
||||
* get property's type.
|
||||
* @return name
|
||||
*/
|
||||
abstract SourceType getType();
|
||||
|
||||
/**
|
||||
* get property, if the value can not be got by the special key, the null will be returned.
|
||||
* @param key special key
|
||||
* @return value or null
|
||||
*/
|
||||
abstract String getProperty(String key);
|
||||
|
||||
/**
|
||||
* Tests if the specified object is a key in this propertySource.
|
||||
* @param key key – possible key
|
||||
* @return true if and only if the specified object is a key in this propertySource, false otherwise.
|
||||
*/
|
||||
abstract boolean containsKey(String key);
|
||||
|
||||
/**
|
||||
* to properties.
|
||||
* @return properties
|
||||
*/
|
||||
abstract Properties asProperties();
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
class JvmArgsPropertySource extends AbstractPropertySource {
|
||||
|
||||
private final Properties properties;
|
||||
|
||||
JvmArgsPropertySource() {
|
||||
this.properties = System.getProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
SourceType getType() {
|
||||
return SourceType.JVM;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getProperty(String key) {
|
||||
return properties.getProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean containsKey(String key) {
|
||||
return properties.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
Properties asProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.putAll(this.properties);
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* NacosClientProperties interface. include all the properties from jvm args, system environment, default setting. more
|
||||
* details you can see https://github.com/alibaba/nacos/issues/8622
|
||||
*
|
||||
* @author onewe
|
||||
*/
|
||||
public interface NacosClientProperties {
|
||||
|
||||
/**
|
||||
* all the NacosClientProperties object must be created by PROTOTYPE, so child NacosClientProperties can read
|
||||
* properties from the PROTOTYPE. it looks like this: |-PROTOTYPE----------------> ip=127.0.0.1
|
||||
* |---|-child1---------------> port=6379 if you search key called "port" from child1, certainly you will get 6379
|
||||
* if you search key called "ip" from child1, you will get 127.0.0.1. because the child can read properties from
|
||||
* parent NacosClientProperties
|
||||
*/
|
||||
NacosClientProperties PROTOTYPE = SearchableProperties.INSTANCE;
|
||||
|
||||
/**
|
||||
* get property, if the value can not be got by the special key, the null will be returned.
|
||||
*
|
||||
* @param key special key
|
||||
* @return string value or null.
|
||||
*/
|
||||
String getProperty(String key);
|
||||
|
||||
/**
|
||||
* get property, if the value can not be got by the special key, the default value will be returned.
|
||||
*
|
||||
* @param key special key
|
||||
* @param defaultValue default value
|
||||
* @return string value or default value.
|
||||
*/
|
||||
String getProperty(String key, String defaultValue);
|
||||
|
||||
/**
|
||||
* get property from special property source.
|
||||
*
|
||||
* @param source source type
|
||||
* @param key special key
|
||||
* @return string value or null.
|
||||
* @see SourceType
|
||||
*/
|
||||
String getPropertyFrom(SourceType source, String key);
|
||||
|
||||
/**
|
||||
* get property from special property source.
|
||||
*
|
||||
* @param source source type
|
||||
* @return string value or null.
|
||||
* @see SourceType
|
||||
*/
|
||||
Properties getProperties(SourceType source);
|
||||
|
||||
/**
|
||||
* get boolean, if the value can not be got by the special key, the null will be returned.
|
||||
*
|
||||
* @param key special key
|
||||
* @return boolean value or null.
|
||||
*/
|
||||
Boolean getBoolean(String key);
|
||||
|
||||
/**
|
||||
* get boolean, if the value can not be got by the special key, the default value will be returned.
|
||||
*
|
||||
* @param key special key
|
||||
* @param defaultValue default value
|
||||
* @return boolean value or defaultValue.
|
||||
*/
|
||||
Boolean getBoolean(String key, Boolean defaultValue);
|
||||
|
||||
/**
|
||||
* get integer, if the value can not be got by the special key, the null will be returned.
|
||||
*
|
||||
* @param key special key
|
||||
* @return integer value or null
|
||||
*/
|
||||
Integer getInteger(String key);
|
||||
|
||||
/**
|
||||
* get integer, if the value can not be got by the special key, the default value will be returned.
|
||||
*
|
||||
* @param key special key
|
||||
* @param defaultValue default value
|
||||
* @return integer value or default value
|
||||
*/
|
||||
Integer getInteger(String key, Integer defaultValue);
|
||||
|
||||
/**
|
||||
* get long, if the value can not be got by the special key, the null will be returned.
|
||||
*
|
||||
* @param key special key
|
||||
* @return long value or null
|
||||
*/
|
||||
Long getLong(String key);
|
||||
|
||||
/**
|
||||
* get long, if the value can not be got by the special key, the default value will be returned.
|
||||
*
|
||||
* @param key special key
|
||||
* @param defaultValue default value
|
||||
* @return long value or default value
|
||||
*/
|
||||
Long getLong(String key, Long defaultValue);
|
||||
|
||||
/**
|
||||
* set property.
|
||||
*
|
||||
* @param key key
|
||||
* @param value value
|
||||
*/
|
||||
void setProperty(String key, String value);
|
||||
|
||||
/**
|
||||
* add properties.
|
||||
*
|
||||
* @param properties properties
|
||||
*/
|
||||
void addProperties(Properties properties);
|
||||
|
||||
/**
|
||||
* Tests if the specified object is a key in this NacosClientProperties.
|
||||
*
|
||||
* @param key key – possible key
|
||||
* @return true if and only if the specified object is a key in this NacosClientProperties, false otherwise.
|
||||
*/
|
||||
boolean containsKey(String key);
|
||||
|
||||
/**
|
||||
* get properties from NacosClientProperties.
|
||||
*
|
||||
* @return properties
|
||||
*/
|
||||
Properties asProperties();
|
||||
|
||||
/**
|
||||
* create a new NacosClientProperties which scope is itself.
|
||||
*
|
||||
* @return NacosClientProperties
|
||||
*/
|
||||
NacosClientProperties derive();
|
||||
|
||||
/**
|
||||
* create a new NacosClientProperties from NacosClientProperties#PROTOTYPE and init.
|
||||
*
|
||||
* @param properties properties
|
||||
* @return NacosClientProperties
|
||||
*/
|
||||
NacosClientProperties derive(Properties properties);
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Properties;
|
||||
|
||||
class PropertiesPropertySource extends AbstractPropertySource {
|
||||
|
||||
private final Properties properties = new Properties();
|
||||
|
||||
private final PropertiesPropertySource parent;
|
||||
|
||||
PropertiesPropertySource() {
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
PropertiesPropertySource(PropertiesPropertySource parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
SourceType getType() {
|
||||
return SourceType.PROPERTIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getProperty(String key) {
|
||||
return getProperty(this, key);
|
||||
}
|
||||
|
||||
private String getProperty(PropertiesPropertySource propertiesPropertySource, String key) {
|
||||
final String value = propertiesPropertySource.properties.getProperty(key);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
final PropertiesPropertySource parent = propertiesPropertySource.parent;
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
return getProperty(parent, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean containsKey(String key) {
|
||||
return containsKey(this, key);
|
||||
}
|
||||
|
||||
boolean containsKey(PropertiesPropertySource propertiesPropertySource, String key) {
|
||||
final boolean exist = propertiesPropertySource.properties.containsKey(key);
|
||||
if (exist) {
|
||||
return true;
|
||||
}
|
||||
final PropertiesPropertySource parent = propertiesPropertySource.parent;
|
||||
if (parent == null) {
|
||||
return false;
|
||||
}
|
||||
return containsKey(parent, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
Properties asProperties() {
|
||||
List<Properties> propertiesList = new ArrayList<>(8);
|
||||
|
||||
propertiesList = lookForProperties(this, propertiesList);
|
||||
|
||||
Properties ret = new Properties();
|
||||
final ListIterator<Properties> iterator =
|
||||
propertiesList.listIterator(propertiesList.size());
|
||||
while (iterator.hasPrevious()) {
|
||||
final Properties properties = iterator.previous();
|
||||
ret.putAll(properties);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
List<Properties> lookForProperties(PropertiesPropertySource propertiesPropertySource,
|
||||
List<Properties> propertiesList) {
|
||||
propertiesList.add(propertiesPropertySource.properties);
|
||||
final PropertiesPropertySource parent = propertiesPropertySource.parent;
|
||||
if (parent == null) {
|
||||
return propertiesList;
|
||||
}
|
||||
return lookForProperties(parent, propertiesList);
|
||||
}
|
||||
|
||||
synchronized void setProperty(String key, String value) {
|
||||
properties.setProperty(key, value);
|
||||
}
|
||||
|
||||
synchronized void addProperties(Properties source) {
|
||||
properties.putAll(source);
|
||||
}
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
import com.alibaba.nacos.client.constant.Constants;
|
||||
import com.alibaba.nacos.client.env.convert.CompositeConverter;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Searchable NacosClientProperties. the SearchableProperties that it can be specified search order by nacos.env.first
|
||||
*
|
||||
* @author onewe
|
||||
*/
|
||||
class SearchableProperties implements NacosClientProperties {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SearchableProperties.class);
|
||||
|
||||
private static final JvmArgsPropertySource JVM_ARGS_PROPERTY_SOURCE =
|
||||
new JvmArgsPropertySource();
|
||||
|
||||
private static final SystemEnvPropertySource SYSTEM_ENV_PROPERTY_SOURCE =
|
||||
new SystemEnvPropertySource();
|
||||
|
||||
private static final List<SourceType> SEARCH_ORDER;
|
||||
|
||||
private static final CompositeConverter CONVERTER = new CompositeConverter();
|
||||
|
||||
static {
|
||||
SEARCH_ORDER = init();
|
||||
StringBuilder orderInfo = new StringBuilder("properties search order:");
|
||||
for (int i = 0; i < SEARCH_ORDER.size(); i++) {
|
||||
orderInfo.append(SEARCH_ORDER.get(i).toString());
|
||||
if (i < SEARCH_ORDER.size() - 1) {
|
||||
orderInfo.append("->");
|
||||
}
|
||||
}
|
||||
LOGGER.debug(orderInfo.toString());
|
||||
}
|
||||
|
||||
private static List<SourceType> init() {
|
||||
List<SourceType> initOrder =
|
||||
Arrays.asList(SourceType.PROPERTIES, SourceType.JVM, SourceType.ENV);
|
||||
|
||||
String firstEnv = JVM_ARGS_PROPERTY_SOURCE.getProperty(Constants.SysEnv.NACOS_ENV_FIRST);
|
||||
if (StringUtils.isBlank(firstEnv)) {
|
||||
firstEnv = SYSTEM_ENV_PROPERTY_SOURCE.getProperty(Constants.SysEnv.NACOS_ENV_FIRST);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(firstEnv)) {
|
||||
try {
|
||||
final SourceType sourceType = SourceType.valueOf(firstEnv.toUpperCase());
|
||||
if (!sourceType.equals(SourceType.PROPERTIES)) {
|
||||
final int index = initOrder.indexOf(sourceType);
|
||||
final SourceType replacedSourceType = initOrder.set(0, sourceType);
|
||||
initOrder.set(index, replacedSourceType);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("first source type parse error, it will be used default order!", e);
|
||||
}
|
||||
}
|
||||
return initOrder;
|
||||
}
|
||||
|
||||
static final SearchableProperties INSTANCE = new SearchableProperties();
|
||||
|
||||
private final List<AbstractPropertySource> propertySources;
|
||||
|
||||
private final PropertiesPropertySource propertiesPropertySource;
|
||||
|
||||
private SearchableProperties() {
|
||||
this(new PropertiesPropertySource());
|
||||
}
|
||||
|
||||
private SearchableProperties(PropertiesPropertySource propertiesPropertySource) {
|
||||
this.propertiesPropertySource = propertiesPropertySource;
|
||||
this.propertySources = build(propertiesPropertySource, JVM_ARGS_PROPERTY_SOURCE,
|
||||
SYSTEM_ENV_PROPERTY_SOURCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
return getProperty(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key, String defaultValue) {
|
||||
return this.search(key, String.class).orElse(defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPropertyFrom(SourceType source, String key) {
|
||||
if (source == null) {
|
||||
return this.getProperty(key);
|
||||
}
|
||||
switch (source) {
|
||||
case JVM:
|
||||
return JVM_ARGS_PROPERTY_SOURCE.getProperty(key);
|
||||
case ENV:
|
||||
return SYSTEM_ENV_PROPERTY_SOURCE.getProperty(key);
|
||||
case PROPERTIES:
|
||||
return this.propertiesPropertySource.getProperty(key);
|
||||
default:
|
||||
return this.getProperty(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getProperties(SourceType source) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
switch (source) {
|
||||
case JVM:
|
||||
return JVM_ARGS_PROPERTY_SOURCE.asProperties();
|
||||
case ENV:
|
||||
return SYSTEM_ENV_PROPERTY_SOURCE.asProperties();
|
||||
case PROPERTIES:
|
||||
return this.propertiesPropertySource.asProperties();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBoolean(String key) {
|
||||
return getBoolean(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBoolean(String key, Boolean defaultValue) {
|
||||
return this.search(key, Boolean.class).orElse(defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInteger(String key) {
|
||||
return getInteger(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInteger(String key, Integer defaultValue) {
|
||||
return this.search(key, Integer.class).orElse(defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String key) {
|
||||
return getLong(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String key, Long defaultValue) {
|
||||
return this.search(key, Long.class).orElse(defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String key, String value) {
|
||||
propertiesPropertySource.setProperty(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProperties(Properties properties) {
|
||||
propertiesPropertySource.addProperties(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties asProperties() {
|
||||
Properties properties = new Properties();
|
||||
final ListIterator<AbstractPropertySource> iterator =
|
||||
propertySources.listIterator(propertySources.size());
|
||||
while (iterator.hasPrevious()) {
|
||||
final AbstractPropertySource previous = iterator.previous();
|
||||
properties.putAll(previous.asProperties());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(String key) {
|
||||
for (AbstractPropertySource propertySource : propertySources) {
|
||||
final boolean containing = propertySource.containsKey(key);
|
||||
if (containing) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private <T> Optional<T> search(String key, Class<T> targetType) {
|
||||
for (AbstractPropertySource propertySource : propertySources) {
|
||||
final String value = propertySource.getProperty(key);
|
||||
if (value != null) {
|
||||
if (targetType.isAssignableFrom(String.class)) {
|
||||
return (Optional<T>) Optional.of(value);
|
||||
}
|
||||
return Optional.ofNullable(CONVERTER.convert(value, targetType));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private List<AbstractPropertySource> build(AbstractPropertySource... propertySources) {
|
||||
final Map<SourceType, AbstractPropertySource> sourceMap = Arrays.stream(propertySources)
|
||||
.collect(Collectors.toMap(AbstractPropertySource::getType,
|
||||
propertySource -> propertySource));
|
||||
return SEARCH_ORDER.stream().map(sourceMap::get).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NacosClientProperties derive() {
|
||||
return new SearchableProperties(
|
||||
new PropertiesPropertySource(this.propertiesPropertySource));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NacosClientProperties derive(Properties properties) {
|
||||
final NacosClientProperties nacosClientProperties = this.derive();
|
||||
nacosClientProperties.addProperties(properties);
|
||||
return nacosClientProperties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
/**
|
||||
* properties source type enum.
|
||||
* @author onewe
|
||||
*/
|
||||
public enum SourceType {
|
||||
/**
|
||||
* get value from properties.
|
||||
*/
|
||||
PROPERTIES,
|
||||
/**
|
||||
* get value from jvm args.
|
||||
*/
|
||||
JVM,
|
||||
/**
|
||||
* get value from system environment.
|
||||
*/
|
||||
ENV,
|
||||
/**
|
||||
* get value from unknown environment, will be search in all properties by orders.
|
||||
*/
|
||||
UNKNOWN
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
class SystemEnvPropertySource extends AbstractPropertySource {
|
||||
|
||||
private final Map<String, String> env = System.getenv();
|
||||
|
||||
@Override
|
||||
SourceType getType() {
|
||||
return SourceType.ENV;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getProperty(String key) {
|
||||
String checkedKey = checkPropertyName(key);
|
||||
if (checkedKey == null) {
|
||||
final String upperCaseKey = key.toUpperCase();
|
||||
if (!upperCaseKey.equals(key)) {
|
||||
checkedKey = checkPropertyName(upperCaseKey);
|
||||
}
|
||||
}
|
||||
if (checkedKey == null) {
|
||||
return null;
|
||||
}
|
||||
return env.get(checkedKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* copy from https://github.com/spring-projects/spring-framework.git
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Since:
|
||||
* 3.1
|
||||
* Author:
|
||||
* Chris Beams, Juergen Hoeller
|
||||
*/
|
||||
private String checkPropertyName(String name) {
|
||||
// Check name as-is
|
||||
if (containsKey(name)) {
|
||||
return name;
|
||||
}
|
||||
// Check name with just dots replaced
|
||||
String noDotName = name.replace('.', '_');
|
||||
if (!name.equals(noDotName) && containsKey(noDotName)) {
|
||||
return noDotName;
|
||||
}
|
||||
// Check name with just hyphens replaced
|
||||
String noHyphenName = name.replace('-', '_');
|
||||
if (!name.equals(noHyphenName) && containsKey(noHyphenName)) {
|
||||
return noHyphenName;
|
||||
}
|
||||
// Check name with dots and hyphens replaced
|
||||
String noDotNoHyphenName = noDotName.replace('-', '_');
|
||||
if (!noDotName.equals(noDotNoHyphenName) && containsKey(noDotNoHyphenName)) {
|
||||
return noDotNoHyphenName;
|
||||
}
|
||||
// Give up
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean containsKey(String name) {
|
||||
return this.env.containsKey(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
Properties asProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.putAll(this.env);
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env.convert;
|
||||
|
||||
abstract class AbstractPropertyConverter<T> {
|
||||
|
||||
/**
|
||||
* convert property to target object.
|
||||
* @param property the property gets from environments
|
||||
* @return target object
|
||||
*/
|
||||
abstract T convert(String property);
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env.convert;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
class BooleanConverter extends AbstractPropertyConverter<Boolean> {
|
||||
|
||||
private static final Set<String> TRUE_VALUES = new HashSet<>(8);
|
||||
|
||||
private static final Set<String> FALSE_VALUES = new HashSet<>(8);
|
||||
|
||||
static {
|
||||
TRUE_VALUES.add("true");
|
||||
TRUE_VALUES.add("on");
|
||||
TRUE_VALUES.add("yes");
|
||||
TRUE_VALUES.add("1");
|
||||
|
||||
FALSE_VALUES.add("false");
|
||||
FALSE_VALUES.add("off");
|
||||
FALSE_VALUES.add("no");
|
||||
FALSE_VALUES.add("0");
|
||||
}
|
||||
|
||||
@Override
|
||||
Boolean convert(String property) {
|
||||
if (StringUtils.isEmpty(property)) {
|
||||
return null;
|
||||
}
|
||||
property = property.toLowerCase();
|
||||
if (TRUE_VALUES.contains(property)) {
|
||||
return Boolean.TRUE;
|
||||
} else if (FALSE_VALUES.contains(property)) {
|
||||
return Boolean.FALSE;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid boolean value '" + property + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env.convert;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.MissingFormatArgumentException;
|
||||
|
||||
/**
|
||||
* default converters.
|
||||
* @author onewe
|
||||
*/
|
||||
public class CompositeConverter {
|
||||
|
||||
private final Map<Class<?>, AbstractPropertyConverter<?>> converterRegistry = new HashMap<>();
|
||||
|
||||
public CompositeConverter() {
|
||||
converterRegistry.put(Boolean.class, new BooleanConverter());
|
||||
converterRegistry.put(Integer.class, new IntegerConverter());
|
||||
converterRegistry.put(Long.class, new LongConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* convert property to target type.
|
||||
* @param property the property gets from environments
|
||||
* @param targetClass target class object
|
||||
* @param <T> target type
|
||||
* @return the object of target type
|
||||
*/
|
||||
public <T> T convert(String property, Class<T> targetClass) {
|
||||
final AbstractPropertyConverter<?> converter = converterRegistry.get(targetClass);
|
||||
if (converter == null) {
|
||||
throw new MissingFormatArgumentException(
|
||||
"converter not found, can't convert from String to "
|
||||
+ targetClass.getCanonicalName());
|
||||
}
|
||||
return (T) converter.convert(property);
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env.convert;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
class IntegerConverter extends AbstractPropertyConverter<Integer> {
|
||||
|
||||
@Override
|
||||
Integer convert(String property) {
|
||||
if (StringUtils.isEmpty(property)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Integer.valueOf(property);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot convert String [" + property + "] to Integer");
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env.convert;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
class LongConverter extends AbstractPropertyConverter<Long> {
|
||||
|
||||
@Override
|
||||
Long convert(String property) {
|
||||
if (StringUtils.isEmpty(property)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Long.valueOf(property);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Cannot convert String [" + property + "] to Long");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.remote;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.common.http.AbstractHttpClientFactory;
|
||||
import com.alibaba.nacos.common.http.HttpClientBeanHolder;
|
||||
import com.alibaba.nacos.common.http.HttpClientConfig;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.lifecycle.Closeable;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* http Manager.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class HttpClientManager implements Closeable {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientManager.class);
|
||||
|
||||
private static final HttpClientFactory HTTP_CLIENT_FACTORY = new HttpClientFactory();
|
||||
|
||||
private static final int CON_TIME_OUT_MILLIS = 1000;
|
||||
|
||||
private static final int READ_TIME_OUT_MILLIS = 3000;
|
||||
|
||||
private static class HttpClientManagerInstance {
|
||||
|
||||
private static final HttpClientManager INSTANCE = new HttpClientManager();
|
||||
}
|
||||
|
||||
public static HttpClientManager getInstance() {
|
||||
return HttpClientManagerInstance.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
LOGGER.info("[HttpClientManager] Start destroying NacosRestTemplate");
|
||||
try {
|
||||
HttpClientBeanHolder.shutdownNacosSyncRest(HTTP_CLIENT_FACTORY.getClass().getName());
|
||||
} catch (Exception ex) {
|
||||
LOGGER.error(
|
||||
"[HttpClientManager] An exception occurred when the HTTP client was closed : {}",
|
||||
ExceptionUtil.getStackTrace(ex));
|
||||
}
|
||||
LOGGER.info("[HttpClientManager] Completed destruction of NacosRestTemplate");
|
||||
}
|
||||
|
||||
/**
|
||||
* get connectTimeout.
|
||||
*
|
||||
* @param connectTimeout connectTimeout
|
||||
* @return int return max timeout
|
||||
*/
|
||||
public int getConnectTimeoutOrDefault(int connectTimeout) {
|
||||
return Math.max(CON_TIME_OUT_MILLIS, connectTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* get NacosRestTemplate Instance.
|
||||
*
|
||||
* @return NacosRestTemplate
|
||||
*/
|
||||
public NacosRestTemplate getNacosRestTemplate() {
|
||||
return HttpClientBeanHolder.getNacosRestTemplate(HTTP_CLIENT_FACTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* HttpClientFactory.
|
||||
*/
|
||||
private static class HttpClientFactory extends AbstractHttpClientFactory {
|
||||
|
||||
@Override
|
||||
protected HttpClientConfig buildHttpClientConfig() {
|
||||
return HttpClientConfig.builder().setConTimeOutMillis(CON_TIME_OUT_MILLIS)
|
||||
.setReadTimeOutMillis(READ_TIME_OUT_MILLIS).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Logger assignLogger() {
|
||||
return LOGGER;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import com.alibaba.nacos.client.constant.Constants;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* appName util.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class AppNameUtils {
|
||||
|
||||
private static final String PARAM_MARKING_JBOSS = "jboss.server.home.dir";
|
||||
|
||||
private static final String PARAM_MARKING_JETTY = "jetty.home";
|
||||
|
||||
private static final String PARAM_MARKING_TOMCAT = "catalina.base";
|
||||
|
||||
private static final String LINUX_ADMIN_HOME = "/home/admin/";
|
||||
|
||||
private static final String SERVER_JBOSS = "jboss";
|
||||
|
||||
private static final String SERVER_JETTY = "jetty";
|
||||
|
||||
private static final String SERVER_TOMCAT = "tomcat";
|
||||
|
||||
private static final String SERVER_UNKNOWN = "unknown server";
|
||||
|
||||
private static final String DEFAULT_APP_NAME = "unknown";
|
||||
|
||||
public static String getAppName() {
|
||||
String appName;
|
||||
|
||||
appName = getAppNameByProjectName();
|
||||
if (appName != null) {
|
||||
return appName;
|
||||
}
|
||||
|
||||
appName = getAppNameByServerHome();
|
||||
if (appName != null) {
|
||||
return appName;
|
||||
}
|
||||
|
||||
return DEFAULT_APP_NAME;
|
||||
}
|
||||
|
||||
private static String getAppNameByProjectName() {
|
||||
return NacosClientProperties.PROTOTYPE.getProperty(Constants.SysEnv.PROJECT_NAME);
|
||||
}
|
||||
|
||||
private static String getAppNameByServerHome() {
|
||||
String serverHome = null;
|
||||
if (SERVER_JBOSS.equals(getServerType())) {
|
||||
serverHome = NacosClientProperties.PROTOTYPE.getProperty(PARAM_MARKING_JBOSS);
|
||||
} else if (SERVER_JETTY.equals(getServerType())) {
|
||||
serverHome = NacosClientProperties.PROTOTYPE.getProperty(PARAM_MARKING_JETTY);
|
||||
} else if (SERVER_TOMCAT.equals(getServerType())) {
|
||||
serverHome = NacosClientProperties.PROTOTYPE.getProperty(PARAM_MARKING_TOMCAT);
|
||||
}
|
||||
|
||||
if (serverHome != null && serverHome.startsWith(LINUX_ADMIN_HOME)) {
|
||||
return StringUtils.substringBetween(serverHome, LINUX_ADMIN_HOME, File.separator);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getServerType() {
|
||||
String serverType;
|
||||
if (NacosClientProperties.PROTOTYPE.getProperty(PARAM_MARKING_JBOSS) != null) {
|
||||
serverType = SERVER_JBOSS;
|
||||
} else if (NacosClientProperties.PROTOTYPE.getProperty(PARAM_MARKING_JETTY) != null) {
|
||||
serverType = SERVER_JETTY;
|
||||
} else if (NacosClientProperties.PROTOTYPE.getProperty(PARAM_MARKING_TOMCAT) != null) {
|
||||
serverType = SERVER_TOMCAT;
|
||||
} else {
|
||||
serverType = SERVER_UNKNOWN;
|
||||
}
|
||||
return serverType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright 1999-2025 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.SystemPropertyKeyConst;
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.common.utils.ConvertUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.common.utils.VersionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Nacos client basic parameters utils.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class ClientBasicParamUtil {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ClientBasicParamUtil.class);
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile("\\$\\{[^}]+\\}");
|
||||
|
||||
private static final int DESENSITISE_PARAMETER_MIN_LENGTH = 2;
|
||||
|
||||
private static final int DESENSITISE_PARAMETER_KEEP_ONE_CHAR_LENGTH = 8;
|
||||
|
||||
private static final String NACOS_CLIENT_APP_KEY = "nacos.client.appKey";
|
||||
|
||||
private static final String NACOS_CLIENT_CONTEXT_PATH_KEY = "nacos.client.contextPath";
|
||||
|
||||
private static final String DEFAULT_NACOS_CLIENT_CONTEXT_PATH = "nacos";
|
||||
|
||||
private static final String NACOS_SERVER_PORT_KEY = "nacos.server.port";
|
||||
|
||||
private static final String DEFAULT_SERVER_PORT = "8848";
|
||||
|
||||
private static final String BLANK_STR = "";
|
||||
|
||||
private static String defaultContextPath;
|
||||
|
||||
private static String appKey;
|
||||
|
||||
private static String clientVersion = "unknown";
|
||||
|
||||
private static String serverPort;
|
||||
|
||||
private static String defaultNodesPath = "serverlist";
|
||||
|
||||
static {
|
||||
// Client identity information
|
||||
appKey = NacosClientProperties.PROTOTYPE.getProperty(NACOS_CLIENT_APP_KEY, BLANK_STR);
|
||||
|
||||
defaultContextPath =
|
||||
NacosClientProperties.PROTOTYPE.getProperty(NACOS_CLIENT_CONTEXT_PATH_KEY,
|
||||
DEFAULT_NACOS_CLIENT_CONTEXT_PATH);
|
||||
|
||||
serverPort = NacosClientProperties.PROTOTYPE.getProperty(NACOS_SERVER_PORT_KEY,
|
||||
DEFAULT_SERVER_PORT);
|
||||
LOGGER.info("[settings] [req-serv] nacos-server port:{}", serverPort);
|
||||
|
||||
clientVersion = VersionUtils.version;
|
||||
}
|
||||
|
||||
public static String getAppKey() {
|
||||
return appKey;
|
||||
}
|
||||
|
||||
public static void setAppKey(String appKey) {
|
||||
ClientBasicParamUtil.appKey = appKey;
|
||||
}
|
||||
|
||||
public static String getDefaultContextPath() {
|
||||
return defaultContextPath;
|
||||
}
|
||||
|
||||
public static void setDefaultContextPath(String defaultContextPath) {
|
||||
ClientBasicParamUtil.defaultContextPath = defaultContextPath;
|
||||
}
|
||||
|
||||
public static String getClientVersion() {
|
||||
return clientVersion;
|
||||
}
|
||||
|
||||
public static void setClientVersion(String clientVersion) {
|
||||
ClientBasicParamUtil.clientVersion = clientVersion;
|
||||
}
|
||||
|
||||
public static String getDefaultServerPort() {
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
public static String getDefaultNodesPath() {
|
||||
return defaultNodesPath;
|
||||
}
|
||||
|
||||
public static void setDefaultNodesPath(String defaultNodesPath) {
|
||||
ClientBasicParamUtil.defaultNodesPath = defaultNodesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse namespace from properties and environment.
|
||||
*
|
||||
* @param properties properties
|
||||
* @return namespace
|
||||
*/
|
||||
public static String parseNamespace(NacosClientProperties properties) {
|
||||
String namespaceTmp = null;
|
||||
|
||||
String isUseCloudNamespaceParsing =
|
||||
properties.getProperty(PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
|
||||
properties.getProperty(
|
||||
SystemPropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
|
||||
String.valueOf(Constants.DEFAULT_USE_CLOUD_NAMESPACE_PARSING)));
|
||||
|
||||
if (Boolean.parseBoolean(isUseCloudNamespaceParsing)) {
|
||||
namespaceTmp = TenantUtil.getUserTenantForAcm();
|
||||
|
||||
namespaceTmp = TemplateUtils.stringBlankAndThenExecute(namespaceTmp, () -> {
|
||||
String namespace = properties
|
||||
.getProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_NAMESPACE);
|
||||
return StringUtils.isNotBlank(namespace) ? namespace : StringUtils.EMPTY;
|
||||
});
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(namespaceTmp)) {
|
||||
namespaceTmp = properties.getProperty(PropertyKeyConst.NAMESPACE);
|
||||
}
|
||||
return StringUtils.isNotBlank(namespaceTmp) ? namespaceTmp.trim()
|
||||
: Constants.DEFAULT_NAMESPACE_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse end point rule.
|
||||
*
|
||||
* @param endpointUrl endpoint url
|
||||
* @return end point rule
|
||||
*/
|
||||
public static String parsingEndpointRule(String endpointUrl) {
|
||||
// If entered in the configuration file, the priority in ENV will be given priority.
|
||||
if (endpointUrl == null || !PATTERN.matcher(endpointUrl).find()) {
|
||||
// skip retrieve from system property and retrieve directly from system env
|
||||
String endpointUrlSource = NacosClientProperties.PROTOTYPE.getProperty(
|
||||
PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL);
|
||||
if (StringUtils.isNotBlank(endpointUrlSource)) {
|
||||
endpointUrl = endpointUrlSource;
|
||||
}
|
||||
|
||||
return StringUtils.isNotBlank(endpointUrl) ? endpointUrl : "";
|
||||
}
|
||||
|
||||
endpointUrl =
|
||||
endpointUrl.substring(endpointUrl.indexOf("${") + 2, endpointUrl.lastIndexOf("}"));
|
||||
int defStartOf = endpointUrl.indexOf(":");
|
||||
String defaultEndpointUrl = null;
|
||||
if (defStartOf != -1) {
|
||||
defaultEndpointUrl = endpointUrl.substring(defStartOf + 1);
|
||||
endpointUrl = endpointUrl.substring(0, defStartOf);
|
||||
}
|
||||
|
||||
String endpointUrlSource = TemplateUtils.stringBlankAndThenExecute(
|
||||
NacosClientProperties.PROTOTYPE.getProperty(endpointUrl),
|
||||
() -> NacosClientProperties.PROTOTYPE.getProperty(
|
||||
PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL));
|
||||
|
||||
if (StringUtils.isBlank(endpointUrlSource)) {
|
||||
if (StringUtils.isNotBlank(defaultEndpointUrl)) {
|
||||
endpointUrl = defaultEndpointUrl;
|
||||
}
|
||||
} else {
|
||||
endpointUrl = endpointUrlSource;
|
||||
}
|
||||
|
||||
return StringUtils.isNotBlank(endpointUrl) ? endpointUrl : "";
|
||||
}
|
||||
|
||||
public static String getInputParameters(Properties properties) {
|
||||
boolean logAllParameters =
|
||||
ConvertUtils.toBoolean(properties.getProperty(PropertyKeyConst.LOG_ALL_PROPERTIES),
|
||||
false);
|
||||
StringBuilder result = new StringBuilder();
|
||||
if (logAllParameters) {
|
||||
result.append(
|
||||
"Log nacos client init properties with Full mode, This mode is only used for debugging and troubleshooting. ");
|
||||
result.append(
|
||||
"Please close this mode by removing properties `logAllProperties` after finishing debug or troubleshoot.\n");
|
||||
result.append("Nacos client all init properties: \n");
|
||||
properties.forEach(
|
||||
(key, value) -> result.append("\t").append(key.toString()).append("=")
|
||||
.append(value.toString())
|
||||
.append("\n"));
|
||||
} else {
|
||||
result.append("Nacos client key init properties: \n");
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.SERVER_ADDR, false);
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.NAMESPACE, false);
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.ENDPOINT, false);
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.ENDPOINT_PORT, false);
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.USERNAME, false);
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.PASSWORD, true);
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.ACCESS_KEY, true);
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.SECRET_KEY, true);
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.RAM_ROLE_NAME, false);
|
||||
appendKeyParameters(result, properties, PropertyKeyConst.SIGNATURE_REGION_ID, false);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static void appendKeyParameters(StringBuilder result, Properties properties,
|
||||
String propertyKey,
|
||||
boolean needDesensitise) {
|
||||
String propertyValue = properties.getProperty(propertyKey);
|
||||
if (StringUtils.isBlank(propertyValue)) {
|
||||
return;
|
||||
}
|
||||
result.append("\t").append(propertyKey).append("=")
|
||||
.append(needDesensitise ? desensitiseParameter(propertyValue) : propertyValue)
|
||||
.append("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Do desensitise for parameters with `*` to replace inner content.
|
||||
*
|
||||
* @param parameterValue parameter value which need be desensitised.
|
||||
* @return desensitised parameter value.
|
||||
*/
|
||||
public static String desensitiseParameter(String parameterValue) {
|
||||
if (parameterValue.length() <= DESENSITISE_PARAMETER_MIN_LENGTH) {
|
||||
return parameterValue;
|
||||
}
|
||||
if (parameterValue.length() < DESENSITISE_PARAMETER_KEEP_ONE_CHAR_LENGTH) {
|
||||
return doDesensitiseParameter(parameterValue, 1);
|
||||
}
|
||||
return doDesensitiseParameter(parameterValue, 2);
|
||||
}
|
||||
|
||||
private static String doDesensitiseParameter(String parameterValue, int keepCharCount) {
|
||||
StringBuilder result = new StringBuilder(parameterValue);
|
||||
for (int i = keepCharCount; i < parameterValue.length() - keepCharCount; i++) {
|
||||
result.setCharAt(i, '*');
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String getNameSuffixByServerIps(String... serverIps) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String split = "";
|
||||
for (String serverIp : serverIps) {
|
||||
sb.append(split);
|
||||
serverIp = serverIp.replaceAll("http(s)?://", "");
|
||||
sb.append(serverIp.replaceAll(":", "_"));
|
||||
split = "-";
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* Context path Util.
|
||||
*
|
||||
* @author Wei.Wang
|
||||
*/
|
||||
public class ContextPathUtil {
|
||||
|
||||
private static final String ROOT_WEB_CONTEXT_PATH = "/";
|
||||
|
||||
/**
|
||||
* normalize context path.
|
||||
*
|
||||
* @param contextPath origin context path
|
||||
* @return normalized context path
|
||||
*/
|
||||
public static String normalizeContextPath(String contextPath) {
|
||||
if (StringUtils.isBlank(contextPath) || ROOT_WEB_CONTEXT_PATH.equals(contextPath)) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return contextPath.startsWith(ROOT_WEB_CONTEXT_PATH) ? contextPath
|
||||
: ROOT_WEB_CONTEXT_PATH + contextPath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Template Utils.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class TemplateUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TemplateUtils.class);
|
||||
|
||||
/**
|
||||
* Execute if string not empty.
|
||||
*
|
||||
* @param source source
|
||||
* @param runnable execute runnable
|
||||
*/
|
||||
public static void stringNotEmptyAndThenExecute(String source, Runnable runnable) {
|
||||
|
||||
if (StringUtils.isNotEmpty(source)) {
|
||||
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("string not empty and then execute cause an exception.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute if string empty.
|
||||
*
|
||||
* @param source empty source
|
||||
* @param callable execute callable
|
||||
* @return result
|
||||
*/
|
||||
public static String stringEmptyAndThenExecute(String source, Callable<String> callable) {
|
||||
|
||||
if (StringUtils.isEmpty(source)) {
|
||||
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("string empty and then execute cause an exception.", e);
|
||||
}
|
||||
}
|
||||
|
||||
return source == null ? null : source.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute if string blank.
|
||||
*
|
||||
* @param source empty source
|
||||
* @param callable execute callable
|
||||
* @return result
|
||||
*/
|
||||
public static String stringBlankAndThenExecute(String source, Callable<String> callable) {
|
||||
|
||||
if (StringUtils.isBlank(source)) {
|
||||
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("string empty and then execute cause an exception.", e);
|
||||
}
|
||||
}
|
||||
|
||||
return source == null ? null : source.trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import com.alibaba.nacos.api.SystemPropertyKeyConst;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* Tenant Util.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class TenantUtil {
|
||||
|
||||
private static final String USER_TENANT;
|
||||
|
||||
private static final String DEFAULT_ACM_NAMESPACE = "";
|
||||
|
||||
private static final String TENANT_ID = "tenant.id";
|
||||
|
||||
private static final String ACM_NAMESPACE_PROPERTY = "acm.namespace";
|
||||
|
||||
static {
|
||||
USER_TENANT = NacosClientProperties.PROTOTYPE.getProperty(TENANT_ID, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the way ACM gets tenant on the cloud.
|
||||
* <p>
|
||||
* Note the difference between getting and getting ANS. Since the processing logic on the server side is different,
|
||||
* the default value returns differently.
|
||||
* </p>
|
||||
*
|
||||
* @return user tenant for acm
|
||||
*/
|
||||
public static String getUserTenantForAcm() {
|
||||
String tmp = USER_TENANT;
|
||||
|
||||
if (StringUtils.isBlank(USER_TENANT)) {
|
||||
tmp = NacosClientProperties.PROTOTYPE.getProperty(ACM_NAMESPACE_PROPERTY,
|
||||
DEFAULT_ACM_NAMESPACE);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the way ANS gets tenant on the cloud.
|
||||
*
|
||||
* @return user tenant for ans
|
||||
*/
|
||||
public static String getUserTenantForAns() {
|
||||
String tmp = USER_TENANT;
|
||||
|
||||
if (StringUtils.isBlank(USER_TENANT)) {
|
||||
tmp = NacosClientProperties.PROTOTYPE.getProperty(SystemPropertyKeyConst.ANS_NAMESPACE);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
#
|
||||
|
||||
com.alibaba.nacos.client.address.EndpointServerListProvider
|
||||
com.alibaba.nacos.client.address.PropertiesListProvider
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
#
|
||||
|
||||
com.alibaba.nacos.client.auth.impl.NacosClientAuthServiceImpl
|
||||
com.alibaba.nacos.client.auth.ram.RamClientAuthServiceImpl
|
||||
com.alibaba.nacos.client.auth.oidc.OidcClientAuthServiceImpl
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AbstractServerListManagerTest {
|
||||
|
||||
@Mock
|
||||
NacosRestTemplate restTemplate;
|
||||
|
||||
NacosClientProperties properties;
|
||||
|
||||
AbstractServerListManager serverListManager;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
properties = NacosClientProperties.PROTOTYPE.derive();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NacosException {
|
||||
if (null != serverListManager) {
|
||||
serverListManager.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructorWithNamespace() {
|
||||
serverListManager = new MockServerListManager(properties, "test-namespace");
|
||||
assertFalse(properties.containsKey(PropertyKeyConst.NAMESPACE));
|
||||
assertFalse(properties.containsKey(Constants.CLIENT_MODULE_TYPE));
|
||||
assertTrue(serverListManager.getProperties().containsKey(PropertyKeyConst.NAMESPACE));
|
||||
assertEquals("testModule",
|
||||
serverListManager.getProperties().getProperty(Constants.CLIENT_MODULE_TYPE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructorWithoutNamespace() {
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
assertFalse(properties.containsKey(PropertyKeyConst.NAMESPACE));
|
||||
assertFalse(properties.containsKey(Constants.CLIENT_MODULE_TYPE));
|
||||
assertFalse(serverListManager.getProperties().containsKey(PropertyKeyConst.NAMESPACE));
|
||||
assertEquals("testModule",
|
||||
serverListManager.getProperties().getProperty(Constants.CLIENT_MODULE_TYPE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStartWithoutProvider() {
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
assertThrows(NacosException.class, () -> serverListManager.start());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServerList() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
// Mock provider will call this method in init.
|
||||
verify(restTemplate).getInterceptors();
|
||||
assertEquals(1, serverListManager.getServerList().size());
|
||||
assertEquals("mock-server-list", serverListManager.getServerList().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServerNameDefault() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertEquals("testModule-", serverListManager.getServerName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServerName() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
properties.setProperty("ReturnMock", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertEquals("testModule-MockServerName", serverListManager.getServerName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetContextPathDefault() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertEquals("nacos", serverListManager.getContextPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetContextPath() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
properties.setProperty("ReturnMock", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertEquals("MockContextPath", serverListManager.getContextPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetNamespaceDefault() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertEquals("", serverListManager.getNamespace());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetNamespace() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
properties.setProperty("ReturnMock", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertEquals("MockNamespace", serverListManager.getNamespace());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAddressSourceDefault() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertEquals("", serverListManager.getAddressSource());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAddressSource() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
properties.setProperty("ReturnMock", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertEquals("MockAddressSource", serverListManager.getAddressSource());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFixedDefault() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertFalse(serverListManager.isFixed());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsFixed() throws NacosException {
|
||||
properties.setProperty("MockTest", "true");
|
||||
properties.setProperty("ReturnMock", "true");
|
||||
serverListManager = new MockServerListManager(properties);
|
||||
serverListManager.start();
|
||||
assertTrue(serverListManager.isFixed());
|
||||
}
|
||||
|
||||
private class MockServerListManager extends AbstractServerListManager {
|
||||
|
||||
public MockServerListManager(NacosClientProperties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
public MockServerListManager(NacosClientProperties properties, String namespace) {
|
||||
super(properties, namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getModuleName() {
|
||||
return "testModule";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NacosRestTemplate getNacosRestTemplate() {
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String genNextServer() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentServer() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
+461
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.SystemPropertyKeyConst;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.constant.Constants;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.client.utils.ClientBasicParamUtil;
|
||||
import com.alibaba.nacos.client.utils.ContextPathUtil;
|
||||
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
|
||||
import com.alibaba.nacos.common.http.HttpRestResult;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.http.param.Header;
|
||||
import com.alibaba.nacos.common.http.param.Query;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class EndpointServerListProviderTest {
|
||||
|
||||
@Mock
|
||||
NacosRestTemplate nacosRestTemplate;
|
||||
|
||||
private EndpointServerListProvider serverListProvider;
|
||||
|
||||
private NacosClientProperties properties;
|
||||
|
||||
private HttpRestResult requestSuccess;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
requestSuccess =
|
||||
new HttpRestResult<>(Header.EMPTY, 200, "\n127.0.0.1\nlocalhost:9848", "success");
|
||||
serverListProvider = new EndpointServerListProvider();
|
||||
properties = NacosClientProperties.PROTOTYPE.derive();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NacosException {
|
||||
System.clearProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL);
|
||||
System.clearProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_PORT);
|
||||
System.clearProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_CONTEXT_PATH);
|
||||
System.clearProperty(PropertyKeyConst.ENDPOINT_CLUSTER_NAME);
|
||||
System.clearProperty(SystemPropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE);
|
||||
serverListProvider.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithoutProperties() throws NacosException {
|
||||
assertThrows(NacosException.class, () -> serverListProvider.init(null, nacosRestTemplate));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchAndInitForPropertiesEndpoint() throws Exception {
|
||||
assertFalse(serverListProvider.match(properties));
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
assertTrue(serverListProvider.match(properties));
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(),
|
||||
"", ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchAndInitForSystemEndpoint() throws Exception {
|
||||
assertFalse(serverListProvider.match(properties));
|
||||
System.setProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL,
|
||||
"endpointFromSystem");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
assertTrue(serverListProvider.match(properties));
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromSystem", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(), "",
|
||||
ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchAndInitByParsingFalseFromProperties() throws Exception {
|
||||
assertFalse(serverListProvider.match(properties));
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
System.setProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL,
|
||||
"endpointFromSystem");
|
||||
properties.setProperty(PropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE, "false");
|
||||
assertTrue(serverListProvider.match(properties));
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(),
|
||||
"", ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchAndInitByParsingFalseFromSystem() throws Exception {
|
||||
assertFalse(serverListProvider.match(properties));
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
System.setProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL,
|
||||
"endpointFromSystem");
|
||||
System.setProperty(SystemPropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE, "false");
|
||||
assertTrue(serverListProvider.match(properties));
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(),
|
||||
"", ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchAndInitByParsingTrue() throws Exception {
|
||||
assertFalse(serverListProvider.match(properties));
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
System.setProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL,
|
||||
"endpointFromSystem");
|
||||
assertTrue(serverListProvider.match(properties));
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromSystem", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(), "",
|
||||
ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithPropertiesEndpointPort() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT_PORT, "80");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 80, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(), "",
|
||||
ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithSystemEndpointPort() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
System.setProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_PORT, "443");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 443, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(),
|
||||
"", ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithPropertiesEndpointContextPath() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT_CONTEXT_PATH, "address");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, "address",
|
||||
ClientBasicParamUtil.getDefaultNodesPath(), "",
|
||||
ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithSystemEndpointContextPath() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
System.setProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_CONTEXT_PATH,
|
||||
"addresses");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, "addresses",
|
||||
ClientBasicParamUtil.getDefaultNodesPath(), "",
|
||||
ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitContextPathWithFull() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.CONTEXT_PATH, "globalContextPath");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, "globalContextPath",
|
||||
ClientBasicParamUtil.getDefaultNodesPath(), "",
|
||||
"globalContextPath");
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithPropertiesEndpointClusterName() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT_CLUSTER_NAME, "endpointClusterName");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
"endpointClusterName", "",
|
||||
ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithPropertiesEndpointClusterNameWithFull() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.CLUSTER_NAME, "clusterName");
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT_CLUSTER_NAME, "endpointClusterName");
|
||||
properties.setProperty(PropertyKeyConst.IS_ADAPT_CLUSTER_NAME_USAGE, "true");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
"endpointClusterName", "",
|
||||
ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithSystemEndpointClusterNameByOldWay() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.CLUSTER_NAME, "clusterName");
|
||||
properties.setProperty(PropertyKeyConst.IS_ADAPT_CLUSTER_NAME_USAGE, "true");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
"clusterName", "",
|
||||
ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithSystemEndpointClusterWithoutAdapt() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.CLUSTER_NAME, "clusterName");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(),
|
||||
"", ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithNamespace() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.NAMESPACE, "customNamespace");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(),
|
||||
"customNamespace", ClientBasicParamUtil.getDefaultContextPath());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithQuery() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT_QUERY_PARAMS, "nofix=1");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(),
|
||||
"", ClientBasicParamUtil.getDefaultContextPath(), "nofix=1");
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithNamespaceAndQuery() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.NAMESPACE, "customNamespace");
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT_QUERY_PARAMS, "nofix=1");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertInit("endpointFromProperties", 8080, ClientBasicParamUtil.getDefaultContextPath(),
|
||||
ClientBasicParamUtil.getDefaultNodesPath(),
|
||||
"customNamespace", ClientBasicParamUtil.getDefaultContextPath(), "nofix=1");
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithModuleType() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(com.alibaba.nacos.api.common.Constants.CLIENT_MODULE_TYPE, "naming");
|
||||
when(nacosRestTemplate.get(anyString(),
|
||||
argThat(header -> "naming"
|
||||
.equals(header.getValue(HttpHeaderConsts.REQUEST_MODULE))),
|
||||
any(Query.class),
|
||||
eq(String.class))).thenReturn(requestSuccess);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertFalse(serverListProvider.getServerList().isEmpty());
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitGetServerListWithException() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenThrow(
|
||||
new IOException("test"));
|
||||
assertThrows(NacosException.class,
|
||||
() -> serverListProvider.init(properties, nacosRestTemplate));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitGetServerListWithError() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
HttpRestResult failedResult = new HttpRestResult<>(Header.EMPTY, 500, null, "test");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
failedResult);
|
||||
assertThrows(NacosException.class,
|
||||
() -> serverListProvider.init(properties, nacosRestTemplate));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRefreshServerList() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT_REFRESH_INTERVAL_SECONDS, "1");
|
||||
HttpRestResult newResult =
|
||||
new HttpRestResult<>(Header.EMPTY, 200, "\n1.1.1.1 \nlocalhost:9848", "success");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess, newResult);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
assertEquals("127.0.0.1:8848", serverListProvider.getServerList().get(0));
|
||||
assertEquals("localhost:9848", serverListProvider.getServerList().get(1));
|
||||
Field field =
|
||||
EndpointServerListProvider.class.getDeclaredField("lastServerListRefreshTime");
|
||||
field.setAccessible(true);
|
||||
field.set(serverListProvider, 0L);
|
||||
// wait refresh
|
||||
TimeUnit.MILLISECONDS.sleep(2000);
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
assertEquals("1.1.1.1:8848", serverListProvider.getServerList().get(0));
|
||||
assertEquals("localhost:9848", serverListProvider.getServerList().get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRefreshServerListWithDiffSort() throws Exception {
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT, "endpointFromProperties");
|
||||
properties.setProperty(PropertyKeyConst.ENDPOINT_REFRESH_INTERVAL_SECONDS, "1");
|
||||
HttpRestResult newResult =
|
||||
new HttpRestResult<>(Header.EMPTY, 200, "\nlocalhost:9848\n127.0.0.1", "success");
|
||||
when(nacosRestTemplate.get(anyString(), any(Header.class), any(Query.class),
|
||||
eq(String.class))).thenReturn(
|
||||
requestSuccess, newResult);
|
||||
serverListProvider.init(properties, nacosRestTemplate);
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
assertEquals("127.0.0.1:8848", serverListProvider.getServerList().get(0));
|
||||
assertEquals("localhost:9848", serverListProvider.getServerList().get(1));
|
||||
Field field =
|
||||
EndpointServerListProvider.class.getDeclaredField("lastServerListRefreshTime");
|
||||
field.setAccessible(true);
|
||||
field.set(serverListProvider, 0L);
|
||||
// wait refresh
|
||||
TimeUnit.MILLISECONDS.sleep(2000);
|
||||
assertEquals(2, serverListProvider.getServerList().size());
|
||||
assertEquals("127.0.0.1:8848", serverListProvider.getServerList().get(0));
|
||||
assertEquals("localhost:9848", serverListProvider.getServerList().get(1));
|
||||
}
|
||||
|
||||
private void assertInit(String expectedEndpoint, int expectEndpointPort,
|
||||
String expectedEndpointContext,
|
||||
String expectedServiceName, String expectedNamespace, String expectedContextPath) {
|
||||
assertInit(expectedEndpoint, expectEndpointPort, expectedEndpointContext,
|
||||
expectedServiceName,
|
||||
expectedNamespace, expectedContextPath, null);
|
||||
}
|
||||
|
||||
private void assertInit(String expectedEndpoint, int expectEndpointPort,
|
||||
String expectedEndpointContext,
|
||||
String expectedServiceName, String expectedNamespace, String expectedContextPath,
|
||||
String expectedQuery) {
|
||||
String expectedAddressServerUrl = String.format("http://%s:%d%s/%s", expectedEndpoint,
|
||||
expectEndpointPort,
|
||||
ContextPathUtil.normalizeContextPath(expectedEndpointContext), expectedServiceName);
|
||||
assertEquals(Constants.Address.ENDPOINT_SERVER_LIST_PROVIDER_ORDER,
|
||||
serverListProvider.getOrder());
|
||||
String expectedServerName =
|
||||
String.format("%s-%s_%d_%s_%s", "custom", expectedEndpoint, expectEndpointPort,
|
||||
expectedEndpointContext, expectedServiceName);
|
||||
if (StringUtils.isNotBlank(expectedNamespace)) {
|
||||
expectedServerName = String.format("%s_%s", expectedServerName, expectedNamespace);
|
||||
expectedAddressServerUrl += "?namespace=" + expectedNamespace;
|
||||
}
|
||||
if (StringUtils.isNotBlank(expectedQuery)) {
|
||||
String queryTag = StringUtils.isBlank(expectedNamespace) ? "?" : "&";
|
||||
expectedAddressServerUrl += queryTag + expectedQuery;
|
||||
}
|
||||
assertEquals(expectedAddressServerUrl, serverListProvider.getAddressSource());
|
||||
assertEquals(expectedServerName, serverListProvider.getServerName());
|
||||
assertEquals(expectedNamespace, serverListProvider.getNamespace());
|
||||
assertEquals(expectedContextPath, serverListProvider.getContextPath());
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.constant.Constants;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class PropertiesListProviderTest {
|
||||
|
||||
private PropertiesListProvider propertiesListProvider;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
propertiesListProvider = new PropertiesListProvider();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NacosException {
|
||||
propertiesListProvider.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithoutProperties() throws NacosException {
|
||||
assertThrows(NacosException.class, () -> propertiesListProvider.init(null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInit() throws NacosException {
|
||||
NacosClientProperties properties = NacosClientProperties.PROTOTYPE.derive();
|
||||
assertFalse(propertiesListProvider.match(properties));
|
||||
properties.setProperty(PropertyKeyConst.SERVER_ADDR,
|
||||
"localhost:1111,http://127.0.0.1:2222;https://1.1.1.1:3333,2.2.2.2;http://3.3.3.3,https://4.4.4.4");
|
||||
assertTrue(propertiesListProvider.match(properties));
|
||||
propertiesListProvider.init(properties, null);
|
||||
assertEquals(6, propertiesListProvider.getServerList().size());
|
||||
assertEquals("localhost:1111", propertiesListProvider.getServerList().get(0));
|
||||
assertEquals("http://127.0.0.1:2222", propertiesListProvider.getServerList().get(1));
|
||||
assertEquals("https://1.1.1.1:3333", propertiesListProvider.getServerList().get(2));
|
||||
assertEquals("2.2.2.2:8848", propertiesListProvider.getServerList().get(3));
|
||||
assertEquals("http://3.3.3.3", propertiesListProvider.getServerList().get(4));
|
||||
assertEquals("https://4.4.4.4", propertiesListProvider.getServerList().get(5));
|
||||
assertTrue(propertiesListProvider.isFixed());
|
||||
assertEquals(Constants.Address.ADDRESS_SERVER_LIST_PROVIDER_ORDER,
|
||||
propertiesListProvider.getOrder());
|
||||
assertEquals(
|
||||
"fixed-localhost_1111-127.0.0.1_2222-1.1.1.1_3333-2.2.2.2_8848-3.3.3.3-4.4.4.4",
|
||||
propertiesListProvider.getServerName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServerNameWithNamespace() throws NacosException {
|
||||
NacosClientProperties properties = NacosClientProperties.PROTOTYPE.derive();
|
||||
properties.setProperty(PropertyKeyConst.NAMESPACE, "test_namespace");
|
||||
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "localhost:1111");
|
||||
propertiesListProvider.init(properties, null);
|
||||
assertEquals("fixed-test_namespace-localhost_1111", propertiesListProvider.getServerName());
|
||||
assertEquals("test_namespace", propertiesListProvider.getNamespace());
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.address.mock;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.address.ServerListProvider;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MockServerListProvider implements ServerListProvider {
|
||||
|
||||
private NacosClientProperties properties;
|
||||
|
||||
@Override
|
||||
public void init(NacosClientProperties properties, NacosRestTemplate nacosRestTemplate)
|
||||
throws NacosException {
|
||||
this.properties = properties;
|
||||
nacosRestTemplate.getInterceptors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getServerList() {
|
||||
if (properties.containsKey("EmptyList")) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.singletonList("mock-server-list");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(NacosClientProperties properties) {
|
||||
return properties.containsKey("MockTest");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
if (isReturnMock()) {
|
||||
return "MockServerName";
|
||||
}
|
||||
return ServerListProvider.super.getServerName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
if (isReturnMock()) {
|
||||
return "MockNamespace";
|
||||
}
|
||||
return ServerListProvider.super.getNamespace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextPath() {
|
||||
if (isReturnMock()) {
|
||||
return "MockContextPath";
|
||||
}
|
||||
return ServerListProvider.super.getContextPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFixed() {
|
||||
if (isReturnMock()) {
|
||||
return true;
|
||||
}
|
||||
return ServerListProvider.super.isFixed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAddressSource() {
|
||||
if (isReturnMock()) {
|
||||
return "MockAddressSource";
|
||||
}
|
||||
return ServerListProvider.super.getAddressSource();
|
||||
}
|
||||
|
||||
private boolean isReturnMock() {
|
||||
return properties.getBoolean("ReturnMock", false);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 1999-2026 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.impl;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
class NacosAuthLoginConstantTest {
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
assertNotNull(new NacosAuthLoginConstant());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFields() {
|
||||
assertEquals("accessToken", NacosAuthLoginConstant.ACCESSTOKEN);
|
||||
assertEquals("tokenTtl", NacosAuthLoginConstant.TOKENTTL);
|
||||
assertEquals("tokenRefreshWindow", NacosAuthLoginConstant.TOKENREFRESHWINDOW);
|
||||
assertEquals("username", NacosAuthLoginConstant.USERNAME);
|
||||
assertEquals("password", NacosAuthLoginConstant.PASSWORD);
|
||||
assertEquals(":", NacosAuthLoginConstant.COLON);
|
||||
assertEquals("server", NacosAuthLoginConstant.SERVER);
|
||||
assertEquals("reLoginFlag", NacosAuthLoginConstant.RELOGINFLAG);
|
||||
}
|
||||
}
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.impl;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.common.http.HttpRestResult;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.http.param.Header;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class NacosClientAuthServiceImplTest {
|
||||
|
||||
@Test
|
||||
void testLoginSuccess() throws Exception {
|
||||
//given
|
||||
NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class);
|
||||
HttpRestResult<Object> result = new HttpRestResult<>();
|
||||
result.setData("{\"accessToken\":\"ttttttttttttttttt\",\"tokenTtl\":1000}");
|
||||
result.setCode(200);
|
||||
when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any()))
|
||||
.thenReturn(result);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.setServerList(serverList);
|
||||
nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate);
|
||||
//when
|
||||
boolean ret = nacosClientAuthService.login(properties);
|
||||
//then
|
||||
assertTrue(ret);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTestLoginFailCode() throws Exception {
|
||||
NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class);
|
||||
HttpRestResult<Object> result = new HttpRestResult<>();
|
||||
result.setCode(400);
|
||||
when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any()))
|
||||
.thenReturn(result);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.setServerList(serverList);
|
||||
nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate);
|
||||
boolean ret = nacosClientAuthService.login(properties);
|
||||
assertFalse(ret);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTestLoginFailHttp() throws Exception {
|
||||
NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class);
|
||||
when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any()))
|
||||
.thenThrow(new Exception());
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.setServerList(serverList);
|
||||
nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate);
|
||||
boolean ret = nacosClientAuthService.login(properties);
|
||||
assertFalse(ret);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTestLoginServerListSuccess() throws Exception {
|
||||
//given
|
||||
NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class);
|
||||
HttpRestResult<Object> result = new HttpRestResult<>();
|
||||
result.setData("{\"accessToken\":\"ttttttttttttttttt\",\"tokenTtl\":1000}");
|
||||
result.setCode(200);
|
||||
when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any()))
|
||||
.thenReturn(result);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
serverList.add("localhost");
|
||||
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.setServerList(serverList);
|
||||
nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate);
|
||||
boolean ret = nacosClientAuthService.login(properties);
|
||||
assertTrue(ret);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTestLoginServerListLoginInWindow() throws Exception {
|
||||
//given
|
||||
NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class);
|
||||
HttpRestResult<Object> result = new HttpRestResult<>();
|
||||
result.setData("{\"accessToken\":\"ttttttttttttttttt\",\"tokenTtl\":1000}");
|
||||
result.setCode(200);
|
||||
when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any()))
|
||||
.thenReturn(result);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.setServerList(serverList);
|
||||
nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate);
|
||||
//when
|
||||
nacosClientAuthService.login(properties);
|
||||
//then
|
||||
boolean ret = nacosClientAuthService.login(properties);
|
||||
assertTrue(ret);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccessToken() throws Exception {
|
||||
NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class);
|
||||
HttpRestResult<Object> result = new HttpRestResult<>();
|
||||
result.setData("{\"accessToken\":\"abc\",\"tokenTtl\":1000}");
|
||||
result.setCode(200);
|
||||
when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any()))
|
||||
.thenReturn(result);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.setServerList(serverList);
|
||||
nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate);
|
||||
//when
|
||||
assertTrue(nacosClientAuthService.login(properties));
|
||||
//then
|
||||
assertEquals("abc",
|
||||
nacosClientAuthService.getLoginIdentityContext(null)
|
||||
.getParameter(NacosAuthLoginConstant.ACCESSTOKEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccessEmptyToken() throws Exception {
|
||||
NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class);
|
||||
HttpRestResult<Object> result = new HttpRestResult<>();
|
||||
result.setData("{\"accessToken\":\"\",\"tokenTtl\":1000}");
|
||||
result.setCode(200);
|
||||
when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any()))
|
||||
.thenReturn(result);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.setServerList(serverList);
|
||||
nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate);
|
||||
//when
|
||||
assertTrue(nacosClientAuthService.login(properties));
|
||||
//then
|
||||
assertEquals("",
|
||||
nacosClientAuthService.getLoginIdentityContext(null)
|
||||
.getParameter(NacosAuthLoginConstant.ACCESSTOKEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccessTokenWithoutToken() throws Exception {
|
||||
NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class);
|
||||
HttpRestResult<Object> result = new HttpRestResult<>();
|
||||
result.setData("{\"tokenTtl\":1000}");
|
||||
result.setCode(200);
|
||||
when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any()))
|
||||
.thenReturn(result);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.setServerList(serverList);
|
||||
nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate);
|
||||
//when
|
||||
assertTrue(nacosClientAuthService.login(properties));
|
||||
//then
|
||||
assertNull(
|
||||
nacosClientAuthService.getLoginIdentityContext(null)
|
||||
.getParameter(NacosAuthLoginConstant.ACCESSTOKEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAccessTokenWithInvalidTtl() throws Exception {
|
||||
NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class);
|
||||
HttpRestResult<Object> result = new HttpRestResult<>();
|
||||
result.setData("{\"accessToken\":\"abc\",\"tokenTtl\":\"abc\"}");
|
||||
result.setCode(200);
|
||||
when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any()))
|
||||
.thenReturn(result);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.setServerList(serverList);
|
||||
nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate);
|
||||
//when
|
||||
assertFalse(nacosClientAuthService.login(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReLogin() {
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
nacosClientAuthService.login(new Properties());
|
||||
// reLogin
|
||||
nacosClientAuthService.getLoginIdentityContext(null)
|
||||
.setParameter(NacosAuthLoginConstant.RELOGINFLAG, "true");
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.USERNAME, "aaa");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "123456");
|
||||
List<String> serverList = new ArrayList<>();
|
||||
serverList.add("localhost");
|
||||
//when
|
||||
assertTrue(nacosClientAuthService.login(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateTokenWithInvalidToken() {
|
||||
NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl();
|
||||
long tokenTtl = 18000L;
|
||||
long tokenRefreshWindow = nacosClientAuthService.generateTokenRefreshWindow(tokenTtl);
|
||||
assertTrue(tokenRefreshWindow <= tokenTtl / 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShutdownDoesNotThrow() {
|
||||
NacosClientAuthServiceImpl service = new NacosClientAuthServiceImpl();
|
||||
org.junit.jupiter.api.Assertions.assertDoesNotThrow(service::shutdown);
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.impl.process;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.auth.impl.NacosAuthLoginConstant;
|
||||
import com.alibaba.nacos.common.http.HttpRestResult;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.http.param.Header;
|
||||
import com.alibaba.nacos.common.http.param.Query;
|
||||
import com.alibaba.nacos.common.tls.TlsSystemConfig;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class HttpLoginProcessorTest {
|
||||
|
||||
@Mock
|
||||
NacosRestTemplate restTemplate;
|
||||
|
||||
@Mock
|
||||
HttpRestResult result;
|
||||
|
||||
Properties properties;
|
||||
|
||||
HttpLoginProcessor loginProcessor;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
loginProcessor = new HttpLoginProcessor(restTemplate);
|
||||
properties = new Properties();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetResponseSuccess() throws Exception {
|
||||
properties.setProperty(NacosAuthLoginConstant.SERVER, "http://localhost:8848");
|
||||
when(restTemplate.postForm(eq("http://localhost:8848/nacos/v3/auth/user/login"),
|
||||
eq(Header.EMPTY),
|
||||
any(Query.class), anyMap(), eq(String.class))).thenReturn(result);
|
||||
when(result.ok()).thenReturn(true);
|
||||
Map<String, String> mockMap = new HashMap<>();
|
||||
mockMap.put(Constants.ACCESS_TOKEN, "mock_access_token");
|
||||
mockMap.put(Constants.TOKEN_TTL, "100L");
|
||||
when(result.getData()).thenReturn(JacksonUtils.toJson(mockMap));
|
||||
LoginIdentityContext actual = loginProcessor.getResponse(properties);
|
||||
assertEquals("mock_access_token", actual.getParameter(NacosAuthLoginConstant.ACCESSTOKEN));
|
||||
assertEquals("100L", actual.getParameter(NacosAuthLoginConstant.TOKENTTL));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetResponseFailed() throws Exception {
|
||||
properties.setProperty(NacosAuthLoginConstant.SERVER, "localhost");
|
||||
when(restTemplate.postForm(eq("http://localhost:8848/nacos/v3/auth/user/login"),
|
||||
eq(Header.EMPTY),
|
||||
any(Query.class), anyMap(), eq(String.class))).thenReturn(result);
|
||||
assertNull(loginProcessor.getResponse(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetResponseException() throws Exception {
|
||||
properties.setProperty(NacosAuthLoginConstant.SERVER, "localhost");
|
||||
when(restTemplate.postForm(eq("http://localhost:8848/nacos/v3/auth/user/login"),
|
||||
eq(Header.EMPTY),
|
||||
any(Query.class), anyMap(), eq(String.class)))
|
||||
.thenThrow(new RuntimeException("test"));
|
||||
assertNull(loginProcessor.getResponse(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetResponseUsesHttpsWhenTlsEnabled() throws Exception {
|
||||
String previousTlsEnable = System.getProperty(TlsSystemConfig.TLS_ENABLE);
|
||||
System.setProperty(TlsSystemConfig.TLS_ENABLE, "true");
|
||||
try {
|
||||
properties.setProperty(NacosAuthLoginConstant.SERVER, "localhost");
|
||||
when(restTemplate.postForm(anyString(),
|
||||
eq(Header.EMPTY),
|
||||
any(Query.class), anyMap(), eq(String.class))).thenReturn(result);
|
||||
assertNull(loginProcessor.getResponse(properties));
|
||||
verify(restTemplate).postForm(eq("https://localhost:8848/nacos/v3/auth/user/login"),
|
||||
eq(Header.EMPTY), any(Query.class), anyMap(), eq(String.class));
|
||||
} finally {
|
||||
if (previousTlsEnable == null) {
|
||||
System.clearProperty(TlsSystemConfig.TLS_ENABLE);
|
||||
} else {
|
||||
System.setProperty(TlsSystemConfig.TLS_ENABLE, previousTlsEnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetResponseSuccessFromV1() throws Exception {
|
||||
properties.setProperty(NacosAuthLoginConstant.SERVER, "localhost");
|
||||
HttpRestResult httpRes = new HttpRestResult<>();
|
||||
httpRes.setCode(NacosException.SERVER_NOT_IMPLEMENTED);
|
||||
when(restTemplate.postForm(eq("http://localhost:8848/nacos/v3/auth/user/login"),
|
||||
eq(Header.EMPTY),
|
||||
any(Query.class), anyMap(), eq(String.class))).thenReturn(httpRes);
|
||||
when(result.ok()).thenReturn(true);
|
||||
Map<String, String> mockMap = new HashMap<>();
|
||||
mockMap.put(Constants.ACCESS_TOKEN, "mock_access_token");
|
||||
mockMap.put(Constants.TOKEN_TTL, "100L");
|
||||
when(result.getData()).thenReturn(JacksonUtils.toJson(mockMap));
|
||||
when(restTemplate.postForm(eq("http://localhost:8848/nacos/v1/auth/users/login"),
|
||||
eq(Header.EMPTY),
|
||||
any(Query.class), anyMap(), eq(String.class))).thenReturn(result);
|
||||
LoginIdentityContext actual = loginProcessor.getResponse(properties);
|
||||
assertEquals("mock_access_token", actual.getParameter(NacosAuthLoginConstant.ACCESSTOKEN));
|
||||
assertEquals("100L", actual.getParameter(NacosAuthLoginConstant.TOKENTTL));
|
||||
}
|
||||
}
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.oidc;
|
||||
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import com.alibaba.nacos.plugin.auth.constant.OidcProtocolConstants;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test for {@link OidcClientAuthServiceImpl}.
|
||||
*
|
||||
* @author wangzji
|
||||
*/
|
||||
class OidcClientAuthServiceImplTest {
|
||||
|
||||
private OidcClientAuthServiceImpl oidcClientAuthService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
oidcClientAuthService = new OidcClientAuthServiceImpl();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginWithoutOidcConfig() {
|
||||
// Given: no OIDC properties configured
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("serverAddr", "localhost:8848");
|
||||
properties.setProperty("username", "nacos");
|
||||
properties.setProperty("password", "nacos");
|
||||
|
||||
// When
|
||||
boolean result = oidcClientAuthService.login(properties);
|
||||
|
||||
// Then: should succeed silently (OIDC not configured, let other plugins handle)
|
||||
assertTrue(result);
|
||||
|
||||
// LoginIdentityContext should not contain accessToken
|
||||
LoginIdentityContext ctx = oidcClientAuthService.getLoginIdentityContext(
|
||||
RequestResource.configBuilder().build());
|
||||
assertNotNull(ctx);
|
||||
assertNull(ctx.getParameter(OidcProtocolConstants.ACCESS_TOKEN_PARAM));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginWithoutOidcConfigSkipsOnSubsequentCalls() {
|
||||
// Given: no OIDC properties configured
|
||||
Properties properties = new Properties();
|
||||
|
||||
// When: call login multiple times
|
||||
boolean result1 = oidcClientAuthService.login(properties);
|
||||
boolean result2 = oidcClientAuthService.login(properties);
|
||||
|
||||
// Then: both should succeed
|
||||
assertTrue(result1);
|
||||
assertTrue(result2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginWithPartialOidcConfigMissingSecret() {
|
||||
// Given: only client-id but no client-secret
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, "https://idp.example.com");
|
||||
|
||||
// When
|
||||
boolean result = oidcClientAuthService.login(properties);
|
||||
|
||||
// Then: should succeed (incomplete OIDC config, skip)
|
||||
assertTrue(result);
|
||||
LoginIdentityContext ctx = oidcClientAuthService.getLoginIdentityContext(
|
||||
RequestResource.configBuilder().build());
|
||||
assertNull(ctx.getParameter(OidcProtocolConstants.ACCESS_TOKEN_PARAM));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginWithPartialOidcConfigMissingEndpoint() {
|
||||
// Given: client-id and secret but no issuer-uri or token-endpoint
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
|
||||
// When
|
||||
boolean result = oidcClientAuthService.login(properties);
|
||||
|
||||
// Then: should succeed (incomplete OIDC config, skip)
|
||||
assertTrue(result);
|
||||
LoginIdentityContext ctx = oidcClientAuthService.getLoginIdentityContext(
|
||||
RequestResource.configBuilder().build());
|
||||
assertNull(ctx.getParameter(OidcProtocolConstants.ACCESS_TOKEN_PARAM));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLoginIdentityContextReturnsEmptyByDefault() {
|
||||
LoginIdentityContext ctx = oidcClientAuthService.getLoginIdentityContext(
|
||||
RequestResource.configBuilder().build());
|
||||
assertNotNull(ctx);
|
||||
}
|
||||
|
||||
private HttpServer httpServer;
|
||||
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
if (httpServer != null) {
|
||||
httpServer.stop(0);
|
||||
httpServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeJson(HttpExchange exchange, int status, String body)
|
||||
throws IOException {
|
||||
byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
|
||||
exchange.sendResponseHeaders(status, bytes.length);
|
||||
try (OutputStream os = exchange.getResponseBody()) {
|
||||
os.write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private void startServer(String path, HttpHandler handler) throws IOException {
|
||||
httpServer = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
|
||||
httpServer.createContext(path, handler);
|
||||
httpServer.start();
|
||||
}
|
||||
|
||||
private String baseUri() {
|
||||
return "http://127.0.0.1:" + httpServer.getAddress().getPort();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginFullFlowSuccess() throws Exception {
|
||||
startServer("/", exchange -> {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
if (path.endsWith("/.well-known/openid-configuration")) {
|
||||
writeJson(exchange, 200, "{\"token_endpoint\":\"" + baseUri() + "/token\"}");
|
||||
} else if (path.endsWith("/token")) {
|
||||
writeJson(exchange, 200, "{\"access_token\":\"abc\",\"expires_in\":3600}");
|
||||
} else {
|
||||
writeJson(exchange, 404, "");
|
||||
}
|
||||
});
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, baseUri());
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
|
||||
assertTrue(oidcClientAuthService.login(properties));
|
||||
|
||||
LoginIdentityContext ctx = oidcClientAuthService.getLoginIdentityContext(
|
||||
RequestResource.configBuilder().build());
|
||||
assertEquals("abc", ctx.getParameter(OidcProtocolConstants.ACCESS_TOKEN_PARAM));
|
||||
assertEquals(OidcProtocolConstants.BEARER_PREFIX + "abc",
|
||||
ctx.getParameter(OidcProtocolConstants.AUTHORIZATION_HEADER));
|
||||
|
||||
// second call: token still fresh, no refresh needed → still success
|
||||
assertTrue(oidcClientAuthService.login(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginDiscoveryFails() throws Exception {
|
||||
startServer("/.well-known/openid-configuration",
|
||||
exchange -> writeJson(exchange, 500, ""));
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, baseUri());
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
|
||||
assertFalse(oidcClientAuthService.login(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginTokenFetchFails() throws Exception {
|
||||
startServer("/", exchange -> {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
if (path.endsWith("/.well-known/openid-configuration")) {
|
||||
writeJson(exchange, 200, "{\"token_endpoint\":\"" + baseUri() + "/token\"}");
|
||||
} else {
|
||||
writeJson(exchange, 500, "");
|
||||
}
|
||||
});
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, baseUri());
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
|
||||
assertFalse(oidcClientAuthService.login(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginCatchesUnexpectedException() {
|
||||
// Pass a Properties impl that throws on getProperty to trigger the catch (Throwable) block
|
||||
Properties properties = new Properties() {
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
throw new RuntimeException("boom");
|
||||
}
|
||||
};
|
||||
assertFalse(oidcClientAuthService.login(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShutdownDoesNotThrow() {
|
||||
Assertions.assertDoesNotThrow(oidcClientAuthService::shutdown);
|
||||
}
|
||||
}
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.oidc;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test for {@link OidcClientContext}.
|
||||
*
|
||||
* @author wangzji
|
||||
*/
|
||||
class OidcClientContextTest {
|
||||
|
||||
private OidcClientContext context;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
context = new OidcClientContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithFullConfig() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI,
|
||||
"https://idp.example.com/realms/test");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
properties.setProperty(OidcClientConstants.PROP_SCOPE, "openid profile");
|
||||
|
||||
boolean configured = context.init(properties);
|
||||
|
||||
assertTrue(configured);
|
||||
assertTrue(context.isConfigured());
|
||||
assertEquals("https://idp.example.com/realms/test", context.getIssuerUri());
|
||||
assertEquals("my-client", context.getClientId());
|
||||
assertEquals("my-secret", context.getClientSecret());
|
||||
assertEquals("openid profile", context.getScope());
|
||||
assertFalse(context.isDiscovered());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithDefaultScope() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, "https://idp.example.com");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
|
||||
boolean configured = context.init(properties);
|
||||
|
||||
assertTrue(configured);
|
||||
assertEquals(OidcClientConstants.DEFAULT_SCOPE, context.getScope());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithDirectTokenEndpoint() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
properties.setProperty(OidcClientConstants.PROP_TOKEN_ENDPOINT,
|
||||
"https://idp.example.com/token");
|
||||
|
||||
boolean configured = context.init(properties);
|
||||
|
||||
assertTrue(configured);
|
||||
assertTrue(context.isDiscovered()); // discovery is skipped
|
||||
assertEquals("https://idp.example.com/token", context.getTokenEndpoint());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithEmptyConfig() {
|
||||
Properties properties = new Properties();
|
||||
|
||||
boolean configured = context.init(properties);
|
||||
|
||||
assertFalse(configured);
|
||||
assertFalse(context.isConfigured());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithOnlyClientId() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
|
||||
boolean configured = context.init(properties);
|
||||
|
||||
assertFalse(configured);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithClientCredentialsButNoEndpoint() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
|
||||
boolean configured = context.init(properties);
|
||||
|
||||
assertFalse(configured, "Should not be configured without issuer-uri or token-endpoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverWithoutIssuerUri() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
context.init(properties);
|
||||
|
||||
boolean result = context.discover();
|
||||
|
||||
assertFalse(result, "Discovery should fail without issuer-uri");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverSkipsIfAlreadyDone() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
properties.setProperty(OidcClientConstants.PROP_TOKEN_ENDPOINT,
|
||||
"https://idp.example.com/token");
|
||||
context.init(properties);
|
||||
|
||||
// Already discovered via direct token endpoint
|
||||
assertTrue(context.isDiscovered());
|
||||
boolean result = context.discover();
|
||||
assertTrue(result, "Should return true when already discovered");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverWithInvalidUrl() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, "http://0.0.0.0");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
context.init(properties);
|
||||
|
||||
boolean result = context.discover();
|
||||
|
||||
assertFalse(result, "Discovery should fail with invalid URL");
|
||||
}
|
||||
|
||||
private HttpServer httpServer;
|
||||
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
if (httpServer != null) {
|
||||
httpServer.stop(0);
|
||||
httpServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void startServer(String path, HttpHandler handler) throws IOException {
|
||||
httpServer = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
|
||||
httpServer.createContext(path, handler);
|
||||
httpServer.start();
|
||||
}
|
||||
|
||||
private String baseIssuerUri() {
|
||||
return "http://127.0.0.1:" + httpServer.getAddress().getPort();
|
||||
}
|
||||
|
||||
private static void writeJson(HttpExchange exchange, int status, String body)
|
||||
throws IOException {
|
||||
byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
|
||||
exchange.sendResponseHeaders(status, bytes.length);
|
||||
try (OutputStream os = exchange.getResponseBody()) {
|
||||
os.write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverSuccess() throws Exception {
|
||||
startServer("/.well-known/openid-configuration", exchange -> writeJson(exchange, 200,
|
||||
"{\"token_endpoint\":\"http://idp.example.com/token\"}"));
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, baseIssuerUri());
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
context.init(properties);
|
||||
assertTrue(context.discover());
|
||||
assertTrue(context.isDiscovered());
|
||||
assertEquals("http://idp.example.com/token", context.getTokenEndpoint());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverSuccessWithTrailingSlashIssuer() throws Exception {
|
||||
startServer("/.well-known/openid-configuration", exchange -> writeJson(exchange, 200,
|
||||
"{\"token_endpoint\":\"http://idp.example.com/token\"}"));
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, baseIssuerUri() + "/");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
context.init(properties);
|
||||
assertTrue(context.discover());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverHttpErrorReturnsFalse() throws Exception {
|
||||
startServer("/.well-known/openid-configuration",
|
||||
exchange -> writeJson(exchange, 500, "boom"));
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, baseIssuerUri());
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
context.init(properties);
|
||||
assertFalse(context.discover());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverMissingTokenEndpointReturnsFalse() throws Exception {
|
||||
startServer("/.well-known/openid-configuration",
|
||||
exchange -> writeJson(exchange, 200, "{\"issuer\":\"x\"}"));
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, baseIssuerUri());
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
context.init(properties);
|
||||
assertFalse(context.discover());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverNullTokenEndpointReturnsFalse() throws Exception {
|
||||
startServer("/.well-known/openid-configuration",
|
||||
exchange -> writeJson(exchange, 200, "{\"token_endpoint\":null}"));
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, baseIssuerUri());
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "my-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "my-secret");
|
||||
context.init(properties);
|
||||
assertFalse(context.discover());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReadInputStreamAsString() throws Exception {
|
||||
String payload = "abcdef-数据";
|
||||
ByteArrayInputStream bis =
|
||||
new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8));
|
||||
assertEquals(payload, OidcClientContext.readInputStreamAsString(bis));
|
||||
}
|
||||
}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.oidc;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test for {@link OidcTokenHolder}.
|
||||
*
|
||||
* @author wangzji
|
||||
*/
|
||||
class OidcTokenHolderTest {
|
||||
|
||||
private OidcTokenHolder tokenHolder;
|
||||
|
||||
private HttpServer httpServer;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
tokenHolder = new OidcTokenHolder();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
if (httpServer != null) {
|
||||
httpServer.stop(0);
|
||||
httpServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private OidcClientContext newContextWithEndpoint(String tokenEndpoint) {
|
||||
OidcClientContext context = new OidcClientContext();
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, "http://example.com");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "test-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "test-secret");
|
||||
properties.setProperty(OidcClientConstants.PROP_TOKEN_ENDPOINT, tokenEndpoint);
|
||||
context.init(properties);
|
||||
return context;
|
||||
}
|
||||
|
||||
private OidcClientContext newContextWithEndpointAndScope(String tokenEndpoint, String scope) {
|
||||
OidcClientContext context = new OidcClientContext();
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(OidcClientConstants.PROP_ISSUER_URI, "http://example.com");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_ID, "test-client");
|
||||
properties.setProperty(OidcClientConstants.PROP_CLIENT_SECRET, "test-secret");
|
||||
properties.setProperty(OidcClientConstants.PROP_TOKEN_ENDPOINT, tokenEndpoint);
|
||||
properties.setProperty(OidcClientConstants.PROP_SCOPE, scope);
|
||||
context.init(properties);
|
||||
return context;
|
||||
}
|
||||
|
||||
private void startServer(HttpHandler handler) throws IOException {
|
||||
httpServer = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
|
||||
httpServer.createContext("/token", handler);
|
||||
httpServer.start();
|
||||
}
|
||||
|
||||
private String tokenEndpointUrl() {
|
||||
return "http://127.0.0.1:" + httpServer.getAddress().getPort() + "/token";
|
||||
}
|
||||
|
||||
private static void writeResponse(HttpExchange exchange, int status, String body)
|
||||
throws IOException {
|
||||
byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
|
||||
exchange.sendResponseHeaders(status, bytes.length);
|
||||
try (OutputStream os = exchange.getResponseBody()) {
|
||||
os.write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitialStateNeedsRefresh() {
|
||||
// Token holder starts with no token
|
||||
assertNull(tokenHolder.getAccessToken());
|
||||
assertTrue(tokenHolder.isExpiredOrNeedRefresh());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenWithNullEndpoint() {
|
||||
OidcClientContext context = new OidcClientContext();
|
||||
// context has no token endpoint
|
||||
boolean result = tokenHolder.fetchToken(context);
|
||||
assertFalse(result, "Should fail when token endpoint is null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateTokenRefreshWindowWithZeroTtl() {
|
||||
long window = tokenHolder.generateTokenRefreshWindow(0);
|
||||
assertTrue(window == 0, "Window should be 0 for TTL 0");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateTokenRefreshWindowWithNegativeTtl() {
|
||||
long window = tokenHolder.generateTokenRefreshWindow(-1);
|
||||
assertTrue(window == 0, "Window should be 0 for negative TTL");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateTokenRefreshWindowWithNormalTtl() {
|
||||
// TTL = 300s => startNumber = 300/15 = 20, endNumber = 300/10 = 30
|
||||
long window = tokenHolder.generateTokenRefreshWindow(300);
|
||||
assertTrue(window >= 20 && window < 30,
|
||||
"Window should be in range [20, 30), got: " + window);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateTokenRefreshWindowWithSmallTtl() {
|
||||
// TTL = 10s => startNumber = 0, endNumber = 1
|
||||
long window = tokenHolder.generateTokenRefreshWindow(10);
|
||||
assertTrue(window >= 0 && window <= 1,
|
||||
"Window should be 0 or 1 for TTL 10, got: " + window);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateTokenRefreshWindowWithVerySmallTtl() {
|
||||
// TTL = 5s => startNumber = 0, endNumber = 0 => falls to startNumber
|
||||
long window = tokenHolder.generateTokenRefreshWindow(5);
|
||||
assertTrue(window == 0, "Window should be 0 for very small TTL, got: " + window);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenSuccess() throws Exception {
|
||||
startServer(exchange -> writeResponse(exchange, 200,
|
||||
"{\"access_token\":\"abc123\",\"expires_in\":600}"));
|
||||
OidcClientContext context = newContextWithEndpoint(tokenEndpointUrl());
|
||||
assertTrue(tokenHolder.fetchToken(context));
|
||||
assertEquals("abc123", tokenHolder.getAccessToken());
|
||||
assertEquals(600, tokenHolder.getExpiresInSeconds());
|
||||
assertTrue(tokenHolder.getObtainedAtMs() > 0);
|
||||
assertFalse(tokenHolder.isExpiredOrNeedRefresh());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenSuccessWithScope() throws Exception {
|
||||
AtomicReference<String> bodyRef = new AtomicReference<>();
|
||||
startServer(exchange -> {
|
||||
byte[] buf = new byte[4096];
|
||||
int n = exchange.getRequestBody().read(buf);
|
||||
bodyRef.set(new String(buf, 0, Math.max(n, 0), StandardCharsets.UTF_8));
|
||||
writeResponse(exchange, 200,
|
||||
"{\"access_token\":\"with-scope\",\"expires_in\":120}");
|
||||
});
|
||||
OidcClientContext context = newContextWithEndpointAndScope(tokenEndpointUrl(),
|
||||
"openid profile");
|
||||
assertTrue(tokenHolder.fetchToken(context));
|
||||
assertEquals("with-scope", tokenHolder.getAccessToken());
|
||||
assertNotNull(bodyRef.get());
|
||||
assertTrue(bodyRef.get().contains("scope=openid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenWithMissingExpiresInUsesDefault() throws Exception {
|
||||
startServer(exchange -> writeResponse(exchange, 200,
|
||||
"{\"access_token\":\"no-expires\"}"));
|
||||
OidcClientContext context = newContextWithEndpoint(tokenEndpointUrl());
|
||||
assertTrue(tokenHolder.fetchToken(context));
|
||||
assertEquals(300L, tokenHolder.getExpiresInSeconds());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenServerErrorReturnsFalse() throws Exception {
|
||||
startServer(exchange -> writeResponse(exchange, 500, "{\"error\":\"server\"}"));
|
||||
OidcClientContext context = newContextWithEndpoint(tokenEndpointUrl());
|
||||
assertFalse(tokenHolder.fetchToken(context));
|
||||
assertNull(tokenHolder.getAccessToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenServerErrorWithoutBodyReturnsFalse() throws Exception {
|
||||
startServer(exchange -> {
|
||||
// 401 with no body
|
||||
exchange.sendResponseHeaders(401, -1);
|
||||
exchange.close();
|
||||
});
|
||||
OidcClientContext context = newContextWithEndpoint(tokenEndpointUrl());
|
||||
assertFalse(tokenHolder.fetchToken(context));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenIoExceptionReturnsFalse() {
|
||||
// Use unreachable port (0 means kernel-chosen, but here we use 1 which usually fails)
|
||||
OidcClientContext context = newContextWithEndpoint("http://127.0.0.1:1/token");
|
||||
assertFalse(tokenHolder.fetchToken(context));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenInvalidJsonReturnsFalse() throws Exception {
|
||||
startServer(exchange -> writeResponse(exchange, 200, "not-json{"));
|
||||
OidcClientContext context = newContextWithEndpoint(tokenEndpointUrl());
|
||||
assertFalse(tokenHolder.fetchToken(context));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenMissingAccessTokenReturnsFalse() throws Exception {
|
||||
startServer(exchange -> writeResponse(exchange, 200, "{\"expires_in\":300}"));
|
||||
OidcClientContext context = newContextWithEndpoint(tokenEndpointUrl());
|
||||
assertFalse(tokenHolder.fetchToken(context));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchTokenAccessTokenIsNullReturnsFalse() throws Exception {
|
||||
startServer(exchange -> writeResponse(exchange, 200,
|
||||
"{\"access_token\":null,\"expires_in\":300}"));
|
||||
OidcClientContext context = newContextWithEndpoint(tokenEndpointUrl());
|
||||
assertFalse(tokenHolder.fetchToken(context));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsExpiredOrNeedRefreshAfterRecentFetch() throws Exception {
|
||||
startServer(exchange -> writeResponse(exchange, 200,
|
||||
"{\"access_token\":\"fresh\",\"expires_in\":3600}"));
|
||||
OidcClientContext context = newContextWithEndpoint(tokenEndpointUrl());
|
||||
assertTrue(tokenHolder.fetchToken(context));
|
||||
// freshly fetched 1h token should not need refresh
|
||||
assertFalse(tokenHolder.isExpiredOrNeedRefresh());
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.auth.ram.injector.AbstractResourceInjector;
|
||||
import com.alibaba.nacos.common.utils.ReflectUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class RamClientAuthServiceImplTest {
|
||||
|
||||
private static final String MOCK = "mock";
|
||||
|
||||
@Mock
|
||||
private AbstractResourceInjector mockResourceInjector;
|
||||
|
||||
private RamClientAuthServiceImpl ramClientAuthService;
|
||||
|
||||
private Properties akSkProperties;
|
||||
|
||||
private Properties roleProperties;
|
||||
|
||||
private RamContext ramContext;
|
||||
|
||||
private RequestResource resource;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
ramClientAuthService = new RamClientAuthServiceImpl();
|
||||
Map<String, AbstractResourceInjector> resourceInjectors =
|
||||
(Map<String, AbstractResourceInjector>) ReflectUtils.getFieldValue(
|
||||
ramClientAuthService, "resourceInjectors");
|
||||
resourceInjectors.clear();
|
||||
resourceInjectors.put(MOCK, mockResourceInjector);
|
||||
ramContext = (RamContext) ReflectUtils.getFieldValue(ramClientAuthService, "ramContext");
|
||||
akSkProperties = new Properties();
|
||||
roleProperties = new Properties();
|
||||
akSkProperties.setProperty(PropertyKeyConst.ACCESS_KEY, PropertyKeyConst.ACCESS_KEY);
|
||||
akSkProperties.setProperty(PropertyKeyConst.SECRET_KEY, PropertyKeyConst.SECRET_KEY);
|
||||
roleProperties.setProperty(PropertyKeyConst.RAM_ROLE_NAME, PropertyKeyConst.RAM_ROLE_NAME);
|
||||
resource = new RequestResource();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NacosException {
|
||||
ramClientAuthService.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginWithAkSk() {
|
||||
assertTrue(ramClientAuthService.login(akSkProperties));
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, ramContext.getAccessKey());
|
||||
assertEquals(PropertyKeyConst.SECRET_KEY, ramContext.getSecretKey());
|
||||
assertNull(ramContext.getRamRoleName());
|
||||
assertTrue(ramClientAuthService.login(roleProperties));
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, ramContext.getAccessKey());
|
||||
assertEquals(PropertyKeyConst.SECRET_KEY, ramContext.getSecretKey());
|
||||
assertNull(ramContext.getRamRoleName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoginWithRoleName() {
|
||||
assertTrue(ramClientAuthService.login(roleProperties));
|
||||
assertNull(ramContext.getAccessKey(), PropertyKeyConst.ACCESS_KEY);
|
||||
assertNull(ramContext.getSecretKey(), PropertyKeyConst.SECRET_KEY);
|
||||
assertEquals(PropertyKeyConst.RAM_ROLE_NAME, ramContext.getRamRoleName());
|
||||
assertTrue(ramClientAuthService.login(akSkProperties));
|
||||
assertNull(ramContext.getAccessKey(), PropertyKeyConst.ACCESS_KEY);
|
||||
assertNull(ramContext.getSecretKey(), PropertyKeyConst.SECRET_KEY);
|
||||
assertEquals(PropertyKeyConst.RAM_ROLE_NAME, ramContext.getRamRoleName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLoginIdentityContextWithoutLogin() {
|
||||
LoginIdentityContext actual = ramClientAuthService.getLoginIdentityContext(resource);
|
||||
assertTrue(actual.getAllKey().isEmpty());
|
||||
verify(mockResourceInjector, never()).doInject(resource, ramContext, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLoginIdentityContextWithoutInjector() {
|
||||
ramClientAuthService.login(akSkProperties);
|
||||
LoginIdentityContext actual = ramClientAuthService.getLoginIdentityContext(resource);
|
||||
assertTrue(actual.getAllKey().isEmpty());
|
||||
verify(mockResourceInjector, never()).doInject(resource, ramContext, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLoginIdentityContextWithInjector() {
|
||||
ramClientAuthService.login(akSkProperties);
|
||||
resource.setType(MOCK);
|
||||
LoginIdentityContext actual = ramClientAuthService.getLoginIdentityContext(resource);
|
||||
assertTrue(actual.getAllKey().isEmpty());
|
||||
verify(mockResourceInjector).doInject(resource, ramContext, actual);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 1999-2026 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
class RamConstantsTest {
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
assertNotNull(new RamConstants());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFields() {
|
||||
assertEquals("signatureVersion", RamConstants.SIGNATURE_VERSION);
|
||||
assertEquals("v4", RamConstants.V4);
|
||||
assertEquals("HmacSHA256", RamConstants.SIGNATURE_V4_METHOD);
|
||||
assertEquals("mse-nacos", RamConstants.SIGNATURE_V4_PRODUCE);
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
class CredentialServiceTest {
|
||||
|
||||
private static final String APP_NAME = "app";
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
CredentialService.freeInstance();
|
||||
CredentialService.freeInstance(APP_NAME);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
System.clearProperty(IdentifyConstants.PROJECT_NAME_PROPERTY);
|
||||
CredentialService.freeInstance();
|
||||
CredentialService.freeInstance(APP_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInstance() {
|
||||
CredentialService credentialService1 = CredentialService.getInstance();
|
||||
CredentialService credentialService2 = CredentialService.getInstance();
|
||||
assertEquals(credentialService1, credentialService2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInstance2() {
|
||||
CredentialService credentialService1 = CredentialService.getInstance(APP_NAME);
|
||||
CredentialService credentialService2 = CredentialService.getInstance(APP_NAME);
|
||||
assertEquals(credentialService1, credentialService2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInstance3() throws NoSuchFieldException, IllegalAccessException {
|
||||
System.setProperty(IdentifyConstants.PROJECT_NAME_PROPERTY, APP_NAME);
|
||||
CredentialService credentialService1 = CredentialService.getInstance();
|
||||
Field appNameField = credentialService1.getClass().getDeclaredField("appName");
|
||||
appNameField.setAccessible(true);
|
||||
String appName = (String) appNameField.get(credentialService1);
|
||||
assertEquals(APP_NAME, appName);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFreeInstance() {
|
||||
CredentialService credentialService1 = CredentialService.getInstance();
|
||||
CredentialService credentialService2 = CredentialService.freeInstance();
|
||||
assertEquals(credentialService1, credentialService2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFreeInstance2() {
|
||||
CredentialService credentialService1 = CredentialService.getInstance();
|
||||
CredentialService credentialService2 = CredentialService.freeInstance();
|
||||
assertEquals(credentialService1, credentialService2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFree() throws NoSuchFieldException, IllegalAccessException {
|
||||
CredentialService credentialService1 = CredentialService.getInstance();
|
||||
CredentialWatcher mockWatcher = mock(CredentialWatcher.class);
|
||||
Field watcherField = CredentialService.class.getDeclaredField("watcher");
|
||||
watcherField.setAccessible(true);
|
||||
watcherField.set(credentialService1, mockWatcher);
|
||||
//when
|
||||
credentialService1.free();
|
||||
//then
|
||||
verify(mockWatcher, times(1)).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetCredential() {
|
||||
CredentialService credentialService1 = CredentialService.getInstance();
|
||||
Credentials credential = credentialService1.getCredential();
|
||||
assertNotNull(credential);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetCredential() {
|
||||
CredentialService credentialService1 = CredentialService.getInstance();
|
||||
Credentials credential = new Credentials();
|
||||
//when
|
||||
credentialService1.setCredential(credential);
|
||||
//then
|
||||
assertEquals(credential, credentialService1.getCredential());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetStaticCredential() throws NoSuchFieldException, IllegalAccessException {
|
||||
CredentialService credentialService1 = CredentialService.getInstance();
|
||||
CredentialWatcher mockWatcher = mock(CredentialWatcher.class);
|
||||
Field watcherField = CredentialService.class.getDeclaredField("watcher");
|
||||
watcherField.setAccessible(true);
|
||||
watcherField.set(credentialService1, mockWatcher);
|
||||
Credentials credential = new Credentials();
|
||||
//when
|
||||
credentialService1.setStaticCredential(credential);
|
||||
//then
|
||||
assertEquals(credential, credentialService1.getCredential());
|
||||
verify(mockWatcher, times(1)).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRegisterCredentialListener() {
|
||||
CredentialListener expect = mock(CredentialListener.class);
|
||||
CredentialService credentialService1 = CredentialService.getInstance();
|
||||
credentialService1.registerCredentialListener(expect);
|
||||
Credentials newCredentials = new Credentials();
|
||||
newCredentials.setAccessKey("ak");
|
||||
credentialService1.setCredential(newCredentials);
|
||||
verify(expect, times(1)).onUpdateCredential();
|
||||
}
|
||||
}
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CredentialWatcherTest {
|
||||
|
||||
@Mock
|
||||
private CredentialService credentialService;
|
||||
|
||||
private CredentialWatcher credentialWatcher;
|
||||
|
||||
private Method loadCredentialMethod;
|
||||
|
||||
private Method loadCredentialFromPropertiesMethod;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
credentialWatcher = new CredentialWatcher("testApp", credentialService);
|
||||
loadCredentialMethod =
|
||||
CredentialWatcher.class.getDeclaredMethod("loadCredential", boolean.class);
|
||||
loadCredentialMethod.setAccessible(true);
|
||||
loadCredentialFromPropertiesMethod =
|
||||
CredentialWatcher.class.getDeclaredMethod("loadCredentialFromProperties",
|
||||
InputStream.class, boolean.class, Credentials.class);
|
||||
loadCredentialFromPropertiesMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
credentialWatcher.stop();
|
||||
System.clearProperty("spas.identity");
|
||||
System.clearProperty(IdentifyConstants.ENV_ACCESS_KEY);
|
||||
System.clearProperty(IdentifyConstants.ENV_SECRET_KEY);
|
||||
CredentialService.freeInstance();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStop() throws NoSuchFieldException, IllegalAccessException {
|
||||
credentialWatcher.stop();
|
||||
Field executorField = CredentialWatcher.class.getDeclaredField("executor");
|
||||
executorField.setAccessible(true);
|
||||
ScheduledExecutorService executor =
|
||||
(ScheduledExecutorService) executorField.get(credentialWatcher);
|
||||
assertTrue(executor.isShutdown());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadCredentialByEnv() throws InvocationTargetException, IllegalAccessException {
|
||||
System.setProperty(IdentifyConstants.ENV_ACCESS_KEY, "testAk");
|
||||
System.setProperty(IdentifyConstants.ENV_SECRET_KEY, "testSk");
|
||||
final AtomicReference<String> readAk = new AtomicReference<>("");
|
||||
final AtomicReference<String> readSK = new AtomicReference<>("");
|
||||
final AtomicReference<String> readTenantId = new AtomicReference<>("");
|
||||
doAnswer(invocationOnMock -> {
|
||||
Credentials credentials = invocationOnMock.getArgument(0, Credentials.class);
|
||||
readAk.set(credentials.getAccessKey());
|
||||
readSK.set(credentials.getSecretKey());
|
||||
readTenantId.set(credentials.getTenantId());
|
||||
return null;
|
||||
}).when(credentialService).setCredential(any());
|
||||
loadCredentialMethod.invoke(credentialWatcher, true);
|
||||
assertEquals("testAk", readAk.get());
|
||||
assertEquals("testSk", readSK.get());
|
||||
assertNull(readTenantId.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadCredentialByIdentityFile()
|
||||
throws InvocationTargetException, IllegalAccessException {
|
||||
URL url = CredentialWatcherTest.class.getClassLoader().getResource("spas.identity");
|
||||
System.setProperty("spas.identity", url.getPath());
|
||||
final AtomicReference<String> readAk = new AtomicReference<>("");
|
||||
final AtomicReference<String> readSK = new AtomicReference<>("");
|
||||
final AtomicReference<String> readTenantId = new AtomicReference<>("");
|
||||
doAnswer(invocationOnMock -> {
|
||||
Credentials credentials = invocationOnMock.getArgument(0, Credentials.class);
|
||||
readAk.set(credentials.getAccessKey());
|
||||
readSK.set(credentials.getSecretKey());
|
||||
readTenantId.set(credentials.getTenantId());
|
||||
return null;
|
||||
}).when(credentialService).setCredential(any());
|
||||
loadCredentialMethod.invoke(credentialWatcher, true);
|
||||
assertEquals("testAk", readAk.get());
|
||||
assertEquals("testSk", readSK.get());
|
||||
assertEquals("testTenantId", readTenantId.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadCredentialByInvalidIdentityFile()
|
||||
throws InvocationTargetException, IllegalAccessException {
|
||||
URL url = CredentialWatcherTest.class.getClassLoader().getResource("spas_invalid.identity");
|
||||
System.setProperty("spas.identity", url.getPath());
|
||||
final AtomicReference<String> readAk = new AtomicReference<>("");
|
||||
final AtomicReference<String> readSK = new AtomicReference<>("");
|
||||
final AtomicReference<String> readTenantId = new AtomicReference<>("");
|
||||
doAnswer(invocationOnMock -> {
|
||||
Credentials credentials = invocationOnMock.getArgument(0, Credentials.class);
|
||||
readAk.set(credentials.getAccessKey());
|
||||
readSK.set(credentials.getSecretKey());
|
||||
readTenantId.set(credentials.getTenantId());
|
||||
return null;
|
||||
}).when(credentialService).setCredential(any());
|
||||
loadCredentialMethod.invoke(credentialWatcher, true);
|
||||
assertEquals("", readAk.get());
|
||||
assertEquals("testSk", readSK.get());
|
||||
assertEquals("testTenantId", readTenantId.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* The docker file is need /etc permission, which depend environment. So use mock InputStream to test.
|
||||
*/
|
||||
@Test
|
||||
void testLoadCredentialByDockerFile()
|
||||
throws FileNotFoundException, InvocationTargetException, IllegalAccessException,
|
||||
NoSuchFieldException {
|
||||
URL url = CredentialWatcherTest.class.getClassLoader().getResource("spas_docker.identity");
|
||||
InputStream propertiesIS = new FileInputStream(url.getPath());
|
||||
Credentials actual = new Credentials();
|
||||
Field propertyPathField = CredentialWatcher.class.getDeclaredField("propertyPath");
|
||||
propertyPathField.setAccessible(true);
|
||||
propertyPathField.set(credentialWatcher, IdentifyConstants.DOCKER_CREDENTIAL_PATH);
|
||||
loadCredentialFromPropertiesMethod.invoke(credentialWatcher, propertiesIS, true, actual);
|
||||
assertEquals("testAk", actual.getAccessKey());
|
||||
assertEquals("testSk", actual.getSecretKey());
|
||||
assertEquals("testTenantId", actual.getTenantId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadCredentialByFileWithIoException()
|
||||
throws IOException, InvocationTargetException, IllegalAccessException {
|
||||
InputStream propertiesIS = mock(InputStream.class);
|
||||
when(propertiesIS.read(any())).thenThrow(new IOException("test"));
|
||||
doThrow(new IOException("test")).when(propertiesIS).close();
|
||||
Credentials actual = new Credentials();
|
||||
loadCredentialFromPropertiesMethod.invoke(credentialWatcher, propertiesIS, true, actual);
|
||||
assertNull(actual.getAccessKey());
|
||||
assertNull(actual.getSecretKey());
|
||||
assertNull(actual.getTenantId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReLoadCredential()
|
||||
throws InvocationTargetException, IllegalAccessException, InterruptedException {
|
||||
URL url =
|
||||
CredentialWatcherTest.class.getClassLoader().getResource("spas_modified.identity");
|
||||
modifiedFile(url, true);
|
||||
System.setProperty("spas.identity", url.getPath());
|
||||
final AtomicReference<String> readAk = new AtomicReference<>("");
|
||||
final AtomicReference<String> readSK = new AtomicReference<>("");
|
||||
final AtomicReference<String> readTenantId = new AtomicReference<>("");
|
||||
doAnswer(invocationOnMock -> {
|
||||
Credentials credentials = invocationOnMock.getArgument(0, Credentials.class);
|
||||
readAk.set(credentials.getAccessKey());
|
||||
readSK.set(credentials.getSecretKey());
|
||||
readTenantId.set(credentials.getTenantId());
|
||||
return null;
|
||||
}).when(credentialService).setCredential(any());
|
||||
loadCredentialMethod.invoke(credentialWatcher, true);
|
||||
assertEquals("testAk", readAk.get());
|
||||
assertEquals("testSk", readSK.get());
|
||||
assertNull(readTenantId.get());
|
||||
// waiting reload thread work
|
||||
modifiedFile(url, false);
|
||||
TimeUnit.MILLISECONDS.sleep(10500);
|
||||
assertEquals("testAk", readAk.get());
|
||||
assertEquals("testSk", readSK.get());
|
||||
assertEquals("testTenantId", readTenantId.get());
|
||||
}
|
||||
|
||||
private boolean modifiedFile(URL url, boolean init) {
|
||||
File file = new File(url.getPath());
|
||||
boolean result;
|
||||
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
|
||||
if (init) {
|
||||
bw.write("accessKey=testAk\nsecretKey=testSk");
|
||||
} else {
|
||||
bw.write("accessKey=testAk\nsecretKey=testSk\ntenantId=testTenantId");
|
||||
}
|
||||
bw.flush();
|
||||
result = true;
|
||||
} catch (IOException ignored) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class CredentialsTest {
|
||||
|
||||
@Test
|
||||
void testGetter() {
|
||||
// given
|
||||
String ak = "ak";
|
||||
String sk = "sk";
|
||||
String tenantId = "100";
|
||||
Credentials credentials = new Credentials(ak, sk, tenantId);
|
||||
// when then
|
||||
assertEquals(ak, credentials.getAccessKey());
|
||||
assertEquals(sk, credentials.getSecretKey());
|
||||
assertEquals(tenantId, credentials.getTenantId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetter() {
|
||||
//given
|
||||
String ak = "ak";
|
||||
String sk = "sk";
|
||||
String tenantId = "100";
|
||||
Credentials credentials = new Credentials();
|
||||
//when
|
||||
credentials.setAccessKey(ak);
|
||||
credentials.setSecretKey(sk);
|
||||
credentials.setTenantId(tenantId);
|
||||
//then
|
||||
assertEquals(ak, credentials.getAccessKey());
|
||||
assertEquals(sk, credentials.getSecretKey());
|
||||
assertEquals(tenantId, credentials.getTenantId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValid() {
|
||||
//given
|
||||
String ak = "ak";
|
||||
String sk = "sk";
|
||||
String tenantId = "100";
|
||||
Credentials credentials = new Credentials(ak, sk, tenantId);
|
||||
//when
|
||||
boolean actual = credentials.valid();
|
||||
//then
|
||||
assertTrue(actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIdentical() {
|
||||
//given
|
||||
String ak = "ak";
|
||||
String sk = "sk";
|
||||
String tenantId = "100";
|
||||
Credentials credentials1 = new Credentials(ak, sk, "101");
|
||||
Credentials credentials2 = new Credentials(ak, sk, "100");
|
||||
//then
|
||||
boolean actual = credentials1.identical(credentials2);
|
||||
//then
|
||||
assertTrue(actual);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 1999-2026 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
class IdentifyConstantsTest {
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
assertNotNull(new IdentifyConstants());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFields() {
|
||||
assertEquals("accessKey", IdentifyConstants.ACCESS_KEY);
|
||||
assertEquals("secretKey", IdentifyConstants.SECRET_KEY);
|
||||
assertEquals("Spas-SecurityToken", IdentifyConstants.SECURITY_TOKEN_HEADER);
|
||||
assertEquals("tenantId", IdentifyConstants.TENANT_ID);
|
||||
assertEquals("spas.properties", IdentifyConstants.PROPERTIES_FILENAME);
|
||||
assertEquals("/home/admin/.spas_key/", IdentifyConstants.CREDENTIAL_PATH);
|
||||
assertEquals("default", IdentifyConstants.CREDENTIAL_DEFAULT);
|
||||
assertEquals("/etc/instanceInfo", IdentifyConstants.DOCKER_CREDENTIAL_PATH);
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class StsConfigTest {
|
||||
|
||||
private static void resetStsConfig() {
|
||||
StsConfig.getInstance().setRamRoleName(null);
|
||||
StsConfig.getInstance().setTimeToRefreshInMillisecond(3 * 60 * 1000);
|
||||
StsConfig.getInstance().setCacheSecurityCredentials(true);
|
||||
StsConfig.getInstance().setSecurityCredentials(null);
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(null);
|
||||
System.clearProperty(IdentifyConstants.RAM_ROLE_NAME_PROPERTY);
|
||||
System.clearProperty(IdentifyConstants.REFRESH_TIME_PROPERTY);
|
||||
System.clearProperty(IdentifyConstants.SECURITY_PROPERTY);
|
||||
System.clearProperty(IdentifyConstants.SECURITY_URL_PROPERTY);
|
||||
System.clearProperty(IdentifyConstants.SECURITY_CACHE_PROPERTY);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void before() {
|
||||
resetStsConfig();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() {
|
||||
resetStsConfig();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInstance() {
|
||||
StsConfig instance1 = StsConfig.getInstance();
|
||||
StsConfig instance2 = StsConfig.getInstance();
|
||||
assertEquals(instance1, instance2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetRamRoleName() {
|
||||
StsConfig.getInstance().setRamRoleName("test");
|
||||
assertEquals("test", StsConfig.getInstance().getRamRoleName());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTimeToRefreshInMillisecond() {
|
||||
assertEquals(3 * 60 * 1000, StsConfig.getInstance().getTimeToRefreshInMillisecond());
|
||||
StsConfig.getInstance().setTimeToRefreshInMillisecond(3000);
|
||||
assertEquals(3000, StsConfig.getInstance().getTimeToRefreshInMillisecond());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSecurityCredentialsUrl() {
|
||||
assertNull(StsConfig.getInstance().getSecurityCredentialsUrl());
|
||||
String expect = "localhost";
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(expect);
|
||||
assertEquals(expect, StsConfig.getInstance().getSecurityCredentialsUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSecurityCredentialsUrlDefault() {
|
||||
StsConfig.getInstance().setRamRoleName("test");
|
||||
assertEquals("http://100.100.100.200/latest/meta-data/ram/security-credentials/test",
|
||||
StsConfig.getInstance().getSecurityCredentialsUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSecurityCredentials() {
|
||||
assertNull(StsConfig.getInstance().getSecurityCredentials());
|
||||
String expect = "abc";
|
||||
StsConfig.getInstance().setSecurityCredentials(expect);
|
||||
assertEquals(expect, StsConfig.getInstance().getSecurityCredentials());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsCacheSecurityCredentials() {
|
||||
assertTrue(StsConfig.getInstance().isCacheSecurityCredentials());
|
||||
StsConfig.getInstance().setCacheSecurityCredentials(false);
|
||||
assertFalse(StsConfig.getInstance().isCacheSecurityCredentials());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsOnFalse() {
|
||||
boolean stsOn = StsConfig.getInstance().isStsOn();
|
||||
assertFalse(stsOn);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsOnTrue() {
|
||||
StsConfig.getInstance().setSecurityCredentials("abc");
|
||||
boolean stsOn = StsConfig.getInstance().isStsOn();
|
||||
assertTrue(stsOn);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFromEnv()
|
||||
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
|
||||
InstantiationException {
|
||||
Constructor<StsConfig> constructor = StsConfig.class.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
System.setProperty(IdentifyConstants.RAM_ROLE_NAME_PROPERTY, "test");
|
||||
System.setProperty(IdentifyConstants.REFRESH_TIME_PROPERTY, "3000");
|
||||
System.setProperty(IdentifyConstants.SECURITY_PROPERTY, "abc");
|
||||
System.setProperty(IdentifyConstants.SECURITY_URL_PROPERTY, "localhost");
|
||||
System.setProperty(IdentifyConstants.SECURITY_CACHE_PROPERTY, "false");
|
||||
StsConfig stsConfig = constructor.newInstance();
|
||||
assertEquals("test", stsConfig.getRamRoleName());
|
||||
assertEquals(3000, stsConfig.getTimeToRefreshInMillisecond());
|
||||
assertEquals("abc", stsConfig.getSecurityCredentials());
|
||||
assertEquals("localhost", stsConfig.getSecurityCredentialsUrl());
|
||||
assertFalse(stsConfig.isCacheSecurityCredentials());
|
||||
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.identify;
|
||||
|
||||
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
|
||||
import com.alibaba.nacos.common.http.HttpClientBeanHolder;
|
||||
import com.alibaba.nacos.common.http.HttpRestResult;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class StsCredentialHolderTest {
|
||||
|
||||
private String securityCredentialsUrl;
|
||||
|
||||
private NacosRestTemplate cachedNacosRestTemplate;
|
||||
|
||||
@Mock
|
||||
private HttpRestResult mockResult;
|
||||
|
||||
@Mock
|
||||
private NacosRestTemplate nacosRestTemplate;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
securityCredentialsUrl = StsConfig.getInstance().getSecurityCredentialsUrl();
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl("url");
|
||||
Field restMapField = HttpClientBeanHolder.class.getDeclaredField("SINGLETON_REST");
|
||||
restMapField.setAccessible(true);
|
||||
Map<String, NacosRestTemplate> restMap =
|
||||
(Map<String, NacosRestTemplate>) restMapField.get(null);
|
||||
cachedNacosRestTemplate = restMap.get(
|
||||
"com.alibaba.nacos.client.remote.HttpClientManager$HttpClientFactory");
|
||||
restMap.put("com.alibaba.nacos.client.remote.HttpClientManager$HttpClientFactory",
|
||||
nacosRestTemplate);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
StsConfig.getInstance().setSecurityCredentials(null);
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(securityCredentialsUrl);
|
||||
if (null != cachedNacosRestTemplate) {
|
||||
Field restMapField = HttpClientBeanHolder.class.getDeclaredField("SINGLETON_REST");
|
||||
restMapField.setAccessible(true);
|
||||
Map<String, NacosRestTemplate> restMap =
|
||||
(Map<String, NacosRestTemplate>) restMapField.get(null);
|
||||
restMap.put("com.alibaba.nacos.client.remote.HttpClientManager$HttpClientFactory",
|
||||
cachedNacosRestTemplate);
|
||||
}
|
||||
clearForSts();
|
||||
}
|
||||
|
||||
private void clearForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(null);
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStsCredentialFromCache() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsCredential stsCredential = buildMockStsCredential();
|
||||
setStsCredential(stsCredential);
|
||||
assertEquals(stsCredential, StsCredentialHolder.getInstance().getStsCredential());
|
||||
}
|
||||
|
||||
private void setStsCredential(StsCredential stsCredential)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), stsCredential);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStsCredentialFromStringCache() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsCredential stsCredential = buildMockStsCredential();
|
||||
StsConfig.getInstance().setSecurityCredentials(JacksonUtils.toJson(stsCredential));
|
||||
assertEquals(stsCredential.toString(),
|
||||
StsCredentialHolder.getInstance().getStsCredential().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStsCredentialFromRequest() throws Exception {
|
||||
StsCredential stsCredential = buildMockStsCredential();
|
||||
mockResult = new HttpRestResult<String>();
|
||||
mockResult.setData(JacksonUtils.toJson(stsCredential));
|
||||
mockResult.setCode(200);
|
||||
when(nacosRestTemplate.get(any(), any(), any(), any())).thenReturn(mockResult);
|
||||
assertEquals(stsCredential.toString(),
|
||||
StsCredentialHolder.getInstance().getStsCredential().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStsCredentialFromRequestFailure() throws Exception {
|
||||
assertThrows(NacosRuntimeException.class, () -> {
|
||||
mockResult = new HttpRestResult<String>();
|
||||
mockResult.setData("");
|
||||
mockResult.setCode(500);
|
||||
when(nacosRestTemplate.get(any(), any(), any(), any())).thenReturn(mockResult);
|
||||
StsCredentialHolder.getInstance().getStsCredential();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetStsCredentialFromRequestException() throws Exception {
|
||||
assertThrows(NacosRuntimeException.class, () -> {
|
||||
when(nacosRestTemplate.get(any(), any(), any(), any()))
|
||||
.thenThrow(new RuntimeException("test"));
|
||||
StsCredentialHolder.getInstance().getStsCredential();
|
||||
});
|
||||
}
|
||||
|
||||
private StsCredential buildMockStsCredential() {
|
||||
StsCredential stsCredential = new StsCredential();
|
||||
stsCredential.setAccessKeyId("test-sts-ak");
|
||||
stsCredential.setAccessKeySecret("test-sts-sk");
|
||||
stsCredential.setSecurityToken("test-sts-token");
|
||||
stsCredential.setExpiration(new Date(System.currentTimeMillis() + 1000000));
|
||||
stsCredential.setCode("200");
|
||||
stsCredential.setLastUpdated(new Date());
|
||||
return stsCredential;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AbstractResourceInjectorTest {
|
||||
|
||||
AbstractResourceInjector injector;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
injector = new AbstractResourceInjector() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO, fill test case after AbstractResourceInjector include default logic.
|
||||
*/
|
||||
@Test
|
||||
void testDoInject() {
|
||||
injector.doInject(null, null, null);
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 1999-2026 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.client.auth.ram.RamConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.IdentifyConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsConfig;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredential;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredentialHolder;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import com.alibaba.nacos.plugin.auth.constant.SignType;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class AiResourceInjectorTest {
|
||||
|
||||
private AiResourceInjector aiResourceInjector;
|
||||
|
||||
private RamContext ramContext;
|
||||
|
||||
private RequestResource resource;
|
||||
|
||||
private String cachedSecurityCredentialsUrl;
|
||||
|
||||
private String cachedSecurityCredentials;
|
||||
|
||||
private StsCredential stsCredential;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
aiResourceInjector = new AiResourceInjector();
|
||||
ramContext = new RamContext();
|
||||
ramContext.setAccessKey(PropertyKeyConst.ACCESS_KEY);
|
||||
ramContext.setSecretKey(PropertyKeyConst.SECRET_KEY);
|
||||
resource = new RequestResource();
|
||||
resource.setType(SignType.AI);
|
||||
resource.setNamespace("ai-namespace");
|
||||
resource.setGroup("ai-group");
|
||||
cachedSecurityCredentialsUrl = StsConfig.getInstance().getSecurityCredentialsUrl();
|
||||
cachedSecurityCredentials = StsConfig.getInstance().getSecurityCredentials();
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl("");
|
||||
StsConfig.getInstance().setSecurityCredentials("");
|
||||
stsCredential = new StsCredential();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(cachedSecurityCredentialsUrl);
|
||||
StsConfig.getInstance().setSecurityCredentials(cachedSecurityCredentials);
|
||||
clearForSts();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWhenContextInvalid() {
|
||||
RamContext invalidContext = new RamContext();
|
||||
// missing ak/sk → invalid
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
aiResourceInjector.doInject(resource, invalidContext, actual);
|
||||
assertEquals(0, actual.getAllKey().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithFullResource() {
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
aiResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(3, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("Spas-AccessKey"));
|
||||
assertTrue(actual.getAllKey().contains("Timestamp"));
|
||||
assertTrue(actual.getAllKey().contains("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
prepareForSts();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
aiResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(4, actual.getAllKey().size());
|
||||
assertEquals("test-sts-ak", actual.getParameter("Spas-AccessKey"));
|
||||
assertTrue(actual.getAllKey().contains("Timestamp"));
|
||||
assertTrue(actual.getAllKey().contains("Spas-Signature"));
|
||||
assertTrue(actual.getAllKey().contains(IdentifyConstants.SECURITY_TOKEN_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectForV4Sign() {
|
||||
ramContext.setRegionId("cn-hangzhou");
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
aiResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(4, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("Spas-AccessKey"));
|
||||
assertEquals(RamConstants.V4, actual.getParameter(RamConstants.SIGNATURE_VERSION));
|
||||
assertTrue(actual.getAllKey().contains("Timestamp"));
|
||||
assertTrue(actual.getAllKey().contains("Spas-Signature"));
|
||||
}
|
||||
|
||||
private void prepareForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl("test");
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), stsCredential);
|
||||
stsCredential.setAccessKeyId("test-sts-ak");
|
||||
stsCredential.setAccessKeySecret("test-sts-sk");
|
||||
stsCredential.setSecurityToken("test-sts-token");
|
||||
stsCredential.setExpiration(new Date(System.currentTimeMillis() + 1_000_000));
|
||||
}
|
||||
|
||||
private void clearForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(null);
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), null);
|
||||
}
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.client.auth.ram.RamConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.IdentifyConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsConfig;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredential;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredentialHolder;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import com.alibaba.nacos.plugin.auth.constant.SignType;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class ConfigResourceInjectorTest {
|
||||
|
||||
private ConfigResourceInjector configResourceInjector;
|
||||
|
||||
private RamContext ramContext;
|
||||
|
||||
private RequestResource resource;
|
||||
|
||||
private String cachedSecurityCredentialsUrl;
|
||||
|
||||
private String cachedSecurityCredentials;
|
||||
|
||||
private StsCredential stsCredential;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
configResourceInjector = new ConfigResourceInjector();
|
||||
ramContext = new RamContext();
|
||||
ramContext.setAccessKey(PropertyKeyConst.ACCESS_KEY);
|
||||
ramContext.setSecretKey(PropertyKeyConst.SECRET_KEY);
|
||||
resource = new RequestResource();
|
||||
resource.setType(SignType.CONFIG);
|
||||
resource.setNamespace("tenant");
|
||||
resource.setGroup("group");
|
||||
cachedSecurityCredentialsUrl = StsConfig.getInstance().getSecurityCredentialsUrl();
|
||||
cachedSecurityCredentials = StsConfig.getInstance().getSecurityCredentials();
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl("");
|
||||
StsConfig.getInstance().setSecurityCredentials("");
|
||||
stsCredential = new StsCredential();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(cachedSecurityCredentialsUrl);
|
||||
StsConfig.getInstance().setSecurityCredentials(cachedSecurityCredentials);
|
||||
clearForSts();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithFullResource() throws Exception {
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
configResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(3, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("Spas-AccessKey"));
|
||||
assertTrue(actual.getAllKey().contains("Timestamp"));
|
||||
assertTrue(actual.getAllKey().contains("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithTenant() throws Exception {
|
||||
resource.setGroup("");
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
configResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(3, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("Spas-AccessKey"));
|
||||
assertTrue(actual.getAllKey().contains("Timestamp"));
|
||||
assertTrue(actual.getAllKey().contains("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithGroup() throws Exception {
|
||||
resource.setNamespace("");
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
configResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(3, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("Spas-AccessKey"));
|
||||
assertTrue(actual.getAllKey().contains("Timestamp"));
|
||||
assertTrue(actual.getAllKey().contains("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithoutResource() throws Exception {
|
||||
resource = new RequestResource();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
configResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(3, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("Spas-AccessKey"));
|
||||
assertTrue(actual.getAllKey().contains("Timestamp"));
|
||||
assertTrue(actual.getAllKey().contains("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
prepareForSts();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
configResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(4, actual.getAllKey().size());
|
||||
assertEquals("test-sts-ak", actual.getParameter("Spas-AccessKey"));
|
||||
assertTrue(actual.getAllKey().contains("Timestamp"));
|
||||
assertTrue(actual.getAllKey().contains("Spas-Signature"));
|
||||
assertTrue(actual.getAllKey().contains(IdentifyConstants.SECURITY_TOKEN_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectForV4Sign() {
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
ramContext.setRegionId("cn-hangzhou");
|
||||
configResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(4, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("Spas-AccessKey"));
|
||||
assertEquals(RamConstants.V4, actual.getParameter(RamConstants.SIGNATURE_VERSION));
|
||||
assertTrue(actual.getAllKey().contains("Timestamp"));
|
||||
assertTrue(actual.getAllKey().contains("Spas-Signature"));
|
||||
}
|
||||
|
||||
private void prepareForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl("test");
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), stsCredential);
|
||||
stsCredential.setAccessKeyId("test-sts-ak");
|
||||
stsCredential.setAccessKeySecret("test-sts-sk");
|
||||
stsCredential.setSecurityToken("test-sts-token");
|
||||
stsCredential.setExpiration(new Date(System.currentTimeMillis() + 1000000));
|
||||
}
|
||||
|
||||
private void clearForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(null);
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), null);
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 1999-2026 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.IdentifyConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsConfig;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredential;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredentialHolder;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class LockResourceInjectorTest {
|
||||
|
||||
private LockResourceInjector lockResourceInjector;
|
||||
|
||||
private RamContext ramContext;
|
||||
|
||||
private RequestResource resource;
|
||||
|
||||
private String cachedSecurityCredentialsUrl;
|
||||
|
||||
private String cachedSecurityCredentials;
|
||||
|
||||
private StsCredential stsCredential;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
lockResourceInjector = new LockResourceInjector();
|
||||
ramContext = new RamContext();
|
||||
ramContext.setAccessKey(PropertyKeyConst.ACCESS_KEY);
|
||||
ramContext.setSecretKey(PropertyKeyConst.SECRET_KEY);
|
||||
resource = new RequestResource();
|
||||
cachedSecurityCredentialsUrl = StsConfig.getInstance().getSecurityCredentialsUrl();
|
||||
cachedSecurityCredentials = StsConfig.getInstance().getSecurityCredentials();
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl("");
|
||||
StsConfig.getInstance().setSecurityCredentials("");
|
||||
stsCredential = new StsCredential();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(cachedSecurityCredentialsUrl);
|
||||
StsConfig.getInstance().setSecurityCredentials(cachedSecurityCredentials);
|
||||
clearForSts();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithAkSk() {
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
lockResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(1, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("ak"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithoutSecretKey() {
|
||||
ramContext.setSecretKey(null);
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
lockResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(0, actual.getAllKey().size());
|
||||
assertNull(actual.getParameter("ak"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
prepareForSts();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
lockResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(2, actual.getAllKey().size());
|
||||
assertEquals("test-sts-ak", actual.getParameter("ak"));
|
||||
assertTrue(actual.getAllKey().contains(IdentifyConstants.SECURITY_TOKEN_HEADER));
|
||||
}
|
||||
|
||||
private void prepareForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl("test");
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), stsCredential);
|
||||
stsCredential.setAccessKeyId("test-sts-ak");
|
||||
stsCredential.setAccessKeySecret("test-sts-sk");
|
||||
stsCredential.setSecurityToken("test-sts-token");
|
||||
stsCredential.setExpiration(new Date(System.currentTimeMillis() + 1_000_000));
|
||||
}
|
||||
|
||||
private void clearForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(null);
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), null);
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.injector;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.client.auth.ram.RamConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsConfig;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredential;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.StsCredentialHolder;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.CalculateV4SigningKeyUtil;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.SignUtil;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class NamingResourceInjectorTest {
|
||||
|
||||
private NamingResourceInjector namingResourceInjector;
|
||||
|
||||
private RamContext ramContext;
|
||||
|
||||
private RequestResource resource;
|
||||
|
||||
private StsCredential stsCredential;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
namingResourceInjector = new NamingResourceInjector();
|
||||
ramContext = new RamContext();
|
||||
ramContext.setAccessKey(PropertyKeyConst.ACCESS_KEY);
|
||||
ramContext.setSecretKey(PropertyKeyConst.SECRET_KEY);
|
||||
stsCredential = new StsCredential();
|
||||
StsConfig.getInstance().setRamRoleName(null);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NoSuchFieldException, IllegalAccessException {
|
||||
clearForSts();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithEmpty() throws Exception {
|
||||
resource = RequestResource.namingBuilder().setResource("").build();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
namingResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(3, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("ak"));
|
||||
assertTrue(Long.parseLong(actual.getParameter("data")) - System.currentTimeMillis() < 100);
|
||||
String expectSign = SignUtil.sign(actual.getParameter("data"), PropertyKeyConst.SECRET_KEY);
|
||||
assertEquals(expectSign, actual.getParameter("signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithGroup() throws Exception {
|
||||
resource =
|
||||
RequestResource.namingBuilder().setResource("test@@aaa").setGroup("group").build();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
namingResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(3, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("ak"));
|
||||
assertTrue(actual.getParameter("data").endsWith("@@test@@aaa"));
|
||||
String expectSign = SignUtil.sign(actual.getParameter("data"), PropertyKeyConst.SECRET_KEY);
|
||||
assertEquals(expectSign, actual.getParameter("signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithoutGroup() throws Exception {
|
||||
resource = RequestResource.namingBuilder().setResource("aaa").setGroup("group").build();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
namingResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertTrue(actual.getParameter("data").endsWith("@@group@@aaa"));
|
||||
assertEquals(3, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("ak"));
|
||||
String expectSign = SignUtil.sign(actual.getParameter("data"), PropertyKeyConst.SECRET_KEY);
|
||||
assertEquals(expectSign, actual.getParameter("signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithGroupForSts() throws Exception {
|
||||
prepareForSts();
|
||||
resource =
|
||||
RequestResource.namingBuilder().setResource("test@@aaa").setGroup("group").build();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
namingResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(4, actual.getAllKey().size());
|
||||
assertEquals("test-sts-ak", actual.getParameter("ak"));
|
||||
assertTrue(actual.getParameter("data").endsWith("@@test@@aaa"));
|
||||
String expectSign = SignUtil.sign(actual.getParameter("data"), "test-sts-sk");
|
||||
assertEquals(expectSign, actual.getParameter("signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectWithoutGroupForSts() throws Exception {
|
||||
prepareForSts();
|
||||
resource = RequestResource.namingBuilder().setResource("aaa").setGroup("group").build();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
namingResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(4, actual.getAllKey().size());
|
||||
assertEquals("test-sts-ak", actual.getParameter("ak"));
|
||||
assertTrue(actual.getParameter("data").endsWith("@@group@@aaa"));
|
||||
String expectSign = SignUtil.sign(actual.getParameter("data"), "test-sts-sk");
|
||||
assertEquals(expectSign, actual.getParameter("signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectForStsWithException() throws Exception {
|
||||
prepareForSts();
|
||||
stsCredential.setExpiration(new Date());
|
||||
resource = RequestResource.namingBuilder().setResource("aaa").setGroup("group").build();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
namingResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(0, actual.getAllKey().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoInjectForV4Sign() throws Exception {
|
||||
resource =
|
||||
RequestResource.namingBuilder().setResource("test@@aaa").setGroup("group").build();
|
||||
LoginIdentityContext actual = new LoginIdentityContext();
|
||||
ramContext.setRegionId("cn-hangzhou");
|
||||
namingResourceInjector.doInject(resource, ramContext, actual);
|
||||
assertEquals(4, actual.getAllKey().size());
|
||||
assertEquals(PropertyKeyConst.ACCESS_KEY, actual.getParameter("ak"));
|
||||
assertEquals(RamConstants.V4, actual.getParameter(RamConstants.SIGNATURE_VERSION));
|
||||
assertTrue(actual.getParameter("data").endsWith("@@test@@aaa"));
|
||||
String signatureKey = CalculateV4SigningKeyUtil.finalSigningKeyStringWithDefaultInfo(
|
||||
PropertyKeyConst.SECRET_KEY, "cn-hangzhou");
|
||||
String expectSign = SignUtil.sign(actual.getParameter("data"), signatureKey);
|
||||
assertEquals(expectSign, actual.getParameter("signature"));
|
||||
}
|
||||
|
||||
private void prepareForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl("test");
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), stsCredential);
|
||||
stsCredential.setAccessKeyId("test-sts-ak");
|
||||
stsCredential.setAccessKeySecret("test-sts-sk");
|
||||
stsCredential.setSecurityToken("test-sts-token");
|
||||
stsCredential.setExpiration(new Date(System.currentTimeMillis() + 1000000));
|
||||
}
|
||||
|
||||
private void clearForSts() throws NoSuchFieldException, IllegalAccessException {
|
||||
StsConfig.getInstance().setSecurityCredentialsUrl(null);
|
||||
StsConfig.getInstance().setSecurityCredentials(null);
|
||||
Field field = StsCredentialHolder.class.getDeclaredField("stsCredential");
|
||||
field.setAccessible(true);
|
||||
field.set(StsCredentialHolder.getInstance(), null);
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.utils;
|
||||
|
||||
import com.alibaba.nacos.client.auth.ram.RamConstants;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
class CalculateV4SigningKeyUtilTest {
|
||||
|
||||
@Test
|
||||
void testFinalSigningKeyStringWithException() {
|
||||
assertThrows(RuntimeException.class,
|
||||
() -> CalculateV4SigningKeyUtil.finalSigningKeyString("", "2021-01-01",
|
||||
"cn-hangzhou",
|
||||
RamConstants.SIGNATURE_V4_PRODUCE, "non-exist"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFinalSigningKeyStringWithDefaultInfo() {
|
||||
assertNotNull(
|
||||
CalculateV4SigningKeyUtil.finalSigningKeyStringWithDefaultInfo("", "cn-hangzhou"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFinalSigningKeyStringWithInvalidKey() throws Exception {
|
||||
Mac macMock = mock(Mac.class);
|
||||
doThrow(new InvalidKeyException("forced")).when(macMock).init(any());
|
||||
try (MockedStatic<Mac> mocked = Mockito.mockStatic(Mac.class)) {
|
||||
mocked.when(() -> Mac.getInstance(anyString())).thenReturn(macMock);
|
||||
assertThrows(RuntimeException.class,
|
||||
() -> CalculateV4SigningKeyUtil.finalSigningKeyString("secret", "20210101",
|
||||
"cn-hangzhou", RamConstants.SIGNATURE_V4_PRODUCE,
|
||||
RamConstants.SIGNATURE_V4_METHOD));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
new CalculateV4SigningKeyUtil();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.utils;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.CredentialService;
|
||||
import com.alibaba.nacos.client.auth.ram.identify.Credentials;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class RamUtilTest {
|
||||
|
||||
private Properties properties;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
SpasAdapter.freeCredentialInstance();
|
||||
Credentials credentials = new Credentials("spasAk", "spasSk", "spasNamespaceId");
|
||||
CredentialService.getInstance().setStaticCredential(credentials);
|
||||
properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.ACCESS_KEY, "userAk");
|
||||
properties.setProperty(PropertyKeyConst.SECRET_KEY, "userSk");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() throws Exception {
|
||||
SpasAdapter.freeCredentialInstance();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAccessKeyWithUserAkSk() {
|
||||
assertEquals("userAk", RamUtil.getAccessKey(properties));
|
||||
assertEquals("userSk", RamUtil.getSecretKey(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAccessKeyWithSpasAkSk() {
|
||||
assertEquals("spasAk", RamUtil.getAccessKey(new Properties()));
|
||||
assertEquals("spasSk", RamUtil.getSecretKey(new Properties()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAccessKeyWithoutSpasAkSk() {
|
||||
Properties properties1 = new Properties();
|
||||
properties1.setProperty(PropertyKeyConst.IS_USE_RAM_INFO_PARSING, "false");
|
||||
assertNull(RamUtil.getAccessKey(properties1));
|
||||
assertNull(RamUtil.getSecretKey(properties1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructor() {
|
||||
new RamUtil();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class SignUtilTest {
|
||||
|
||||
@Test
|
||||
void testSign() throws Exception {
|
||||
String actual = SignUtil.sign("aaa", "b");
|
||||
assertEquals("DxyaKScrqL26yXYOuHXE3OwfQ0Y=", actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSignWithException() throws Exception {
|
||||
assertThrows(Exception.class, () -> {
|
||||
SignUtil.sign(null, "b");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSignWithException2() throws Exception {
|
||||
assertThrows(Exception.class, () -> {
|
||||
SignUtil.sign("aaa".getBytes(StandardCharsets.UTF_8),
|
||||
"b".getBytes(StandardCharsets.UTF_8), null);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
new SignUtil();
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 1999-2021 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.auth.ram.utils;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class SpasAdapterTest {
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
assertNull(SpasAdapter.getAk());
|
||||
assertNull(SpasAdapter.getSk());
|
||||
Assertions.assertDoesNotThrow(() -> {
|
||||
SpasAdapter.freeCredentialInstance();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSign() {
|
||||
|
||||
assertNull(SpasAdapter.getSignHeaders("", "", "123"));
|
||||
|
||||
final Map<String, String> map1 = SpasAdapter.getSignHeaders("aa", "bb", "123");
|
||||
assertEquals(2, map1.size());
|
||||
assertEquals(SpasAdapter.signWithHmacSha1Encrypt("bb+aa+" + map1.get("Timestamp"), "123"),
|
||||
map1.get("Spas-Signature"));
|
||||
|
||||
final Map<String, String> map2 = SpasAdapter.getSignHeaders("aa", "", "123");
|
||||
assertEquals(2, map2.size());
|
||||
assertEquals(SpasAdapter.signWithHmacSha1Encrypt("aa" + "+" + map2.get("Timestamp"), "123"),
|
||||
map2.get("Spas-Signature"));
|
||||
|
||||
final Map<String, String> map3 = SpasAdapter.getSignHeaders("", "bb", "123");
|
||||
assertEquals(2, map3.size());
|
||||
assertEquals(SpasAdapter.signWithHmacSha1Encrypt(map3.get("Timestamp"), "123"),
|
||||
map3.get("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSign2() {
|
||||
|
||||
assertNull(SpasAdapter.getSignHeaders((Map) null, "123"));
|
||||
|
||||
Map<String, String> param1 = new HashMap<>();
|
||||
param1.put("tenant", "bb");
|
||||
param1.put("group", "aa");
|
||||
final Map<String, String> map1 = SpasAdapter.getSignHeaders(param1, "123");
|
||||
assertEquals(2, map1.size());
|
||||
assertEquals(SpasAdapter.signWithHmacSha1Encrypt("bb+aa+" + map1.get("Timestamp"), "123"),
|
||||
map1.get("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSignHeadersWithoutTenant() {
|
||||
Map<String, String> param1 = new HashMap<>();
|
||||
param1.put("group", "aa");
|
||||
final Map<String, String> map1 = SpasAdapter.getSignHeaders(param1, "123");
|
||||
assertEquals(2, map1.size());
|
||||
assertEquals(SpasAdapter.signWithHmacSha1Encrypt("aa+" + map1.get("Timestamp"), "123"),
|
||||
map1.get("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSignWithHmacSha1EncryptWithException() {
|
||||
assertThrows(Exception.class, () -> {
|
||||
SpasAdapter.signWithHmacSha1Encrypt(null, "123");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
new SpasAdapter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 1999-2026 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.constant;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
class ConstantsTest {
|
||||
|
||||
@Test
|
||||
void testConstructors() {
|
||||
assertNotNull(new Constants());
|
||||
assertNotNull(new Constants.SysEnv());
|
||||
assertNotNull(new Constants.Security());
|
||||
assertNotNull(new Constants.Address());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSysEnvFields() {
|
||||
assertEquals("user.home", Constants.SysEnv.USER_HOME);
|
||||
assertEquals("project.name", Constants.SysEnv.PROJECT_NAME);
|
||||
assertEquals("JM.LOG.PATH", Constants.SysEnv.JM_LOG_PATH);
|
||||
assertEquals("JM.SNAPSHOT.PATH", Constants.SysEnv.JM_SNAPSHOT_PATH);
|
||||
assertEquals("nacos.env.first", Constants.SysEnv.NACOS_ENV_FIRST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSecurityFields() {
|
||||
assertEquals(5_000L, Constants.Security.SECURITY_INFO_REFRESH_INTERVAL_MILLS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddressFields() {
|
||||
assertEquals(500, Constants.Address.ENDPOINT_SERVER_LIST_PROVIDER_ORDER);
|
||||
assertEquals(499, Constants.Address.ADDRESS_SERVER_LIST_PROVIDER_ORDER);
|
||||
}
|
||||
}
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class NacosClientPropertiesTest {
|
||||
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
System.setProperty("nacos.env.first", "jvm");
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void teardown() {
|
||||
System.clearProperty("nacos.env.first");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetProperty() {
|
||||
NacosClientProperties.PROTOTYPE.setProperty("nacos.home", "/home/nacos");
|
||||
final String value = NacosClientProperties.PROTOTYPE.getProperty("nacos.home");
|
||||
assertEquals("/home/nacos", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertyMultiLayer() {
|
||||
|
||||
NacosClientProperties.PROTOTYPE.setProperty("top.layer", "top");
|
||||
|
||||
final NacosClientProperties layerAEnv = NacosClientProperties.PROTOTYPE.derive();
|
||||
layerAEnv.setProperty("a.layer", "a");
|
||||
|
||||
final NacosClientProperties layerBEnv = layerAEnv.derive();
|
||||
layerBEnv.setProperty("b.layer", "b");
|
||||
|
||||
final NacosClientProperties layerCEnv = layerBEnv.derive();
|
||||
layerCEnv.setProperty("c.layer", "c");
|
||||
|
||||
String value = layerCEnv.getProperty("c.layer");
|
||||
assertEquals("c", value);
|
||||
|
||||
value = layerCEnv.getProperty("b.layer");
|
||||
assertEquals("b", value);
|
||||
|
||||
value = layerCEnv.getProperty("a.layer");
|
||||
assertEquals("a", value);
|
||||
|
||||
value = layerCEnv.getProperty("top.layer");
|
||||
assertEquals("top", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertyDefaultValue() {
|
||||
final String value = NacosClientProperties.PROTOTYPE.getProperty("nacos.home.default",
|
||||
"/home/default_value");
|
||||
assertEquals("/home/default_value", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBoolean() {
|
||||
NacosClientProperties.PROTOTYPE.setProperty("use.cluster", "true");
|
||||
final Boolean value = NacosClientProperties.PROTOTYPE.getBoolean("use.cluster");
|
||||
assertTrue(value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBooleanDefaultValue() {
|
||||
final Boolean value =
|
||||
NacosClientProperties.PROTOTYPE.getBoolean("use.cluster.default", false);
|
||||
assertFalse(value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInteger() {
|
||||
NacosClientProperties.PROTOTYPE.setProperty("max.timeout", "200");
|
||||
final Integer value = NacosClientProperties.PROTOTYPE.getInteger("max.timeout");
|
||||
assertEquals(200, value.intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetIntegerDefaultValue() {
|
||||
final Integer value =
|
||||
NacosClientProperties.PROTOTYPE.getInteger("max.timeout.default", 400);
|
||||
assertEquals(400, value.intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLong() {
|
||||
NacosClientProperties.PROTOTYPE.setProperty("connection.timeout", "200");
|
||||
final Long value = NacosClientProperties.PROTOTYPE.getLong("connection.timeout");
|
||||
assertEquals(200L, value.longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetLongDefault() {
|
||||
final Long value =
|
||||
NacosClientProperties.PROTOTYPE.getLong("connection.timeout.default", 400L);
|
||||
assertEquals(400L, value.longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void setProperty() {
|
||||
NacosClientProperties.PROTOTYPE.setProperty("nacos.set.property", "true");
|
||||
final String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.set.property");
|
||||
assertEquals("true", ret);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPropertyWithScope() {
|
||||
|
||||
final NacosClientProperties properties = NacosClientProperties.PROTOTYPE.derive();
|
||||
properties.setProperty("nacos.set.property.scope", "config");
|
||||
|
||||
String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.set.property.scope");
|
||||
assertNull(ret);
|
||||
|
||||
ret = properties.getProperty("nacos.set.property.scope");
|
||||
assertEquals("config", ret);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("nacos.add.properties", "true");
|
||||
|
||||
NacosClientProperties.PROTOTYPE.addProperties(properties);
|
||||
|
||||
final String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.add.properties");
|
||||
|
||||
assertEquals("true", ret);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddPropertiesWithScope() {
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("nacos.add.properties.scope", "config");
|
||||
|
||||
final NacosClientProperties nacosClientProperties =
|
||||
NacosClientProperties.PROTOTYPE.derive();
|
||||
nacosClientProperties.addProperties(properties);
|
||||
|
||||
String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.add.properties.scope");
|
||||
assertNull(ret);
|
||||
|
||||
ret = nacosClientProperties.getProperty("nacos.add.properties.scope");
|
||||
assertEquals("config", ret);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTestDerive() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("nacos.derive.properties.scope", "derive");
|
||||
|
||||
final NacosClientProperties nacosClientProperties =
|
||||
NacosClientProperties.PROTOTYPE.derive(properties);
|
||||
|
||||
final String value = nacosClientProperties.getProperty("nacos.derive.properties.scope");
|
||||
|
||||
assertEquals("derive", value);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testContainsKey() {
|
||||
NacosClientProperties.PROTOTYPE.setProperty("nacos.contains.key", "true");
|
||||
|
||||
boolean ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.key");
|
||||
assertTrue(ret);
|
||||
|
||||
ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.key.in.sys");
|
||||
assertFalse(ret);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testContainsKeyMultiLayers() {
|
||||
|
||||
NacosClientProperties.PROTOTYPE.setProperty("top.layer", "top");
|
||||
|
||||
final NacosClientProperties layerAEnv = NacosClientProperties.PROTOTYPE.derive();
|
||||
layerAEnv.setProperty("a.layer", "a");
|
||||
|
||||
final NacosClientProperties layerBEnv = layerAEnv.derive();
|
||||
layerBEnv.setProperty("b.layer", "b");
|
||||
|
||||
final NacosClientProperties layerCEnv = layerBEnv.derive();
|
||||
layerCEnv.setProperty("c.layer", "c");
|
||||
|
||||
boolean exist = layerCEnv.containsKey("c.layer");
|
||||
assertTrue(exist);
|
||||
|
||||
exist = layerCEnv.containsKey("b.layer");
|
||||
assertTrue(exist);
|
||||
|
||||
exist = layerCEnv.containsKey("a.layer");
|
||||
assertTrue(exist);
|
||||
|
||||
exist = layerCEnv.containsKey("top.layer");
|
||||
assertTrue(exist);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testContainsKeyWithScope() {
|
||||
NacosClientProperties.PROTOTYPE.setProperty("nacos.contains.global.scope", "global");
|
||||
final NacosClientProperties namingProperties = NacosClientProperties.PROTOTYPE.derive();
|
||||
namingProperties.setProperty("nacos.contains.naming.scope", "naming");
|
||||
|
||||
boolean ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.global.scope");
|
||||
assertTrue(ret);
|
||||
|
||||
ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.naming.scope");
|
||||
assertFalse(ret);
|
||||
|
||||
ret = namingProperties.containsKey("nacos.contains.naming.scope");
|
||||
assertTrue(ret);
|
||||
|
||||
ret = namingProperties.containsKey("nacos.contains.global.scope");
|
||||
assertTrue(ret);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAsProperties() {
|
||||
NacosClientProperties.PROTOTYPE.setProperty("nacos.as.properties", "true");
|
||||
final Properties properties = NacosClientProperties.PROTOTYPE.asProperties();
|
||||
assertNotNull(properties);
|
||||
assertEquals("true", properties.getProperty("nacos.as.properties"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAsPropertiesWithScope() {
|
||||
|
||||
NacosClientProperties.PROTOTYPE.setProperty("nacos.as.properties.global.scope", "global");
|
||||
NacosClientProperties.PROTOTYPE.setProperty("nacos.server.addr.scope", "global");
|
||||
|
||||
final NacosClientProperties configProperties = NacosClientProperties.PROTOTYPE.derive();
|
||||
configProperties.setProperty("nacos.server.addr.scope", "config");
|
||||
|
||||
final Properties properties = configProperties.asProperties();
|
||||
assertNotNull(properties);
|
||||
|
||||
String ret = properties.getProperty("nacos.as.properties.global.scope");
|
||||
assertEquals("global", ret);
|
||||
|
||||
ret = properties.getProperty("nacos.server.addr.scope");
|
||||
assertEquals("config", ret);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertyWithScope() {
|
||||
|
||||
NacosClientProperties.PROTOTYPE.setProperty("nacos.global.scope", "global");
|
||||
|
||||
final NacosClientProperties configProperties = NacosClientProperties.PROTOTYPE.derive();
|
||||
configProperties.setProperty("nacos.config.scope", "config");
|
||||
|
||||
final NacosClientProperties namingProperties = NacosClientProperties.PROTOTYPE.derive();
|
||||
namingProperties.setProperty("nacos.naming.scope", "naming");
|
||||
|
||||
String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.global.scope");
|
||||
assertEquals("global", ret);
|
||||
|
||||
ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.config.scope");
|
||||
assertNull(ret);
|
||||
|
||||
ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.naming.scope");
|
||||
assertNull(ret);
|
||||
|
||||
ret = configProperties.getProperty("nacos.config.scope");
|
||||
assertEquals("config", ret);
|
||||
ret = configProperties.getProperty("nacos.global.scope");
|
||||
assertEquals("global", ret);
|
||||
ret = configProperties.getProperty("nacos.naming.scope");
|
||||
assertNull(ret);
|
||||
|
||||
ret = namingProperties.getProperty("nacos.naming.scope");
|
||||
assertEquals("naming", ret);
|
||||
ret = namingProperties.getProperty("nacos.global.scope");
|
||||
assertEquals("global", ret);
|
||||
ret = namingProperties.getProperty("nacos.config.scope");
|
||||
assertNull(ret);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertyFrom() {
|
||||
System.setProperty("nacos.home.default.test", "/home/jvm_args");
|
||||
NacosClientProperties.PROTOTYPE.setProperty("nacos.home.default.test",
|
||||
"/home/properties_args");
|
||||
|
||||
assertEquals("/home/jvm_args",
|
||||
NacosClientProperties.PROTOTYPE.getPropertyFrom(SourceType.JVM,
|
||||
"nacos.home.default.test"));
|
||||
assertEquals("/home/properties_args",
|
||||
NacosClientProperties.PROTOTYPE.getPropertyFrom(SourceType.PROPERTIES,
|
||||
"nacos.home.default.test"));
|
||||
assertEquals(
|
||||
NacosClientProperties.PROTOTYPE.getPropertyFrom(null, "nacos.home.default.test"),
|
||||
NacosClientProperties.PROTOTYPE.getProperty("nacos.home.default.test"));
|
||||
}
|
||||
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
import com.alibaba.nacos.client.constant.Constants;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
/**
|
||||
* Additional test cases for SearchableProperties.
|
||||
*
|
||||
* <p> Common cases see {@link NacosClientPropertiesTest}.</p>
|
||||
*/
|
||||
class SearchablePropertiesTest {
|
||||
|
||||
Method initMethod;
|
||||
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
System.setProperty(Constants.SysEnv.NACOS_ENV_FIRST, "jvm");
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void teardown() {
|
||||
System.clearProperty(Constants.SysEnv.NACOS_ENV_FIRST);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
initMethod = SearchableProperties.class.getDeclaredMethod("init");
|
||||
initMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
init();
|
||||
initMethod.invoke(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithInvalidOrder() throws IllegalAccessException, InvocationTargetException {
|
||||
System.setProperty(Constants.SysEnv.NACOS_ENV_FIRST, "invalid");
|
||||
List<SourceType> order = (List<SourceType>) initMethod.invoke(null);
|
||||
assertOrder(order, SourceType.PROPERTIES, SourceType.JVM, SourceType.ENV);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithoutSpecifiedOrder() throws IllegalAccessException, InvocationTargetException {
|
||||
System.clearProperty(Constants.SysEnv.NACOS_ENV_FIRST);
|
||||
List<SourceType> order = (List<SourceType>) initMethod.invoke(null);
|
||||
assertOrder(order, SourceType.PROPERTIES, SourceType.JVM, SourceType.ENV);
|
||||
}
|
||||
|
||||
private void assertOrder(List<SourceType> order, SourceType... sourceTypes) {
|
||||
assertEquals(sourceTypes.length, order.size());
|
||||
for (int i = 0; i < sourceTypes.length; i++) {
|
||||
assertEquals(sourceTypes[i], order.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertyFromEnv() {
|
||||
System.setProperty("testFromSource", "jvm");
|
||||
NacosClientProperties properties = SearchableProperties.INSTANCE.derive();
|
||||
properties.setProperty("testFromSource", "properties");
|
||||
assertNull(properties.getPropertyFrom(SourceType.ENV, "testFromSource"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertyFromUnknown() {
|
||||
System.setProperty("testFromSource", "jvm");
|
||||
NacosClientProperties properties = SearchableProperties.INSTANCE.derive();
|
||||
properties.setProperty("testFromSource", "properties");
|
||||
assertEquals(properties.getProperty("testFromSource"),
|
||||
properties.getPropertyFrom(SourceType.UNKNOWN, "testFromSource"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertiesByJvmSource() {
|
||||
NacosClientProperties properties = SearchableProperties.INSTANCE.derive();
|
||||
java.util.Properties jvm = properties.getProperties(SourceType.JVM);
|
||||
org.junit.jupiter.api.Assertions.assertNotNull(jvm);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertiesByPropertiesSource() {
|
||||
NacosClientProperties properties = SearchableProperties.INSTANCE.derive();
|
||||
properties.setProperty("propsKey", "propsVal");
|
||||
java.util.Properties props = properties.getProperties(SourceType.PROPERTIES);
|
||||
org.junit.jupiter.api.Assertions.assertNotNull(props);
|
||||
assertEquals("propsVal", props.getProperty("propsKey"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertiesByUnknownSource() {
|
||||
NacosClientProperties properties = SearchableProperties.INSTANCE.derive();
|
||||
assertNull(properties.getProperties(SourceType.UNKNOWN));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertiesByNullSource() {
|
||||
NacosClientProperties properties = SearchableProperties.INSTANCE.derive();
|
||||
assertNull(properties.getProperties(null));
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Additional test cases for SystemEnvPropertySource.
|
||||
*
|
||||
* <p> Common cases see {@link NacosClientPropertiesTest}.</p>
|
||||
*/
|
||||
class SystemEnvPropertySourceTest {
|
||||
|
||||
SystemEnvPropertySource systemEnvPropertySource;
|
||||
|
||||
private Map<String, String> mockEnvMap;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
systemEnvPropertySource = new SystemEnvPropertySource();
|
||||
mockEnvMap = new HashMap<>();
|
||||
Field envField = SystemEnvPropertySource.class.getDeclaredField("env");
|
||||
envField.setAccessible(true);
|
||||
envField.set(systemEnvPropertySource, mockEnvMap);
|
||||
mockEnvMap.put("testcase1", "value1");
|
||||
mockEnvMap.put("test_case_2", "value2");
|
||||
mockEnvMap.put("TESTCASE3", "value3");
|
||||
mockEnvMap.put("TEST_CASE_4", "value4");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEnvForLowerCaseKey() {
|
||||
assertEquals("value1", systemEnvPropertySource.getProperty("testcase1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEnvForLowerCaseKeyWithDot() {
|
||||
assertEquals("value2", systemEnvPropertySource.getProperty("test.case.2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEnvForLowerCaseKeyWithHyphen() {
|
||||
assertEquals("value2", systemEnvPropertySource.getProperty("test-case-2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEnvForLowerCaseKeyWithHyphenAndDot() {
|
||||
assertEquals("value2", systemEnvPropertySource.getProperty("test.case-2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEnvForUpperCaseKey() {
|
||||
assertEquals("value3", systemEnvPropertySource.getProperty("TESTCASE3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEnvForUpperCaseKeyWithDot() {
|
||||
assertEquals("value4", systemEnvPropertySource.getProperty("TEST.CASE.4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEnvForUpperCaseKeyWithHyphen() {
|
||||
assertEquals("value4", systemEnvPropertySource.getProperty("TEST-CASE-4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEnvForUpperCaseKeyWithHyphenAndDot() {
|
||||
assertEquals("value4", systemEnvPropertySource.getProperty("TEST_CASE.4"));
|
||||
}
|
||||
}
|
||||
Vendored
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.env.convert;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.MissingFormatArgumentException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class CompositeConverterTest {
|
||||
|
||||
CompositeConverter compositeConverter;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
compositeConverter = new CompositeConverter();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertNotSupportType() {
|
||||
assertThrows(MissingFormatArgumentException.class, () -> {
|
||||
compositeConverter.convert("test", CompositeConverter.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertBooleanForEmptyProperty() {
|
||||
assertNull(compositeConverter.convert(null, Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertBooleanTrue() {
|
||||
assertTrue(compositeConverter.convert("true", Boolean.class));
|
||||
assertTrue(compositeConverter.convert("on", Boolean.class));
|
||||
assertTrue(compositeConverter.convert("yes", Boolean.class));
|
||||
assertTrue(compositeConverter.convert("1", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertBooleanFalse() {
|
||||
assertFalse(compositeConverter.convert("false", Boolean.class));
|
||||
assertFalse(compositeConverter.convert("off", Boolean.class));
|
||||
assertFalse(compositeConverter.convert("no", Boolean.class));
|
||||
assertFalse(compositeConverter.convert("0", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertBooleanIllegal() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
compositeConverter.convert("aaa", Boolean.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertIntegerForEmptyProperty() {
|
||||
assertNull(compositeConverter.convert(null, Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertInteger() {
|
||||
assertEquals(100, (int) compositeConverter.convert("100", Integer.class));
|
||||
assertEquals(Integer.MAX_VALUE,
|
||||
(int) compositeConverter.convert(String.valueOf(Integer.MAX_VALUE), Integer.class));
|
||||
assertEquals(Integer.MIN_VALUE,
|
||||
(int) compositeConverter.convert(String.valueOf(Integer.MIN_VALUE), Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertIntegerIllegal() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
compositeConverter.convert("aaa", Integer.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertLongForEmptyProperty() {
|
||||
assertNull(compositeConverter.convert(null, Long.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertLong() {
|
||||
assertEquals(100L, (long) compositeConverter.convert("100", Long.class));
|
||||
assertEquals(Long.MAX_VALUE,
|
||||
(long) compositeConverter.convert(String.valueOf(Long.MAX_VALUE), Long.class));
|
||||
assertEquals(Long.MIN_VALUE,
|
||||
(long) compositeConverter.convert(String.valueOf(Long.MIN_VALUE), Long.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertLongIllegal() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
compositeConverter.convert("aaa", Long.class);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 1999-2026 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.remote;
|
||||
|
||||
import com.alibaba.nacos.common.http.HttpClientBeanHolder;
|
||||
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
|
||||
class HttpClientManagerTest {
|
||||
|
||||
@Test
|
||||
void testGetInstanceReturnsSingleton() {
|
||||
HttpClientManager first = HttpClientManager.getInstance();
|
||||
HttpClientManager second = HttpClientManager.getInstance();
|
||||
assertNotNull(first);
|
||||
assertSame(first, second);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetConnectTimeoutOrDefaultUsesMin() {
|
||||
// Below 1000 ms minimum → returns 1000
|
||||
assertEquals(1000, HttpClientManager.getInstance().getConnectTimeoutOrDefault(500));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetConnectTimeoutOrDefaultUsesProvidedWhenLarger() {
|
||||
assertEquals(2000, HttpClientManager.getInstance().getConnectTimeoutOrDefault(2000));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetNacosRestTemplate() {
|
||||
NacosRestTemplate template = HttpClientManager.getInstance().getNacosRestTemplate();
|
||||
assertNotNull(template);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShutdownDoesNotThrow() {
|
||||
// Note: shutdown closes the shared NacosRestTemplate. Run this test last via
|
||||
// method name ordering (JUnit runs in alphabetical order without explicit ordering).
|
||||
Assertions.assertDoesNotThrow(() -> HttpClientManager.getInstance().shutdown());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShutdownSwallowsException() {
|
||||
try (MockedStatic<HttpClientBeanHolder> mocked =
|
||||
Mockito.mockStatic(HttpClientBeanHolder.class)) {
|
||||
mocked.when(() -> HttpClientBeanHolder.shutdownNacosSyncRest(anyString()))
|
||||
.thenThrow(new RuntimeException("forced"));
|
||||
Assertions.assertDoesNotThrow(() -> HttpClientManager.getInstance().shutdown());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHttpClientFactoryInternalsViaReflection() throws Exception {
|
||||
Field factoryField = HttpClientManager.class.getDeclaredField("HTTP_CLIENT_FACTORY");
|
||||
factoryField.setAccessible(true);
|
||||
Object factory = factoryField.get(null);
|
||||
Method buildConfig = factory.getClass().getDeclaredMethod("buildHttpClientConfig");
|
||||
buildConfig.setAccessible(true);
|
||||
Object config = buildConfig.invoke(factory);
|
||||
assertNotNull(config);
|
||||
Method assignLogger = factory.getClass().getDeclaredMethod("assignLogger");
|
||||
assignLogger.setAccessible(true);
|
||||
assertNotNull(assignLogger.invoke(factory));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import com.alibaba.nacos.client.constant.Constants;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class AppNameUtilsTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
System.clearProperty(Constants.SysEnv.PROJECT_NAME);
|
||||
System.clearProperty("jboss.server.home.dir");
|
||||
System.clearProperty("jetty.home");
|
||||
System.clearProperty("catalina.base");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAppNameByDefault() {
|
||||
String appName = AppNameUtils.getAppName();
|
||||
assertEquals("unknown", appName);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAppNameByProjectName() {
|
||||
System.setProperty(Constants.SysEnv.PROJECT_NAME, "testAppName");
|
||||
String appName = AppNameUtils.getAppName();
|
||||
assertEquals("testAppName", appName);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAppNameByServerTypeForJboss() {
|
||||
System.setProperty("jboss.server.home.dir", "/home/admin/testAppName/");
|
||||
String appName = AppNameUtils.getAppName();
|
||||
assertEquals("testAppName", appName);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAppNameByServerTypeForJetty() {
|
||||
System.setProperty("jetty.home", "/home/admin/testAppName/");
|
||||
String appName = AppNameUtils.getAppName();
|
||||
assertEquals("testAppName", appName);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAppNameByServerTypeForTomcat() {
|
||||
System.setProperty("catalina.base", "/home/admin/testAppName/");
|
||||
String appName = AppNameUtils.getAppName();
|
||||
assertEquals("testAppName", appName);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
new AppNameUtils();
|
||||
}
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 1999-2025 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.client.env.NacosClientProperties;
|
||||
import com.alibaba.nacos.client.env.SourceType;
|
||||
import com.alibaba.nacos.common.utils.VersionUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class ClientBasicParamUtilTest {
|
||||
|
||||
private String defaultAppKey;
|
||||
|
||||
private String defaultContextPath;
|
||||
|
||||
private String defaultVersion;
|
||||
|
||||
private String defaultNodesPath;
|
||||
|
||||
@BeforeEach
|
||||
void before() {
|
||||
defaultAppKey = "";
|
||||
defaultContextPath = "nacos";
|
||||
defaultVersion = VersionUtils.version;
|
||||
defaultNodesPath = "serverlist";
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() {
|
||||
ClientBasicParamUtil.setAppKey(defaultAppKey);
|
||||
ClientBasicParamUtil.setDefaultContextPath(defaultContextPath);
|
||||
ClientBasicParamUtil.setClientVersion(defaultVersion);
|
||||
ClientBasicParamUtil.setDefaultNodesPath(defaultNodesPath);
|
||||
System.clearProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAppKey() {
|
||||
String defaultVal = ClientBasicParamUtil.getAppKey();
|
||||
assertEquals(defaultAppKey, defaultVal);
|
||||
|
||||
String expect = "test";
|
||||
ClientBasicParamUtil.setAppKey(expect);
|
||||
assertEquals(expect, ClientBasicParamUtil.getAppKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDefaultContextPath() {
|
||||
String defaultVal = ClientBasicParamUtil.getDefaultContextPath();
|
||||
assertEquals(defaultContextPath, defaultVal);
|
||||
|
||||
String expect = "test";
|
||||
ClientBasicParamUtil.setDefaultContextPath(expect);
|
||||
assertEquals(expect, ClientBasicParamUtil.getDefaultContextPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetClientVersion() {
|
||||
String defaultVal = ClientBasicParamUtil.getClientVersion();
|
||||
assertEquals(defaultVersion, defaultVal);
|
||||
|
||||
String expect = "test";
|
||||
ClientBasicParamUtil.setClientVersion(expect);
|
||||
assertEquals(expect, ClientBasicParamUtil.getClientVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDefaultServerPort() {
|
||||
String actual = ClientBasicParamUtil.getDefaultServerPort();
|
||||
assertEquals("8848", actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDefaultNodesPath() {
|
||||
String defaultVal = ClientBasicParamUtil.getDefaultNodesPath();
|
||||
assertEquals("serverlist", defaultVal);
|
||||
|
||||
String expect = "test";
|
||||
ClientBasicParamUtil.setDefaultNodesPath(expect);
|
||||
assertEquals(expect, ClientBasicParamUtil.getDefaultNodesPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseNamespace() {
|
||||
String expect = "test";
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.NAMESPACE, expect);
|
||||
|
||||
final NacosClientProperties nacosClientProperties =
|
||||
NacosClientProperties.PROTOTYPE.derive(properties);
|
||||
String actual = ClientBasicParamUtil.parseNamespace(nacosClientProperties);
|
||||
assertEquals(expect, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParsingEndpointRule() {
|
||||
String url = "${test:www.example.com}";
|
||||
String actual = ClientBasicParamUtil.parsingEndpointRule(url);
|
||||
assertEquals("www.example.com", actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParsingEndpointRuleFromSystem() {
|
||||
System.setProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL,
|
||||
"alibaba_aliware_endpoint_url");
|
||||
assertEquals("alibaba_aliware_endpoint_url",
|
||||
ClientBasicParamUtil.parsingEndpointRule(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParsingEndpointRuleFromSystemWithParam() {
|
||||
System.setProperty(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL,
|
||||
"alibaba_aliware_endpoint_url");
|
||||
assertEquals("alibaba_aliware_endpoint_url",
|
||||
ClientBasicParamUtil.parsingEndpointRule("${abc:xxx}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInputParametersWithFullMode() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("testKey", "testValue");
|
||||
properties.setProperty(PropertyKeyConst.LOG_ALL_PROPERTIES, "true");
|
||||
NacosClientProperties clientProperties = NacosClientProperties.PROTOTYPE.derive(properties);
|
||||
String actual = ClientBasicParamUtil.getInputParameters(clientProperties.asProperties());
|
||||
assertTrue(actual.startsWith(
|
||||
"Log nacos client init properties with Full mode, This mode is only used for debugging and troubleshooting."));
|
||||
assertTrue(actual.contains("\ttestKey=testValue\n"));
|
||||
Properties envProperties = clientProperties.getProperties(SourceType.ENV);
|
||||
String envCaseKey = envProperties.stringPropertyNames().iterator().next();
|
||||
String envCaseValue = envProperties.getProperty(envCaseKey);
|
||||
assertTrue(actual.contains(String.format("\t%s=%s\n", envCaseKey, envCaseValue)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInputParameters() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("testKey", "testValue");
|
||||
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "localhost:8848");
|
||||
properties.setProperty(PropertyKeyConst.PASSWORD, "testPassword");
|
||||
NacosClientProperties clientProperties = NacosClientProperties.PROTOTYPE.derive(properties);
|
||||
String actual = ClientBasicParamUtil.getInputParameters(clientProperties.asProperties());
|
||||
assertEquals(
|
||||
"Nacos client key init properties: \n\tserverAddr=localhost:8848\n\tpassword=te********rd\n",
|
||||
actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDesensitiseParameter() {
|
||||
String shortParameter = "aa";
|
||||
assertEquals(shortParameter, ClientBasicParamUtil.desensitiseParameter(shortParameter));
|
||||
String middleParameter = "aaa";
|
||||
assertEquals("a*a", ClientBasicParamUtil.desensitiseParameter(middleParameter));
|
||||
middleParameter = "aaaaaaa";
|
||||
assertEquals("a*****a", ClientBasicParamUtil.desensitiseParameter(middleParameter));
|
||||
String longParameter = "testPass";
|
||||
assertEquals("te****ss", ClientBasicParamUtil.desensitiseParameter(longParameter));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetNameSuffixByServerIps() {
|
||||
assertEquals("1.1.1.1-2.2.2.2_8848",
|
||||
ClientBasicParamUtil.getNameSuffixByServerIps("http://1.1.1.1", "2.2.2.2:8848"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseNamespaceCloudParsingDefaultsWhenAllBlank() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING, "true");
|
||||
NacosClientProperties clientProperties = NacosClientProperties.PROTOTYPE.derive(properties);
|
||||
// No tenant, no ALIBABA_ALIWARE_NAMESPACE, no NAMESPACE → returns DEFAULT_NAMESPACE_ID
|
||||
assertEquals(com.alibaba.nacos.api.common.Constants.DEFAULT_NAMESPACE_ID,
|
||||
ClientBasicParamUtil.parseNamespace(clientProperties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
new ClientBasicParamUtil();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* ContextPathUtil test.
|
||||
*
|
||||
* @author Wei.Wang
|
||||
* @date 2020/11/26 3:13 PM
|
||||
*/
|
||||
class ContextPathUtilTest {
|
||||
|
||||
@Test
|
||||
void testNormalizeContextPath() {
|
||||
assertEquals("/nacos", ContextPathUtil.normalizeContextPath("/nacos"));
|
||||
assertEquals("/nacos", ContextPathUtil.normalizeContextPath("nacos"));
|
||||
assertEquals("", ContextPathUtil.normalizeContextPath("/"));
|
||||
assertEquals("", ContextPathUtil.normalizeContextPath(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
new ContextPathUtil();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class TemplateUtilsTest {
|
||||
|
||||
@Test
|
||||
void testStringNotEmptyAndThenExecuteSuccess() {
|
||||
String word = "run";
|
||||
Runnable task = Mockito.mock(Runnable.class);
|
||||
TemplateUtils.stringNotEmptyAndThenExecute(word, task);
|
||||
Mockito.verify(task, Mockito.times(1)).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringNotEmptyAndThenExecuteFail() {
|
||||
String word = "";
|
||||
Runnable task = Mockito.mock(Runnable.class);
|
||||
TemplateUtils.stringNotEmptyAndThenExecute(word, task);
|
||||
Mockito.verify(task, Mockito.times(0)).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringNotEmptyAndThenExecuteException() {
|
||||
String word = "run";
|
||||
Runnable task = Mockito.mock(Runnable.class);
|
||||
doThrow(new RuntimeException("test")).when(task).run();
|
||||
TemplateUtils.stringNotEmptyAndThenExecute(word, task);
|
||||
Mockito.verify(task, Mockito.times(1)).run();
|
||||
// NO exception thrown
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringEmptyAndThenExecuteSuccess() {
|
||||
String word = " ";
|
||||
String actual = TemplateUtils.stringEmptyAndThenExecute(word, () -> "call");
|
||||
assertEquals("", actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringEmptyAndThenExecuteFail() {
|
||||
String word = "";
|
||||
final String expect = "call";
|
||||
String actual = TemplateUtils.stringEmptyAndThenExecute(word, () -> expect);
|
||||
assertEquals(expect, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringEmptyAndThenExecuteException() throws Exception {
|
||||
Callable callable = mock(Callable.class);
|
||||
when(callable.call()).thenThrow(new RuntimeException("test"));
|
||||
String actual = TemplateUtils.stringEmptyAndThenExecute(null, callable);
|
||||
assertNull(actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringBlankAndThenExecuteSuccess() {
|
||||
String word = "success";
|
||||
String actual = TemplateUtils.stringBlankAndThenExecute(word, () -> "call");
|
||||
assertEquals(word, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringBlankAndThenExecuteFail() {
|
||||
String word = " ";
|
||||
final String expect = "call";
|
||||
String actual = TemplateUtils.stringBlankAndThenExecute(word, () -> expect);
|
||||
assertEquals(expect, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringBlankAndThenExecuteException() throws Exception {
|
||||
Callable callable = mock(Callable.class);
|
||||
when(callable.call()).thenThrow(new RuntimeException("test"));
|
||||
String actual = TemplateUtils.stringBlankAndThenExecute(null, callable);
|
||||
assertNull(actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
new TemplateUtils();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed 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 com.alibaba.nacos.client.utils;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class TenantUtilTest {
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
System.clearProperty("acm.namespace");
|
||||
System.clearProperty("ans.namespace");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetUserTenantForAcm() {
|
||||
String expect = "test";
|
||||
System.setProperty("acm.namespace", expect);
|
||||
String actual = TenantUtil.getUserTenantForAcm();
|
||||
assertEquals(expect, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetUserTenantForAns() {
|
||||
String expect = "test";
|
||||
System.setProperty("ans.namespace", expect);
|
||||
String actual = TenantUtil.getUserTenantForAns();
|
||||
assertEquals(expect, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetUserTenantForAcmWhenAbsent() {
|
||||
System.clearProperty("acm.namespace");
|
||||
assertEquals("", TenantUtil.getUserTenantForAcm());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor() {
|
||||
new TenantUtil();
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
#
|
||||
|
||||
com.alibaba.nacos.client.address.mock.MockServerListProvider
|
||||
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
accessKey=testAk
|
||||
secretKey=testSk
|
||||
tenantId=testTenantId
|
||||
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
env_spas_accessKey=testAk
|
||||
env_spas_secretKey=testSk
|
||||
ebv_spas_tenantId=testTenantId
|
||||
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
accessKey=
|
||||
secretKey=testSk
|
||||
tenantId=testTenantId
|
||||
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
Reference in New Issue
Block a user