Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix some 3.0 admin api problem. #13049

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public abstract class AbstractProtocolAuthService<R> implements ProtocolAuthServ

protected AbstractProtocolAuthService(NacosAuthConfig authConfig) {
this.authConfig = authConfig;
this.checker = ServerIdentityCheckerHolder.getInstance().getChecker();
this.checker = ServerIdentityCheckerHolder.getInstance().newChecker();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;

/**
Expand All @@ -33,7 +34,7 @@ public class ServerIdentityCheckerHolder {

private static final ServerIdentityCheckerHolder INSTANCE = new ServerIdentityCheckerHolder();

private ServerIdentityChecker checker;
private Class<? extends ServerIdentityChecker> checkerClass;

private ServerIdentityCheckerHolder() {
tryGetCheckerBySpi();
Expand All @@ -43,32 +44,41 @@ public static ServerIdentityCheckerHolder getInstance() {
return INSTANCE;
}

public ServerIdentityChecker getChecker() {
return checker;
/**
* Build a new checker.
*
* @return new checker instance.
*/
public ServerIdentityChecker newChecker() {
try {
return checkerClass.getDeclaredConstructor(new Class[0]).newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
return new DefaultChecker();
}
}

private synchronized void tryGetCheckerBySpi() {
Collection<ServerIdentityChecker> checkers = NacosServiceLoader.load(ServerIdentityChecker.class);
if (checkers.isEmpty()) {
checker = new DefaultChecker();
checkerClass = DefaultChecker.class;
LOGGER.info("Not found ServerIdentityChecker implementation from SPI, use default.");
return;
}
if (checkers.size() > 1) {
checker = showAllImplementations(checkers);
checkerClass = showAllImplementations(checkers);
return;
}
checker = checkers.iterator().next();
LOGGER.info("Found ServerIdentityChecker implementation {}", checker.getClass().getCanonicalName());
checkerClass = checkers.iterator().next().getClass();
LOGGER.info("Found ServerIdentityChecker implementation {}", checkerClass.getClass().getCanonicalName());
}

private ServerIdentityChecker showAllImplementations(Collection<ServerIdentityChecker> checkers) {
private Class<? extends ServerIdentityChecker> showAllImplementations(Collection<ServerIdentityChecker> checkers) {
ServerIdentityChecker result = checkers.iterator().next();
for (ServerIdentityChecker each : checkers) {
LOGGER.warn("Found ServerIdentityChecker implementation {}", each.getClass().getCanonicalName());
}
LOGGER.warn("Found more than one ServerIdentityChecker implementation from SPI, use the first one {}.",
result.getClass().getCanonicalName());
return result;
return result.getClass();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ void tearDown() {
void testConstructorWithSingleImplementation()
throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
ServerIdentityCheckerHolder holder = getNewHolder(1);
assertInstanceOf(MockChecker.class, holder.getChecker());
assertInstanceOf(MockChecker.class, holder.newChecker());
}

@Test
void testConstructorWithMultipleImplementation()
throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
ServerIdentityCheckerHolder holder = getNewHolder(2);
assertInstanceOf(MockChecker.class, holder.getChecker());
assertInstanceOf(MockChecker.class, holder.newChecker());
}

ServerIdentityCheckerHolder getNewHolder(int size)
Expand Down
4 changes: 3 additions & 1 deletion bootstrap/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ server.error.include-message=ALWAYS
### Enabled for open API compatibility
# nacos.core.api.compatibility.client.enabled=true
### Enabled for admin API compatibility
# nacos.core.api.compatibility.admin.enabled=true
# nacos.core.api.compatibility.admin.enabled=false
### Enabled for console API compatibility
# nacos.core.api.compatibility.console.enabled=false

Expand Down Expand Up @@ -220,6 +220,8 @@ nacos.core.auth.system.type=nacos
### If turn on auth system:
# Whether open nacos server API auth system
nacos.core.auth.enabled=false
# Whether open nacos admin API auth system
nacos.core.auth.admin.enabled=true
# Whether open nacos console API auth system
nacos.core.auth.console.enabled=true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
chain.doFilter(request, response);
return;
}

try {
if (Loggers.AUTH.isDebugEnabled()) {
Loggers.AUTH.debug("auth start, request: {} {}", req.getMethod(), req.getRequestURI());
Expand All @@ -93,7 +94,10 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
default:
break;
}

if (!isMatchFilter(secured)) {
chain.doFilter(request, response);
return;
}
if (!protocolAuthService.enableAuth(secured)) {
chain.doFilter(request, response);
return;
Expand Down Expand Up @@ -132,6 +136,16 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
}
}

/**
* Check whether this filter should be applied for this {@link Secured} API.
*
* @param secured api Secured annotation
* @return {@code true} if this auth filter should handle this request, {@code false} otherwise
*/
protected boolean isMatchFilter(Secured secured) {
return true;
}

protected ServerIdentityResult checkServerIdentity(HttpServletRequest request, Secured secured) {
return protocolAuthService.checkServerIdentity(request, secured);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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.core.auth;

import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.config.NacosAuthConfig;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
import com.alibaba.nacos.plugin.auth.constant.ApiType;

/**
* Unified filter to handle authentication and authorization.
*
* @author nkorange
* @since 1.2.0
*/
public class AuthAdminFilter extends AbstractWebAuthFilter {

private final NacosAuthConfig authConfig;

public AuthAdminFilter(NacosAuthConfig authConfig, ControllerMethodsCache methodsCache) {
super(authConfig, methodsCache);
this.authConfig = authConfig;
}

@Override
protected boolean isAuthEnabled() {
return authConfig.isAuthEnabled();
}

@Override
protected boolean isMatchFilter(Secured secured) {
// Other API authed by {@link AuthFilter}
return ApiType.ADMIN_API.equals(secured.apiType());
}
}
16 changes: 15 additions & 1 deletion core/src/main/java/com/alibaba/nacos/core/auth/AuthConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,26 @@ public FilterRegistrationBean<AuthFilter> authFilterRegistration(AuthFilter auth
registration.addUrlPatterns("/*");
registration.setName("authFilter");
registration.setOrder(6);

return registration;
}

@Bean
public FilterRegistrationBean<AuthAdminFilter> authAdminFilterRegistration(AuthAdminFilter authAdminFilter) {
FilterRegistrationBean<AuthAdminFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(authAdminFilter);
registration.addUrlPatterns("/*");
registration.setName("authAdminFilter");
registration.setOrder(6);
return registration;
}

@Bean
public AuthFilter authFilter(ControllerMethodsCache methodsCache) {
return new AuthFilter(NacosServerAuthConfig.getInstance(), methodsCache);
}

@Bean
public AuthAdminFilter authAdminFilter(ControllerMethodsCache methodsCache) {
return new AuthAdminFilter(NacosServerAdminAuthConfig.getInstance(), methodsCache);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

package com.alibaba.nacos.core.auth;

import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.config.NacosAuthConfig;
import com.alibaba.nacos.core.code.ControllerMethodsCache;
import com.alibaba.nacos.plugin.auth.constant.ApiType;

/**
* Unified filter to handle authentication and authorization.
Expand All @@ -38,4 +40,10 @@ public AuthFilter(NacosAuthConfig authConfig, ControllerMethodsCache methodsCach
protected boolean isAuthEnabled() {
return authConfig.isAuthEnabled();
}

@Override
protected boolean isMatchFilter(Secured secured) {
// ADMIN API use {@link AuthAdminFilter} to handle
return !ApiType.ADMIN_API.equals(secured.apiType());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* 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.core.auth;

import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import com.alibaba.nacos.auth.config.AuthErrorCode;
import com.alibaba.nacos.auth.config.NacosAuthConfig;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.config.AbstractDynamicConfig;
import com.alibaba.nacos.plugin.auth.constant.Constants;
import com.alibaba.nacos.sys.env.EnvUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Nacos Server auth configurations.
*
* @author xiweng.yy
*/
public class NacosServerAdminAuthConfig extends AbstractDynamicConfig implements NacosAuthConfig {

private static final Logger LOGGER = LoggerFactory.getLogger(NacosServerAdminAuthConfig.class);

private static final NacosServerAdminAuthConfig INSTANCE = new NacosServerAdminAuthConfig();

/**
* Whether server auth enabled.
*/
private boolean authEnabled;

/**
* Which auth system is in use.
*/
private String nacosAuthSystemType;

private String serverIdentityKey;

private String serverIdentityValue;

private NacosServerAdminAuthConfig() {
super("NacosServerAdminAuth");
resetConfig();
validate();
}

public static NacosServerAdminAuthConfig getInstance() {
return INSTANCE;
}

/**
* Validate auth config.
*/
private void validate() {
if (!authEnabled) {
return;
}
if (StringUtils.isEmpty(nacosAuthSystemType)) {
throw new NacosRuntimeException(AuthErrorCode.INVALID_TYPE.getCode(), AuthErrorCode.INVALID_TYPE.getMsg());
}
if (StringUtils.isEmpty(serverIdentityKey) || StringUtils.isEmpty(serverIdentityValue)) {
throw new NacosRuntimeException(AuthErrorCode.EMPTY_IDENTITY.getCode(),
AuthErrorCode.EMPTY_IDENTITY.getMsg());
}
}

/**
* server auth function is open.
*
* @return server auth function is open
*/
@Override
public boolean isAuthEnabled() {
return authEnabled;
}

@Override
public String getNacosAuthSystemType() {
return nacosAuthSystemType;
}

@Override
public boolean isSupportServerIdentity() {
return true;
}

@Override
public String getServerIdentityKey() {
return serverIdentityKey;
}

@Override
public String getServerIdentityValue() {
return serverIdentityValue;
}

@Override
protected void getConfigFromEnv() {
try {
authEnabled = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_ADMIN_ENABLED, Boolean.class, true);
nacosAuthSystemType = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SYSTEM_TYPE, "");
serverIdentityKey = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SERVER_IDENTITY_KEY, "");
serverIdentityValue = EnvUtil.getProperty(Constants.Auth.NACOS_CORE_AUTH_SERVER_IDENTITY_VALUE, "");
} catch (Exception e) {
LOGGER.warn("Upgrade auth config from env failed, use old value", e);
}
}

@Override
protected String printConfig() {
return toString();
}

@Override
public String toString() {
return "NacosServerAdminAuthConfig{" + "authEnabled=" + authEnabled + ", nacosAuthSystemType='"
+ nacosAuthSystemType + '\'' + ", serverIdentityKey='" + serverIdentityKey + '\''
+ ", serverIdentityValue='" + serverIdentityValue + '\'' + '}';
}
}
Loading