Add new ProtocolAuthService to replace AuthManager.
This commit is contained in:
parent
347494c380
commit
d2e11a3de7
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
|
import com.alibaba.nacos.auth.api.IdentityContext;
|
||||||
|
import com.alibaba.nacos.auth.api.Permission;
|
||||||
|
import com.alibaba.nacos.auth.api.Resource;
|
||||||
|
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||||
|
import com.alibaba.nacos.auth.constant.Constants;
|
||||||
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
|
import com.alibaba.nacos.auth.util.Loggers;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract protocol auth service.
|
||||||
|
*
|
||||||
|
* <p>Implement #validateIdentity and #validateAuthority method template.
|
||||||
|
*
|
||||||
|
* @author xiweng.yy
|
||||||
|
*/
|
||||||
|
public abstract class AbstractProtocolAuthService<R> implements ProtocolAuthService<R> {
|
||||||
|
|
||||||
|
protected final AuthConfigs authConfigs;
|
||||||
|
|
||||||
|
protected AbstractProtocolAuthService(AuthConfigs authConfigs) {
|
||||||
|
this.authConfigs = authConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateIdentity(IdentityContext identityContext) throws AccessException {
|
||||||
|
if (!authConfigs.isAuthEnabled()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Optional<AuthPluginService> authPluginService = AuthPluginManager.getInstance()
|
||||||
|
.findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType());
|
||||||
|
if (authPluginService.isPresent()) {
|
||||||
|
return authPluginService.get().validateIdentity(identityContext);
|
||||||
|
}
|
||||||
|
Loggers.AUTH.warn("Can't find auth plugin for type {}, please add plugin to classpath or set {} as false",
|
||||||
|
authConfigs.getNacosAuthSystemType(), Constants.Auth.NACOS_CORE_AUTH_ENABLED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateAuthority(IdentityContext identityContext, Permission permission) {
|
||||||
|
if (!authConfigs.isAuthEnabled()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Optional<AuthPluginService> authPluginService = AuthPluginManager.getInstance()
|
||||||
|
.findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType());
|
||||||
|
if (authPluginService.isPresent()) {
|
||||||
|
return authPluginService.get().validateAuthority(identityContext, permission);
|
||||||
|
}
|
||||||
|
Loggers.AUTH.warn("Can't find auth plugin for type {}, please add plugin to classpath or set {} as false",
|
||||||
|
authConfigs.getNacosAuthSystemType(), Constants.Auth.NACOS_CORE_AUTH_ENABLED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get resource from secured annotation specified resource.
|
||||||
|
*
|
||||||
|
* @param secured secured annotation
|
||||||
|
* @return resource
|
||||||
|
*/
|
||||||
|
protected Resource parseSpecifiedResource(Secured secured) {
|
||||||
|
return new Resource(null, null, secured.resource(), secured.signType(), null);
|
||||||
|
}
|
||||||
|
}
|
@ -40,10 +40,10 @@ public interface AuthPluginService {
|
|||||||
* To validate whether the identity context from request is legal or illegal.
|
* To validate whether the identity context from request is legal or illegal.
|
||||||
*
|
*
|
||||||
* @param identityContext where we can find the user information
|
* @param identityContext where we can find the user information
|
||||||
* @return IdentityContext user auth result
|
* @return {@code true} if legal, otherwise {@code false}
|
||||||
* @throws AccessException if authentication is failed
|
* @throws AccessException if authentication is failed
|
||||||
*/
|
*/
|
||||||
IdentityContext validateIdentity(IdentityContext identityContext) throws AccessException;
|
boolean validateIdentity(IdentityContext identityContext) throws AccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the identity whether has the resource authority.
|
* Validate the identity whether has the resource authority.
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.remote.request.Request;
|
||||||
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
|
import com.alibaba.nacos.auth.api.IdentityContext;
|
||||||
|
import com.alibaba.nacos.auth.api.Resource;
|
||||||
|
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||||
|
import com.alibaba.nacos.auth.constant.SignType;
|
||||||
|
import com.alibaba.nacos.auth.context.GrpcIdentityContextBuilder;
|
||||||
|
import com.alibaba.nacos.auth.parser.grpc.AbstractGrpcResourceParser;
|
||||||
|
import com.alibaba.nacos.auth.parser.grpc.ConfigGrpcResourceParser;
|
||||||
|
import com.alibaba.nacos.auth.parser.grpc.NamingGrpcResourceParser;
|
||||||
|
import com.alibaba.nacos.auth.util.Loggers;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auth Service for Http protocol.
|
||||||
|
*
|
||||||
|
* @author xiweng.yy
|
||||||
|
*/
|
||||||
|
public class GrpcProtocolAuthService extends AbstractProtocolAuthService<Request> {
|
||||||
|
|
||||||
|
private final Map<String, AbstractGrpcResourceParser> resourceParserMap;
|
||||||
|
|
||||||
|
private final GrpcIdentityContextBuilder identityContextBuilder;
|
||||||
|
|
||||||
|
protected GrpcProtocolAuthService(AuthConfigs authConfigs) {
|
||||||
|
super(authConfigs);
|
||||||
|
resourceParserMap = new HashMap<>(2);
|
||||||
|
identityContextBuilder = new GrpcIdentityContextBuilder(authConfigs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
resourceParserMap.put(SignType.NAMING, new NamingGrpcResourceParser());
|
||||||
|
resourceParserMap.put(SignType.CONFIG, new ConfigGrpcResourceParser());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Resource parseResource(Request request, Secured secured) {
|
||||||
|
if (StringUtils.isNotBlank(secured.resource())) {
|
||||||
|
return parseSpecifiedResource(secured);
|
||||||
|
}
|
||||||
|
String type = secured.signType();
|
||||||
|
if (!resourceParserMap.containsKey(type)) {
|
||||||
|
Loggers.AUTH.warn("Can't find Grpc request resourceParser for type {}", type);
|
||||||
|
return Resource.EMPTY_RESOURCE;
|
||||||
|
}
|
||||||
|
return resourceParserMap.get(type).parse(request, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IdentityContext parseIdentity(Request request) {
|
||||||
|
return identityContextBuilder.build(request);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
|
import com.alibaba.nacos.auth.api.IdentityContext;
|
||||||
|
import com.alibaba.nacos.auth.api.Resource;
|
||||||
|
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||||
|
import com.alibaba.nacos.auth.constant.SignType;
|
||||||
|
import com.alibaba.nacos.auth.context.HttpIdentityContextBuilder;
|
||||||
|
import com.alibaba.nacos.auth.parser.http.AbstractHttpResourceParser;
|
||||||
|
import com.alibaba.nacos.auth.parser.http.ConfigHttpResourceParser;
|
||||||
|
import com.alibaba.nacos.auth.parser.http.NamingHttpResourceParser;
|
||||||
|
import com.alibaba.nacos.auth.util.Loggers;
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auth Service for Http protocol.
|
||||||
|
*
|
||||||
|
* @author xiweng.yy
|
||||||
|
*/
|
||||||
|
public class HttpProtocolAuthService extends AbstractProtocolAuthService<HttpServletRequest> {
|
||||||
|
|
||||||
|
private final Map<String, AbstractHttpResourceParser> resourceParserMap;
|
||||||
|
|
||||||
|
private final HttpIdentityContextBuilder identityContextBuilder;
|
||||||
|
|
||||||
|
protected HttpProtocolAuthService(AuthConfigs authConfigs) {
|
||||||
|
super(authConfigs);
|
||||||
|
resourceParserMap = new HashMap<>(2);
|
||||||
|
identityContextBuilder = new HttpIdentityContextBuilder(authConfigs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
resourceParserMap.put(SignType.NAMING, new NamingHttpResourceParser());
|
||||||
|
resourceParserMap.put(SignType.CONFIG, new ConfigHttpResourceParser());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Resource parseResource(HttpServletRequest request, Secured secured) {
|
||||||
|
if (StringUtils.isNotBlank(secured.resource())) {
|
||||||
|
return parseSpecifiedResource(secured);
|
||||||
|
}
|
||||||
|
String type = secured.signType();
|
||||||
|
if (!resourceParserMap.containsKey(type)) {
|
||||||
|
Loggers.AUTH.warn("Can't find Http request resourceParser for type {}", type);
|
||||||
|
return Resource.EMPTY_RESOURCE;
|
||||||
|
}
|
||||||
|
return resourceParserMap.get(type).parse(request, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IdentityContext parseIdentity(HttpServletRequest request) {
|
||||||
|
return identityContextBuilder.build(request);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
|
import com.alibaba.nacos.auth.api.IdentityContext;
|
||||||
|
import com.alibaba.nacos.auth.api.Permission;
|
||||||
|
import com.alibaba.nacos.auth.api.Resource;
|
||||||
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protocol auth service.
|
||||||
|
*
|
||||||
|
* @author xiweng.yy
|
||||||
|
*/
|
||||||
|
public interface ProtocolAuthService<R> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init protocol auth service.
|
||||||
|
*/
|
||||||
|
void initialize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse resource from protocol request and secured annotation.
|
||||||
|
*
|
||||||
|
* @param request protocol request
|
||||||
|
* @param secured api secured annotation
|
||||||
|
* @return resource
|
||||||
|
*/
|
||||||
|
Resource parseResource(R request, Secured secured);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse identity context from protocol request.
|
||||||
|
*
|
||||||
|
* @param request protocol request
|
||||||
|
* @return identity context
|
||||||
|
*/
|
||||||
|
IdentityContext parseIdentity(R request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate identity whether is legal.
|
||||||
|
*
|
||||||
|
* @param identityContext identity context
|
||||||
|
* @return {@code true} if legal, otherwise {@code false}
|
||||||
|
* @throws AccessException exception during validating
|
||||||
|
*/
|
||||||
|
boolean validateIdentity(IdentityContext identityContext) throws AccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate identity whether had permission for the resource and action.
|
||||||
|
*
|
||||||
|
* @param identityContext identity context
|
||||||
|
* @param permission permssion include resource and action
|
||||||
|
* @return {@code true} if legal, otherwise {@code false}
|
||||||
|
* @throws AccessException exception during validating
|
||||||
|
*/
|
||||||
|
boolean validateAuthority(IdentityContext identityContext, Permission permission) throws AccessException;
|
||||||
|
}
|
@ -23,6 +23,7 @@ import java.io.Serializable;
|
|||||||
*
|
*
|
||||||
* @author nkorange
|
* @author nkorange
|
||||||
* @author mai.jh
|
* @author mai.jh
|
||||||
|
* @author xiweng.yy
|
||||||
* @since 1.2.0
|
* @since 1.2.0
|
||||||
*/
|
*/
|
||||||
public class Permission implements Serializable {
|
public class Permission implements Serializable {
|
||||||
@ -32,7 +33,7 @@ public class Permission implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* An unique key of resource.
|
* An unique key of resource.
|
||||||
*/
|
*/
|
||||||
private String resource;
|
private Resource resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action on resource, refer to class ActionTypes.
|
* Action on resource, refer to class ActionTypes.
|
||||||
@ -43,16 +44,16 @@ public class Permission implements Serializable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Permission(String resource, String action) {
|
public Permission(Resource resource, String action) {
|
||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getResource() {
|
public Resource getResource() {
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResource(String resource) {
|
public void setResource(Resource resource) {
|
||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.alibaba.nacos.auth.api;
|
package com.alibaba.nacos.auth.api;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.common.utils.StringUtils;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
@ -30,6 +32,9 @@ public class Resource implements Serializable {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 925971662931204553L;
|
private static final long serialVersionUID = 925971662931204553L;
|
||||||
|
|
||||||
|
public static final Resource EMPTY_RESOURCE = new Resource(StringUtils.EMPTY, StringUtils.EMPTY, StringUtils.EMPTY,
|
||||||
|
StringUtils.EMPTY, null);
|
||||||
|
|
||||||
private final String namespaceId;
|
private final String namespaceId;
|
||||||
|
|
||||||
private final String group;
|
private final String group;
|
||||||
|
41
auth/src/main/java/com/alibaba/nacos/auth/util/Loggers.java
Normal file
41
auth/src/main/java/com/alibaba/nacos/auth/util/Loggers.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth.util;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loggers for core.
|
||||||
|
*
|
||||||
|
* @author nkorange
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public class Loggers {
|
||||||
|
|
||||||
|
private static final String AUTH_LOG_NAME = "auth";
|
||||||
|
|
||||||
|
public static final Logger AUTH = LoggerFactory.getLogger("com.alibaba.nacos.auth");
|
||||||
|
|
||||||
|
public static void setLogLevel(String logName, String level) {
|
||||||
|
|
||||||
|
if (AUTH_LOG_NAME.equals(logName)) {
|
||||||
|
((ch.qos.logback.classic.Logger) AUTH).setLevel(Level.valueOf(level));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.config.remote.request.ConfigPublishRequest;
|
||||||
|
import com.alibaba.nacos.api.naming.remote.request.AbstractNamingRequest;
|
||||||
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
|
import com.alibaba.nacos.auth.api.IdentityContext;
|
||||||
|
import com.alibaba.nacos.auth.api.Permission;
|
||||||
|
import com.alibaba.nacos.auth.api.Resource;
|
||||||
|
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||||
|
import com.alibaba.nacos.auth.constant.SignType;
|
||||||
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
|
import com.alibaba.nacos.auth.mock.MockAuthPluginService;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class GrpcProtocolAuthServiceTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AuthConfigs authConfigs;
|
||||||
|
|
||||||
|
private ConfigPublishRequest configRequest;
|
||||||
|
|
||||||
|
private AbstractNamingRequest namingRequest;
|
||||||
|
|
||||||
|
private GrpcProtocolAuthService protocolAuthService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
protocolAuthService = new GrpcProtocolAuthService(authConfigs);
|
||||||
|
protocolAuthService.initialize();
|
||||||
|
mockConfigRequest();
|
||||||
|
mockNamingRequest();
|
||||||
|
Mockito.when(authConfigs.isAuthEnabled()).thenReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mockConfigRequest() {
|
||||||
|
configRequest = new ConfigPublishRequest();
|
||||||
|
configRequest.setTenant("testCNs");
|
||||||
|
configRequest.setGroup("testCG");
|
||||||
|
configRequest.setDataId("testD");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mockNamingRequest() {
|
||||||
|
namingRequest = new AbstractNamingRequest() {
|
||||||
|
};
|
||||||
|
namingRequest.setNamespace("testNNs");
|
||||||
|
namingRequest.setGroupName("testNG");
|
||||||
|
namingRequest.setServiceName("testS");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Secured(resource = "testResource")
|
||||||
|
public void testParseResourceWithSpecifiedResource() throws NoSuchMethodException {
|
||||||
|
Secured secured = getMethodSecure("testParseResourceWithSpecifiedResource");
|
||||||
|
Resource actual = protocolAuthService.parseResource(namingRequest, secured);
|
||||||
|
assertEquals("testResource", actual.getName());
|
||||||
|
assertEquals(SignType.NAMING, actual.getType());
|
||||||
|
assertNull(actual.getNamespaceId());
|
||||||
|
assertNull(actual.getGroup());
|
||||||
|
assertNull(actual.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Secured(signType = "non-exist")
|
||||||
|
public void testParseResourceWithNonExistType() throws NoSuchMethodException {
|
||||||
|
Secured secured = getMethodSecure("testParseResourceWithNonExistType");
|
||||||
|
Resource actual = protocolAuthService.parseResource(namingRequest, secured);
|
||||||
|
assertEquals(Resource.EMPTY_RESOURCE, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Secured()
|
||||||
|
public void testParseResourceWithNamingType() throws NoSuchMethodException {
|
||||||
|
Secured secured = getMethodSecure("testParseResourceWithNamingType");
|
||||||
|
Resource actual = protocolAuthService.parseResource(namingRequest, secured);
|
||||||
|
assertEquals(SignType.NAMING, actual.getType());
|
||||||
|
assertEquals("testS", actual.getName());
|
||||||
|
assertEquals("testNNs", actual.getNamespaceId());
|
||||||
|
assertEquals("testNG", actual.getGroup());
|
||||||
|
assertNotNull(actual.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Secured(signType = SignType.CONFIG)
|
||||||
|
public void testParseResourceWithConfigType() throws NoSuchMethodException {
|
||||||
|
Secured secured = getMethodSecure("testParseResourceWithConfigType");
|
||||||
|
Resource actual = protocolAuthService.parseResource(configRequest, secured);
|
||||||
|
assertEquals(SignType.CONFIG, actual.getType());
|
||||||
|
assertEquals("testD", actual.getName());
|
||||||
|
assertEquals("testCNs", actual.getNamespaceId());
|
||||||
|
assertEquals("testCG", actual.getGroup());
|
||||||
|
assertNotNull(actual.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseIdentity() {
|
||||||
|
IdentityContext actual = protocolAuthService.parseIdentity(namingRequest);
|
||||||
|
assertNotNull(actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateIdentityWithoutPlugin() throws AccessException {
|
||||||
|
IdentityContext identityContext = new IdentityContext();
|
||||||
|
assertTrue(protocolAuthService.validateIdentity(identityContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateIdentityWithPlugin() throws AccessException {
|
||||||
|
Mockito.when(authConfigs.getNacosAuthSystemType()).thenReturn(MockAuthPluginService.TEST_PLUGIN);
|
||||||
|
IdentityContext identityContext = new IdentityContext();
|
||||||
|
assertFalse(protocolAuthService.validateIdentity(identityContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAuthorityWithoutPlugin() {
|
||||||
|
assertTrue(protocolAuthService
|
||||||
|
.validateAuthority(new IdentityContext(), new Permission(Resource.EMPTY_RESOURCE, "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAuthorityWithPlugin() {
|
||||||
|
Mockito.when(authConfigs.getNacosAuthSystemType()).thenReturn(MockAuthPluginService.TEST_PLUGIN);
|
||||||
|
assertFalse(protocolAuthService
|
||||||
|
.validateAuthority(new IdentityContext(), new Permission(Resource.EMPTY_RESOURCE, "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Secured getMethodSecure(String methodName) throws NoSuchMethodException {
|
||||||
|
Method method = GrpcProtocolAuthServiceTest.class.getMethod(methodName);
|
||||||
|
return method.getAnnotation(Secured.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* 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.auth;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.common.Constants;
|
||||||
|
import com.alibaba.nacos.api.naming.CommonParams;
|
||||||
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
|
import com.alibaba.nacos.auth.api.IdentityContext;
|
||||||
|
import com.alibaba.nacos.auth.api.Permission;
|
||||||
|
import com.alibaba.nacos.auth.api.Resource;
|
||||||
|
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||||
|
import com.alibaba.nacos.auth.constant.SignType;
|
||||||
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
|
import com.alibaba.nacos.auth.mock.MockAuthPluginService;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class HttpProtocolAuthServiceTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AuthConfigs authConfigs;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HttpServletRequest request;
|
||||||
|
|
||||||
|
private HttpProtocolAuthService httpProtocolAuthService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
httpProtocolAuthService = new HttpProtocolAuthService(authConfigs);
|
||||||
|
httpProtocolAuthService.initialize();
|
||||||
|
Mockito.when(request.getParameter(eq(CommonParams.NAMESPACE_ID))).thenReturn("testNNs");
|
||||||
|
Mockito.when(request.getParameter(eq(CommonParams.GROUP_NAME))).thenReturn("testNG");
|
||||||
|
Mockito.when(request.getParameter(eq(CommonParams.SERVICE_NAME))).thenReturn("testS");
|
||||||
|
Mockito.when(request.getParameter(eq("tenant"))).thenReturn("testCNs");
|
||||||
|
Mockito.when(request.getParameter(eq(Constants.GROUP))).thenReturn("testCG");
|
||||||
|
Mockito.when(request.getParameter(eq(Constants.DATAID))).thenReturn("testD");
|
||||||
|
Mockito.when(authConfigs.isAuthEnabled()).thenReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Secured(resource = "testResource")
|
||||||
|
public void testParseResourceWithSpecifiedResource() throws NoSuchMethodException {
|
||||||
|
Secured secured = getMethodSecure("testParseResourceWithSpecifiedResource");
|
||||||
|
Resource actual = httpProtocolAuthService.parseResource(request, secured);
|
||||||
|
assertEquals("testResource", actual.getName());
|
||||||
|
assertEquals(SignType.NAMING, actual.getType());
|
||||||
|
assertNull(actual.getNamespaceId());
|
||||||
|
assertNull(actual.getGroup());
|
||||||
|
assertNull(actual.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Secured(signType = "non-exist")
|
||||||
|
public void testParseResourceWithNonExistType() throws NoSuchMethodException {
|
||||||
|
Secured secured = getMethodSecure("testParseResourceWithNonExistType");
|
||||||
|
Resource actual = httpProtocolAuthService.parseResource(request, secured);
|
||||||
|
assertEquals(Resource.EMPTY_RESOURCE, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Secured()
|
||||||
|
public void testParseResourceWithNamingType() throws NoSuchMethodException {
|
||||||
|
Secured secured = getMethodSecure("testParseResourceWithNamingType");
|
||||||
|
Resource actual = httpProtocolAuthService.parseResource(request, secured);
|
||||||
|
assertEquals(SignType.NAMING, actual.getType());
|
||||||
|
assertEquals("testS", actual.getName());
|
||||||
|
assertEquals("testNNs", actual.getNamespaceId());
|
||||||
|
assertEquals("testNG", actual.getGroup());
|
||||||
|
assertNotNull(actual.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Secured(signType = SignType.CONFIG)
|
||||||
|
public void testParseResourceWithConfigType() throws NoSuchMethodException {
|
||||||
|
Secured secured = getMethodSecure("testParseResourceWithConfigType");
|
||||||
|
Resource actual = httpProtocolAuthService.parseResource(request, secured);
|
||||||
|
assertEquals(SignType.CONFIG, actual.getType());
|
||||||
|
assertEquals("testD", actual.getName());
|
||||||
|
assertEquals("testCNs", actual.getNamespaceId());
|
||||||
|
assertEquals("testCG", actual.getGroup());
|
||||||
|
assertNotNull(actual.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseIdentity() {
|
||||||
|
IdentityContext actual = httpProtocolAuthService.parseIdentity(request);
|
||||||
|
assertNotNull(actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateIdentityWithoutPlugin() throws AccessException {
|
||||||
|
IdentityContext identityContext = new IdentityContext();
|
||||||
|
assertTrue(httpProtocolAuthService.validateIdentity(identityContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateIdentityWithPlugin() throws AccessException {
|
||||||
|
Mockito.when(authConfigs.getNacosAuthSystemType()).thenReturn(MockAuthPluginService.TEST_PLUGIN);
|
||||||
|
IdentityContext identityContext = new IdentityContext();
|
||||||
|
assertFalse(httpProtocolAuthService.validateIdentity(identityContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAuthorityWithoutPlugin() {
|
||||||
|
assertTrue(httpProtocolAuthService
|
||||||
|
.validateAuthority(new IdentityContext(), new Permission(Resource.EMPTY_RESOURCE, "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateAuthorityWithPlugin() {
|
||||||
|
Mockito.when(authConfigs.getNacosAuthSystemType()).thenReturn(MockAuthPluginService.TEST_PLUGIN);
|
||||||
|
assertFalse(httpProtocolAuthService
|
||||||
|
.validateAuthority(new IdentityContext(), new Permission(Resource.EMPTY_RESOURCE, "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Secured getMethodSecure(String methodName) throws NoSuchMethodException {
|
||||||
|
Method method = HttpProtocolAuthServiceTest.class.getMethod(methodName);
|
||||||
|
return method.getAnnotation(Secured.class);
|
||||||
|
}
|
||||||
|
}
|
@ -132,7 +132,7 @@ public class NacosRoleServiceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Old global admin can pass resource 'console/':
|
// Old global admin can pass resource 'console/':
|
||||||
if (permission.getResource().startsWith(AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX)) {
|
if (permission.getResource().getName().startsWith(AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ public class NacosRoleServiceImpl {
|
|||||||
String permissionResource = permissionInfo.getResource().replaceAll("\\*", ".*");
|
String permissionResource = permissionInfo.getResource().replaceAll("\\*", ".*");
|
||||||
String permissionAction = permissionInfo.getAction();
|
String permissionAction = permissionInfo.getAction();
|
||||||
if (permissionAction.contains(permission.getAction()) && Pattern
|
if (permissionAction.contains(permission.getAction()) && Pattern
|
||||||
.matches(permissionResource, permission.getResource())) {
|
.matches(permissionResource, permission.getResource().getName())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package com.alibaba.nacos.core.auth;
|
|||||||
|
|
||||||
import com.alibaba.nacos.auth.AuthManager;
|
import com.alibaba.nacos.auth.AuthManager;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
|
import com.alibaba.nacos.auth.api.Resource;
|
||||||
import com.alibaba.nacos.auth.config.AuthConfigs;
|
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.auth.api.Permission;
|
import com.alibaba.nacos.auth.api.Permission;
|
||||||
@ -125,8 +126,9 @@ public class AuthFilter implements Filter {
|
|||||||
// deny if we don't find any resource:
|
// deny if we don't find any resource:
|
||||||
throw new AccessException("resource name invalid!");
|
throw new AccessException("resource name invalid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
authManager.auth(new Permission(resource, action), authManager.login(req));
|
Resource resourceObj = new Resource(null, null, resource, secured.signType(), null);
|
||||||
|
authManager.auth(new Permission(resourceObj, action), authManager.login(req));
|
||||||
|
|
||||||
}
|
}
|
||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
|
@ -22,6 +22,7 @@ import com.alibaba.nacos.api.remote.request.RequestMeta;
|
|||||||
import com.alibaba.nacos.api.remote.response.Response;
|
import com.alibaba.nacos.api.remote.response.Response;
|
||||||
import com.alibaba.nacos.auth.AuthManager;
|
import com.alibaba.nacos.auth.AuthManager;
|
||||||
import com.alibaba.nacos.auth.annotation.Secured;
|
import com.alibaba.nacos.auth.annotation.Secured;
|
||||||
|
import com.alibaba.nacos.auth.api.Resource;
|
||||||
import com.alibaba.nacos.auth.config.AuthConfigs;
|
import com.alibaba.nacos.auth.config.AuthConfigs;
|
||||||
import com.alibaba.nacos.auth.exception.AccessException;
|
import com.alibaba.nacos.auth.exception.AccessException;
|
||||||
import com.alibaba.nacos.auth.api.Permission;
|
import com.alibaba.nacos.auth.api.Permission;
|
||||||
@ -75,8 +76,9 @@ public class RemoteRequestAuthFilter extends AbstractRequestFilter {
|
|||||||
// deny if we don't find any resource:
|
// deny if we don't find any resource:
|
||||||
throw new AccessException("resource name invalid!");
|
throw new AccessException("resource name invalid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
authManager.auth(new Permission(resource, action), authManager.loginRemote(request));
|
Resource resourceObj = new Resource(null, null, resource, secured.signType(), null);
|
||||||
|
authManager.auth(new Permission(resourceObj, action), authManager.loginRemote(request));
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (AccessException e) {
|
} catch (AccessException e) {
|
||||||
|
Loading…
Reference in New Issue
Block a user