* Remove default password * admin role check fix * remove tmp admin
This commit is contained in:
parent
b2e506d7fe
commit
70ad2eb991
@ -78,6 +78,8 @@ public class AuthConfigs extends Subscriber<ServerConfigChangeEvent> {
|
||||
@Value("${" + Constants.Auth.NACOS_CORE_AUTH_ENABLE_USER_AGENT_AUTH_WHITE + ":false}")
|
||||
private boolean enableUserAgentAuthWhite;
|
||||
|
||||
private boolean hasGlobalAdminRole;
|
||||
|
||||
private Map<String, Properties> authPluginProperties = new HashMap<>();
|
||||
|
||||
public AuthConfigs() {
|
||||
@ -125,6 +127,14 @@ public class AuthConfigs extends Subscriber<ServerConfigChangeEvent> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHasGlobalAdminRole() {
|
||||
return hasGlobalAdminRole;
|
||||
}
|
||||
|
||||
public void setHasGlobalAdminRole(boolean hasGlobalAdminRole) {
|
||||
this.hasGlobalAdminRole = hasGlobalAdminRole;
|
||||
}
|
||||
|
||||
public String getNacosAuthSystemType() {
|
||||
return nacosAuthSystemType;
|
||||
}
|
||||
|
@ -210,10 +210,6 @@ CREATE TABLE permissions (
|
||||
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');
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* ipv6 support */
|
||||
|
@ -208,6 +208,3 @@ CREATE TABLE `permissions` (
|
||||
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
|
||||
);
|
||||
|
||||
INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
|
||||
|
||||
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
|
||||
|
@ -210,9 +210,6 @@ CREATE TABLE permissions (
|
||||
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');
|
||||
|
||||
|
||||
/******************************************/
|
||||
|
@ -210,10 +210,6 @@ CREATE TABLE permissions (
|
||||
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');
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* ipv6 support */
|
||||
|
@ -208,6 +208,3 @@ CREATE TABLE `permissions` (
|
||||
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
|
||||
);
|
||||
|
||||
INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
|
||||
|
||||
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
|
||||
|
@ -57,7 +57,6 @@ public class AbstractAuthenticationManager implements IAuthenticationManager {
|
||||
if (StringUtils.isBlank(username) || StringUtils.isBlank(rawPassword)) {
|
||||
throw new AccessException("user not found!");
|
||||
}
|
||||
|
||||
NacosUserDetails nacosUserDetails = (NacosUserDetails) userDetailsService.loadUserByUsername(username);
|
||||
if (nacosUserDetails == null || !PasswordEncoderUtil.matches(rawPassword, nacosUserDetails.getPassword())) {
|
||||
throw new AccessException("user not found!");
|
||||
@ -121,6 +120,11 @@ public class AbstractAuthenticationManager implements IAuthenticationManager {
|
||||
return roleService.hasGlobalAdminRole(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlobalAdminRole() {
|
||||
return roleService.hasGlobalAdminRole();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlobalAdminRole(NacosUser nacosUser) {
|
||||
if (nacosUser.isGlobalAdmin()) {
|
||||
|
@ -71,6 +71,11 @@ public class AuthenticationManagerDelegator implements IAuthenticationManager {
|
||||
return getManager().hasGlobalAdminRole(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlobalAdminRole() {
|
||||
return getManager().hasGlobalAdminRole();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlobalAdminRole(NacosUser nacosUser) {
|
||||
return getManager().hasGlobalAdminRole(nacosUser);
|
||||
|
@ -75,6 +75,13 @@ public interface IAuthenticationManager {
|
||||
*/
|
||||
boolean hasGlobalAdminRole(String username);
|
||||
|
||||
/**
|
||||
* Whether the user exist the administrator role.
|
||||
*
|
||||
* @return if the user exist the administrator role.
|
||||
*/
|
||||
boolean hasGlobalAdminRole();
|
||||
|
||||
/**
|
||||
* Whether the user has the administrator role.
|
||||
*
|
||||
|
@ -35,6 +35,8 @@ public class AuthConstants {
|
||||
|
||||
public static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
public static final String DEFAULT_USER = "nacos";
|
||||
|
||||
public static final String PARAM_USERNAME = "username";
|
||||
|
||||
public static final String PARAM_PASSWORD = "password";
|
||||
|
@ -22,6 +22,7 @@ import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||
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.StringUtils;
|
||||
import com.alibaba.nacos.persistence.model.Page;
|
||||
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
|
||||
@ -36,6 +37,7 @@ import com.alibaba.nacos.plugin.auth.impl.token.TokenManagerDelegate;
|
||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUser;
|
||||
import com.alibaba.nacos.plugin.auth.impl.users.NacosUserDetailsServiceImpl;
|
||||
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordEncoderUtil;
|
||||
import com.alibaba.nacos.plugin.auth.impl.utils.PasswordGeneratorUtil;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@ -109,6 +111,33 @@ public class UserController {
|
||||
return RestResultUtils.success("create user ok!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a admin user only not exist admin user can use.
|
||||
*/
|
||||
@PostMapping("/admin")
|
||||
public Object createAdminUser(@RequestParam(required = false) String username,
|
||||
@RequestParam(required = false) String password) {
|
||||
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||
if (roleService.hasGlobalAdminRole()) {
|
||||
return RestResultUtils.failed("have admin user cannot use it");
|
||||
}
|
||||
if (StringUtils.isBlank(password)) {
|
||||
password = PasswordGeneratorUtil.generateRandomPassword();
|
||||
}
|
||||
if (StringUtils.isBlank(username)) {
|
||||
username = AuthConstants.DEFAULT_USER;
|
||||
}
|
||||
userDetailsService.createUser(username, PasswordEncoderUtil.encode(password));
|
||||
roleService.addAdminRole(username);
|
||||
ObjectNode result = JacksonUtils.createEmptyJsonNode();
|
||||
result.put(AuthConstants.PARAM_USERNAME, username);
|
||||
result.put(AuthConstants.PARAM_PASSWORD, password);
|
||||
return result;
|
||||
} else {
|
||||
return RestResultUtils.failed("not support");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existed user.
|
||||
*
|
||||
@ -122,7 +151,7 @@ public class UserController {
|
||||
List<RoleInfo> roleInfoList = roleService.getRoles(username);
|
||||
if (roleInfoList != null) {
|
||||
for (RoleInfo roleInfo : roleInfoList) {
|
||||
if (roleInfo.getRole().equals(AuthConstants.GLOBAL_ADMIN_ROLE)) {
|
||||
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole())) {
|
||||
throw new IllegalArgumentException("cannot delete admin: " + username);
|
||||
}
|
||||
}
|
||||
@ -170,7 +199,8 @@ public class UserController {
|
||||
return RestResultUtils.success("update user ok!");
|
||||
}
|
||||
|
||||
private boolean hasPermission(String username, HttpServletRequest request) throws HttpSessionRequiredException, AccessException {
|
||||
private boolean hasPermission(String username, HttpServletRequest request)
|
||||
throws HttpSessionRequiredException, AccessException {
|
||||
if (!authConfigs.isAuthEnabled()) {
|
||||
return true;
|
||||
}
|
||||
@ -232,10 +262,14 @@ public class UserController {
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public Object login(@RequestParam String username, @RequestParam String password, HttpServletResponse response,
|
||||
HttpServletRequest request) throws AccessException {
|
||||
HttpServletRequest request) throws AccessException, IOException {
|
||||
|
||||
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())
|
||||
|| AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||
if (!iAuthenticationManager.hasGlobalAdminRole()) {
|
||||
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, "admin role user not exist");
|
||||
return null;
|
||||
}
|
||||
NacosUser user = iAuthenticationManager.authenticate(request);
|
||||
|
||||
response.addHeader(AuthConstants.AUTHORIZATION_HEADER, AuthConstants.TOKEN_PREFIX + user.getToken());
|
||||
|
@ -176,6 +176,15 @@ public class NacosRoleServiceImpl {
|
||||
return roleInfoList;
|
||||
}
|
||||
|
||||
public List<RoleInfo> getAllRoles() {
|
||||
Page<RoleInfo> roleInfoPage = rolePersistService.getRolesByUserNameAndRoleName(StringUtils.EMPTY,
|
||||
StringUtils.EMPTY, DEFAULT_PAGE_NO, Integer.MAX_VALUE);
|
||||
if (roleInfoPage == null) {
|
||||
return null;
|
||||
}
|
||||
return roleInfoPage.getPageItems();
|
||||
}
|
||||
|
||||
public Page<RoleInfo> getRolesFromDatabase(String userName, String role, int pageNo, int pageSize) {
|
||||
Page<RoleInfo> roles = rolePersistService.getRolesByUserNameAndRoleName(userName, role, pageNo, pageSize);
|
||||
if (roles == null) {
|
||||
@ -213,6 +222,7 @@ public class NacosRoleServiceImpl {
|
||||
if (userDetailsService.getUserFromDatabase(username) == null) {
|
||||
throw new IllegalArgumentException("user '" + username + "' not found!");
|
||||
}
|
||||
|
||||
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {
|
||||
throw new IllegalArgumentException(
|
||||
"role '" + AuthConstants.GLOBAL_ADMIN_ROLE + "' is not permitted to create!");
|
||||
@ -221,10 +231,39 @@ public class NacosRoleServiceImpl {
|
||||
roleSet.add(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add role.
|
||||
*
|
||||
* @param username user name
|
||||
*/
|
||||
public void addAdminRole(String username) {
|
||||
if (userDetailsService.getUserFromDatabase(username) == null) {
|
||||
throw new IllegalArgumentException("user '" + username + "' not found!");
|
||||
}
|
||||
if (hasGlobalAdminRole()) {
|
||||
throw new IllegalArgumentException("role '" + AuthConstants.GLOBAL_ADMIN_ROLE + "' already exist !");
|
||||
}
|
||||
|
||||
rolePersistService.addRole(AuthConstants.GLOBAL_ADMIN_ROLE, username);
|
||||
roleSet.add(AuthConstants.GLOBAL_ADMIN_ROLE);
|
||||
authConfigs.setHasGlobalAdminRole(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete user Role.
|
||||
*
|
||||
* @param role role
|
||||
* @param userName userName
|
||||
*/
|
||||
public void deleteRole(String role, String userName) {
|
||||
rolePersistService.deleteRole(role, userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* deleteRole.
|
||||
*
|
||||
* @param role role
|
||||
*/
|
||||
public void deleteRole(String role) {
|
||||
rolePersistService.deleteRole(role);
|
||||
roleSet.remove(role);
|
||||
@ -307,4 +346,21 @@ public class NacosRoleServiceImpl {
|
||||
|
||||
return roles.stream().anyMatch(roleInfo -> AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole()));
|
||||
}
|
||||
|
||||
/**
|
||||
* check if all user has at least one admin role.
|
||||
*
|
||||
* @return true if all user has at least one admin role.
|
||||
*/
|
||||
public boolean hasGlobalAdminRole() {
|
||||
if (authConfigs.isHasGlobalAdminRole()) {
|
||||
return true;
|
||||
}
|
||||
List<RoleInfo> roles = getAllRoles();
|
||||
boolean hasGlobalAdminRole = CollectionUtils.isNotEmpty(roles) && roles.stream()
|
||||
.anyMatch(roleInfo -> AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole()));
|
||||
authConfigs.setHasGlobalAdminRole(hasGlobalAdminRole);
|
||||
return hasGlobalAdminRole;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package com.alibaba.nacos.plugin.auth.impl.users;
|
||||
|
||||
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import com.alibaba.nacos.plugin.auth.impl.persistence.UserPersistService;
|
||||
import com.alibaba.nacos.persistence.model.Page;
|
||||
import com.alibaba.nacos.plugin.auth.impl.persistence.User;
|
||||
@ -116,7 +117,7 @@ public class NacosUserDetailsServiceImpl implements UserDetailsService {
|
||||
public void deleteUser(String username) {
|
||||
userPersistService.deleteUser(username);
|
||||
}
|
||||
|
||||
|
||||
public Page<User> findUsersLike4Page(String username, int pageNo, int pageSize) {
|
||||
return userPersistService.findUsersLike4Page(username, pageNo, pageSize);
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.plugin.auth.impl.utils;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* RandomPasswordGenerator .
|
||||
*
|
||||
* @author : huangtianhui
|
||||
*/
|
||||
public class PasswordGeneratorUtil {
|
||||
|
||||
private static final String LOWER_CASE = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
private static final String UPPER_CASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
private static final String DIGITS = "0123456789";
|
||||
|
||||
private static final String SPECIAL_CHARS = "!@#$%&";
|
||||
|
||||
private static final int PASSWORD_LENGTH = 8;
|
||||
|
||||
/**
|
||||
* generateRandomPassword.
|
||||
* @return
|
||||
*/
|
||||
public static String generateRandomPassword() {
|
||||
SecureRandom random = new SecureRandom();
|
||||
|
||||
List<Character> pwdChars = new ArrayList<>();
|
||||
|
||||
pwdChars.add(LOWER_CASE.charAt(random.nextInt(LOWER_CASE.length())));
|
||||
pwdChars.add(UPPER_CASE.charAt(random.nextInt(UPPER_CASE.length())));
|
||||
pwdChars.add(DIGITS.charAt(random.nextInt(DIGITS.length())));
|
||||
pwdChars.add(SPECIAL_CHARS.charAt(random.nextInt(SPECIAL_CHARS.length())));
|
||||
|
||||
// Fill the rest of the password with random characters from all categories
|
||||
String allCharacters = LOWER_CASE + UPPER_CASE + DIGITS + SPECIAL_CHARS;
|
||||
while (pwdChars.size() < PASSWORD_LENGTH) {
|
||||
pwdChars.add(allCharacters.charAt(random.nextInt(allCharacters.length())));
|
||||
}
|
||||
|
||||
// Shuffle to avoid predictable order
|
||||
Collections.shuffle(pwdChars, random);
|
||||
|
||||
// Build the final password string
|
||||
return pwdChars.stream().map(String::valueOf).collect(Collectors.joining());
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
@ -86,9 +87,10 @@ public class UserControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginWithAuthedUser() throws AccessException {
|
||||
public void testLoginWithAuthedUser() throws AccessException, IOException {
|
||||
when(authenticationManager.authenticate(request)).thenReturn(user);
|
||||
when(authenticationManager.hasGlobalAdminRole(user)).thenReturn(true);
|
||||
when(authenticationManager.hasGlobalAdminRole()).thenReturn(true);
|
||||
when(authConfigs.getNacosAuthSystemType()).thenReturn(AuthSystemTypes.NACOS.name());
|
||||
when(tokenManagerDelegate.getTokenTtlInSeconds(anyString())).thenReturn(18000L);
|
||||
Object actual = userController.login("nacos", "nacos", response, request);
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.plugin.auth.impl.utils;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PasswordGeneratorUtilTest {
|
||||
|
||||
/**
|
||||
* generatePwd test.
|
||||
*/
|
||||
@Test
|
||||
public void generatePwd() {
|
||||
String pwd = PasswordGeneratorUtil.generateRandomPassword();
|
||||
Assert.assertEquals(8, pwd.length());
|
||||
}
|
||||
|
||||
}
|
@ -210,10 +210,6 @@ CREATE TABLE permissions (
|
||||
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');
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* ipv6 support */
|
||||
|
Loading…
Reference in New Issue
Block a user