[ISSUE#5696] IdentityContext build from resource and remote ip. (#7745)

* validateIdentity add Resource input for extension.

* IdentityContext parse remoteIp.
This commit is contained in:
杨翊 SionYang 2022-02-09 17:57:39 +08:00 committed by GitHub
parent 080f1ff592
commit 64dcc0ed0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 59 additions and 15 deletions

View File

@ -46,14 +46,14 @@ public abstract class AbstractProtocolAuthService<R> implements ProtocolAuthServ
}
@Override
public boolean validateIdentity(IdentityContext identityContext) throws AccessException {
public boolean validateIdentity(IdentityContext identityContext, Resource resource) throws AccessException {
if (!authConfigs.isAuthEnabled()) {
return true;
}
Optional<AuthPluginService> authPluginService = AuthPluginManager.getInstance()
.findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType());
if (authPluginService.isPresent()) {
return authPluginService.get().validateIdentity(identityContext);
return authPluginService.get().validateIdentity(identityContext, resource);
}
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);

View File

@ -55,16 +55,17 @@ public interface ProtocolAuthService<R> {
* Validate identity whether is legal.
*
* @param identityContext identity context
* @param resource resource
* @return {@code true} if legal, otherwise {@code false}
* @throws AccessException exception during validating
*/
boolean validateIdentity(IdentityContext identityContext) throws AccessException;
boolean validateIdentity(IdentityContext identityContext, Resource resource) throws AccessException;
/**
* Validate identity whether had permission for the resource and action.
*
* @param identityContext identity context
* @param permission permssion include resource and action
* @param permission permission include resource and action
* @return {@code true} if legal, otherwise {@code false}
* @throws AccessException exception during validating
*/

View File

@ -17,10 +17,11 @@
package com.alibaba.nacos.auth.context;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.plugin.auth.constant.Constants;
import com.alibaba.nacos.plugin.auth.spi.server.AuthPluginManager;
import com.alibaba.nacos.plugin.auth.spi.server.AuthPluginService;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.auth.config.AuthConfigs;
import java.util.HashSet;
import java.util.Map;
@ -52,6 +53,7 @@ public class GrpcIdentityContextBuilder implements IdentityContextBuilder<Reques
Optional<AuthPluginService> authPluginService = AuthPluginManager.getInstance()
.findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType());
IdentityContext result = new IdentityContext();
getRemoteIp(request, result);
if (!authPluginService.isPresent()) {
return result;
}
@ -64,4 +66,8 @@ public class GrpcIdentityContextBuilder implements IdentityContextBuilder<Reques
}
return result;
}
private void getRemoteIp(Request request, IdentityContext result) {
result.setParameter(Constants.Identity.REMOTE_IP, request.getHeader(Constants.Identity.X_REAL_IP));
}
}

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.auth.context;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.plugin.auth.constant.Constants;
import com.alibaba.nacos.plugin.auth.spi.server.AuthPluginManager;
import com.alibaba.nacos.plugin.auth.spi.server.AuthPluginService;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
@ -35,6 +37,10 @@ import java.util.Set;
*/
public class HttpIdentityContextBuilder implements IdentityContextBuilder<HttpServletRequest> {
private static final String X_FORWARDED_FOR = "X-Forwarded-For";
private static final String X_FORWARDED_FOR_SPLIT_SYMBOL = ",";
private final AuthConfigs authConfigs;
public HttpIdentityContextBuilder(AuthConfigs authConfigs) {
@ -50,6 +56,7 @@ public class HttpIdentityContextBuilder implements IdentityContextBuilder<HttpSe
@Override
public IdentityContext build(HttpServletRequest request) {
IdentityContext result = new IdentityContext();
getRemoteIp(request, result);
Optional<AuthPluginService> authPluginService = AuthPluginManager.getInstance()
.findAuthServiceSpiImpl(authConfigs.getNacosAuthSystemType());
if (!authPluginService.isPresent()) {
@ -80,4 +87,17 @@ public class HttpIdentityContextBuilder implements IdentityContextBuilder<HttpSe
}
}
}
private void getRemoteIp(HttpServletRequest request, IdentityContext result) {
String remoteIp = StringUtils.EMPTY;
String xForwardedFor = request.getHeader(X_FORWARDED_FOR);
if (!StringUtils.isBlank(xForwardedFor)) {
remoteIp = xForwardedFor.split(X_FORWARDED_FOR_SPLIT_SYMBOL)[0].trim();
}
if (StringUtils.isBlank(remoteIp)) {
String nginxHeader = request.getHeader(Constants.Identity.X_REAL_IP);
remoteIp = StringUtils.isBlank(nginxHeader) ? request.getRemoteAddr() : nginxHeader;
}
result.setParameter(Constants.Identity.REMOTE_IP, remoteIp);
}
}

View File

@ -130,14 +130,14 @@ public class GrpcProtocolAuthServiceTest {
@Test
public void testValidateIdentityWithoutPlugin() throws AccessException {
IdentityContext identityContext = new IdentityContext();
assertTrue(protocolAuthService.validateIdentity(identityContext));
assertTrue(protocolAuthService.validateIdentity(identityContext, Resource.EMPTY_RESOURCE));
}
@Test
public void testValidateIdentityWithPlugin() throws AccessException {
Mockito.when(authConfigs.getNacosAuthSystemType()).thenReturn(MockAuthPluginService.TEST_PLUGIN);
IdentityContext identityContext = new IdentityContext();
assertFalse(protocolAuthService.validateIdentity(identityContext));
assertFalse(protocolAuthService.validateIdentity(identityContext, Resource.EMPTY_RESOURCE));
}
@Test

View File

@ -120,14 +120,14 @@ public class HttpProtocolAuthServiceTest {
@Test
public void testValidateIdentityWithoutPlugin() throws AccessException {
IdentityContext identityContext = new IdentityContext();
assertTrue(httpProtocolAuthService.validateIdentity(identityContext));
assertTrue(httpProtocolAuthService.validateIdentity(identityContext, Resource.EMPTY_RESOURCE));
}
@Test
public void testValidateIdentityWithPlugin() throws AccessException {
Mockito.when(authConfigs.getNacosAuthSystemType()).thenReturn(MockAuthPluginService.TEST_PLUGIN);
IdentityContext identityContext = new IdentityContext();
assertFalse(httpProtocolAuthService.validateIdentity(identityContext));
assertFalse(httpProtocolAuthService.validateIdentity(identityContext, Resource.EMPTY_RESOURCE));
}
@Test

View File

@ -19,6 +19,7 @@ package com.alibaba.nacos.auth.context;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.plugin.auth.constant.Constants;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -56,6 +57,7 @@ public class GrpcIdentityContextBuilderTest {
Map<String, String> headers = new HashMap<>();
headers.put(IDENTITY_TEST_KEY, IDENTITY_TEST_VALUE);
when(request.getHeaders()).thenReturn(headers);
when(request.getHeader(Constants.Identity.X_REAL_IP)).thenReturn("1.1.1.1");
}
@Test
@ -69,5 +71,6 @@ public class GrpcIdentityContextBuilderTest {
public void testBuild() {
IdentityContext actual = identityContextBuilder.build(request);
assertEquals(IDENTITY_TEST_VALUE, actual.getParameter(IDENTITY_TEST_KEY));
assertEquals("1.1.1.1", actual.getParameter(Constants.Identity.REMOTE_IP));
}
}

View File

@ -18,6 +18,7 @@ package com.alibaba.nacos.auth.context;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.auth.config.AuthConfigs;
import com.alibaba.nacos.plugin.auth.constant.Constants;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -75,6 +76,7 @@ public class HtppIdentityContextBuilderTest {
mockParameter(false);
IdentityContext actual = identityContextBuilder.build(request);
assertEquals(IDENTITY_TEST_VALUE, actual.getParameter(IDENTITY_TEST_KEY));
assertEquals("1.1.1.1", actual.getParameter(Constants.Identity.REMOTE_IP));
}
@Test
@ -91,6 +93,7 @@ public class HtppIdentityContextBuilderTest {
when(headerNames.hasMoreElements()).thenReturn(true, false);
when(headerNames.nextElement()).thenReturn(IDENTITY_TEST_KEY, (String) null);
when(request.getHeader(IDENTITY_TEST_KEY)).thenReturn(IDENTITY_TEST_VALUE);
when(request.getHeader(Constants.Identity.X_REAL_IP)).thenReturn("1.1.1.1");
}
}

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.auth.mock;
import com.alibaba.nacos.plugin.auth.api.Resource;
import com.alibaba.nacos.plugin.auth.spi.server.AuthPluginService;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.plugin.auth.api.Permission;
@ -36,7 +37,7 @@ public class MockAuthPluginService implements AuthPluginService {
}
@Override
public boolean validateIdentity(IdentityContext identityContext) throws AccessException {
public boolean validateIdentity(IdentityContext identityContext, Resource resource) throws AccessException {
return false;
}

View File

@ -115,7 +115,7 @@ public class AuthFilter implements Filter {
Secured secured = method.getAnnotation(Secured.class);
Resource resource = protocolAuthService.parseResource(req, secured);
IdentityContext identityContext = protocolAuthService.parseIdentity(req);
boolean result = protocolAuthService.validateIdentity(identityContext);
boolean result = protocolAuthService.validateIdentity(identityContext, resource);
if (!result) {
// TODO Get reason of failure
throw new AccessException("Validate Identity failed.");

View File

@ -29,6 +29,7 @@ import com.alibaba.nacos.core.utils.Loggers;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.plugin.auth.api.Permission;
import com.alibaba.nacos.plugin.auth.api.Resource;
import com.alibaba.nacos.plugin.auth.constant.Constants;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import org.springframework.stereotype.Component;
@ -66,9 +67,11 @@ public class RemoteRequestAuthFilter extends AbstractRequestFilter {
}
Secured secured = method.getAnnotation(Secured.class);
String clientIp = meta.getClientIp();
request.putHeader(Constants.Identity.X_REAL_IP, clientIp);
Resource resource = protocolAuthService.parseResource(request, secured);
IdentityContext identityContext = protocolAuthService.parseIdentity(request);
boolean result = protocolAuthService.validateIdentity(identityContext);
boolean result = protocolAuthService.validateIdentity(identityContext, resource);
if (!result) {
// TODO Get reason of failure
throw new AccessException("Validate Identity failed.");

View File

@ -17,6 +17,7 @@
package com.alibaba.nacos.plugin.auth.impl;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.plugin.auth.api.Resource;
import com.alibaba.nacos.plugin.auth.impl.users.User;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.plugin.auth.api.Permission;
@ -57,7 +58,7 @@ public class NacosAuthPluginService implements AuthPluginService {
}
@Override
public boolean validateIdentity(IdentityContext identityContext) throws AccessException {
public boolean validateIdentity(IdentityContext identityContext, Resource resource) throws AccessException {
checkNacosAuthManager();
User user = nacosAuthManager.login(identityContext);
identityContext.setParameter(USER_IDENTITY_PARAM_KEY, user);

View File

@ -48,5 +48,9 @@ public class Constants {
public static class Identity {
public static final String IDENTITY_ID = "identity_id";
public static final String X_REAL_IP = "X-Real-IP";
public static final String REMOTE_IP = "remote_ip";
}
}

View File

@ -18,6 +18,7 @@ package com.alibaba.nacos.plugin.auth.spi.server;
import com.alibaba.nacos.plugin.auth.api.IdentityContext;
import com.alibaba.nacos.plugin.auth.api.Permission;
import com.alibaba.nacos.plugin.auth.api.Resource;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import java.util.Collection;
@ -40,10 +41,11 @@ public interface AuthPluginService {
* To validate whether the identity context from request is legal or illegal.
*
* @param identityContext where we can find the user information
* @param resource resource about this user information
* @return {@code true} if legal, otherwise {@code false}
* @throws AccessException if authentication is failed
*/
boolean validateIdentity(IdentityContext identityContext) throws AccessException;
boolean validateIdentity(IdentityContext identityContext, Resource resource) throws AccessException;
/**
* Validate the identity whether has the resource authority.