⬆️ #2838 up nacos 2.0.2

This commit is contained in:
lbw committed 2021-06-25 16:58:41 +08:00
1 parent 864e0948a3
commit c85bdab9be
154 files changed
+808 -142

No files matched your search

+7 -1
View File
@@ -27,7 +27,7 @@
<description>nacos 注册配置中心</description>
<properties>
<nacos.version>1.4.1</nacos.version>
<nacos.version>2.0.2</nacos.version>
</properties>
<dependencies>
@@ -56,6 +56,12 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-system</artifactId>
<version>${hutool.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
@@ -16,7 +16,10 @@
package com.alibaba.nacos;
import cn.hutool.core.lang.Validator;
import cn.hutool.system.SystemUtil;
import com.alibaba.nacos.config.ConfigConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@@ -26,15 +29,32 @@ import org.springframework.scheduling.annotation.EnableScheduling;
* <p>
* nacos console 源码运行,方便开发 生产建议从官网下载最新版配置运行
*/
@Slf4j
@EnableScheduling
@SpringBootApplication
public class PigxNacosApplication {
public static void main(String[] args) {
if (initEnv()) {
SpringApplication.run(PigxNacosApplication.class, args);
}
}
/**
* 初始化运行环境
*/
private static boolean initEnv() {
// 特殊处理 window 且用户名包含中文的用户,避免RocksDB 初始化失败
// System.setProperty(SystemUtil.USER_HOME, "不包含中文的路径");
if (SystemUtil.getOsInfo().isWindows() && Validator.hasChinese(SystemUtil.getUserInfo().getHomeDir())) {
log.error("路径包含中文,需要打开以上注释配置指定不包含中文目录");
return false;
}
System.setProperty(ConfigConstants.STANDALONE_MODE, "true");
System.setProperty(ConfigConstants.AUTH_ENABLED, "false");
System.setProperty(ConfigConstants.LOG_BASEDIR, "logs");
SpringApplication.run(PigxNacosApplication.class, args);
return true;
}
}
+19 -5
View File
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config;
import javax.annotation.PostConstruct;
package com.alibaba.nacos.config;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.EnableScheduling;
@@ -27,7 +27,12 @@ import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import javax.annotation.PostConstruct;
import java.time.ZoneId;
/**
* Console config.
*
* @author yshen
* @author nkorange
* @since 1.2.0
@@ -40,24 +45,33 @@ public class ConsoleConfig {
@Autowired
private ControllerMethodsCache methodsCache;
/**
* Init.
*/
@PostConstruct
public void init() {
methodsCache.initClassMethod("com.alibaba.nacos.core.controller");
methodsCache.initClassMethod("com.alibaba.nacos.naming.controllers");
methodsCache.initClassMethod("com.alibaba.nacos.controller");
methodsCache.initClassMethod("com.alibaba.nacos.config.server.controller");
methodsCache.initClassMethod("com.alibaba.nacos.controller");
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.setMaxAge(18000L);
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(ZoneId.systemDefault().toString());
}
}
+9 -8
View File
@@ -16,19 +16,19 @@
package com.alibaba.nacos.controller;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.naming.controllers.OperatorController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* Health Controller.
*
@@ -57,7 +57,7 @@ public class HealthController {
* equal to 500 indicates that Nacos is in broken states.
*/
@GetMapping("/liveness")
public ResponseEntity liveness() {
public ResponseEntity<String> liveness() {
return ResponseEntity.ok().body("OK");
}
@@ -67,7 +67,7 @@ public class HealthController {
* 500 indicates that Nacos is not ready.
*/
@GetMapping("/readiness")
public ResponseEntity readiness(HttpServletRequest request) {
public ResponseEntity<String> readiness(HttpServletRequest request) {
boolean isConfigReadiness = isConfigReadiness();
boolean isNamingReadiness = isNamingReadiness(request);
@@ -76,14 +76,15 @@ public class HealthController {
}
if (!isConfigReadiness && !isNamingReadiness) {
return ResponseEntity.status(500).body("Config and Naming are not in readiness");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Config and Naming are not in readiness");
}
if (!isConfigReadiness) {
return ResponseEntity.status(500).body("Config is not in readiness");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Config is not in readiness");
}
return ResponseEntity.status(500).body("Naming is not in readiness");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Naming is not in readiness");
}
private boolean isConfigReadiness() {
+40 -32
View File
@@ -16,31 +16,26 @@
package com.alibaba.nacos.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.config.server.model.TenantInfo;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.enums.NamespaceTypeEnum;
import com.alibaba.nacos.model.Namespace;
import com.alibaba.nacos.model.NamespaceAllInfo;
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
/**
* namespace service.
@@ -58,6 +53,20 @@ public class NamespaceController {
private static final int NAMESPACE_ID_MAX_LENGTH = 128;
private static final String DEFAULT_NAMESPACE = "public";
private static final int DEFAULT_QUOTA = 200;
private static final String DEFAULT_CREATE_SOURCE = "nacos";
private static final String DEFAULT_NAMESPACE_SHOW_NAME = "Public";
private static final String DEFAULT_NAMESPACE_DESCRIPTION = "Public Namespace";
private static final String DEFAULT_TENANT = "";
private static final String DEFAULT_KP = "1";
/**
* Get namespace list.
* @param request request
@@ -66,21 +75,19 @@ public class NamespaceController {
*/
@GetMapping
public RestResult<List<Namespace>> getNamespaces(HttpServletRequest request, HttpServletResponse response) {
RestResult<List<Namespace>> rr = new RestResult<List<Namespace>>();
rr.setCode(200);
// TODO 获取用kp
List<TenantInfo> tenantInfos = persistService.findTenantByKp("1");
Namespace namespace0 = new Namespace("", "public", 200, persistService.configInfoCount(""), 0);
List<TenantInfo> tenantInfos = persistService.findTenantByKp(DEFAULT_KP);
Namespace namespace0 = new Namespace("", DEFAULT_NAMESPACE, DEFAULT_QUOTA,
persistService.configInfoCount(DEFAULT_TENANT), NamespaceTypeEnum.GLOBAL.getType());
List<Namespace> namespaces = new ArrayList<Namespace>();
namespaces.add(namespace0);
for (TenantInfo tenantInfo : tenantInfos) {
int configCount = persistService.configInfoCount(tenantInfo.getTenantId());
Namespace namespaceTmp = new Namespace(tenantInfo.getTenantId(), tenantInfo.getTenantName(), 200,
configCount, 2);
Namespace namespaceTmp = new Namespace(tenantInfo.getTenantId(), tenantInfo.getTenantName(), DEFAULT_QUOTA,
configCount, NamespaceTypeEnum.CUSTOM.getType());
namespaces.add(namespaceTmp);
}
rr.setData(namespaces);
return rr;
return RestResultUtils.success(namespaces);
}
/**
@@ -95,14 +102,15 @@ public class NamespaceController {
@RequestParam("namespaceId") String namespaceId) {
// TODO 获取用kp
if (StringUtils.isBlank(namespaceId)) {
return new NamespaceAllInfo(namespaceId, "Public", 200, persistService.configInfoCount(""), 0,
"Public Namespace");
return new NamespaceAllInfo(namespaceId, DEFAULT_NAMESPACE_SHOW_NAME, DEFAULT_QUOTA,
persistService.configInfoCount(DEFAULT_TENANT), NamespaceTypeEnum.GLOBAL.getType(),
DEFAULT_NAMESPACE_DESCRIPTION);
}
else {
TenantInfo tenantInfo = persistService.findTenantByKp("1", namespaceId);
TenantInfo tenantInfo = persistService.findTenantByKp(DEFAULT_KP, namespaceId);
int configCount = persistService.configInfoCount(namespaceId);
return new NamespaceAllInfo(namespaceId, tenantInfo.getTenantName(), 200, configCount, 2,
tenantInfo.getTenantDesc());
return new NamespaceAllInfo(namespaceId, tenantInfo.getTenantName(), DEFAULT_QUOTA, configCount,
NamespaceTypeEnum.CUSTOM.getType(), tenantInfo.getTenantDesc());
}
}
@@ -135,8 +143,8 @@ public class NamespaceController {
return false;
}
}
persistService.insertTenantInfoAtomic("1", namespaceId, namespaceName, namespaceDesc, "nacos",
System.currentTimeMillis());
persistService.insertTenantInfoAtomic(DEFAULT_KP, namespaceId, namespaceName, namespaceDesc,
DEFAULT_CREATE_SOURCE, System.currentTimeMillis());
return true;
}
@@ -166,7 +174,7 @@ public class NamespaceController {
@RequestParam("namespaceShowName") String namespaceShowName,
@RequestParam(value = "namespaceDesc", required = false) String namespaceDesc) {
// TODO 获取用kp
persistService.updateTenantNameAtomic("1", namespace, namespaceShowName, namespaceDesc);
persistService.updateTenantNameAtomic(DEFAULT_KP, namespace, namespaceShowName, namespaceDesc);
return true;
}
@@ -181,7 +189,7 @@ public class NamespaceController {
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
public Boolean deleteConfig(HttpServletRequest request, HttpServletResponse response,
@RequestParam("namespaceId") String namespaceId) {
persistService.removeTenantInfoAtomic("1", namespaceId);
persistService.removeTenantInfoAtomic(DEFAULT_KP, namespaceId);
return true;
}
@@ -18,7 +18,7 @@ package com.alibaba.nacos.controller;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
import com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl;
import org.apache.commons.lang3.StringUtils;
@@ -68,7 +68,7 @@ public class PermissionController {
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "permissions", action = ActionTypes.WRITE)
public Object addPermission(@RequestParam String role, @RequestParam String resource, @RequestParam String action) {
nacosRoleService.addPermission(role, resource, action);
return new RestResult<>(200, "add permission ok!");
return RestResultUtils.success("add permission ok!");
}
/**
@@ -83,7 +83,7 @@ public class PermissionController {
public Object deletePermission(@RequestParam String role, @RequestParam String resource,
@RequestParam String action) {
nacosRoleService.deletePermission(role, resource, action);
return new RestResult<>(200, "delete permission ok!");
return RestResultUtils.success("delete permission ok!");
}
}
+3 -3
View File
@@ -18,7 +18,7 @@ package com.alibaba.nacos.controller;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
import com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl;
import org.apache.commons.lang3.StringUtils;
@@ -84,7 +84,7 @@ public class RoleController {
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "roles", action = ActionTypes.WRITE)
public Object addRole(@RequestParam String role, @RequestParam String username) {
roleService.addRole(role, username);
return new RestResult<>(200, "add role ok!");
return RestResultUtils.success("add role ok!");
}
/**
@@ -103,7 +103,7 @@ public class RoleController {
else {
roleService.deleteRole(role, username);
}
return new RestResult<>(200, "delete role of user " + username + " ok!");
return RestResultUtils.success("delete role of user " + username + " ok!");
}
}
@@ -40,8 +40,8 @@ public class ServerStateController {
* @return state json.
*/
@GetMapping("/state")
public ResponseEntity serverState() {
Map<String, String> serverState = new HashMap<>(3);
public ResponseEntity<Map<String, String>> serverState() {
Map<String, String> serverState = new HashMap<>(4);
serverState.put("standalone_mode",
EnvUtil.getStandaloneMode() ? EnvUtil.STANDALONE_MODE_ALONE : EnvUtil.STANDALONE_MODE_CLUSTER);
+25 -36
View File
@@ -16,12 +16,6 @@
package com.alibaba.nacos.controller;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
@@ -29,6 +23,7 @@ import com.alibaba.nacos.auth.common.AuthConfigs;
import com.alibaba.nacos.auth.common.AuthSystemTypes;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.Objects;
import com.alibaba.nacos.config.server.auth.RoleInfo;
@@ -42,8 +37,8 @@ import com.alibaba.nacos.security.nacos.users.NacosUser;
import com.alibaba.nacos.security.nacos.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.utils.PasswordEncoderUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -58,6 +53,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* User related methods entry.
*
@@ -103,7 +103,7 @@ public class UserController {
throw new IllegalArgumentException("user '" + username + "' already exist!");
}
userDetailsService.createUser(username, PasswordEncoderUtil.encode(password));
return new RestResult<>(200, "create user ok!");
return RestResultUtils.success("create user ok!");
}
/**
@@ -124,7 +124,7 @@ public class UserController {
}
}
userDetailsService.deleteUser(username);
return new RestResult<>(200, "delete user ok!");
return RestResultUtils.success("delete user ok!");
}
/**
@@ -153,7 +153,7 @@ public class UserController {
userDetailsService.updateUserPassword(username, PasswordEncoderUtil.encode(newPassword));
return new RestResult<>(200, "update user ok!");
return RestResultUtils.success("update user ok!");
}
private boolean hasPermission(String username, HttpServletRequest request) {
@@ -202,42 +202,39 @@ public class UserController {
public Object login(@RequestParam String username, @RequestParam String password, HttpServletResponse response,
HttpServletRequest request) throws AccessException {
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())
|| AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
NacosUser user = (NacosUser) authManager.login(request);
response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER, NacosAuthConfig.TOKEN_PREFIX + user.getToken());
ObjectNode result = JacksonUtils.createEmptyJsonNode();
// JSONObject result = new JSONObject();
result.put(Constants.ACCESS_TOKEN, user.getToken());
result.put(Constants.TOKEN_TTL, authConfigs.getTokenValidityInSeconds());
result.put(Constants.GLOBAL_ADMIN, user.isGlobalAdmin());
result.put(Constants.USERNAME, user.getUserName());
return result;
}
// 通过用户名和密码创建一个 Authentication 认证对象,实现类为 UsernamePasswordAuthenticationToken
// create Authentication class through username and password, the implement class
// is UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,
password);
RestResult<String> rr = new RestResult<String>();
try {
// 通过 AuthenticationManager(默认实现为ProviderManager)的authenticate方法验证
// Authentication 对象
// use the method authenticate of AuthenticationManager(default implement is
// ProviderManager) to valid Authentication
Authentication authentication = authenticationManager.authenticate(authenticationToken);
// 将 Authentication 绑定到 SecurityContext
// bind SecurityContext to Authentication
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成Token
// generate Token
String token = jwtTokenManager.createToken(authentication);
// 将Token写入到Http头部
// write Token to Http header
response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER, "Bearer " + token);
rr.setCode(200);
rr.setData("Bearer " + token);
return rr;
return RestResultUtils.success("Bearer " + token);
}
catch (BadCredentialsException authentication) {
rr.setCode(401);
rr.setMessage("Login failed");
return rr;
return RestResultUtils.failed(HttpStatus.UNAUTHORIZED.value(), null, "Login failed");
}
}
@@ -252,8 +249,6 @@ public class UserController {
@Deprecated
public RestResult<String> updatePassword(@RequestParam(value = "oldPassword") String oldPassword,
@RequestParam(value = "newPassword") String newPassword) {
RestResult<String> rr = new RestResult<String>();
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = ((UserDetails) principal).getUsername();
User user = userDetailsService.getUserFromDatabase(username);
@@ -263,19 +258,13 @@ public class UserController {
try {
if (PasswordEncoderUtil.matches(oldPassword, password)) {
userDetailsService.updateUserPassword(username, PasswordEncoderUtil.encode(newPassword));
rr.setCode(200);
rr.setMessage("Update password success");
}
else {
rr.setCode(401);
rr.setMessage("Old password is invalid");
return RestResultUtils.success("Update password success");
}
return RestResultUtils.failed(HttpStatus.UNAUTHORIZED.value(), "Old password is invalid");
}
catch (Exception e) {
rr.setCode(500);
rr.setMessage("Update userpassword failed");
return RestResultUtils.failed(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Update userpassword failed");
}
return rr;
}
/**
@@ -0,0 +1,66 @@
/*
* 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.enums;
/**
* the enum of namespace. 0 : Global configuration, 1 : Default private namespace ,2 :
* Custom namespace.
*
* @author chenglu
* @date 2021-05-25 17:01
*/
public enum NamespaceTypeEnum {
/**
* Global configuration.
*/
GLOBAL(0, "Global configuration"),
/**
* Default private namespace.
*/
PRIVATE(1, "Default private namespace"),
/**
* Custom namespace.
*/
CUSTOM(2, "Custom namespace");
/**
* the namespace type.
*/
private final int type;
/**
* the description.
*/
private final String description;
NamespaceTypeEnum(int type, String description) {
this.type = type;
this.description = description;
}
public int getType() {
return type;
}
public String getDescription() {
return description;
}
}
File mode changed.
@@ -65,7 +65,7 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
return bearerToken.substring(7);
return bearerToken.substring(TOKEN_PREFIX.length());
}
String jwt = request.getParameter(Constants.ACCESS_TOKEN);
if (StringUtils.isNotBlank(jwt)) {
+1 -1
View File
@@ -32,7 +32,7 @@ public class Namespace {
private int configCount;
/**
* 0 : Global configuration, 1 : Default private namespace ,2 : Custom namespace.
* see {@link com.alibaba.nacos.console.enums.NamespaceTypeEnum}.
*/
private int type;
File mode changed.
File mode changed.
File mode changed.
File mode changed.
@@ -0,0 +1,172 @@
/*
* 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.security.nacos;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.config.server.auth.RoleInfo;
import com.alibaba.nacos.config.server.model.User;
import com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.security.nacos.users.NacosUserDetails;
import com.alibaba.nacos.security.nacos.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.utils.PasswordEncoderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import java.util.Hashtable;
import java.util.List;
import static com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE;
/**
* LDAP auth provider.
*
* @author zjw
*/
@Component
public class LdapAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOG = LoggerFactory.getLogger(LdapAuthenticationProvider.class);
private static final String FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
private static final String TIMEOUT = "com.sun.jndi.ldap.connect.timeout";
private static final String DEFAULT_PASSWORD = "nacos";
private static final String LDAP_PREFIX = "LDAP_";
private static final String DEFAULT_SECURITY_AUTH = "simple";
@Autowired
private NacosUserDetailsServiceImpl userDetailsService;
@Autowired
private NacosRoleServiceImpl nacosRoleService;
@Value(("${nacos.core.auth.ldap.url:ldap://localhost:389}"))
private String ldapUrl;
@Value(("${nacos.core.auth.ldap.timeout:3000}"))
private String time;
@Value(("${nacos.core.auth.ldap.userdn:cn={0},ou=user,dc=company,dc=com}"))
private String userNamePattern;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
if (isAdmin(username)) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (PasswordEncoderUtil.matches(password, userDetails.getPassword())) {
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
}
else {
return null;
}
}
if (!ldapLogin(username, password)) {
return null;
}
UserDetails userDetails;
try {
userDetails = userDetailsService.loadUserByUsername(LDAP_PREFIX + username);
}
catch (UsernameNotFoundException exception) {
String nacosPassword = PasswordEncoderUtil.encode(DEFAULT_PASSWORD);
userDetailsService.createUser(LDAP_PREFIX + username, nacosPassword);
User user = new User();
user.setUsername(LDAP_PREFIX + username);
user.setPassword(nacosPassword);
userDetails = new NacosUserDetails(user);
}
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
}
private boolean isAdmin(String username) {
List<RoleInfo> roleInfos = nacosRoleService.getRoles(username);
if (CollectionUtils.isEmpty(roleInfos)) {
return false;
}
for (RoleInfo roleinfo : roleInfos) {
if (GLOBAL_ADMIN_ROLE.equals(roleinfo.getRole())) {
return true;
}
}
return false;
}
private boolean ldapLogin(String username, String password) throws AuthenticationException {
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
env.put(Context.PROVIDER_URL, ldapUrl);
env.put(Context.SECURITY_AUTHENTICATION, DEFAULT_SECURITY_AUTH);
env.put(Context.SECURITY_PRINCIPAL, userNamePattern.replace("{0}", username));
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(TIMEOUT, time);
LdapContext ctx = null;
try {
ctx = new InitialLdapContext(env, null);
}
catch (CommunicationException e) {
throw new RuntimeException("LDAP Service connect timeout");
}
catch (Exception e) {
LOG.warn("Exception cause by:{}", e.getMessage());
return false;
}
finally {
closeContext(ctx);
}
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return aClass.equals(UsernamePasswordAuthenticationToken.class);
}
private void closeContext(DirContext ctx) {
if (ctx != null) {
try {
ctx.close();
}
catch (Exception e) {
LOG.error("Exception closing context", e);
}
}
}
}
+24 -17
View File
@@ -59,6 +59,10 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
public static final String UPDATE_PASSWORD_ENTRY_POINT = CONSOLE_RESOURCE_NAME_PREFIX + "user/password";
private static final String DEFAULT_ALL_PATH_PATTERN = "/**";
private static final String PROPERTY_IGNORE_URLS = "nacos.security.ignore.urls";
@Autowired
private Environment env;
@@ -71,6 +75,9 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
@Autowired
private NacosUserDetailsServiceImpl userDetailsService;
@Autowired
private LdapAuthenticationProvider ldapAuthenticationProvider;
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
@@ -82,10 +89,13 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
String ignoreUrls = null;
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
ignoreUrls = "/**";
ignoreUrls = DEFAULT_ALL_PATH_PATTERN;
}
else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
ignoreUrls = DEFAULT_ALL_PATH_PATTERN;
}
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
ignoreUrls = env.getProperty("nacos.security.ignore.urls", "/**");
ignoreUrls = env.getProperty(PROPERTY_IGNORE_URLS, DEFAULT_ALL_PATH_PATTERN);
}
if (StringUtils.isNotBlank(ignoreUrls)) {
for (String each : ignoreUrls.trim().split(SECURITY_IGNORE_URLS_SPILT_CHAR)) {
@@ -96,27 +106,24 @@ public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
auth.authenticationProvider(ldapAuthenticationProvider);
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
http
.csrf().disable().cors() // We don't need CSRF for JWT based
// authentication
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers(LOGIN_ENTRY_POINT).permitAll()
.and().authorizeRequests().antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated()
.and().exceptionHandling().authenticationEntryPoint(new JwtAuthenticationEntryPoint());
http.csrf().disable().cors()// We don't need CSRF for JWT based authentication
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers(LOGIN_ENTRY_POINT).permitAll().and().authorizeRequests()
.antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated().and().exceptionHandling()
.authenticationEntryPoint(new JwtAuthenticationEntryPoint());
// disable cache
http.headers().cacheControl();
@@ -17,15 +17,16 @@
package com.alibaba.nacos.security.nacos;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.auth.AuthManager;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.auth.model.Permission;
import com.alibaba.nacos.auth.model.User;
import com.alibaba.nacos.config.server.auth.RoleInfo;
import com.alibaba.nacos.config.server.utils.RequestUtil;
import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.security.nacos.users.NacosUser;
import com.alibaba.nacos.core.utils.Loggers;
import io.jsonwebtoken.ExpiredJwtException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -50,6 +51,10 @@ public class NacosAuthManager implements AuthManager {
private static final String TOKEN_PREFIX = "Bearer ";
private static final String PARAM_USERNAME = "username";
private static final String PARAM_PASSWORD = "password";
@Autowired
private JwtTokenManager tokenManager;
@@ -97,6 +102,43 @@ public class NacosAuthManager implements AuthManager {
return user;
}
@Override
public User loginRemote(Object request) throws AccessException {
Request req = (Request) request;
String token = resolveToken(req);
if (StringUtils.isBlank(token)) {
throw new AccessException("user not found!");
}
try {
tokenManager.validateToken(token);
}
catch (ExpiredJwtException e) {
throw new AccessException("token expired!");
}
catch (Exception e) {
throw new AccessException("token invalid!");
}
Authentication authentication = tokenManager.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
String username = authentication.getName();
NacosUser user = new NacosUser();
user.setUserName(username);
user.setToken(token);
List<RoleInfo> roleInfoList = roleService.getRoles(username);
if (roleInfoList != null) {
for (RoleInfo roleInfo : roleInfoList) {
if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
user.setGlobalAdmin(true);
break;
}
}
}
return user;
}
@Override
public void auth(Permission permission, User user) throws AccessException {
if (Loggers.AUTH.isDebugEnabled()) {
@@ -118,8 +160,26 @@ public class NacosAuthManager implements AuthManager {
}
bearerToken = request.getParameter(Constants.ACCESS_TOKEN);
if (StringUtils.isBlank(bearerToken)) {
String userName = request.getParameter("username");
String password = request.getParameter("password");
String userName = request.getParameter(PARAM_USERNAME);
String password = request.getParameter(PARAM_PASSWORD);
bearerToken = resolveTokenFromUser(userName, password);
}
return bearerToken;
}
/**
* Get token from header.
*/
private String resolveToken(Request request) throws AccessException {
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
return bearerToken.substring(7);
}
bearerToken = request.getHeader(Constants.ACCESS_TOKEN);
if (StringUtils.isBlank(bearerToken)) {
String userName = request.getHeader(PARAM_USERNAME);
String password = request.getHeader(PARAM_PASSWORD);
bearerToken = resolveTokenFromUser(userName, password);
}
@@ -127,17 +187,25 @@ public class NacosAuthManager implements AuthManager {
}
private String resolveTokenFromUser(String userName, String rawPassword) throws AccessException {
String finalName;
Authentication authenticate;
try {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userName,
rawPassword);
authenticationManager.authenticate(authenticationToken);
authenticate = authenticationManager.authenticate(authenticationToken);
}
catch (AuthenticationException e) {
throw new AccessException("unknown user!");
}
return tokenManager.createToken(userName);
if (null == authenticate || StringUtils.isBlank(authenticate.getName())) {
finalName = userName;
}
else {
finalName = authenticate.getName();
}
return tokenManager.createToken(finalName);
}
}
@@ -23,9 +23,9 @@ import com.alibaba.nacos.config.server.auth.PermissionPersistService;
import com.alibaba.nacos.config.server.auth.RoleInfo;
import com.alibaba.nacos.config.server.auth.RolePersistService;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
import com.alibaba.nacos.security.nacos.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.core.utils.Loggers;
import io.jsonwebtoken.lang.Collections;
import org.apache.commons.lang3.StringUtils;
import org.apache.mina.util.ConcurrentHashSet;
@@ -52,6 +52,8 @@ public class NacosRoleServiceImpl {
public static final String GLOBAL_ADMIN_ROLE = "ROLE_ADMIN";
private static final int DEFAULT_PAGE_NO = 1;
@Autowired
private AuthConfigs authConfigs;
@@ -73,7 +75,7 @@ public class NacosRoleServiceImpl {
@Scheduled(initialDelay = 5000, fixedDelay = 15000)
private void reload() {
try {
Page<RoleInfo> roleInfoPage = rolePersistService.getRolesByUserName(StringUtils.EMPTY, 1,
Page<RoleInfo> roleInfoPage = rolePersistService.getRolesByUserName(StringUtils.EMPTY, DEFAULT_PAGE_NO,
Integer.MAX_VALUE);
if (roleInfoPage == null) {
return;
@@ -90,7 +92,7 @@ public class NacosRoleServiceImpl {
Map<String, List<PermissionInfo>> tmpPermissionInfoMap = new ConcurrentHashMap<>(16);
for (String role : tmpRoleSet) {
Page<PermissionInfo> permissionInfoPage = permissionPersistService.getPermissions(role, 1,
Page<PermissionInfo> permissionInfoPage = permissionPersistService.getPermissions(role, DEFAULT_PAGE_NO,
Integer.MAX_VALUE);
tmpPermissionInfoMap.put(role, permissionInfoPage.getPageItems());
}
@@ -158,7 +160,7 @@ public class NacosRoleServiceImpl {
public List<RoleInfo> getRoles(String username) {
List<RoleInfo> roleInfoList = roleInfoMap.get(username);
if (!authConfigs.isCachingEnabled()) {
Page<RoleInfo> roleInfoPage = getRolesFromDatabase(username, 1, Integer.MAX_VALUE);
Page<RoleInfo> roleInfoPage = getRolesFromDatabase(username, DEFAULT_PAGE_NO, Integer.MAX_VALUE);
if (roleInfoPage != null) {
roleInfoList = roleInfoPage.getPageItems();
}
@@ -177,7 +179,8 @@ public class NacosRoleServiceImpl {
public List<PermissionInfo> getPermissions(String role) {
List<PermissionInfo> permissionInfoList = permissionInfoMap.get(role);
if (!authConfigs.isCachingEnabled()) {
Page<PermissionInfo> permissionInfoPage = getPermissionsFromDatabase(role, 1, Integer.MAX_VALUE);
Page<PermissionInfo> permissionInfoPage = getPermissionsFromDatabase(role, DEFAULT_PAGE_NO,
Integer.MAX_VALUE);
if (permissionInfoPage != null) {
permissionInfoList = permissionInfoPage.getPageItems();
}
File mode changed.
File mode changed.
@@ -25,10 +25,6 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
*/
public class PasswordEncoderUtil {
public static void main(String[] args) {
System.out.println(new BCryptPasswordEncoder().encode("nacos"));
}
public static Boolean matches(String raw, String encoded) {
return new BCryptPasswordEncoder().matches(raw, encoded);
}
+8 -12
View File
@@ -5,11 +5,12 @@ server:
db:
num: 1
user: ${MYSQL_USER:root}
password: ${MYSQL_PWD:root}
user: ${MYSQL-USER:root}
password: ${MYSQL-PWD:root}
url:
0: jdbc:mysql://${MYSQL_HOST:pigx-mysql}:${MYSQL_PORT:3306}/${MYSQL_DB:pigxx_config}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
nacos:
core:
auth:
@@ -20,20 +21,20 @@ nacos:
urls: /,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
spring:
application:
name: @artifactId@
datasource:
platform: mysql
platform: mysql #这个过期属性不能修改,nacos 代码对此有硬编码
security:
enabled: true
boot: # 接入 spring boot admin
admin:
client:
url: http://pigx-monitor:5001
username: pigx
password: pigx
username: pig
password: pig
instance:
prefer-ip: true
application:
name: @project.artifactId@
useAddressServer: true
@@ -48,8 +49,3 @@ management:
enabled: false
elastic:
enabled: false
# 屏蔽scanner warning 日志
logging:
level:
org.apache.tomcat.util.scan.StandardJarScanner: ERROR
View File
File mode changed.
File mode changed.
File mode changed.
View File
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
View File
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

File mode changed.
File mode changed.
File mode changed.

Before

Width:  |  Height:  |  Size: 114 B

After

Width:  |  Height:  |  Size: 114 B

File mode changed.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

File mode changed.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

File mode changed.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

File mode changed.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
View File
File mode changed.
View File
File mode changed.
View File
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
Loaded 100 of 154 files, more files were not shown because too many files have changed in this diff. Show more