mirror of https://github.com/grpc/grpc-java.git
xds: add rbac http filter (#8251)
This commit is contained in:
parent
2cbc7fc3a5
commit
c8ba601529
|
|
@ -65,8 +65,9 @@ interface Filter {
|
|||
ScheduledExecutorService scheduler);
|
||||
}
|
||||
|
||||
// Server side filters are not currently supported, but this interface is defined for clarity.
|
||||
/** Uses the FilterConfigs produced above to produce an HTTP filter interceptor for the server. */
|
||||
interface ServerInterceptorBuilder {
|
||||
@Nullable
|
||||
ServerInterceptor buildServerInterceptor(
|
||||
FilterConfig config, @Nullable FilterConfig overrideConfig);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,10 @@ final class FilterRegistry {
|
|||
|
||||
static synchronized FilterRegistry getDefaultRegistry() {
|
||||
if (instance == null) {
|
||||
instance = newRegistry().register(FaultFilter.INSTANCE, RouterFilter.INSTANCE);
|
||||
instance = newRegistry().register(
|
||||
FaultFilter.INSTANCE,
|
||||
RouterFilter.INSTANCE,
|
||||
RbacFilter.INSTANCE);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2021 The gRPC Authors
|
||||
*
|
||||
* 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 io.grpc.xds;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import io.grpc.xds.Filter.FilterConfig;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthConfig;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Rbac configuration for Rbac filter. */
|
||||
@AutoValue
|
||||
abstract class RbacConfig implements FilterConfig {
|
||||
@Override
|
||||
public final String typeUrl() {
|
||||
return RbacFilter.TYPE_URL;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
abstract AuthConfig authConfig();
|
||||
|
||||
static RbacConfig create(@Nullable AuthConfig authConfig) {
|
||||
return new AutoValue_RbacConfig(authConfig);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* Copyright 2021 The gRPC Authors
|
||||
*
|
||||
* 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 io.grpc.xds;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.protobuf.Any;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import io.envoyproxy.envoy.config.core.v3.CidrRange;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Permission;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Policy;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Principal;
|
||||
import io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC;
|
||||
import io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBACPerRoute;
|
||||
import io.grpc.Metadata;
|
||||
import io.grpc.ServerCall;
|
||||
import io.grpc.ServerCallHandler;
|
||||
import io.grpc.ServerInterceptor;
|
||||
import io.grpc.Status;
|
||||
import io.grpc.xds.Filter.ServerInterceptorBuilder;
|
||||
import io.grpc.xds.internal.MatcherParser;
|
||||
import io.grpc.xds.internal.Matchers;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AlwaysTrueMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AndMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthConfig;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthDecision;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthHeaderMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthenticatedMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.DestinationIpMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.DestinationPortMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.InvertMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.Matcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.OrMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.PathMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.PolicyMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.RequestedServerNameMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.SourceIpMatcher;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** RBAC Http filter implementation. */
|
||||
final class RbacFilter implements Filter, ServerInterceptorBuilder {
|
||||
private static final Logger logger = Logger.getLogger(RbacFilter.class.getName());
|
||||
|
||||
static final RbacFilter INSTANCE = new RbacFilter();
|
||||
|
||||
static final String TYPE_URL =
|
||||
"type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC";
|
||||
|
||||
RbacFilter() {}
|
||||
|
||||
@Override
|
||||
public String[] typeUrls() {
|
||||
return new String[] { TYPE_URL };
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigOrError<RbacConfig> parseFilterConfig(Message rawProtoMessage) {
|
||||
RBAC rbacProto;
|
||||
if (!(rawProtoMessage instanceof Any)) {
|
||||
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
|
||||
}
|
||||
Any anyMessage = (Any) rawProtoMessage;
|
||||
try {
|
||||
rbacProto = anyMessage.unpack(RBAC.class);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
return ConfigOrError.fromError("Invalid proto: " + e);
|
||||
}
|
||||
return parseRbacConfig(rbacProto);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static ConfigOrError<RbacConfig> parseRbacConfig(RBAC rbac) {
|
||||
if (!rbac.hasRules()) {
|
||||
return ConfigOrError.fromConfig(RbacConfig.create(null));
|
||||
}
|
||||
io.envoyproxy.envoy.config.rbac.v3.RBAC rbacConfig = rbac.getRules();
|
||||
GrpcAuthorizationEngine.Action authAction;
|
||||
switch (rbacConfig.getAction()) {
|
||||
case ALLOW:
|
||||
authAction = GrpcAuthorizationEngine.Action.ALLOW;
|
||||
break;
|
||||
case DENY:
|
||||
authAction = GrpcAuthorizationEngine.Action.DENY;
|
||||
break;
|
||||
case LOG:
|
||||
return ConfigOrError.fromConfig(RbacConfig.create(null));
|
||||
case UNRECOGNIZED:
|
||||
default:
|
||||
return ConfigOrError.fromError("Unknown rbacConfig action type: " + rbacConfig.getAction());
|
||||
}
|
||||
Map<String, Policy> policyMap = rbacConfig.getPoliciesMap();
|
||||
List<GrpcAuthorizationEngine.PolicyMatcher> policyMatchers = new ArrayList<>();
|
||||
for (Map.Entry<String, Policy> entry: policyMap.entrySet()) {
|
||||
try {
|
||||
Policy policy = entry.getValue();
|
||||
if (policy.hasCondition() || policy.hasCheckedCondition()) {
|
||||
return ConfigOrError.fromError(
|
||||
"Policy.condition and Policy.checked_condition must not set: " + entry.getKey());
|
||||
}
|
||||
policyMatchers.add(new PolicyMatcher(entry.getKey(),
|
||||
parsePermissionList(policy.getPermissionsList()),
|
||||
parsePrincipalList(policy.getPrincipalsList())));
|
||||
} catch (Exception e) {
|
||||
return ConfigOrError.fromError("Encountered error parsing policy: " + e);
|
||||
}
|
||||
}
|
||||
return ConfigOrError.fromConfig(RbacConfig.create(new AuthConfig(policyMatchers, authAction)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigOrError<RbacConfig> parseFilterConfigOverride(Message rawProtoMessage) {
|
||||
RBACPerRoute rbacPerRoute;
|
||||
if (!(rawProtoMessage instanceof Any)) {
|
||||
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
|
||||
}
|
||||
Any anyMessage = (Any) rawProtoMessage;
|
||||
try {
|
||||
rbacPerRoute = anyMessage.unpack(RBACPerRoute.class);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
return ConfigOrError.fromError("Invalid proto: " + e);
|
||||
}
|
||||
if (rbacPerRoute.hasRbac()) {
|
||||
return parseRbacConfig(rbacPerRoute.getRbac());
|
||||
} else {
|
||||
return ConfigOrError.fromConfig(RbacConfig.create(null));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ServerInterceptor buildServerInterceptor(FilterConfig config,
|
||||
@Nullable FilterConfig overrideConfig) {
|
||||
checkNotNull(config, "config");
|
||||
if (overrideConfig != null) {
|
||||
config = overrideConfig;
|
||||
}
|
||||
AuthConfig authConfig = ((RbacConfig) config).authConfig();
|
||||
return authConfig == null ? null : generateAuthorizationInterceptor(authConfig);
|
||||
}
|
||||
|
||||
private ServerInterceptor generateAuthorizationInterceptor(AuthConfig config) {
|
||||
checkNotNull(config, "config");
|
||||
final GrpcAuthorizationEngine authEngine = new GrpcAuthorizationEngine(config);
|
||||
return new ServerInterceptor() {
|
||||
@Override
|
||||
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
|
||||
final ServerCall<ReqT, RespT> call,
|
||||
final Metadata headers, ServerCallHandler<ReqT, RespT> next) {
|
||||
AuthDecision authResult = authEngine.evaluate(headers, call);
|
||||
logger.log(Level.FINE,
|
||||
"Authorization result for serverCall {0}: {1}, matching policy: {2}.",
|
||||
new Object[]{call, authResult.decision(), authResult.matchingPolicyName()});
|
||||
if (GrpcAuthorizationEngine.Action.DENY.equals(authResult.decision())) {
|
||||
Status status = Status.UNAUTHENTICATED.withDescription(
|
||||
"Access Denied, matching policy: " + authResult.matchingPolicyName());
|
||||
call.close(status, new Metadata());
|
||||
return new ServerCall.Listener<ReqT>(){};
|
||||
}
|
||||
return next.startCall(call, headers);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static OrMatcher parsePermissionList(List<Permission> permissions) {
|
||||
List<Matcher> anyMatch = new ArrayList<>();
|
||||
for (Permission permission : permissions) {
|
||||
anyMatch.add(parsePermission(permission));
|
||||
}
|
||||
return new OrMatcher(anyMatch);
|
||||
}
|
||||
|
||||
private static Matcher parsePermission(Permission permission) {
|
||||
switch (permission.getRuleCase()) {
|
||||
case AND_RULES:
|
||||
List<Matcher> andMatch = new ArrayList<>();
|
||||
for (Permission p : permission.getAndRules().getRulesList()) {
|
||||
andMatch.add(parsePermission(p));
|
||||
}
|
||||
return new AndMatcher(andMatch);
|
||||
case OR_RULES:
|
||||
return parsePermissionList(permission.getOrRules().getRulesList());
|
||||
case ANY:
|
||||
return AlwaysTrueMatcher.INSTANCE;
|
||||
case HEADER:
|
||||
return parseHeaderMatcher(permission.getHeader());
|
||||
case URL_PATH:
|
||||
return parsePathMatcher(permission.getUrlPath());
|
||||
case DESTINATION_IP:
|
||||
return createDestinationIpMatcher(permission.getDestinationIp());
|
||||
case DESTINATION_PORT:
|
||||
return createDestinationPortMatcher(permission.getDestinationPort());
|
||||
case NOT_RULE:
|
||||
return new InvertMatcher(parsePermission(permission.getNotRule()));
|
||||
case METADATA: // hard coded, never match.
|
||||
return new InvertMatcher(AlwaysTrueMatcher.INSTANCE);
|
||||
case REQUESTED_SERVER_NAME:
|
||||
return parseRequestedServerNameMatcher(permission.getRequestedServerName());
|
||||
case RULE_NOT_SET:
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown permission rule case: " + permission.getRuleCase());
|
||||
}
|
||||
}
|
||||
|
||||
private static OrMatcher parsePrincipalList(List<Principal> principals) {
|
||||
List<Matcher> anyMatch = new ArrayList<>();
|
||||
for (Principal principal: principals) {
|
||||
anyMatch.add(parsePrincipal(principal));
|
||||
}
|
||||
return new OrMatcher(anyMatch);
|
||||
}
|
||||
|
||||
private static Matcher parsePrincipal(Principal principal) {
|
||||
switch (principal.getIdentifierCase()) {
|
||||
case OR_IDS:
|
||||
return parsePrincipalList(principal.getOrIds().getIdsList());
|
||||
case AND_IDS:
|
||||
List<Matcher> nextMatchers = new ArrayList<>();
|
||||
for (Principal next : principal.getAndIds().getIdsList()) {
|
||||
nextMatchers.add(parsePrincipal(next));
|
||||
}
|
||||
return new AndMatcher(nextMatchers);
|
||||
case ANY:
|
||||
return AlwaysTrueMatcher.INSTANCE;
|
||||
case AUTHENTICATED:
|
||||
return parseAuthenticatedMatcher(principal.getAuthenticated());
|
||||
case DIRECT_REMOTE_IP:
|
||||
return createSourceIpMatcher(principal.getDirectRemoteIp());
|
||||
case REMOTE_IP:
|
||||
return createSourceIpMatcher(principal.getRemoteIp());
|
||||
case SOURCE_IP:
|
||||
return createSourceIpMatcher(principal.getSourceIp());
|
||||
case HEADER:
|
||||
return parseHeaderMatcher(principal.getHeader());
|
||||
case NOT_ID:
|
||||
return new InvertMatcher(parsePrincipal(principal.getNotId()));
|
||||
case URL_PATH:
|
||||
return parsePathMatcher(principal.getUrlPath());
|
||||
case METADATA: // hard coded, never match.
|
||||
return new InvertMatcher(AlwaysTrueMatcher.INSTANCE);
|
||||
case IDENTIFIER_NOT_SET:
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown principal identifier case: " + principal.getIdentifierCase());
|
||||
}
|
||||
}
|
||||
|
||||
private static PathMatcher parsePathMatcher(
|
||||
io.envoyproxy.envoy.type.matcher.v3.PathMatcher proto) {
|
||||
switch (proto.getRuleCase()) {
|
||||
case PATH:
|
||||
return new PathMatcher(MatcherParser.parseStringMatcher(proto.getPath()));
|
||||
case RULE_NOT_SET:
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown path matcher rule type: " + proto.getRuleCase());
|
||||
}
|
||||
}
|
||||
|
||||
private static RequestedServerNameMatcher parseRequestedServerNameMatcher(
|
||||
io.envoyproxy.envoy.type.matcher.v3.StringMatcher proto) {
|
||||
return new RequestedServerNameMatcher(MatcherParser.parseStringMatcher(proto));
|
||||
}
|
||||
|
||||
private static AuthHeaderMatcher parseHeaderMatcher(
|
||||
io.envoyproxy.envoy.config.route.v3.HeaderMatcher proto) {
|
||||
return new AuthHeaderMatcher(MatcherParser.parseHeaderMatcher(proto));
|
||||
}
|
||||
|
||||
private static AuthenticatedMatcher parseAuthenticatedMatcher(
|
||||
Principal.Authenticated proto) {
|
||||
Matchers.StringMatcher matcher = MatcherParser.parseStringMatcher(proto.getPrincipalName());
|
||||
return new AuthenticatedMatcher(matcher);
|
||||
}
|
||||
|
||||
private static DestinationPortMatcher createDestinationPortMatcher(int port) {
|
||||
return new DestinationPortMatcher(port);
|
||||
}
|
||||
|
||||
private static DestinationIpMatcher createDestinationIpMatcher(CidrRange cidrRange) {
|
||||
return new DestinationIpMatcher(Matchers.CidrMatcher.create(
|
||||
resolve(cidrRange), cidrRange.getPrefixLen().getValue()));
|
||||
}
|
||||
|
||||
private static SourceIpMatcher createSourceIpMatcher(CidrRange cidrRange) {
|
||||
return new SourceIpMatcher(Matchers.CidrMatcher.create(
|
||||
resolve(cidrRange), cidrRange.getPrefixLen().getValue()));
|
||||
}
|
||||
|
||||
private static InetAddress resolve(CidrRange cidrRange) {
|
||||
try {
|
||||
return InetAddress.getByName(cidrRange.getAddressPrefix());
|
||||
} catch (UnknownHostException ex) {
|
||||
throw new IllegalArgumentException("IP address can not be found: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright 2021 The gRPC Authors
|
||||
*
|
||||
* 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 io.grpc.xds.internal;
|
||||
|
||||
import com.google.re2j.Pattern;
|
||||
import com.google.re2j.PatternSyntaxException;
|
||||
|
||||
// TODO(zivy@): may reuse common matchers parsers.
|
||||
public final class MatcherParser {
|
||||
/** Translates envoy proto HeaderMatcher to internal HeaderMatcher.*/
|
||||
public static Matchers.HeaderMatcher parseHeaderMatcher(
|
||||
io.envoyproxy.envoy.config.route.v3.HeaderMatcher proto) {
|
||||
switch (proto.getHeaderMatchSpecifierCase()) {
|
||||
case EXACT_MATCH:
|
||||
return Matchers.HeaderMatcher.forExactValue(
|
||||
proto.getName(), proto.getExactMatch(), proto.getInvertMatch());
|
||||
case SAFE_REGEX_MATCH:
|
||||
String rawPattern = proto.getSafeRegexMatch().getRegex();
|
||||
Pattern safeRegExMatch;
|
||||
try {
|
||||
safeRegExMatch = Pattern.compile(rawPattern);
|
||||
} catch (PatternSyntaxException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"HeaderMatcher [" + proto.getName() + "] contains malformed safe regex pattern: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
return Matchers.HeaderMatcher.forSafeRegEx(
|
||||
proto.getName(), safeRegExMatch, proto.getInvertMatch());
|
||||
case RANGE_MATCH:
|
||||
Matchers.HeaderMatcher.Range rangeMatch = Matchers.HeaderMatcher.Range.create(
|
||||
proto.getRangeMatch().getStart(), proto.getRangeMatch().getEnd());
|
||||
return Matchers.HeaderMatcher.forRange(
|
||||
proto.getName(), rangeMatch, proto.getInvertMatch());
|
||||
case PRESENT_MATCH:
|
||||
return Matchers.HeaderMatcher.forPresent(
|
||||
proto.getName(), proto.getPresentMatch(), proto.getInvertMatch());
|
||||
case PREFIX_MATCH:
|
||||
return Matchers.HeaderMatcher.forPrefix(
|
||||
proto.getName(), proto.getPrefixMatch(), proto.getInvertMatch());
|
||||
case SUFFIX_MATCH:
|
||||
return Matchers.HeaderMatcher.forSuffix(
|
||||
proto.getName(), proto.getSuffixMatch(), proto.getInvertMatch());
|
||||
case HEADERMATCHSPECIFIER_NOT_SET:
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown header matcher type: " + proto.getHeaderMatchSpecifierCase());
|
||||
}
|
||||
}
|
||||
|
||||
/** Translate StringMatcher envoy proto to internal StringMatcher. */
|
||||
public static Matchers.StringMatcher parseStringMatcher(
|
||||
io.envoyproxy.envoy.type.matcher.v3.StringMatcher proto) {
|
||||
switch (proto.getMatchPatternCase()) {
|
||||
case EXACT:
|
||||
return Matchers.StringMatcher.forExact(proto.getExact(), proto.getIgnoreCase());
|
||||
case PREFIX:
|
||||
return Matchers.StringMatcher.forPrefix(proto.getPrefix(), proto.getIgnoreCase());
|
||||
case SUFFIX:
|
||||
return Matchers.StringMatcher.forSuffix(proto.getSuffix(), proto.getIgnoreCase());
|
||||
case SAFE_REGEX:
|
||||
return Matchers.StringMatcher.forSafeRegEx(
|
||||
Pattern.compile(proto.getSafeRegex().getRegex()));
|
||||
case CONTAINS:
|
||||
return Matchers.StringMatcher.forContains(proto.getContains());
|
||||
case MATCHPATTERN_NOT_SET:
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown StringMatcher match pattern: " + proto.getMatchPatternCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -208,10 +208,10 @@ public final class GrpcAuthorizationEngine {
|
|||
}
|
||||
}
|
||||
|
||||
public static final class HeaderMatcher implements Matcher {
|
||||
public static final class AuthHeaderMatcher implements Matcher {
|
||||
private final Matchers.HeaderMatcher delegate;
|
||||
|
||||
public HeaderMatcher(Matchers.HeaderMatcher delegate) {
|
||||
public AuthHeaderMatcher(Matchers.HeaderMatcher delegate) {
|
||||
this.delegate = checkNotNull(delegate, "delegate");
|
||||
}
|
||||
|
||||
|
|
@ -234,6 +234,19 @@ public final class GrpcAuthorizationEngine {
|
|||
}
|
||||
}
|
||||
|
||||
public static final class RequestedServerNameMatcher implements Matcher {
|
||||
private final Matchers.StringMatcher delegate;
|
||||
|
||||
public RequestedServerNameMatcher(Matchers.StringMatcher delegate) {
|
||||
this.delegate = checkNotNull(delegate, "delegate");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(EvaluateArgs args) {
|
||||
return delegate.matches(args.getRequestedServerName());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class EvaluateArgs {
|
||||
private final Metadata metadata;
|
||||
private final ServerCall<?,?> serverCall;
|
||||
|
|
@ -330,9 +343,13 @@ public final class GrpcAuthorizationEngine {
|
|||
SocketAddress addr = serverCall.getAttributes().get(Grpc.TRANSPORT_ATTR_LOCAL_ADDR);
|
||||
return addr == null ? -1 : ((InetSocketAddress) addr).getPort();
|
||||
}
|
||||
|
||||
private String getRequestedServerName() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
interface Matcher {
|
||||
public interface Matcher {
|
||||
boolean matches(EvaluateArgs args);
|
||||
}
|
||||
|
||||
|
|
@ -392,7 +409,7 @@ public final class GrpcAuthorizationEngine {
|
|||
|
||||
/** Always true matcher.*/
|
||||
public static final class AlwaysTrueMatcher implements Matcher {
|
||||
static final AlwaysTrueMatcher INSTANCE = new AlwaysTrueMatcher();
|
||||
public static AlwaysTrueMatcher INSTANCE = new AlwaysTrueMatcher();
|
||||
|
||||
@Override
|
||||
public boolean matches(EvaluateArgs args) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* Copyright 2021 The gRPC Authors
|
||||
*
|
||||
* 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 io.grpc.xds;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.expr.v1alpha1.Expr;
|
||||
import com.google.protobuf.Any;
|
||||
import com.google.protobuf.Message;
|
||||
import com.google.protobuf.UInt32Value;
|
||||
import io.envoyproxy.envoy.config.core.v3.CidrRange;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Permission;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Policy;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Principal;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Principal.Authenticated;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.RBAC;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.RBAC.Action;
|
||||
import io.envoyproxy.envoy.config.route.v3.HeaderMatcher;
|
||||
import io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBACPerRoute;
|
||||
import io.envoyproxy.envoy.type.matcher.v3.MetadataMatcher;
|
||||
import io.envoyproxy.envoy.type.matcher.v3.PathMatcher;
|
||||
import io.envoyproxy.envoy.type.matcher.v3.StringMatcher;
|
||||
import io.grpc.Attributes;
|
||||
import io.grpc.Grpc;
|
||||
import io.grpc.Metadata;
|
||||
import io.grpc.MethodDescriptor;
|
||||
import io.grpc.MethodDescriptor.MethodType;
|
||||
import io.grpc.ServerCall;
|
||||
import io.grpc.ServerCallHandler;
|
||||
import io.grpc.ServerInterceptor;
|
||||
import io.grpc.Status;
|
||||
import io.grpc.testing.TestMethodDescriptors;
|
||||
import io.grpc.xds.Filter.ConfigOrError;
|
||||
import io.grpc.xds.Filter.FilterConfig;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AlwaysTrueMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthConfig;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthDecision;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.DestinationPortMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.OrMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.PolicyMatcher;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
/** Tests for {@link RbacFilter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RbacFilterTest {
|
||||
private static final String PATH = "auth";
|
||||
private static final StringMatcher STRING_MATCHER =
|
||||
StringMatcher.newBuilder().setExact("/" + PATH).setIgnoreCase(true).build();
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"unchecked", "deprecation"})
|
||||
public void ipPortParser() {
|
||||
CidrRange cidrRange = CidrRange.newBuilder().setAddressPrefix("10.10.10.0")
|
||||
.setPrefixLen(UInt32Value.of(24)).build();
|
||||
List<Permission> permissionList = Arrays.asList(
|
||||
Permission.newBuilder().setAndRules(Permission.Set.newBuilder()
|
||||
.addRules(Permission.newBuilder().setDestinationIp(cidrRange).build())
|
||||
.addRules(Permission.newBuilder().setDestinationPort(9090).build()).build()
|
||||
).build());
|
||||
List<Principal> principalList = Arrays.asList(
|
||||
Principal.newBuilder().setAndIds(Principal.Set.newBuilder()
|
||||
.addIds(Principal.newBuilder().setDirectRemoteIp(cidrRange).build())
|
||||
.addIds(Principal.newBuilder().setRemoteIp(cidrRange).build())
|
||||
.addIds(Principal.newBuilder().setSourceIp(cidrRange).build())
|
||||
.build()).build());
|
||||
ConfigOrError<?> result = parseRaw(permissionList, principalList);
|
||||
assertThat(result.errorDetail).isNull();
|
||||
ServerCall<Void,Void> serverCall = mock(ServerCall.class);
|
||||
Attributes attributes = Attributes.newBuilder()
|
||||
.set(Grpc.TRANSPORT_ATTR_REMOTE_ADDR, new InetSocketAddress("10.10.10.0", 1))
|
||||
.set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, new InetSocketAddress("10.10.10.0",9090))
|
||||
.build();
|
||||
when(serverCall.getAttributes()).thenReturn(attributes);
|
||||
when(serverCall.getMethodDescriptor()).thenReturn(method().build());
|
||||
GrpcAuthorizationEngine engine =
|
||||
new GrpcAuthorizationEngine(((RbacConfig)result.config).authConfig());
|
||||
AuthDecision decision = engine.evaluate(new Metadata(), serverCall);
|
||||
assertThat(decision.decision()).isEqualTo(GrpcAuthorizationEngine.Action.DENY);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void pathParser() {
|
||||
PathMatcher pathMatcher = PathMatcher.newBuilder().setPath(STRING_MATCHER).build();
|
||||
List<Permission> permissionList = Arrays.asList(
|
||||
Permission.newBuilder().setUrlPath(pathMatcher).build());
|
||||
List<Principal> principalList = Arrays.asList(
|
||||
Principal.newBuilder().setUrlPath(pathMatcher).build());
|
||||
ConfigOrError<RbacConfig> result = parse(permissionList, principalList);
|
||||
assertThat(result.errorDetail).isNull();
|
||||
ServerCall<Void,Void> serverCall = mock(ServerCall.class);
|
||||
when(serverCall.getMethodDescriptor()).thenReturn(method().build());
|
||||
GrpcAuthorizationEngine engine =
|
||||
new GrpcAuthorizationEngine(result.config.authConfig());
|
||||
AuthDecision decision = engine.evaluate(new Metadata(), serverCall);
|
||||
assertThat(decision.decision()).isEqualTo(GrpcAuthorizationEngine.Action.DENY);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void authenticatedParser() throws Exception {
|
||||
List<Permission> permissionList = Arrays.asList(
|
||||
Permission.newBuilder().setNotRule(
|
||||
Permission.newBuilder().setRequestedServerName(STRING_MATCHER).build()).build());
|
||||
List<Principal> principalList = Arrays.asList(
|
||||
Principal.newBuilder().setAuthenticated(Authenticated.newBuilder()
|
||||
.setPrincipalName(STRING_MATCHER).build()).build());
|
||||
ConfigOrError<?> result = parse(permissionList, principalList);
|
||||
assertThat(result.errorDetail).isNull();
|
||||
SSLSession sslSession = mock(SSLSession.class);
|
||||
X509Certificate mockCert = mock(X509Certificate.class);
|
||||
when(sslSession.getPeerCertificates()).thenReturn(new X509Certificate[]{mockCert});
|
||||
when(mockCert.getSubjectAlternativeNames()).thenReturn(
|
||||
Arrays.<List<?>>asList(Arrays.asList(2, "/" + PATH)));
|
||||
Attributes attributes = Attributes.newBuilder()
|
||||
.set(Grpc.TRANSPORT_ATTR_SSL_SESSION, sslSession)
|
||||
.build();
|
||||
ServerCall<Void,Void> serverCall = mock(ServerCall.class);
|
||||
when(serverCall.getAttributes()).thenReturn(attributes);
|
||||
GrpcAuthorizationEngine engine =
|
||||
new GrpcAuthorizationEngine(((RbacConfig)result.config).authConfig());
|
||||
AuthDecision decision = engine.evaluate(new Metadata(), serverCall);
|
||||
assertThat(decision.decision()).isEqualTo(GrpcAuthorizationEngine.Action.DENY);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void headerParser() {
|
||||
HeaderMatcher headerMatcher = HeaderMatcher.newBuilder()
|
||||
.setName("party").setExactMatch("win").build();
|
||||
List<Permission> permissionList = Arrays.asList(
|
||||
Permission.newBuilder().setHeader(headerMatcher).build());
|
||||
List<Principal> principalList = Arrays.asList(
|
||||
Principal.newBuilder().setHeader(headerMatcher).build());
|
||||
ConfigOrError<RbacConfig> result = parseOverride(permissionList, principalList);
|
||||
assertThat(result.errorDetail).isNull();
|
||||
ServerCall<Void,Void> serverCall = mock(ServerCall.class);
|
||||
GrpcAuthorizationEngine engine =
|
||||
new GrpcAuthorizationEngine(result.config.authConfig());
|
||||
AuthDecision decision = engine.evaluate(metadata("party", "win"), serverCall);
|
||||
assertThat(decision.decision()).isEqualTo(GrpcAuthorizationEngine.Action.DENY);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void compositeRules() {
|
||||
MetadataMatcher metadataMatcher = MetadataMatcher.newBuilder().build();
|
||||
List<Permission> permissionList = Arrays.asList(
|
||||
Permission.newBuilder().setOrRules(Permission.Set.newBuilder().addRules(
|
||||
Permission.newBuilder().setMetadata(metadataMatcher).build()
|
||||
).build()).build());
|
||||
List<Principal> principalList = Arrays.asList(
|
||||
Principal.newBuilder().setNotId(
|
||||
Principal.newBuilder().setMetadata(metadataMatcher).build()
|
||||
).build());
|
||||
ConfigOrError<? extends FilterConfig> result = parse(permissionList, principalList);
|
||||
assertThat(result.errorDetail).isNull();
|
||||
assertThat(result.config).isInstanceOf(RbacConfig.class);
|
||||
ServerCall<Void,Void> serverCall = mock(ServerCall.class);
|
||||
GrpcAuthorizationEngine engine =
|
||||
new GrpcAuthorizationEngine(((RbacConfig)result.config).authConfig());
|
||||
AuthDecision decision = engine.evaluate(new Metadata(), serverCall);
|
||||
assertThat(decision.decision()).isEqualTo(GrpcAuthorizationEngine.Action.ALLOW);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testAuthorizationInterceptor() {
|
||||
ServerCallHandler<Void, Void> mockHandler = mock(ServerCallHandler.class);
|
||||
ServerCall<Void, Void> mockServerCall = mock(ServerCall.class);
|
||||
Attributes attr = Attributes.newBuilder()
|
||||
.set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, new InetSocketAddress("1::", 20))
|
||||
.build();
|
||||
when(mockServerCall.getAttributes()).thenReturn(attr);
|
||||
PolicyMatcher policyMatcher = new PolicyMatcher("policy-matcher",
|
||||
OrMatcher.create(new DestinationPortMatcher(99999)),
|
||||
OrMatcher.create(AlwaysTrueMatcher.INSTANCE));
|
||||
AuthConfig authconfig = new AuthConfig(Collections.singletonList(policyMatcher),
|
||||
GrpcAuthorizationEngine.Action.ALLOW);
|
||||
new RbacFilter().buildServerInterceptor(RbacConfig.create(authconfig), null)
|
||||
.interceptCall(mockServerCall, new Metadata(), mockHandler);
|
||||
verify(mockHandler, never()).startCall(eq(mockServerCall), any(Metadata.class));
|
||||
ArgumentCaptor<Status> captor = ArgumentCaptor.forClass(Status.class);
|
||||
verify(mockServerCall).close(captor.capture(), any(Metadata.class));
|
||||
assertThat(captor.getValue().getCode()).isEqualTo(Status.UNAUTHENTICATED.getCode());
|
||||
verify(mockServerCall).getAttributes();
|
||||
verifyNoMoreInteractions(mockServerCall);
|
||||
|
||||
authconfig = new AuthConfig(Collections.singletonList(policyMatcher),
|
||||
GrpcAuthorizationEngine.Action.DENY);
|
||||
new RbacFilter().buildServerInterceptor(RbacConfig.create(authconfig), null)
|
||||
.interceptCall(mockServerCall, new Metadata(), mockHandler);
|
||||
verify(mockHandler).startCall(eq(mockServerCall), any(Metadata.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleException() {
|
||||
PathMatcher pathMatcher = PathMatcher.newBuilder()
|
||||
.setPath(StringMatcher.newBuilder().build()).build();
|
||||
List<Permission> permissionList = Arrays.asList(
|
||||
Permission.newBuilder().setUrlPath(pathMatcher).build());
|
||||
List<Principal> principalList = Arrays.asList(
|
||||
Principal.newBuilder().setUrlPath(pathMatcher).build());
|
||||
ConfigOrError<?> result = parse(permissionList, principalList);
|
||||
assertThat(result.errorDetail).isNotNull();
|
||||
|
||||
permissionList = Arrays.asList(Permission.newBuilder().build());
|
||||
principalList = Arrays.asList(Principal.newBuilder().build());
|
||||
result = parse(permissionList, principalList);
|
||||
assertThat(result.errorDetail).isNotNull();
|
||||
|
||||
Message rawProto = io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC.newBuilder()
|
||||
.setRules(RBAC.newBuilder().setAction(Action.DENY)
|
||||
.putPolicies("policy-name",
|
||||
Policy.newBuilder().setCondition(Expr.newBuilder().build()).build())
|
||||
.build()).build();
|
||||
result = new RbacFilter().parseFilterConfig(Any.pack(rawProto));
|
||||
assertThat(result.errorDetail).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void overrideConfig() {
|
||||
ServerCallHandler<Void, Void> mockHandler = mock(ServerCallHandler.class);
|
||||
ServerCall<Void, Void> mockServerCall = mock(ServerCall.class);
|
||||
Attributes attr = Attributes.newBuilder()
|
||||
.set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, new InetSocketAddress("1::", 20))
|
||||
.build();
|
||||
when(mockServerCall.getAttributes()).thenReturn(attr);
|
||||
|
||||
PolicyMatcher policyMatcher = new PolicyMatcher("policy-matcher",
|
||||
OrMatcher.create(new DestinationPortMatcher(99999)),
|
||||
OrMatcher.create(AlwaysTrueMatcher.INSTANCE));
|
||||
AuthConfig authconfig = new AuthConfig(Collections.singletonList(policyMatcher),
|
||||
GrpcAuthorizationEngine.Action.ALLOW);
|
||||
RbacConfig original = RbacConfig.create(authconfig);
|
||||
|
||||
RBACPerRoute rbacPerRoute = RBACPerRoute.newBuilder().build();
|
||||
RbacConfig override =
|
||||
new RbacFilter().parseFilterConfigOverride(Any.pack(rbacPerRoute)).config;
|
||||
assertThat(override).isEqualTo(RbacConfig.create(null));
|
||||
ServerInterceptor interceptor = new RbacFilter().buildServerInterceptor(original, override);
|
||||
assertThat(interceptor).isNull();
|
||||
|
||||
policyMatcher = new PolicyMatcher("policy-matcher-override",
|
||||
OrMatcher.create(new DestinationPortMatcher(20)),
|
||||
OrMatcher.create(AlwaysTrueMatcher.INSTANCE));
|
||||
authconfig = new AuthConfig(Collections.singletonList(policyMatcher),
|
||||
GrpcAuthorizationEngine.Action.ALLOW);
|
||||
override = RbacConfig.create(authconfig);
|
||||
|
||||
new RbacFilter().buildServerInterceptor(original, override)
|
||||
.interceptCall(mockServerCall, new Metadata(), mockHandler);
|
||||
verify(mockHandler).startCall(eq(mockServerCall), any(Metadata.class));
|
||||
verify(mockServerCall).getAttributes();
|
||||
verifyNoMoreInteractions(mockServerCall);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoredConfig() {
|
||||
Message rawProto = io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC.newBuilder()
|
||||
.setRules(RBAC.newBuilder().setAction(Action.LOG)
|
||||
.putPolicies("policy-name", Policy.newBuilder().build()).build()).build();
|
||||
ConfigOrError<RbacConfig> result = new RbacFilter().parseFilterConfig(Any.pack(rawProto));
|
||||
assertThat(result.config).isEqualTo(RbacConfig.create(null));
|
||||
}
|
||||
|
||||
private static Metadata metadata(String key, String value) {
|
||||
Metadata metadata = new Metadata();
|
||||
metadata.put(Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER), value);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private MethodDescriptor.Builder<Void, Void> method() {
|
||||
return MethodDescriptor.<Void,Void>newBuilder()
|
||||
.setType(MethodType.BIDI_STREAMING)
|
||||
.setFullMethodName(PATH)
|
||||
.setRequestMarshaller(TestMethodDescriptors.voidMarshaller())
|
||||
.setResponseMarshaller(TestMethodDescriptors.voidMarshaller());
|
||||
}
|
||||
|
||||
private ConfigOrError<RbacConfig> parse(List<Permission> permissionList,
|
||||
List<Principal> principalList) {
|
||||
|
||||
return RbacFilter.parseRbacConfig(buildRbac(permissionList, principalList));
|
||||
}
|
||||
|
||||
private ConfigOrError<RbacConfig> parseRaw(List<Permission> permissionList,
|
||||
List<Principal> principalList) {
|
||||
Message rawProto = buildRbac(permissionList, principalList);
|
||||
Any proto = Any.pack(rawProto);
|
||||
return new RbacFilter().parseFilterConfig(proto);
|
||||
}
|
||||
|
||||
private io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC buildRbac(
|
||||
List<Permission> permissionList, List<Principal> principalList) {
|
||||
return io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC.newBuilder()
|
||||
.setRules(RBAC.newBuilder().setAction(Action.DENY)
|
||||
.putPolicies("policy-name", Policy.newBuilder()
|
||||
.addAllPermissions(permissionList)
|
||||
.addAllPrincipals(principalList).build()).build()).build();
|
||||
|
||||
}
|
||||
|
||||
private ConfigOrError<RbacConfig> parseOverride(List<Permission> permissionList,
|
||||
List<Principal> principalList) {
|
||||
RBACPerRoute rbacPerRoute = RBACPerRoute.newBuilder().setRbac(
|
||||
buildRbac(permissionList, principalList)).build();
|
||||
Any proto = Any.pack(rbacPerRoute);
|
||||
return new RbacFilter().parseFilterConfigOverride(proto);
|
||||
}
|
||||
}
|
||||
|
|
@ -38,10 +38,10 @@ import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AlwaysTrueMatche
|
|||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AndMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthConfig;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthDecision;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthHeaderMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthenticatedMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.DestinationIpMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.DestinationPortMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.HeaderMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.InvertMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.OrMatcher;
|
||||
import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.PathMatcher;
|
||||
|
|
@ -143,7 +143,7 @@ public class GrpcAuthorizationEngineTest {
|
|||
|
||||
@Test
|
||||
public void headerMatcher() {
|
||||
HeaderMatcher headerMatcher = new HeaderMatcher(Matchers.HeaderMatcher
|
||||
AuthHeaderMatcher headerMatcher = new AuthHeaderMatcher(Matchers.HeaderMatcher
|
||||
.forExactValue(HEADER_KEY, HEADER_VALUE, false));
|
||||
OrMatcher principal = OrMatcher.create(headerMatcher);
|
||||
OrMatcher permission = OrMatcher.create(
|
||||
|
|
@ -156,7 +156,7 @@ public class GrpcAuthorizationEngineTest {
|
|||
assertThat(decision.matchingPolicyName()).isEqualTo(POLICY_NAME);
|
||||
|
||||
HEADER.put(Metadata.Key.of(HEADER_KEY, Metadata.ASCII_STRING_MARSHALLER), HEADER_VALUE);
|
||||
headerMatcher = new HeaderMatcher(Matchers.HeaderMatcher
|
||||
headerMatcher = new AuthHeaderMatcher(Matchers.HeaderMatcher
|
||||
.forExactValue(HEADER_KEY, HEADER_VALUE + "," + HEADER_VALUE, false));
|
||||
principal = OrMatcher.create(headerMatcher);
|
||||
policyMatcher = new PolicyMatcher(POLICY_NAME,
|
||||
|
|
@ -166,7 +166,7 @@ public class GrpcAuthorizationEngineTest {
|
|||
decision = engine.evaluate(HEADER, serverCall);
|
||||
assertThat(decision.decision()).isEqualTo(Action.ALLOW);
|
||||
|
||||
headerMatcher = new HeaderMatcher(Matchers.HeaderMatcher
|
||||
headerMatcher = new AuthHeaderMatcher(Matchers.HeaderMatcher
|
||||
.forExactValue(HEADER_KEY + Metadata.BINARY_HEADER_SUFFIX, HEADER_VALUE, false));
|
||||
principal = OrMatcher.create(headerMatcher);
|
||||
policyMatcher = new PolicyMatcher(POLICY_NAME,
|
||||
|
|
@ -271,7 +271,7 @@ public class GrpcAuthorizationEngineTest {
|
|||
new InvertMatcher(new DestinationPortMatcher(PORT + 1))));
|
||||
PolicyMatcher policyMatcher1 = new PolicyMatcher(POLICY_NAME, permission, principal);
|
||||
|
||||
HeaderMatcher headerMatcher = new HeaderMatcher(Matchers.HeaderMatcher
|
||||
AuthHeaderMatcher headerMatcher = new AuthHeaderMatcher(Matchers.HeaderMatcher
|
||||
.forExactValue(HEADER_KEY, HEADER_VALUE + 1, false));
|
||||
authMatcher = new AuthenticatedMatcher(
|
||||
StringMatcher.forContains("TEST.google.fr"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue