[ISSUE #11957] AuthModule add admin exist (#12066)

* AuthModule add admin exist

* test fix

* fix state

* add state cache

* rename to auth_admin_request

* test fix

* auth_admin_request default value fix

* fix admin request
This commit is contained in:
hth 2024-05-24 10:14:40 +08:00 committed by GitHub
parent 6bee5c47a9
commit 992f10a1d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 73 additions and 11 deletions

View File

@ -39,6 +39,10 @@ public class AuthModuleStateBuilder implements ModuleStateBuilder {
public static final String AUTH_SYSTEM_TYPE = "auth_system_type";
public static final String AUTH_ADMIN_REQUEST = "auth_admin_request";
private boolean cacheable;
@Override
public ModuleState build() {
ModuleState result = new ModuleState(AUTH_MODULE);
@ -46,12 +50,28 @@ public class AuthModuleStateBuilder implements ModuleStateBuilder {
result.newState(AUTH_ENABLED, authConfigs.isAuthEnabled());
result.newState(LOGIN_PAGE_ENABLED, isLoginPageEnabled(authConfigs));
result.newState(AUTH_SYSTEM_TYPE, authConfigs.getNacosAuthSystemType());
result.newState(AUTH_ADMIN_REQUEST, isAdminRequest(authConfigs));
return result;
}
@Override
public boolean isCacheable() {
return cacheable;
}
private Boolean isLoginPageEnabled(AuthConfigs authConfigs) {
Optional<AuthPluginService> authPluginService = AuthPluginManager.getInstance()
.findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType());
return authPluginService.map(AuthPluginService::isLoginEnabled).orElse(false);
}
private Boolean isAdminRequest(AuthConfigs authConfigs) {
Optional<AuthPluginService> authPluginService = AuthPluginManager.getInstance()
.findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType());
boolean isAdminRequest = authPluginService.map(AuthPluginService::isAdminRequest).orElse(true);
if (!isAdminRequest) {
cacheable = true;
}
return isAdminRequest;
}
}

View File

@ -29,6 +29,7 @@ import org.springframework.context.ConfigurableApplicationContext;
import static com.alibaba.nacos.auth.config.AuthModuleStateBuilder.AUTH_ENABLED;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
@ -57,5 +58,6 @@ class AuthModuleStateBuilderTest {
assertFalse((Boolean) actual.getStates().get(AUTH_ENABLED));
assertFalse((Boolean) actual.getStates().get("login_page_enabled"));
assertEquals("nacos", actual.getStates().get("auth_system_type"));
assertTrue((Boolean) actual.getStates().get("auth_admin_request"));
}
}

View File

@ -113,6 +113,11 @@ public class NacosAuthPluginService implements AuthPluginService {
return ApplicationUtils.getBean(AuthConfigs.class).isAuthEnabled();
}
@Override
public boolean isAdminRequest() {
return !ApplicationUtils.getBean(IAuthenticationManager.class).hasGlobalAdminRole();
}
protected void checkNacosAuthManager() {
if (null == authenticationManager) {
authenticationManager = ApplicationUtils.getBean(DefaultAuthenticationManager.class);

View File

@ -115,18 +115,16 @@ public class UserController {
* 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) {
public Object createAdminUser(@RequestParam(required = false) String password) {
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
if (roleService.hasGlobalAdminRole()) {
if (iAuthenticationManager.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;
}
String username = AuthConstants.DEFAULT_USER;
userDetailsService.createUser(username, PasswordEncoderUtil.encode(password));
roleService.addAdminRole(username);
ObjectNode result = JacksonUtils.createEmptyJsonNode();
@ -266,10 +264,7 @@ public class UserController {
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());

View File

@ -90,7 +90,6 @@ public class UserControllerTest {
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);

View File

@ -84,4 +84,13 @@ public interface AuthPluginService {
default boolean isLoginEnabled() {
return false;
}
/**
* Whether need administrator .
*
* @return if need the administrator role.
*/
default boolean isAdminRequest() {
return true;
}
}

View File

@ -38,4 +38,14 @@ public interface ModuleStateBuilder {
default boolean isIgnore() {
return false;
}
/**
* Whether module is cache, default return true.
*
* @return boolean
*/
default boolean isCacheable() {
return true;
}
}

View File

@ -21,8 +21,10 @@ import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@ -40,6 +42,8 @@ public class ModuleStateHolder {
private final Map<String, ModuleState> moduleStates;
private final List<ModuleStateBuilder> moduleStateBuilders = new ArrayList<>();
private ModuleStateHolder() {
this.moduleStates = new HashMap<>();
for (ModuleStateBuilder each : NacosServiceLoader.load(ModuleStateBuilder.class)) {
@ -47,6 +51,7 @@ public class ModuleStateHolder {
continue;
}
try {
moduleStateBuilders.add(each);
ModuleState moduleState = each.build();
moduleStates.put(moduleState.getModuleName(), moduleState);
} catch (Exception e) {
@ -59,11 +64,28 @@ public class ModuleStateHolder {
return INSTANCE;
}
private void reBuildModuleState() {
for (ModuleStateBuilder each : moduleStateBuilders) {
if (each.isCacheable()) {
continue;
}
try {
ModuleState moduleState = each.build();
moduleStates.put(moduleState.getModuleName(), moduleState);
} catch (Exception e) {
LOGGER.warn("reBuild ModuleState failed in builder:{}", each.getClass().getCanonicalName(), e);
}
}
}
public Optional<ModuleState> getModuleState(String moduleName) {
reBuildModuleState();
return Optional.ofNullable(moduleStates.get(moduleName));
}
public Set<ModuleState> getAllModuleStates() {
reBuildModuleState();
return new HashSet<>(moduleStates.values());
}