Skip to content

Commit 21d7786

Browse files
committed
.
1 parent b78042a commit 21d7786

6 files changed

Lines changed: 565 additions & 13 deletions

File tree

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2025 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.xds;
18+
19+
import com.google.common.collect.ImmutableList;
20+
import io.envoyproxy.envoy.extensions.filters.http.ext_authz.v3.ExtAuthz;
21+
import io.grpc.internal.GrpcUtil;
22+
import io.grpc.xds.client.Bootstrapper.BootstrapInfo;
23+
import io.grpc.xds.client.Bootstrapper.ServerInfo;
24+
import io.grpc.xds.internal.MatcherParser;
25+
import io.grpc.xds.internal.extauthz.ExtAuthzConfig;
26+
import io.grpc.xds.internal.extauthz.ExtAuthzParseException;
27+
import io.grpc.xds.internal.grpcservice.GrpcServiceConfig;
28+
import io.grpc.xds.internal.grpcservice.GrpcServiceParseException;
29+
import io.grpc.xds.internal.headermutations.HeaderMutationRulesParseException;
30+
import io.grpc.xds.internal.headermutations.HeaderMutationRulesParser;
31+
32+
33+
/**
34+
* Parser for {@link io.envoyproxy.envoy.extensions.filters.http.ext_authz.v3.ExtAuthz}.
35+
*/
36+
final class ExtAuthzConfigParser {
37+
38+
private ExtAuthzConfigParser() {}
39+
40+
/**
41+
* Parses the {@link io.envoyproxy.envoy.extensions.filters.http.ext_authz.v3.ExtAuthz} proto to
42+
* create an {@link ExtAuthzConfig} instance.
43+
*
44+
* @param extAuthzProto The ext_authz proto to parse.
45+
* @return An {@link ExtAuthzConfig} instance.
46+
* @throws ExtAuthzParseException if the proto is invalid or contains unsupported features.
47+
*/
48+
public static ExtAuthzConfig parse(
49+
ExtAuthz extAuthzProto, BootstrapInfo bootstrapInfo, ServerInfo serverInfo)
50+
throws ExtAuthzParseException {
51+
if (!extAuthzProto.hasGrpcService()) {
52+
throw new ExtAuthzParseException(
53+
"unsupported ExtAuthz service type: only grpc_service is supported");
54+
}
55+
GrpcServiceConfig grpcServiceConfig;
56+
try {
57+
grpcServiceConfig =
58+
GrpcServiceConfigParser.parse(extAuthzProto.getGrpcService(), bootstrapInfo, serverInfo);
59+
} catch (GrpcServiceParseException e) {
60+
throw new ExtAuthzParseException("Failed to parse GrpcService config: " + e.getMessage(), e);
61+
}
62+
ExtAuthzConfig.Builder builder = ExtAuthzConfig.builder().grpcService(grpcServiceConfig)
63+
.failureModeAllow(extAuthzProto.getFailureModeAllow())
64+
.failureModeAllowHeaderAdd(extAuthzProto.getFailureModeAllowHeaderAdd())
65+
.includePeerCertificate(extAuthzProto.getIncludePeerCertificate())
66+
.denyAtDisable(extAuthzProto.getDenyAtDisable().getDefaultValue().getValue());
67+
68+
if (extAuthzProto.hasFilterEnabled()) {
69+
try {
70+
builder.filterEnabled(
71+
MatcherParser.parseFractionMatcher(extAuthzProto.getFilterEnabled().getDefaultValue()));
72+
} catch (IllegalArgumentException e) {
73+
throw new ExtAuthzParseException(e.getMessage());
74+
}
75+
}
76+
77+
if (extAuthzProto.hasStatusOnError()) {
78+
builder.statusOnError(
79+
GrpcUtil.httpStatusToGrpcStatus(extAuthzProto.getStatusOnError().getCodeValue()));
80+
}
81+
82+
if (extAuthzProto.hasAllowedHeaders()) {
83+
builder.allowedHeaders(extAuthzProto.getAllowedHeaders().getPatternsList().stream()
84+
.map(MatcherParser::parseStringMatcher).collect(ImmutableList.toImmutableList()));
85+
}
86+
87+
if (extAuthzProto.hasDisallowedHeaders()) {
88+
builder.disallowedHeaders(extAuthzProto.getDisallowedHeaders().getPatternsList().stream()
89+
.map(MatcherParser::parseStringMatcher).collect(ImmutableList.toImmutableList()));
90+
}
91+
92+
if (extAuthzProto.hasDecoderHeaderMutationRules()) {
93+
try {
94+
builder.decoderHeaderMutationRules(
95+
HeaderMutationRulesParser.parse(extAuthzProto.getDecoderHeaderMutationRules()));
96+
} catch (HeaderMutationRulesParseException e) {
97+
throw new ExtAuthzParseException(e.getMessage(), e);
98+
}
99+
}
100+
101+
return builder.build();
102+
}
103+
}

xds/src/main/java/io/grpc/xds/FilterRegistry.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@
2525
* A registry for all supported {@link Filter}s. Filters can be queried from the registry
2626
* by any of the {@link Filter.Provider#typeUrls() type URLs}.
2727
*/
28-
public final class FilterRegistry {
28+
final class FilterRegistry {
2929
private static FilterRegistry instance;
3030

3131
private final Map<String, Filter.Provider> supportedFilters = new HashMap<>();
3232

3333
private FilterRegistry() {}
3434

35-
public static synchronized FilterRegistry getDefaultRegistry() {
35+
static synchronized FilterRegistry getDefaultRegistry() {
3636
if (instance == null) {
3737
instance = newRegistry().register(
3838
new FaultFilter.Provider(),
@@ -45,7 +45,7 @@ public static synchronized FilterRegistry getDefaultRegistry() {
4545
}
4646

4747
@VisibleForTesting
48-
public static synchronized void reset() {
48+
static synchronized void reset() {
4949
instance = null;
5050
}
5151

@@ -65,7 +65,7 @@ FilterRegistry register(Filter.Provider... filters) {
6565
}
6666

6767
@Nullable
68-
public Filter.Provider get(String typeUrl) {
68+
Filter.Provider get(String typeUrl) {
6969
return supportedFilters.get(typeUrl);
7070
}
7171
}

xds/src/main/java/io/grpc/xds/XdsNameResolverProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public XdsNameResolverProvider() {
6363
}
6464

6565
private XdsNameResolverProvider(String scheme,
66-
@Nullable Map<String, ?> bootstrapOverride) {
66+
@Nullable Map<String, ?> bootstrapOverride) {
6767
this.scheme = checkNotNull(scheme, "scheme");
6868
this.bootstrapOverride = bootstrapOverride;
6969
}
@@ -73,7 +73,7 @@ private XdsNameResolverProvider(String scheme,
7373
* and bootstrap.
7474
*/
7575
public static XdsNameResolverProvider createForTest(String scheme,
76-
@Nullable Map<String, ?> bootstrapOverride) {
76+
@Nullable Map<String, ?> bootstrapOverride) {
7777
return new XdsNameResolverProvider(scheme, bootstrapOverride);
7878
}
7979

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Copyright 2025 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.xds.internal.extauthz;
18+
19+
import com.google.auto.value.AutoValue;
20+
import com.google.common.collect.ImmutableList;
21+
import io.grpc.Status;
22+
import io.grpc.xds.internal.Matchers;
23+
import io.grpc.xds.internal.grpcservice.GrpcServiceConfig;
24+
import io.grpc.xds.internal.headermutations.HeaderMutationRulesConfig;
25+
import java.util.Optional;
26+
27+
/**
28+
* Represents the configuration for the external authorization (ext_authz) filter. This class
29+
* encapsulates the settings defined in the
30+
* {@link io.envoyproxy.envoy.extensions.filters.http.ext_authz.v3.ExtAuthz} proto, providing a
31+
* structured, immutable representation for use within gRPC. It includes configurations for the gRPC
32+
* service used for authorization, header mutation rules, and other filter behaviors.
33+
*/
34+
@AutoValue
35+
public abstract class ExtAuthzConfig {
36+
37+
/** Creates a new builder for creating {@link ExtAuthzConfig} instances. */
38+
public static Builder builder() {
39+
return new AutoValue_ExtAuthzConfig.Builder().allowedHeaders(ImmutableList.of())
40+
.disallowedHeaders(ImmutableList.of()).statusOnError(Status.PERMISSION_DENIED)
41+
.filterEnabled(Matchers.FractionMatcher.create(100, 100));
42+
}
43+
44+
/**
45+
* The gRPC service configuration for the external authorization service. This is a required
46+
* field.
47+
*
48+
* @see ExtAuthz#getGrpcService()
49+
*/
50+
public abstract GrpcServiceConfig grpcService();
51+
52+
/**
53+
* Changes the filter's behavior on errors from the authorization service. If {@code true}, the
54+
* filter will accept the request even if the authorization service fails or returns an error.
55+
*
56+
* @see ExtAuthz#getFailureModeAllow()
57+
*/
58+
public abstract boolean failureModeAllow();
59+
60+
/**
61+
* Determines if the {@code x-envoy-auth-failure-mode-allowed} header is added to the request when
62+
* {@link #failureModeAllow()} is true.
63+
*
64+
* @see ExtAuthz#getFailureModeAllowHeaderAdd()
65+
*/
66+
public abstract boolean failureModeAllowHeaderAdd();
67+
68+
/**
69+
* Specifies if the peer certificate is sent to the external authorization service.
70+
*
71+
* @see ExtAuthz#getIncludePeerCertificate()
72+
*/
73+
public abstract boolean includePeerCertificate();
74+
75+
/**
76+
* The gRPC status returned to the client when the authorization server returns an error or is
77+
* unreachable. Defaults to {@code PERMISSION_DENIED}.
78+
*
79+
* @see io.envoyproxy.envoy.extensions.filters.http.ext_authz.v3.ExtAuthz#getStatusOnError()
80+
*/
81+
public abstract Status statusOnError();
82+
83+
/**
84+
* Specifies whether to deny requests when the filter is disabled. Defaults to {@code false}.
85+
*
86+
* @see ExtAuthz#getDenyAtDisable()
87+
*/
88+
public abstract boolean denyAtDisable();
89+
90+
/**
91+
* The fraction of requests that will be checked by the authorization service. Defaults to all
92+
* requests.
93+
*
94+
* @see ExtAuthz#getFilterEnabled()
95+
*/
96+
public abstract Matchers.FractionMatcher filterEnabled();
97+
98+
/**
99+
* Specifies which request headers are sent to the authorization service. If empty, all headers
100+
* are sent.
101+
*
102+
* @see ExtAuthz#getAllowedHeaders()
103+
*/
104+
public abstract ImmutableList<Matchers.StringMatcher> allowedHeaders();
105+
106+
/**
107+
* Specifies which request headers are not sent to the authorization service. This overrides
108+
* {@link #allowedHeaders()}.
109+
*
110+
* @see ExtAuthz#getDisallowedHeaders()
111+
*/
112+
public abstract ImmutableList<Matchers.StringMatcher> disallowedHeaders();
113+
114+
/**
115+
* Rules for what modifications an ext_authz server may make to request headers.
116+
*
117+
* @see ExtAuthz#getDecoderHeaderMutationRules()
118+
*/
119+
public abstract Optional<HeaderMutationRulesConfig> decoderHeaderMutationRules();
120+
121+
@AutoValue.Builder
122+
public abstract static class Builder {
123+
public abstract Builder grpcService(GrpcServiceConfig grpcService);
124+
125+
public abstract Builder failureModeAllow(boolean failureModeAllow);
126+
127+
public abstract Builder failureModeAllowHeaderAdd(boolean failureModeAllowHeaderAdd);
128+
129+
public abstract Builder includePeerCertificate(boolean includePeerCertificate);
130+
131+
public abstract Builder statusOnError(Status statusOnError);
132+
133+
public abstract Builder denyAtDisable(boolean denyAtDisable);
134+
135+
public abstract Builder filterEnabled(Matchers.FractionMatcher filterEnabled);
136+
137+
public abstract Builder allowedHeaders(Iterable<Matchers.StringMatcher> allowedHeaders);
138+
139+
public abstract Builder disallowedHeaders(Iterable<Matchers.StringMatcher> disallowedHeaders);
140+
141+
public abstract Builder decoderHeaderMutationRules(HeaderMutationRulesConfig rules);
142+
143+
public abstract ExtAuthzConfig build();
144+
}
145+
}

xds/src/main/java/io/grpc/xds/internal/grpcservice/ChannelCredsConfig.java renamed to xds/src/main/java/io/grpc/xds/internal/extauthz/ExtAuthzParseException.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,21 @@
1414
* limitations under the License.
1515
*/
1616

17-
package io.grpc.xds.internal.grpcservice;
17+
package io.grpc.xds.internal.extauthz;
1818

1919
/**
20-
* Configuration for channel credentials.
20+
* A custom exception for signaling errors during the parsing of external authorization
21+
* (ext_authz) configurations.
2122
*/
22-
public interface ChannelCredsConfig {
23-
/**
24-
* Returns the type of the credentials.
25-
*/
26-
String type();
23+
public class ExtAuthzParseException extends Exception {
24+
25+
private static final long serialVersionUID = 0L;
26+
27+
public ExtAuthzParseException(String message) {
28+
super(message);
29+
}
30+
31+
public ExtAuthzParseException(String message, Throwable cause) {
32+
super(message, cause);
33+
}
2734
}

0 commit comments

Comments
 (0)