Skip to content

Commit

Permalink
#1105 Add integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nkorange committed Jan 9, 2020
1 parent 02fea89 commit 8273198
Show file tree
Hide file tree
Showing 24 changed files with 835 additions and 66 deletions.
2 changes: 1 addition & 1 deletion BUILDING
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ Build Instructions for NACOS
Execute the following command in order to build the tar.gz packages and install JAR into local repository:

#build nacos
$ mvn -Prelease-nacos -DskipTests clean install -U
$ mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
2 changes: 2 additions & 0 deletions api/src/main/java/com/alibaba/nacos/api/common/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public class Constants {

public static final String TOKEN_TTL = "tokenTtl";

public static final String GLOBAL_ADMIN = "globalAdmin";

public static final String TOKEN_REFRESH_WINDOW = "tokenRefreshWindow";

/**
Expand Down
9 changes: 8 additions & 1 deletion config/src/main/resources/META-INF/nacos-db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ CREATE TABLE roles (
role varchar(50) NOT NULL
);

CREATE TABLE permissions (
role varchar(50) NOT NULL,
resource varchar(512) NOT NULL,
action varchar(8) NOT NULL,
constraint uk_role_permission UNIQUE (role,resource,action)
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
INSERT INTO roles (username, role) VALUES ('nacos', 'GLOBAL_ADMIN');
9 changes: 8 additions & 1 deletion config/src/main/resources/META-INF/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ CREATE TABLE roles (
role varchar(50) NOT NULL
);

CREATE TABLE permissions (
role varchar(50) NOT NULL,
resource varchar(512) NOT NULL,
action varchar(8) NOT NULL,
constraint uk_role_permission UNIQUE (role,resource,action)
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
INSERT INTO roles (username, role) VALUES ('nacos', 'GLOBAL_ADMIN');
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public class UserController {
@PostMapping
public Object createUser(@RequestParam String username, @RequestParam String password) {

User user = userDetailsService.getUser(username);
User user = userDetailsService.getUserFromDatabase(username);
if (user != null) {
throw new IllegalArgumentException("user '" + username + "' already exist!");
}
Expand Down Expand Up @@ -112,7 +112,7 @@ public Object deleteUser(@RequestParam String username) {
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
public Object updateUser(@RequestParam String username, @RequestParam String newPassword) {

User user = userDetailsService.getUser(username);
User user = userDetailsService.getUserFromDatabase(username);
if (user == null) {
throw new IllegalArgumentException("user " + username + " not exist!");
}
Expand Down Expand Up @@ -162,6 +162,7 @@ public Object login(@RequestParam String username, @RequestParam String password
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());
return result;
}

Expand Down Expand Up @@ -196,8 +197,8 @@ public RestResult<String> updatePassword(@RequestParam(value = "oldPassword") St
RestResult<String> rr = new RestResult<String>();
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = ((UserDetails) principal).getUsername();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
String password = userDetails.getPassword();
User user = userDetailsService.getUserFromDatabase(username);
String password = user.getPassword();

// TODO: throw out more fine grained exceptions
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package com.alibaba.nacos.console.exception;

import com.alibaba.nacos.core.auth.AccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
Expand All @@ -30,14 +32,21 @@
@ControllerAdvice
public class ConsoleExceptionHandler {

private static final Logger logger = LoggerFactory.getLogger(ConsoleExceptionHandler.class);

@ExceptionHandler(AccessException.class)
private ResponseEntity<String> handleAccessException(AccessException e) {

return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getErrMsg());
}

@ExceptionHandler(IllegalArgumentException.class)
private ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.toString());
}

@ExceptionHandler(Exception.class)
private ResponseEntity<String> handleException(Exception e) {
logger.error("CONSOLE", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.alibaba.nacos.console.security.nacos;

import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.config.server.auth.RoleInfo;
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.console.security.nacos.users.NacosUser;
import com.alibaba.nacos.core.auth.AccessException;
Expand All @@ -34,6 +35,7 @@
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
* Builtin access control entry of Nacos
Expand Down Expand Up @@ -74,10 +76,17 @@ public User login(Object request) throws AccessException {
Authentication authentication = tokenManager.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);

String userId = authentication.getName();
String username = authentication.getName();
NacosUser user = new NacosUser();
user.setUserName(userId);
user.setUserName(username);
user.setToken(token);
List<RoleInfo> roleInfoList = roleService.getRoles(username);
for (RoleInfo roleInfo : roleInfoList) {
if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
user.setGlobalAdmin(true);
break;
}
}
return user;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.core.auth.AuthConfigs;
import com.alibaba.nacos.core.auth.Permission;
import com.alibaba.nacos.core.utils.Loggers;
import io.jsonwebtoken.lang.Collections;
Expand All @@ -44,7 +45,10 @@
@Service
public class NacosRoleServiceImpl {

private static final String GLOBAL_ADMIN_ROLE = "GLOBAL_ADMIN";
public static final String GLOBAL_ADMIN_ROLE = "GLOBAL_ADMIN";

@Autowired
private AuthConfigs authConfigs;

@Autowired
private RolePersistService rolePersistService;
Expand Down Expand Up @@ -95,13 +99,13 @@ private void reload() {
* Note if the user has many roles, this method returns true if any one role of the user has the
* desired permission.
*
* @param username user info
* @param username user info
* @param permission permission to auth
* @return true if granted, false otherwise
*/
public boolean hasPermission(String username, Permission permission) {

List<RoleInfo> roleInfoList = roleInfoMap.get(username);
List<RoleInfo> roleInfoList = getRoles(username);
if (Collections.isEmpty(roleInfoList)) {
return false;
}
Expand All @@ -120,7 +124,7 @@ public boolean hasPermission(String username, Permission permission) {

// For other roles, use a pattern match to decide if pass or not.
for (RoleInfo roleInfo : roleInfoList) {
List<PermissionInfo> permissionInfoList = permissionInfoMap.get(roleInfo.getRole());
List<PermissionInfo> permissionInfoList = getPermissions(roleInfo.getRole());
if (Collections.isEmpty(permissionInfoList)) {
continue;
}
Expand All @@ -136,11 +140,36 @@ public boolean hasPermission(String username, Permission permission) {
return false;
}

public List<RoleInfo> getRoles(String username) {
List<RoleInfo> roleInfoList = roleInfoMap.get(username);
if (!authConfigs.isCachingEnabled()) {
Page<RoleInfo> roleInfoPage = getRolesFromDatabase(username, 1, Integer.MAX_VALUE);
if (roleInfoPage != null) {
roleInfoList = roleInfoPage.getPageItems();
}
}
return roleInfoList;
}

public Page<RoleInfo> getRolesFromDatabase(String userName, int pageNo, int pageSize) {
Page<RoleInfo> roles = rolePersistService.getRolesByUserName(userName, pageNo, pageSize);
if (roles == null) {
return new Page<>();
}
return roles;
}

public List<PermissionInfo> getPermissions(String role) {
List<PermissionInfo> permissionInfoList = permissionInfoMap.get(role);
if (!authConfigs.isCachingEnabled()) {
Page<PermissionInfo> permissionInfoPage = getPermissionsFromDatabase(role, 1, Integer.MAX_VALUE);
if (permissionInfoPage != null) {
permissionInfoList = permissionInfoPage.getPageItems();
}
}
return permissionInfoList;
}

public Page<PermissionInfo> getPermissionsByRoleFromDatabase(String role, int pageNo, int pageSize) {
return permissionPersistService.getPermissions(role, pageNo, pageSize);
}
Expand All @@ -157,11 +186,15 @@ public void deleteRole(String role, String userName) {
}

public void deleteRole(String role) {

rolePersistService.deleteRole(role);
}

public Page<PermissionInfo> getPermissionsFromDatabase(String role, int pageNo, int pageSize) {
Page<PermissionInfo> pageInfo = permissionPersistService.getPermissions(role, pageNo, pageSize);
if (pageInfo == null) {
return new Page<>();
}
return pageInfo;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class NacosUser extends User {

private String token;

private boolean globalAdmin = false;

public String getToken() {
return token;
}
Expand All @@ -35,6 +37,14 @@ public void setToken(String token) {
this.token = token;
}

public boolean isGlobalAdmin() {
return globalAdmin;
}

public void setGlobalAdmin(boolean globalAdmin) {
this.globalAdmin = globalAdmin;
}

@Override
public String toString() {
return JSON.toJSONString(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.alibaba.nacos.config.server.auth.UserPersistService;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.User;
import com.alibaba.nacos.core.auth.AuthConfigs;
import com.alibaba.nacos.core.utils.Loggers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
Expand All @@ -44,6 +45,9 @@ public class NacosUserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserPersistService userPersistService;

@Autowired
private AuthConfigs authConfigs;

@Scheduled(initialDelay = 5000, fixedDelay = 15000)
private void reload() {
try {
Expand All @@ -66,6 +70,10 @@ private void reload() {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

User user = userMap.get(username);
if (!authConfigs.isCachingEnabled()) {
user = userPersistService.findUserByUsername(username);
}

if (user == null) {
throw new UsernameNotFoundException(username);
}
Expand All @@ -81,7 +89,15 @@ public Page<User> getUsersFromDatabase(int pageNo, int pageSize) {
}

public User getUser(String username) {
return userMap.get(username);
User user = userMap.get(username);
if (!authConfigs.isCachingEnabled()) {
user = getUserFromDatabase(username);
}
return user;
}

public User getUserFromDatabase(String username) {
return userPersistService.findUserByUsername(username);
}

public void createUser(String username, String password) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ public boolean isAuthEnabled() {
.getProperty("nacos.core.auth.enabled", "false"));
}

public boolean isCachingEnabled() {
return BooleanUtils.toBoolean(reloadableConfigs.getProperties()
.getProperty("nacos.core.auth.caching.enabled", "true"));
}

@Bean
public FilterRegistrationBean authFilterRegistration() {
FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,12 @@
* @author nkorange
* @since 1.2.0
*/
@ConditionalOnProperty(name = "spring.config.location", matchIfMissing = false)
@Component
public class ReloadableConfigs {

private Properties properties;

@Value("${spring.config.location}")
@Value("${spring.config.location:}")
private String path;

private static final String FILE_PREFIX = "file:";
Expand Down
3 changes: 3 additions & 0 deletions distribution/conf/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ nacos.core.auth.default.token.expire.seconds=18000
### The default token:
nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789

### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=true


#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,10 +419,7 @@ private static HttpResult getResult(HttpURLConnection conn) throws IOException {
inputStream = new GZIPInputStream(inputStream);
}

HttpResult result = new HttpResult(respCode, IoUtils.toString(inputStream, getCharset(conn)), respHeaders);
inputStream.close();

return result;
return new HttpResult(respCode, IoUtils.toString(inputStream, getCharset(conn)), respHeaders);
}

private static String getCharset(HttpURLConnection conn) {
Expand Down
17 changes: 11 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,11 @@
<artifactId>nacos-example</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-address</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
Expand All @@ -539,12 +544,12 @@
<version>1.2.58</version>
</dependency>

<!-- javax libs-->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs</artifactId>
<version>2.1</version>
</dependency>
<!-- &lt;!&ndash; javax libs&ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>javax.ws.rs</groupId>-->
<!-- <artifactId>javax.ws.rs</artifactId>-->
<!-- <version>1.0</version>-->
<!-- </dependency>-->

<dependency>
<groupId>javax.servlet</groupId>
Expand Down
Loading

0 comments on commit 8273198

Please sign in to comment.