From 29baa5f12624991f7d24bac626749c783357aae5 Mon Sep 17 00:00:00 2001 From: Andrey Litvitski Date: Sat, 16 May 2026 20:30:06 +0300 Subject: [PATCH] Move AUTHORIZATION_KEY out of GrpcSecurity to avoid ClassNotFoundException MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The problem is that we don’t include the `spring-security` module in the client's auto-configuration, which causes a `ClassNotFoundException` when we try to use any of its constants. In our case, this is `GrpcSecurity#AUTHORIZATION_KEY`, and since client modules use it, we need to move it out. In our case, I moved it to a separate internal class called `GrpcMetadataKeys`. Closes: gh-409 Signed-off-by: Andrey Litvitski --- .../BasicAuthenticationInterceptor.java | 4 +- .../BearerTokenAuthenticationInterceptor.java | 4 +- .../grpc/internal/GrpcHeaders.java | 46 +++++++++++++++++++ .../BearerTokenAuthenticationExtractor.java | 3 +- .../grpc/server/security/GrpcSecurity.java | 12 ----- .../HttpBasicAuthenticationExtractor.java | 3 +- 6 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 spring-grpc-core/src/main/java/org/springframework/grpc/internal/GrpcHeaders.java diff --git a/spring-grpc-core/src/main/java/org/springframework/grpc/client/interceptor/security/BasicAuthenticationInterceptor.java b/spring-grpc-core/src/main/java/org/springframework/grpc/client/interceptor/security/BasicAuthenticationInterceptor.java index ffd226d4..ddcc9f89 100644 --- a/spring-grpc-core/src/main/java/org/springframework/grpc/client/interceptor/security/BasicAuthenticationInterceptor.java +++ b/spring-grpc-core/src/main/java/org/springframework/grpc/client/interceptor/security/BasicAuthenticationInterceptor.java @@ -18,7 +18,7 @@ import java.util.Base64; -import org.springframework.grpc.server.security.GrpcSecurity; +import org.springframework.grpc.internal.GrpcHeaders; import io.grpc.CallOptions; import io.grpc.Channel; @@ -50,7 +50,7 @@ public ClientCall interceptCall(MethodDescriptor(next.newCall(method, callOptions)) { public void start(ClientCall.Listener responseListener, io.grpc.Metadata headers) { - headers.put(GrpcSecurity.AUTHORIZATION_KEY, + headers.put(GrpcHeaders.AUTHORIZATION_KEY, "Basic " + Base64.getEncoder() .encodeToString((BasicAuthenticationInterceptor.this.username + ":" + BasicAuthenticationInterceptor.this.password) diff --git a/spring-grpc-core/src/main/java/org/springframework/grpc/client/interceptor/security/BearerTokenAuthenticationInterceptor.java b/spring-grpc-core/src/main/java/org/springframework/grpc/client/interceptor/security/BearerTokenAuthenticationInterceptor.java index 27e98a1d..83145c03 100644 --- a/spring-grpc-core/src/main/java/org/springframework/grpc/client/interceptor/security/BearerTokenAuthenticationInterceptor.java +++ b/spring-grpc-core/src/main/java/org/springframework/grpc/client/interceptor/security/BearerTokenAuthenticationInterceptor.java @@ -18,7 +18,7 @@ import java.util.function.Supplier; -import org.springframework.grpc.server.security.GrpcSecurity; +import org.springframework.grpc.internal.GrpcHeaders; import io.grpc.CallOptions; import io.grpc.Channel; @@ -49,7 +49,7 @@ public ClientCall interceptCall(MethodDescriptor(next.newCall(method, callOptions)) { public void start(ClientCall.Listener responseListener, io.grpc.Metadata headers) { - headers.put(GrpcSecurity.AUTHORIZATION_KEY, + headers.put(GrpcHeaders.AUTHORIZATION_KEY, "Bearer " + BearerTokenAuthenticationInterceptor.this.token.get()); super.start(responseListener, headers); } diff --git a/spring-grpc-core/src/main/java/org/springframework/grpc/internal/GrpcHeaders.java b/spring-grpc-core/src/main/java/org/springframework/grpc/internal/GrpcHeaders.java new file mode 100644 index 00000000..d15e1548 --- /dev/null +++ b/spring-grpc-core/src/main/java/org/springframework/grpc/internal/GrpcHeaders.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023-present the original author or 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 + * + * https://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 org.springframework.grpc.internal; + +import io.grpc.Metadata; + +/** + * Common gRPC headers. + *

+ * NOTE: Even though this class visibility is `public` it is intended for internal use + * only and not recommended for direct use. + * + * @author Andrey Litvitski + */ +public final class GrpcHeaders { + + private GrpcHeaders() { + } + + /** + * A constant key used for storing and retrieving the "Authorization" header from gRPC + * metadata. This key is used to handle authorization information in gRPC requests. + * + *

+ * The key is defined with the name "Authorization" and uses the ASCII string + * marshaller for encoding and decoding the header value. + *

+ */ + public static final Metadata.Key AUTHORIZATION_KEY = Metadata.Key.of("Authorization", + Metadata.ASCII_STRING_MARSHALLER); + +} diff --git a/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/BearerTokenAuthenticationExtractor.java b/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/BearerTokenAuthenticationExtractor.java index 6407adab..b2836ae4 100644 --- a/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/BearerTokenAuthenticationExtractor.java +++ b/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/BearerTokenAuthenticationExtractor.java @@ -20,6 +20,7 @@ import org.jspecify.annotations.Nullable; +import org.springframework.grpc.internal.GrpcHeaders; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; @@ -41,7 +42,7 @@ public class BearerTokenAuthenticationExtractor implements GrpcAuthenticationExt @Override public @Nullable Authentication extract(Metadata headers, Attributes attributes, MethodDescriptor method) { - String auth = headers.get(GrpcSecurity.AUTHORIZATION_KEY); + String auth = headers.get(GrpcHeaders.AUTHORIZATION_KEY); if (auth == null) { return null; } diff --git a/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/GrpcSecurity.java b/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/GrpcSecurity.java index eb851c44..be943c07 100644 --- a/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/GrpcSecurity.java +++ b/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/GrpcSecurity.java @@ -61,18 +61,6 @@ public final class GrpcSecurity extends AbstractConfiguredSecurityBuilder { - /** - * A constant key used for storing and retrieving the "Authorization" header from gRPC - * metadata. This key is used to handle authorization information in gRPC requests. - * - *

- * The key is defined with the name "Authorization" and uses the ASCII string - * marshaller for encoding and decoding the header value. - *

- */ - public static final Metadata.Key AUTHORIZATION_KEY = Metadata.Key.of("Authorization", - Metadata.ASCII_STRING_MARSHALLER); - /** * The order value for the context filter in the gRPC security framework. This * constant defines the position of the context filter in the filter chain. A lower diff --git a/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/HttpBasicAuthenticationExtractor.java b/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/HttpBasicAuthenticationExtractor.java index b2deb7b4..3be1995c 100644 --- a/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/HttpBasicAuthenticationExtractor.java +++ b/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/HttpBasicAuthenticationExtractor.java @@ -22,6 +22,7 @@ import org.jspecify.annotations.Nullable; +import org.springframework.grpc.internal.GrpcHeaders; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -42,7 +43,7 @@ public class HttpBasicAuthenticationExtractor implements GrpcAuthenticationExtra @Override public @Nullable Authentication extract(Metadata headers, Attributes attributes, MethodDescriptor method) { - String auth = headers.get(GrpcSecurity.AUTHORIZATION_KEY); + String auth = headers.get(GrpcHeaders.AUTHORIZATION_KEY); if (auth == null) { return null; }