Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id C3802200CFE for ; Fri, 8 Sep 2017 10:44:40 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id C21E21609A7; Fri, 8 Sep 2017 08:44:40 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 49A241609C1 for ; Fri, 8 Sep 2017 10:44:38 +0200 (CEST) Received: (qmail 27469 invoked by uid 500); 8 Sep 2017 08:44:37 -0000 Mailing-List: contact commits-help@camel.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@camel.apache.org Delivered-To: mailing list commits@camel.apache.org Received: (qmail 27451 invoked by uid 99); 8 Sep 2017 08:44:37 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 08 Sep 2017 08:44:37 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 446AFE0395; Fri, 8 Sep 2017 08:44:35 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: acosentino@apache.org To: commits@camel.apache.org Date: Fri, 08 Sep 2017 08:44:37 -0000 Message-Id: In-Reply-To: <1fb3f4a4caaa44a5a77b5092da37bcac@git.apache.org> References: <1fb3f4a4caaa44a5a77b5092da37bcac@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [3/3] camel git commit: CAMEL-11695: Add security and advanced properties to the camel-grpc component archived-at: Fri, 08 Sep 2017 08:44:41 -0000 CAMEL-11695: Add security and advanced properties to the camel-grpc component Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/687ec7b5 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/687ec7b5 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/687ec7b5 Branch: refs/heads/master Commit: 687ec7b5120726e3fb8ab083b8e4f5451c253044 Parents: 6d290b4 Author: Dmitry Volodin Authored: Mon Aug 28 19:54:50 2017 +0300 Committer: Andrea Cosentino Committed: Fri Sep 8 10:43:52 2017 +0200 ---------------------------------------------------------------------- components/camel-grpc/pom.xml | 32 ++- .../src/main/docs/grpc-component.adoc | 67 +++++- .../camel/component/grpc/GrpcAuthType.java | 38 ++++ .../camel/component/grpc/GrpcConfiguration.java | 210 ++++++++++++++++-- .../camel/component/grpc/GrpcConstants.java | 13 ++ .../camel/component/grpc/GrpcConsumer.java | 41 +++- .../camel/component/grpc/GrpcProducer.java | 64 +++++- .../apache/camel/component/grpc/GrpcUtils.java | 44 +++- .../client/auth/jwt/JwtCallCredentials.java | 66 ++++++ .../grpc/client/auth/jwt/JwtHelper.java | 43 ++++ .../server/auth/jwt/JwtServerInterceptor.java | 96 ++++++++ .../grpc/GrpcConsumerPropagationTest.java | 4 +- .../grpc/GrpcConsumerSecurityTest.java | 218 +++++++++++++++++++ .../grpc/GrpcProducerSecurityTest.java | 171 +++++++++++++++ .../camel-grpc/src/test/resources/certs/README | 36 +++ .../src/test/resources/certs/ca-openssl.cnf | 18 ++ .../camel-grpc/src/test/resources/certs/ca.key | 15 ++ .../camel-grpc/src/test/resources/certs/ca.pem | 15 ++ .../src/test/resources/certs/client.key | 16 ++ .../src/test/resources/certs/client.pem | 14 ++ .../src/test/resources/certs/server.key | 16 ++ .../src/test/resources/certs/server.pem | 14 ++ parent/pom.xml | 7 +- .../camel-grpc-starter/pom.xml | 8 + 24 files changed, 1223 insertions(+), 43 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/pom.xml ---------------------------------------------------------------------- diff --git a/components/camel-grpc/pom.xml b/components/camel-grpc/pom.xml index 727fbfb..40850f5 100644 --- a/components/camel-grpc/pom.xml +++ b/components/camel-grpc/pom.xml @@ -43,6 +43,12 @@ org.apache.camel camel-core + + + io.grpc + grpc-auth + ${grpc-version} + io.grpc grpc-netty @@ -58,13 +64,37 @@ grpc-stub ${grpc-version} - + org.javassist javassist ${javassist-version} + + io.netty + netty-tcnative-boringssl-static + ${grpc-netty-tcnative-boringssl-static-version} + + + + com.google.auth + google-auth-library-oauth2-http + ${grpc-google-auth-library-version} + + + + com.google.auth + google-auth-library-credentials + ${grpc-google-auth-library-version} + + + + com.auth0 + java-jwt + ${grpc-java-jwt-version} + + org.apache.camel http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/docs/grpc-component.adoc ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/docs/grpc-component.adoc b/components/camel-grpc/src/main/docs/grpc-component.adoc index 0bea6aa..5c9e90d 100644 --- a/components/camel-grpc/src/main/docs/grpc-component.adoc +++ b/components/camel-grpc/src/main/docs/grpc-component.adoc @@ -44,30 +44,70 @@ with the following path and query parameters: [width="100%",cols="2,5,^1,2",options="header"] |======================================================================= | Name | Description | Default | Type -| **host** | *Required* The gRPC server host name. This is localhost or 0.0.0.0 when being a consumer or remote server hostname when using producer. | | String -| **port** | *Required* The gRPC server port | | int +| **host** | *Required* The gRPC server host name. This is localhost or 0.0.0.0 when being a consumer or remote server host name when using producer. | | String +| **port** | *Required* The gRPC local or remote server port | | int | **service** | *Required* Fully qualified service name from the protocol buffer descriptor file (package dot service definition name) | | String |======================================================================= -#### Query Parameters (11 parameters): +#### Query Parameters (24 parameters): [width="100%",cols="2,5,^1,2",options="header"] |======================================================================= | Name | Description | Default | Type -| **forwardOnCompleted** (common) | Determines if onCompleted events should be pushed to the Camel route. | false | boolean -| **forwardOnError** (common) | Determines if onError events should be pushed to the Camel route. Exceptions will be set as message body. | false | boolean +| **authenticationType** (common) | Authentication method type in advance to the SSL/TLS negotiation | NONE | GrpcAuthType +| **flowControlWindow** (common) | The HTTP/2 flow control window size (MiB) | 1048576 | int +| **jwtIssuer** (common) | JSON Web Token issuer | | String +| **jwtSecret** (common) | JSON Web Token secret | | String +| **jwtSubject** (common) | JSON Web Token subject | | String +| **keyCertChainResource** (common) | The X.509 certificate chain file resource in PEM format link | | String +| **keyPassword** (common) | The PKCS8 private key file password | | String +| **keyResource** (common) | The PKCS8 private key file resource in PEM format link | | String +| **maxMessageSize** (common) | The maximum message size allowed to be received/sent (MiB) | 4194304 | int +| **negotiationType** (common) | Identifies the security negotiation type used for HTTP/2 communication | PLAINTEXT | NegotiationType +| **serviceAccountResource** (common) | Service Account key file in JSON format resource link supported by the Google Cloud SDK | | String +| **trustCertCollectionResource** (common) | The trusted certificates collection file resource in PEM format for verifying the remote endpoint's certificate | | String | **bridgeErrorHandler** (consumer) | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN or ERROR level and ignored. | false | boolean | **consumerStrategy** (consumer) | This option specifies the top-level strategy for processing service requests and responses in streaming mode. If an aggregation strategy is selected all requests will be accumulated in the list then transferred to the flow and the accumulated responses will be sent to the sender. If a propagation strategy is selected request is sent to the stream and the response will be immediately sent back to the sender. | PROPAGATION | GrpcConsumerStrategy +| **forwardOnCompleted** (consumer) | Determines if onCompleted events should be pushed to the Camel route. | false | boolean +| **forwardOnError** (consumer) | Determines if onError events should be pushed to the Camel route. Exceptions will be set as message body. | false | boolean +| **maxConcurrentCallsPer Connection** (consumer) | The maximum number of concurrent calls permitted for each incoming server connection | 2147483647 | int | **exceptionHandler** (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this options is not in use. By default the consumer will deal with exceptions that will be logged at WARN or ERROR level and ignored. | | ExceptionHandler | **exchangePattern** (consumer) | Sets the exchange pattern when the consumer creates an exchange. | | ExchangePattern | **method** (producer) | gRPC method name | | String | **producerStrategy** (producer) | The mode used to communicate with a remote gRPC server. In SIMPLE mode a single exchange is translated into a remote procedure call. In STREAMING mode all exchanges will be sent within the same request (input and output of the recipient gRPC service must be of type 'stream'). | SIMPLE | GrpcProducerStrategy | **streamRepliesTo** (producer) | When using STREAMING client mode it indicates the endpoint where responses should be forwarded. | | String -| **usePlainText** (producer) | The plain text connection to the server flag | true | Boolean +| **userAgent** (producer) | The user agent header passed to the server | | String | **synchronous** (advanced) | Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported). | false | boolean |======================================================================= // endpoint options: END +### Transport security and authentication support (available from *Camel 2.20*) + +The following https://grpc.io/docs/guides/auth.html[authentication] mechanisms are built-in to gRPC and available in this component: + +* *SSL/TLS:* gRPC has SSL/TLS integration and promotes the use of SSL/TLS to authenticate the server, and to encrypt all the data exchanged between the client and the server. Optional mechanisms are available for clients to provide certificates for mutual authentication. +* *Token-based authentication with Google:* gRPC provides a generic mechanism to attach metadata based credentials to requests and responses. Additional support for acquiring access tokens while accessing Google APIs through gRPC is provided. In general this mechanism must be used as well as SSL/TLS on the channel. + +To enable these features the following component properties combinations must be configured: + +[width="100%",cols="10%,20%,25%,15%,30%",options="header",] +|======================================================================= +|Num.|Option |Parameter|Value|Required/Optional +|1|*SSL/TLS*|negotiationType|TLS|Required +|||keyCertChainResource||Required +|||keyResource||Required +|||keyPassword||Optional +|||trustCertCollectionResource||Optional +|2|*Token-based authentication with Google API*|authenticationType|GOOGLE|Required +|||negotiationType|TLS|Required +|||serviceAccountResource||Required +|3|*Custom JSON Web Token implementation authentication*|authenticationType|JWT|Required +|||negotiationType|NONE or TLS|Optional. The TLS/SSL not checking for this type, but strongly recommended. +|||jwtSecret||Required +|||jwtIssuer||Optional +|||jwtSubject||Optional +|======================================================================= + ### gRPC producer resource type mapping The table below shows the types of objects in the message body, depending on the types (simple or stream) of incoming and outgoing parameters, as well as the invocation style (synchronous or asynchronous). Please note, that invocation of the procedures with incoming stream parameter in asynchronous style are not allowed. @@ -145,6 +185,21 @@ from("direct:grpc-response-stream") .log("Response received: ${body}"); ------------------------------------------------------------------------------- +gRPC service consumer TLS/SLL security negotiation enable + +[source,java] +------------------------------------------------------------------------------- +from("grpc://localhost:1101/org.apache.camel.component.grpc.PingPong?consumerStrategy=PROPAGATION&negotiationType=TLS&keyCertChainResource=file:src/test/resources/certs/server.pem&keyResource=file:src/test/resources/certs/server.key&trustCertCollectionResource=file:src/test/resources/certs/ca.pem") +.to("direct:tls-enable") +------------------------------------------------------------------------------- + +gRPC service producer with custom JSON Web Token implementation authentication + +[source,java] +------------------------------------------------------------------------------- +from("direct:grpc-jwt") +.to("grpc://localhost:1101/org.apache.camel.component.grpc.PingPong?method=pingSyncSync&synchronous=true&authenticationType=JWT&jwtSecret=supersecuredsecret"); +------------------------------------------------------------------------------- ### Configuration http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcAuthType.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcAuthType.java b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcAuthType.java new file mode 100644 index 0000000..f76e5d8 --- /dev/null +++ b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcAuthType.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.camel.component.grpc; + +/** + * Authentication method types list in advance to the SSL/TLS negotiation + */ +public enum GrpcAuthType { + /** + * No advanced authentication method + */ + NONE, + + /** + * Google OAuth2 token auth. Valid for producer interacting with Google + * public services with gRPC support only + */ + GOOGLE, + + /** + * Custom JSON Web Token with HmacSHA256 algorithm implementation + */ + JWT +} http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConfiguration.java b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConfiguration.java index 74e011c..6b2ce6c 100644 --- a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConfiguration.java +++ b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConfiguration.java @@ -19,6 +19,9 @@ package org.apache.camel.component.grpc; import java.net.URI; import java.util.Map; +import io.grpc.internal.GrpcUtil; +import io.grpc.netty.NegotiationType; +import io.grpc.netty.NettyChannelBuilder; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriParam; import org.apache.camel.spi.UriParams; @@ -42,25 +45,63 @@ public class GrpcConfiguration { @UriParam(label = "producer") private String method; - @UriParam(label = "producer", defaultValue = "true") - private Boolean usePlainText = true; + @UriParam(defaultValue = "PLAINTEXT") + private NegotiationType negotiationType = NegotiationType.PLAINTEXT; + + @UriParam(defaultValue = "NONE") + private GrpcAuthType authenticationType = GrpcAuthType.NONE; + + @UriParam + private String serviceAccountResource; + + @UriParam(secret = true) + private String jwtSecret; + + @UriParam + private String jwtIssuer; + + @UriParam + private String jwtSubject; + + @UriParam + private String keyCertChainResource; + + @UriParam + private String keyResource; + + @UriParam(secret = true) + private String keyPassword; + + @UriParam + private String trustCertCollectionResource; @UriParam(label = "producer", defaultValue = "SIMPLE") private GrpcProducerStrategy producerStrategy = GrpcProducerStrategy.SIMPLE; @UriParam(label = "producer") private String streamRepliesTo; - + + @UriParam(label = "producer") + private String userAgent; @UriParam(label = "consumer", defaultValue = "PROPAGATION") private GrpcConsumerStrategy consumerStrategy = GrpcConsumerStrategy.PROPAGATION; - @UriParam(defaultValue = "false") + @UriParam(label = "consumer", defaultValue = "false") private boolean forwardOnCompleted; - @UriParam(defaultValue = "false") + @UriParam(label = "consumer", defaultValue = "false") private boolean forwardOnError; - + + @UriParam(defaultValue = "" + NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW) + private int flowControlWindow = NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW; + + @UriParam(defaultValue = "" + GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE) + private int maxMessageSize = GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE; + + @UriParam(label = "consumer", defaultValue = "" + Integer.MAX_VALUE) + private int maxConcurrentCallsPerConnection = Integer.MAX_VALUE; + /** * Fully qualified service name from the protocol buffer descriptor file * (package dot service definition name) @@ -86,7 +127,7 @@ public class GrpcConfiguration { /** * The gRPC server host name. This is localhost or 0.0.0.0 when being a - * consumer or remote server hostname when using producer. + * consumer or remote server host name when using producer. */ public String getHost() { return host; @@ -97,7 +138,7 @@ public class GrpcConfiguration { } /** - * The gRPC server port + * The gRPC local or remote server port */ public int getPort() { return port; @@ -106,16 +147,115 @@ public class GrpcConfiguration { public void setPort(int port) { this.port = port; } + + /** + * Identifies the security negotiation type used for HTTP/2 communication + */ + public void setNegotiationType(NegotiationType negotiationType) { + this.negotiationType = negotiationType; + } + + public NegotiationType getNegotiationType() { + return negotiationType; + } + + /** + * Authentication method type in advance to the SSL/TLS negotiation + */ + public GrpcAuthType getAuthenticationType() { + return authenticationType; + } + + public void setAuthenticationType(GrpcAuthType authenticationType) { + this.authenticationType = authenticationType; + } + + /** + * Service Account key file in JSON format resource link supported by the Google Cloud SDK + */ + public String getServiceAccountResource() { + return serviceAccountResource; + } + + public void setServiceAccountResource(String serviceAccountResource) { + this.serviceAccountResource = serviceAccountResource; + } + + /** + * JSON Web Token secret + */ + public String getJwtSecret() { + return jwtSecret; + } + + public void setJwtSecret(String jwtSecret) { + this.jwtSecret = jwtSecret; + } + + /** + * JSON Web Token issuer + */ + public String getJwtIssuer() { + return jwtIssuer; + } + + public void setJwtIssuer(String jwtIssuer) { + this.jwtIssuer = jwtIssuer; + } /** - * The plain text connection to the server flag + * JSON Web Token subject */ - public Boolean getUsePlainText() { - return usePlainText; + public String getJwtSubject() { + return jwtSubject; } - public void setUsePlainText(Boolean usePlainText) { - this.usePlainText = usePlainText; + public void setJwtSubject(String jwtSubject) { + this.jwtSubject = jwtSubject; + } + + /** + * The X.509 certificate chain file resource in PEM format link + */ + public void setKeyCertChainResource(String keyCertChainResource) { + this.keyCertChainResource = keyCertChainResource; + } + + public String getKeyCertChainResource() { + return keyCertChainResource; + } + + /** + * The PKCS#8 private key file resource in PEM format link + */ + public void setKeyResource(String keyResource) { + this.keyResource = keyResource; + } + + public String getKeyResource() { + return keyResource; + } + + /** + * The PKCS#8 private key file password + */ + public String getKeyPassword() { + return keyPassword; + } + + public void setKeyPassword(String keyPassword) { + this.keyPassword = keyPassword; + } + + /** + * The trusted certificates collection file resource in PEM format for verifying the remote endpoint's certificate + */ + public void setTrustCertCollectionResource(String trustCertCollectionResource) { + this.trustCertCollectionResource = trustCertCollectionResource; + } + + public String getTrustCertCollectionResource() { + return trustCertCollectionResource; } /** @@ -181,6 +321,50 @@ public class GrpcConfiguration { this.streamRepliesTo = streamRepliesTo; } + /** + * The user agent header passed to the server + */ + public String getUserAgent() { + return userAgent; + } + + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } + + /** + * The HTTP/2 flow control window size (MiB) + */ + public int getFlowControlWindow() { + return flowControlWindow; + } + + public void setFlowControlWindow(int flowControlWindow) { + this.flowControlWindow = flowControlWindow; + } + + /** + * The maximum message size allowed to be received/sent (MiB) + */ + public void setMaxMessageSize(int maxMessageSize) { + this.maxMessageSize = maxMessageSize; + } + + public int getMaxMessageSize() { + return maxMessageSize; + } + + /** + * The maximum number of concurrent calls permitted for each incoming server connection + */ + public void setMaxConcurrentCallsPerConnection(int maxConcurrentCallsPerConnection) { + this.maxConcurrentCallsPerConnection = maxConcurrentCallsPerConnection; + } + + public int getMaxConcurrentCallsPerConnection() { + return maxConcurrentCallsPerConnection; + } + public void parseURI(URI uri, Map parameters, GrpcComponent component) { setHost(uri.getHost()); http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConstants.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConstants.java b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConstants.java index f61f3a8..ba8f790 100644 --- a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConstants.java +++ b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConstants.java @@ -16,6 +16,9 @@ */ package org.apache.camel.component.grpc; +import io.grpc.Context; +import io.grpc.Metadata; + /** * gRPC component constants */ @@ -26,6 +29,16 @@ public interface GrpcConstants { String GRPC_SERVICE_SYNC_STUB_METHOD = "newBlockingStub"; String GRPC_SERVICE_ASYNC_STUB_METHOD = "newStub"; String GRPC_SERVICE_FUTURE_STUB_METHOD = "newFutureStub"; + String GRPC_SERVICE_STUB_CALL_CREDS_METHOD = "withCallCredentials"; + + /* + * JSON Web Tokens specific constants + */ + String GRPC_JWT_TOKEN_KEY = "jwt"; + String GRPC_USER_ID_KEY = "userId"; + Metadata.Key GRPC_JWT_METADATA_KEY = Metadata.Key.of(GRPC_JWT_TOKEN_KEY, Metadata.ASCII_STRING_MARSHALLER); + Context.Key GRPC_JWT_CTX_KEY = Context.key(GRPC_JWT_TOKEN_KEY); + Context.Key GRPC_JWT_USER_ID_CTX_KEY = Context.key(GRPC_USER_ID_KEY); /* * This headers will be set after gRPC consumer method is invoked http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConsumer.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConsumer.java b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConsumer.java index f92525b..750ec21 100644 --- a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConsumer.java +++ b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcConsumer.java @@ -23,7 +23,12 @@ import io.grpc.BindableService; import io.grpc.Server; import io.grpc.ServerInterceptor; import io.grpc.ServerInterceptors; +import io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.NegotiationType; import io.grpc.netty.NettyServerBuilder; +import io.netty.handler.ssl.ClientAuth; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SslProvider; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; import org.apache.camel.AsyncCallback; @@ -31,8 +36,11 @@ import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.component.grpc.server.GrpcHeaderInterceptor; import org.apache.camel.component.grpc.server.GrpcMethodHandler; +import org.apache.camel.component.grpc.server.auth.jwt.JwtServerInterceptor; import org.apache.camel.impl.DefaultConsumer; +import org.apache.camel.spi.ClassResolver; import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.ResourceHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,7 +86,7 @@ public class GrpcConsumer extends DefaultConsumer { super.doStop(); } - protected void initializeServer() { + protected void initializeServer() throws Exception { NettyServerBuilder serverBuilder = null; BindableService bindableService = null; ProxyFactory serviceProxy = new ProxyFactory(); @@ -99,7 +107,36 @@ public class GrpcConsumer extends DefaultConsumer { throw new IllegalArgumentException("No server start properties (host, port) specified"); } - server = serverBuilder.addService(ServerInterceptors.intercept(bindableService, headerInterceptor)).build(); + if (configuration.getNegotiationType() == NegotiationType.TLS) { + ObjectHelper.notNull(configuration.getKeyCertChainResource(), "keyCertChainResource"); + ObjectHelper.notNull(configuration.getKeyResource(), "keyResource"); + + ClassResolver classResolver = endpoint.getCamelContext().getClassResolver(); + + SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(ResourceHelper.resolveResourceAsInputStream(classResolver, configuration.getKeyCertChainResource()), + ResourceHelper.resolveResourceAsInputStream(classResolver, configuration.getKeyResource()), + configuration.getKeyPassword()) + .clientAuth(ClientAuth.REQUIRE) + .sslProvider(SslProvider.OPENSSL); + + if (ObjectHelper.isNotEmpty(configuration.getTrustCertCollectionResource())) { + sslContextBuilder = sslContextBuilder.trustManager(ResourceHelper.resolveResourceAsInputStream(classResolver, configuration.getTrustCertCollectionResource())); + } + + serverBuilder = serverBuilder.sslContext(GrpcSslContexts.configure(sslContextBuilder).build()); + } + + if (configuration.getAuthenticationType() == GrpcAuthType.JWT) { + ObjectHelper.notNull(configuration.getJwtSecret(), "jwtSecret"); + + serverBuilder = serverBuilder.intercept(new JwtServerInterceptor(configuration.getJwtSecret(), configuration.getJwtIssuer(), configuration.getJwtSubject())); + } + + server = serverBuilder.addService(ServerInterceptors.intercept(bindableService, headerInterceptor)) + .maxMessageSize(configuration.getMaxMessageSize()) + .flowControlWindow(configuration.getFlowControlWindow()) + .maxConcurrentCallsPerConnection(configuration.getMaxConcurrentCallsPerConnection()) + .build(); } public boolean process(Exchange exchange, AsyncCallback callback) { http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcProducer.java b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcProducer.java index 8cbfdfc..aa7fa37 100644 --- a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcProducer.java +++ b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcProducer.java @@ -16,10 +16,17 @@ */ package org.apache.camel.component.grpc; +import com.google.auth.Credentials; +import com.google.auth.oauth2.GoogleCredentials; +import io.grpc.CallCredentials; import io.grpc.ManagedChannel; +import io.grpc.auth.MoreCallCredentials; +import io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.NegotiationType; import io.grpc.netty.NettyChannelBuilder; import io.grpc.stub.StreamObserver; - +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SslProvider; import org.apache.camel.AsyncCallback; import org.apache.camel.AsyncProcessor; import org.apache.camel.Exchange; @@ -27,8 +34,12 @@ import org.apache.camel.component.grpc.client.GrpcExchangeForwarder; import org.apache.camel.component.grpc.client.GrpcExchangeForwarderFactory; import org.apache.camel.component.grpc.client.GrpcResponseAggregationStreamObserver; import org.apache.camel.component.grpc.client.GrpcResponseRouterStreamObserver; +import org.apache.camel.component.grpc.client.auth.jwt.JwtCallCredentials; +import org.apache.camel.component.grpc.client.auth.jwt.JwtHelper; import org.apache.camel.impl.DefaultProducer; +import org.apache.camel.spi.ClassResolver; import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.ResourceHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,6 +68,10 @@ public class GrpcProducer extends DefaultProducer implements AsyncProcessor { throw new IllegalStateException("The streamReplyTo property is mandatory when using the STREAMING mode"); } } + + if (configuration.getAuthenticationType() == GrpcAuthType.GOOGLE && configuration.getNegotiationType() != NegotiationType.TLS) { + throw new IllegalStateException("Google token-based authentication requires SSL/TLS negotiation mode"); + } } @Override @@ -78,13 +93,28 @@ public class GrpcProducer extends DefaultProducer implements AsyncProcessor { protected void doStart() throws Exception { super.doStart(); if (channel == null) { + CallCredentials callCreds = null; initializeChannel(); + + if (configuration.getAuthenticationType() == GrpcAuthType.GOOGLE) { + ObjectHelper.notNull(configuration.getKeyCertChainResource(), "serviceAccountResource"); + ClassResolver classResolver = endpoint.getCamelContext().getClassResolver(); + + Credentials creds = GoogleCredentials.fromStream(ResourceHelper.resolveResourceAsInputStream(classResolver, configuration.getServiceAccountResource())); + callCreds = MoreCallCredentials.from(creds); + } else if (configuration.getAuthenticationType() == GrpcAuthType.JWT) { + ObjectHelper.notNull(configuration.getJwtSecret(), "jwtSecret"); + + String jwtToken = JwtHelper.createJwtToken(configuration.getJwtSecret(), configuration.getJwtIssuer(), configuration.getJwtSubject()); + callCreds = new JwtCallCredentials(jwtToken); + } + if (endpoint.isSynchronous()) { LOG.debug("Getting synchronous method stub from channel"); - grpcStub = GrpcUtils.constructGrpcBlockingStub(endpoint.getServicePackage(), endpoint.getServiceName(), channel, endpoint.getCamelContext()); + grpcStub = GrpcUtils.constructGrpcBlockingStub(endpoint.getServicePackage(), endpoint.getServiceName(), channel, callCreds, endpoint.getCamelContext()); } else { LOG.debug("Getting asynchronous method stub from channel"); - grpcStub = GrpcUtils.constructGrpcAsyncStub(endpoint.getServicePackage(), endpoint.getServiceName(), channel, endpoint.getCamelContext()); + grpcStub = GrpcUtils.constructGrpcAsyncStub(endpoint.getServicePackage(), endpoint.getServiceName(), channel, callCreds, endpoint.getCamelContext()); } forwarder = GrpcExchangeForwarderFactory.createExchangeForwarder(configuration, grpcStub); @@ -109,14 +139,38 @@ public class GrpcProducer extends DefaultProducer implements AsyncProcessor { super.doStop(); } - protected void initializeChannel() { + protected void initializeChannel() throws Exception { NettyChannelBuilder channelBuilder = null; + if (!ObjectHelper.isEmpty(configuration.getHost()) && !ObjectHelper.isEmpty(configuration.getPort())) { LOG.info("Creating channel to the remote gRPC server {}:{}", configuration.getHost(), configuration.getPort()); channelBuilder = NettyChannelBuilder.forAddress(configuration.getHost(), configuration.getPort()); } else { throw new IllegalArgumentException("No connection properties (host or port) specified"); } - channel = channelBuilder.usePlaintext(configuration.getUsePlainText()).build(); + if (configuration.getNegotiationType() == NegotiationType.TLS) { + ObjectHelper.notNull(configuration.getKeyCertChainResource(), "keyCertChainResource"); + ObjectHelper.notNull(configuration.getKeyResource(), "keyResource"); + + ClassResolver classResolver = endpoint.getCamelContext().getClassResolver(); + + SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient() + .sslProvider(SslProvider.OPENSSL) + .keyManager(ResourceHelper.resolveResourceAsInputStream(classResolver, configuration.getKeyCertChainResource()), + ResourceHelper.resolveResourceAsInputStream(classResolver, configuration.getKeyResource()), + configuration.getKeyPassword()); + + if (ObjectHelper.isNotEmpty(configuration.getTrustCertCollectionResource())) { + sslContextBuilder = sslContextBuilder.trustManager(ResourceHelper.resolveResourceAsInputStream(classResolver, configuration.getTrustCertCollectionResource())); + } + + channelBuilder = channelBuilder.sslContext(sslContextBuilder.build()); + } + + channel = channelBuilder.negotiationType(configuration.getNegotiationType()) + .flowControlWindow(configuration.getFlowControlWindow()) + .userAgent(configuration.getUserAgent()) + .maxInboundMessageSize(configuration.getMaxMessageSize()) + .build(); } } http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcUtils.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcUtils.java b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcUtils.java index fe65a37..474625f 100644 --- a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcUtils.java +++ b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/GrpcUtils.java @@ -16,11 +16,17 @@ */ package org.apache.camel.component.grpc; +import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTCreationException; +import io.grpc.CallCredentials; import io.grpc.Channel; import io.grpc.stub.StreamObserver; import org.apache.camel.CamelContext; @@ -44,12 +50,12 @@ public final class GrpcUtils { return service.contains(".") ? service.substring(0, service.lastIndexOf(".")) : ""; } - public static Object constructGrpcAsyncStub(String packageName, String serviceName, Channel channel, final CamelContext context) { - return constructGrpcStubClass(packageName, serviceName, GrpcConstants.GRPC_SERVICE_ASYNC_STUB_METHOD, channel, context); + public static Object constructGrpcAsyncStub(String packageName, String serviceName, Channel channel, final CallCredentials creds, final CamelContext context) { + return constructGrpcStubClass(packageName, serviceName, GrpcConstants.GRPC_SERVICE_ASYNC_STUB_METHOD, channel, creds, context); } - public static Object constructGrpcBlockingStub(String packageName, String serviceName, Channel channel, final CamelContext context) { - return constructGrpcStubClass(packageName, serviceName, GrpcConstants.GRPC_SERVICE_SYNC_STUB_METHOD, channel, context); + public static Object constructGrpcBlockingStub(String packageName, String serviceName, Channel channel, final CallCredentials creds, final CamelContext context) { + return constructGrpcStubClass(packageName, serviceName, GrpcConstants.GRPC_SERVICE_SYNC_STUB_METHOD, channel, creds, context); } /** @@ -59,24 +65,38 @@ public final class GrpcUtils { * newFutureStub - for ListenableFuture-style (not implemented yet) */ @SuppressWarnings({"rawtypes"}) - private static Object constructGrpcStubClass(String packageName, String serviceName, String stubMethod, Channel channel, final CamelContext context) { - Class[] paramChannel = new Class[1]; - paramChannel[0] = Channel.class; - Object grpcBlockingStub = null; + private static Object constructGrpcStubClass(String packageName, String serviceName, String stubMethod, Channel channel, final CallCredentials creds, final CamelContext context) { + Class[] paramChannel = {Channel.class}; + Object grpcStub = null; String serviceClassName = constructFullClassName(packageName, serviceName + GrpcConstants.GRPC_SERVICE_CLASS_POSTFIX); try { Class grpcServiceClass = context.getClassResolver().resolveMandatoryClass(serviceClassName); - Method grpcBlockingMethod = ReflectionHelper.findMethod(grpcServiceClass, stubMethod, paramChannel); - if (grpcBlockingMethod == null) { + Method grpcMethod = ReflectionHelper.findMethod(grpcServiceClass, stubMethod, paramChannel); + if (grpcMethod == null) { throw new IllegalArgumentException("gRPC service method not found: " + serviceClassName + "." + stubMethod); } - grpcBlockingStub = ObjectHelper.invokeMethod(grpcBlockingMethod, grpcServiceClass, channel); + grpcStub = ObjectHelper.invokeMethod(grpcMethod, grpcServiceClass, channel); + + if (creds != null) { + return addClientCallCredentials(grpcStub, creds); + } } catch (ClassNotFoundException e) { throw new IllegalArgumentException("gRPC service class not found: " + serviceClassName); } - return grpcBlockingStub; + return grpcStub; + } + + @SuppressWarnings("rawtypes") + public static Object addClientCallCredentials(Object grpcStub, final CallCredentials creds) { + Class[] paramCallCreds = {CallCredentials.class}; + Object grpcStubWithCreds = null; + + Method callCredsMethod = ReflectionHelper.findMethod(grpcStub.getClass(), GrpcConstants.GRPC_SERVICE_STUB_CALL_CREDS_METHOD, paramCallCreds); + grpcStubWithCreds = ObjectHelper.invokeMethod(callCredsMethod, grpcStub, creds); + + return grpcStubWithCreds; } @SuppressWarnings("rawtypes") http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/client/auth/jwt/JwtCallCredentials.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/client/auth/jwt/JwtCallCredentials.java b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/client/auth/jwt/JwtCallCredentials.java new file mode 100644 index 0000000..676f284 --- /dev/null +++ b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/client/auth/jwt/JwtCallCredentials.java @@ -0,0 +1,66 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.camel.component.grpc.client.auth.jwt; + +import java.util.concurrent.Executor; + +import io.grpc.Attributes; +import io.grpc.CallCredentials; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; +import io.grpc.Status; +import org.apache.camel.component.grpc.GrpcConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * JSON Web Token client credentials generator and injector + */ +public class JwtCallCredentials implements CallCredentials { + private static final Logger LOG = LoggerFactory.getLogger(JwtCallCredentials.class); + private final String jwtToken; + + public JwtCallCredentials(String jwtToken) { + this.jwtToken = jwtToken; + } + + @Override + public void applyRequestMetadata(MethodDescriptor method, Attributes attrs, Executor executor, MetadataApplier applier) { + String authority = attrs.get(ATTR_AUTHORITY); + + LOG.debug("Using authority {} for credentials", authority); + executor.execute(new Runnable() { + @Override + public void run() { + try { + LOG.debug("Start to apply for the JWT token header"); + Metadata headers = new Metadata(); + Metadata.Key jwtKey = GrpcConstants.GRPC_JWT_METADATA_KEY; + headers.put(jwtKey, jwtToken); + applier.apply(headers); + } catch (Throwable e) { + LOG.debug("Unable to set metadata credentials header", e); + applier.fail(Status.UNAUTHENTICATED.withCause(e)); + } + } + }); + } + + @Override + public void thisUsesUnstableApi() { + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/client/auth/jwt/JwtHelper.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/client/auth/jwt/JwtHelper.java b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/client/auth/jwt/JwtHelper.java new file mode 100644 index 0000000..d58f3a2 --- /dev/null +++ b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/client/auth/jwt/JwtHelper.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.camel.component.grpc.client.auth.jwt; + +import java.io.UnsupportedEncodingException; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTCreationException; + +/** + * JSON Web Token credentials generator helper + */ +public final class JwtHelper { + private JwtHelper() { + } + + public static String createJwtToken(String secret, String issuer, String subject) { + try { + Algorithm algorithm = Algorithm.HMAC256(secret); + String token = JWT.create().withIssuer(issuer).withSubject(subject).sign(algorithm); + return token; + } catch (JWTCreationException e) { + throw new IllegalArgumentException("Unable to create JWT token", e); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException("UTF-8 encoding not supported during JWT token creation", e); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/server/auth/jwt/JwtServerInterceptor.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/server/auth/jwt/JwtServerInterceptor.java b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/server/auth/jwt/JwtServerInterceptor.java new file mode 100644 index 0000000..f332b1e --- /dev/null +++ b/components/camel-grpc/src/main/java/org/apache/camel/component/grpc/server/auth/jwt/JwtServerInterceptor.java @@ -0,0 +1,96 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.camel.component.grpc.server.auth.jwt; + +import java.io.UnsupportedEncodingException; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTCreationException; +import com.auth0.jwt.interfaces.DecodedJWT; +import io.grpc.Context; +import io.grpc.Contexts; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCall.Listener; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import io.grpc.Status; +import org.apache.camel.component.grpc.GrpcConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * JSON Web Token credentials validator implementation + */ +public class JwtServerInterceptor implements ServerInterceptor { + private static final Logger LOG = LoggerFactory.getLogger(JwtServerInterceptor.class); + + @SuppressWarnings("rawtypes") + private static final ServerCall.Listener NOOP_LISTENER = new ServerCall.Listener() { + }; + + private final JWTVerifier verifier; + + public JwtServerInterceptor(String secret, String issuer, String subject) { + verifier = JwtHelper.prepareJwtVerifier(secret, issuer, subject); + } + + @Override + @SuppressWarnings("unchecked") + public Listener interceptCall(ServerCall call, Metadata metadata, ServerCallHandler serverCallHandler) { + String jwtToken = metadata.get(GrpcConstants.GRPC_JWT_METADATA_KEY); + if (jwtToken == null) { + call.close(Status.UNAUTHENTICATED.withDescription("JWT Token is missing from metadata"), metadata); + return NOOP_LISTENER; + } + + Context ctx; + try { + DecodedJWT verified = verifier.verify(jwtToken); + ctx = Context.current() + .withValue(GrpcConstants.GRPC_JWT_USER_ID_CTX_KEY, verified.getSubject() == null ? "anonymous" : verified.getSubject()) + .withValue(GrpcConstants.GRPC_JWT_CTX_KEY, jwtToken); + } catch (Exception e) { + LOG.debug("JWT token verification failed - Unauthenticated"); + call.close(Status.UNAUTHENTICATED.withDescription(e.getMessage()).withCause(e), metadata); + return NOOP_LISTENER; + } + + return Contexts.interceptCall(ctx, call, metadata, serverCallHandler); + } + + /** + * JSON Web Token credentials validator helper + */ + public static final class JwtHelper { + private JwtHelper() { + } + + public static JWTVerifier prepareJwtVerifier(String secret, String issuer, String subject) { + try { + Algorithm algorithm = Algorithm.HMAC256(secret); + return JWT.require(algorithm).withIssuer(issuer).withSubject(subject).build(); + } catch (JWTCreationException e) { + throw new IllegalArgumentException("Unable to create JWT verifier", e); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException("UTF-8 encoding not supported during JWT verifier creation", e); + } + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcConsumerPropagationTest.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcConsumerPropagationTest.java b/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcConsumerPropagationTest.java index 357e4dd..46ebf04 100644 --- a/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcConsumerPropagationTest.java +++ b/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcConsumerPropagationTest.java @@ -57,6 +57,7 @@ public class GrpcConsumerPropagationTest extends CamelTestSupport { @After public void stopGrpcChannels() throws Exception { asyncOnNextChannel.shutdown().awaitTermination(5, TimeUnit.SECONDS); + asyncOnCompletedChannel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } @Test @@ -113,8 +114,7 @@ public class GrpcConsumerPropagationTest extends CamelTestSupport { .bean(new GrpcMessageBuilder(), "buildAsyncPongResponse"); from("grpc://localhost:" + GRPC_ASYNC_COMPLETED_REQUEST_TEST_PORT + "/org.apache.camel.component.grpc.PingPong?consumerStrategy=PROPAGATION&forwardOnCompleted=true") - .to("mock:async-on-completed-propagation") - .bean(new GrpcMessageBuilder(), "buildAsyncPongResponse"); + .to("mock:async-on-completed-propagation"); } }; } http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcConsumerSecurityTest.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcConsumerSecurityTest.java b/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcConsumerSecurityTest.java new file mode 100644 index 0000000..9a89b9d --- /dev/null +++ b/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcConsumerSecurityTest.java @@ -0,0 +1,218 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.camel.component.grpc; + +import java.io.File; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.SSLException; + +import io.grpc.ManagedChannel; +import io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.NettyChannelBuilder; +import io.grpc.stub.StreamObserver; +import io.netty.handler.ssl.SslProvider; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.grpc.client.auth.jwt.JwtCallCredentials; +import org.apache.camel.component.grpc.client.auth.jwt.JwtHelper; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.AvailablePortFinder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GrpcConsumerSecurityTest extends CamelTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(GrpcConsumerSecurityTest.class); + + private static final int GRPC_TLS_TEST_PORT = AvailablePortFinder.getNextAvailable(); + private static final int GRPC_JWT_CORRECT_TEST_PORT = AvailablePortFinder.getNextAvailable(); + private static final int GRPC_JWT_INCORRECT_TEST_PORT = AvailablePortFinder.getNextAvailable(); + private static final int GRPC_TEST_PING_ID = 1; + private static final String GRPC_TEST_PING_VALUE = "PING"; + private static final String GRPC_TEST_PONG_VALUE = "PONG"; + + private static final String GRPC_JWT_CORRECT_SECRET = "correctsecret"; + private static final String GRPC_JWT_INCORRECT_SECRET = "incorrectsecret"; + + private ManagedChannel tlsChannel; + private ManagedChannel jwtCorrectChannel; + private ManagedChannel jwtIncorrectChannel; + + private PingPongGrpc.PingPongStub tlsAsyncStub; + private PingPongGrpc.PingPongStub jwtCorrectAsyncStub; + private PingPongGrpc.PingPongStub jwtIncorrectAsyncStub; + + @Before + public void startGrpcChannels() throws SSLException { + String correctJwtToken = JwtHelper.createJwtToken(GRPC_JWT_CORRECT_SECRET, null, null); + String incorrectJwtToken = JwtHelper.createJwtToken(GRPC_JWT_INCORRECT_SECRET, null, null); + + tlsChannel = NettyChannelBuilder.forAddress("localhost", GRPC_TLS_TEST_PORT) + .sslContext(GrpcSslContexts.forClient() + .sslProvider(SslProvider.OPENSSL) + .keyManager(new File("src/test/resources/certs/client.pem"), new File("src/test/resources/certs/client.key")) + .trustManager(new File("src/test/resources/certs/ca.pem")) + .build()) + .build(); + + jwtCorrectChannel = NettyChannelBuilder.forAddress("localhost", GRPC_JWT_CORRECT_TEST_PORT).usePlaintext(true).build(); + jwtIncorrectChannel = NettyChannelBuilder.forAddress("localhost", GRPC_JWT_INCORRECT_TEST_PORT).usePlaintext(true).build(); + + tlsAsyncStub = PingPongGrpc.newStub(tlsChannel); + jwtCorrectAsyncStub = PingPongGrpc.newStub(jwtCorrectChannel).withCallCredentials(new JwtCallCredentials(correctJwtToken)); + jwtIncorrectAsyncStub = PingPongGrpc.newStub(jwtIncorrectChannel).withCallCredentials(new JwtCallCredentials(incorrectJwtToken)); + + } + + @After + public void stopGrpcChannels() throws Exception { + tlsChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS); + jwtCorrectChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS); + jwtIncorrectChannel.shutdown().awaitTermination(1, TimeUnit.SECONDS); + } + + @Test + public void testWithEnableTLS() throws Exception { + LOG.info("gRPC pingAsyncSync method aync test with TLS enable start"); + + final CountDownLatch latch = new CountDownLatch(1); + PingRequest pingRequest = PingRequest.newBuilder().setPingName(GRPC_TEST_PING_VALUE).setPingId(GRPC_TEST_PING_ID).build(); + PongResponseStreamObserver responseObserver = new PongResponseStreamObserver(latch); + + StreamObserver requestObserver = tlsAsyncStub.pingAsyncSync(responseObserver); + requestObserver.onNext(pingRequest); + latch.await(5, TimeUnit.SECONDS); + + MockEndpoint mockEndpoint = getMockEndpoint("mock:tls-enable"); + mockEndpoint.expectedMessageCount(1); + mockEndpoint.expectedHeaderValuesReceivedInAnyOrder(GrpcConstants.GRPC_EVENT_TYPE_HEADER, GrpcConstants.GRPC_EVENT_TYPE_ON_NEXT); + mockEndpoint.expectedHeaderValuesReceivedInAnyOrder(GrpcConstants.GRPC_METHOD_NAME_HEADER, "pingAsyncSync"); + mockEndpoint.assertIsSatisfied(); + + PongResponse pongResponse = responseObserver.getPongResponse(); + assertNotNull(pongResponse); + assertEquals(GRPC_TEST_PING_ID, pongResponse.getPongId()); + assertEquals(GRPC_TEST_PING_VALUE + GRPC_TEST_PONG_VALUE, pongResponse.getPongName()); + } + + @Test + public void testWithCorrectJWT() throws Exception { + LOG.info("gRPC pingAsyncSync method aync test with correct JWT start"); + + final CountDownLatch latch = new CountDownLatch(1); + PingRequest pingRequest = PingRequest.newBuilder().setPingName(GRPC_TEST_PING_VALUE).setPingId(GRPC_TEST_PING_ID).build(); + PongResponseStreamObserver responseObserver = new PongResponseStreamObserver(latch); + + StreamObserver requestObserver = jwtCorrectAsyncStub.pingAsyncSync(responseObserver); + requestObserver.onNext(pingRequest); + latch.await(5, TimeUnit.SECONDS); + + MockEndpoint mockEndpoint = getMockEndpoint("mock:jwt-correct-secret"); + mockEndpoint.expectedMessageCount(1); + mockEndpoint.expectedHeaderValuesReceivedInAnyOrder(GrpcConstants.GRPC_EVENT_TYPE_HEADER, GrpcConstants.GRPC_EVENT_TYPE_ON_NEXT); + mockEndpoint.expectedHeaderValuesReceivedInAnyOrder(GrpcConstants.GRPC_METHOD_NAME_HEADER, "pingAsyncSync"); + mockEndpoint.assertIsSatisfied(); + + PongResponse pongResponse = responseObserver.getPongResponse(); + assertNotNull(pongResponse); + assertEquals(GRPC_TEST_PING_ID, pongResponse.getPongId()); + assertEquals(GRPC_TEST_PING_VALUE + GRPC_TEST_PONG_VALUE, pongResponse.getPongName()); + } + + @Test + public void testWithIncorrectJWT() throws Exception { + LOG.info("gRPC pingAsyncSync method aync test with correct JWT start"); + + final CountDownLatch latch = new CountDownLatch(1); + PingRequest pingRequest = PingRequest.newBuilder().setPingName(GRPC_TEST_PING_VALUE).setPingId(GRPC_TEST_PING_ID).build(); + PongResponseStreamObserver responseObserver = new PongResponseStreamObserver(latch); + + StreamObserver requestObserver = jwtIncorrectAsyncStub.pingAsyncSync(responseObserver); + requestObserver.onNext(pingRequest); + latch.await(5, TimeUnit.SECONDS); + + MockEndpoint mockEndpoint = getMockEndpoint("mock:jwt-incorrect-secret"); + mockEndpoint.expectedMessageCount(0); + mockEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() { + + from("grpc://localhost:" + GRPC_TLS_TEST_PORT + "/org.apache.camel.component.grpc.PingPong?consumerStrategy=PROPAGATION&" + + "negotiationType=TLS&keyCertChainResource=file:src/test/resources/certs/server.pem&" + + "keyResource=file:src/test/resources/certs/server.key&trustCertCollectionResource=file:src/test/resources/certs/ca.pem") + .to("mock:tls-enable") + .bean(new GrpcMessageBuilder(), "buildAsyncPongResponse"); + + from("grpc://localhost:" + GRPC_JWT_CORRECT_TEST_PORT + "/org.apache.camel.component.grpc.PingPong?consumerStrategy=PROPAGATION&" + + "authenticationType=JWT&jwtSecret=" + GRPC_JWT_CORRECT_SECRET) + .to("mock:jwt-correct-secret") + .bean(new GrpcMessageBuilder(), "buildAsyncPongResponse"); + + from("grpc://localhost:" + GRPC_JWT_INCORRECT_TEST_PORT + "/org.apache.camel.component.grpc.PingPong?consumerStrategy=PROPAGATION&" + + "authenticationType=JWT&jwtSecret=" + GRPC_JWT_CORRECT_SECRET) + .to("mock:jwt-incorrect-secret") + .bean(new GrpcMessageBuilder(), "buildAsyncPongResponse"); + } + }; + } + + public class PongResponseStreamObserver implements StreamObserver { + private PongResponse pongResponse; + private final CountDownLatch latch; + + public PongResponseStreamObserver(CountDownLatch latch) { + this.latch = latch; + } + + public PongResponse getPongResponse() { + return pongResponse; + } + + @Override + public void onNext(PongResponse value) { + pongResponse = value; + latch.countDown(); + } + + @Override + public void onError(Throwable t) { + LOG.info("Exception", t); + latch.countDown(); + } + + @Override + public void onCompleted() { + latch.countDown(); + } + } + + public class GrpcMessageBuilder { + + public PongResponse buildAsyncPongResponse(PingRequest pingRequests) { + return PongResponse.newBuilder().setPongName(pingRequests.getPingName() + GRPC_TEST_PONG_VALUE).setPongId(pingRequests.getPingId()).build(); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcProducerSecurityTest.java ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcProducerSecurityTest.java b/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcProducerSecurityTest.java new file mode 100644 index 0000000..2ba3016 --- /dev/null +++ b/components/camel-grpc/src/test/java/org/apache/camel/component/grpc/GrpcProducerSecurityTest.java @@ -0,0 +1,171 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.camel.component.grpc; + +import java.io.File; +import java.io.IOException; + +import io.grpc.Server; +import io.grpc.StatusRuntimeException; +import io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.NettyServerBuilder; +import io.grpc.stub.StreamObserver; +import io.netty.handler.ssl.ClientAuth; +import io.netty.handler.ssl.SslProvider; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.grpc.server.auth.jwt.JwtServerInterceptor; +import org.apache.camel.test.AvailablePortFinder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GrpcProducerSecurityTest extends CamelTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(GrpcProducerSecurityTest.class); + + private static final int GRPC_TLS_TEST_PORT = AvailablePortFinder.getNextAvailable(); + private static final int GRPC_JWT_TEST_PORT = AvailablePortFinder.getNextAvailable(); + private static final int GRPC_TEST_PING_ID = 1; + private static final int GRPC_TEST_PONG_ID01 = 1; + private static final int GRPC_TEST_PONG_ID02 = 2; + private static final String GRPC_TEST_PING_VALUE = "PING"; + private static final String GRPC_TEST_PONG_VALUE = "PONG"; + + private static final String GRPC_JWT_CORRECT_SECRET = "correctsecret"; + private static final String GRPC_JWT_INCORRECT_SECRET = "incorrectsecret"; + + private static Server grpcServerWithTLS; + private static Server grpcServerWithJWT; + + @BeforeClass + public static void startGrpcServer() throws Exception { + grpcServerWithTLS = NettyServerBuilder.forPort(GRPC_TLS_TEST_PORT) + .sslContext(GrpcSslContexts.forServer(new File("src/test/resources/certs/server.pem"), + new File("src/test/resources/certs/server.key")) + .trustManager(new File("src/test/resources/certs/ca.pem")) + .clientAuth(ClientAuth.REQUIRE) + .sslProvider(SslProvider.OPENSSL) + .build()) + .addService(new PingPongImpl()).build().start(); + + grpcServerWithJWT = NettyServerBuilder.forPort(GRPC_JWT_TEST_PORT) + .addService(new PingPongImpl()) + .intercept(new JwtServerInterceptor(GRPC_JWT_CORRECT_SECRET, null, null)) + .build() + .start(); + + LOG.info("gRPC server with TLS started on port {}", GRPC_TLS_TEST_PORT); + LOG.info("gRPC server with the JWT auth started on port {}", GRPC_JWT_TEST_PORT); + } + + @AfterClass + public static void stopGrpcServer() throws IOException { + if (grpcServerWithTLS != null) { + grpcServerWithTLS.shutdown(); + LOG.info("gRPC server with TLS stoped"); + } + + if (grpcServerWithJWT != null) { + grpcServerWithJWT.shutdown(); + LOG.info("gRPC server with JWT stoped"); + } + } + + @Test + public void testWithEnableTLS() throws Exception { + LOG.info("gRPC PingSyncSync method test start with TLS enable"); + // Testing simple sync method invoke using TLS negotiation + PingRequest pingRequest = PingRequest.newBuilder().setPingName(GRPC_TEST_PING_VALUE).setPingId(GRPC_TEST_PING_ID).build(); + Object pongResponse = template.requestBody("direct:grpc-tls", pingRequest); + + assertNotNull(pongResponse); + assertTrue(pongResponse instanceof PongResponse); + assertEquals(((PongResponse)pongResponse).getPongId(), GRPC_TEST_PING_ID); + assertEquals(((PongResponse)pongResponse).getPongName(), GRPC_TEST_PING_VALUE + GRPC_TEST_PONG_VALUE); + } + + @Test + public void testWithCorrectJWT() throws Exception { + LOG.info("gRPC PingSyncSync method test start with correct JWT authentication"); + // Testing simple sync method invoke using correct JWT authentication + PingRequest pingRequest = PingRequest.newBuilder().setPingName(GRPC_TEST_PING_VALUE).setPingId(GRPC_TEST_PING_ID).build(); + Object pongResponse = template.requestBody("direct:grpc-correct-jwt", pingRequest); + + assertNotNull(pongResponse); + assertTrue(pongResponse instanceof PongResponse); + assertEquals(((PongResponse)pongResponse).getPongId(), GRPC_TEST_PING_ID); + assertEquals(((PongResponse)pongResponse).getPongName(), GRPC_TEST_PING_VALUE + GRPC_TEST_PONG_VALUE); + } + + @Test + public void testWithIncorrectJWT() throws Exception { + LOG.info("gRPC PingSyncSync method test start with incorrect JWT authentication"); + // Testing simple sync method invoke using incorrect JWT authentication + PingRequest pingRequest = PingRequest.newBuilder().setPingName(GRPC_TEST_PING_VALUE).setPingId(GRPC_TEST_PING_ID).build(); + + try { + Object pongResponse = template.requestBody("direct:grpc-incorrect-jwt", pingRequest); + } catch (Exception e) { + assertNotNull(e); + assertTrue(e.getCause().getCause() instanceof StatusRuntimeException); + assertEquals(e.getCause().getCause().getMessage(), "UNAUTHENTICATED: The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256"); + } + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:grpc-tls").to("grpc://localhost:" + GRPC_TLS_TEST_PORT + "/org.apache.camel.component.grpc.PingPong?method=pingSyncSync&synchronous=true&" + + "negotiationType=TLS&keyCertChainResource=file:src/test/resources/certs/client.pem&" + + "keyResource=file:src/test/resources/certs/client.key&trustCertCollectionResource=file:src/test/resources/certs/ca.pem"); + + from("direct:grpc-correct-jwt").to("grpc://localhost:" + GRPC_JWT_TEST_PORT + "/org.apache.camel.component.grpc.PingPong?method=pingSyncSync&synchronous=true&" + + "authenticationType=JWT&jwtSecret=" + GRPC_JWT_CORRECT_SECRET); + + from("direct:grpc-incorrect-jwt").to("grpc://localhost:" + GRPC_JWT_TEST_PORT + "/org.apache.camel.component.grpc.PingPong?method=pingSyncSync&synchronous=true&" + + "authenticationType=JWT&jwtSecret=" + GRPC_JWT_INCORRECT_SECRET); + } + }; + } + + /** + * Test gRPC PingPong server implementation + */ + static class PingPongImpl extends PingPongGrpc.PingPongImplBase { + @Override + public void pingSyncSync(PingRequest request, StreamObserver responseObserver) { + LOG.info("gRPC server received data from PingPong service PingId={} PingName={}", request.getPingId(), request.getPingName()); + PongResponse response = PongResponse.newBuilder().setPongName(request.getPingName() + GRPC_TEST_PONG_VALUE).setPongId(request.getPingId()).build(); + responseObserver.onNext(response); + responseObserver.onCompleted(); + } + + @Override + public void pingSyncAsync(PingRequest request, StreamObserver responseObserver) { + LOG.info("gRPC server received data from PingAsyncResponse service PingId={} PingName={}", request.getPingId(), request.getPingName()); + PongResponse response01 = PongResponse.newBuilder().setPongName(request.getPingName() + GRPC_TEST_PONG_VALUE).setPongId(GRPC_TEST_PONG_ID01).build(); + PongResponse response02 = PongResponse.newBuilder().setPongName(request.getPingName() + GRPC_TEST_PONG_VALUE).setPongId(GRPC_TEST_PONG_ID02).build(); + responseObserver.onNext(response01); + responseObserver.onNext(response02); + responseObserver.onCompleted(); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/resources/certs/README ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/resources/certs/README b/components/camel-grpc/src/test/resources/certs/README new file mode 100644 index 0000000..ce6e025 --- /dev/null +++ b/components/camel-grpc/src/test/resources/certs/README @@ -0,0 +1,36 @@ +The test credentials have been generated with the following +commands: + +The CA is self-signed: +---------------------- +$ openssl genrsa -out ca.key 1024 +$ openssl req -x509 -new -key ca.key -nodes -out ca.pem -config ca-openssl.cnf -days 3650 -extensions v3_req + +When prompted for certificate information, everything is default. + +Client certificate issued by CA: +----------------------- + +$ openssl genrsa -out client.key.rsa 1024 +$ openssl pkcs8 -topk8 -in client.key.rsa -out client.key -nocrypt +$ rm client.key.rsa +$ openssl req -new -key client.key -out client.csr + +When prompted for certificate information, everything is default except the +common name which is set to localhost. + +$ openssl x509 -req -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client.pem -outform PEM -days 5000 + + +Server certificate issued by CA: +------------------------ + +$ openssl genrsa -out server.key.rsa 1024 +$ openssl pkcs8 -topk8 -in server.key.rsa -out server.key -nocrypt +$ rm server.key.rsa +$ openssl req -new -key server.key -out server.csr + +When prompted for certificate information, everything is default except the +common name which is set to localhost for simple testing. + +$ openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out server.pem -outform PEM -days 5000 http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/resources/certs/ca-openssl.cnf ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/resources/certs/ca-openssl.cnf b/components/camel-grpc/src/test/resources/certs/ca-openssl.cnf new file mode 100644 index 0000000..e15866b --- /dev/null +++ b/components/camel-grpc/src/test/resources/certs/ca-openssl.cnf @@ -0,0 +1,18 @@ +[req] +distinguished_name = req_distinguished_name +req_extensions = v3_req + +[req_distinguished_name] +countryName = Country Name (2 letter code) +countryName_default = AU +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State +organizationName = Organization Name (eg, company) +organizationName_default = Internet Widgits Pty Ltd +commonName = Common Name (eg, YOUR name) +commonName_default = testca + +[v3_req] +basicConstraints = CA:true +keyUsage = critical, keyCertSign + http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/resources/certs/ca.key ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/resources/certs/ca.key b/components/camel-grpc/src/test/resources/certs/ca.key new file mode 100644 index 0000000..6e33183 --- /dev/null +++ b/components/camel-grpc/src/test/resources/certs/ca.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCxqJHLzLvQXc7HVlu8hOkhXJ4eFmMwQFU9F7z1tPA5bw1/UTFt +5ov0LPl66dvZnBfZ0vmnqZkMNMv6cIV7R4W6ND+xZYzWw20cCC4SGmDB+7x6JgFz +9MeD539itjmnSxmGrLgmF8yAZDy++iWwWEmX/HdCdnga6Wj/zEGGVigSzwIDAQAB +AoGBAKykCPoo/CIh5r0jGIZ8CiiXXjgSvVS4T5zMop2KtR664jzk48nOjhY8Vjux +Yil3XF4afO0HDGkmLUozaiNAf5uyAkY0Y5kcqDDZUs4mjEG2DxvYTXRgbdmJwGRg +ALkEHo0FSJR6grL8nePfJhD6rgQjv17qEFx6wllk9vAUJsgRAkEA4FqlLNN3x7dG +25nP0UTEYzLBVIcbLbXJFMPmVqjao2zvnd1wDe13FSoF3yVAHA7L1s5Y28udM/rW +2ClFUZHamwJBAMq3wr0Hr2zFk3AD79wZ07N3gUShMt0zcHW9ix21yviqT3F967i5 +cil8NvVzIOxUZlg2u9Jj2jz648r83AGHQd0CQHXWZmcy8vjNBMSW9xZdXiEUKYMy +K05I6sKjWjouGhg4QWrTQeWu0hslpUvdDt0t0FaUrwtS2NDScUG7+5KqXv0CQE4J +sbjtVXXtFVYA3fyAIMQs1CGkYJ1Q6REaV4ynaCyT+6M4E194XF9mBw40NM9lqkR5 +RZK3h9MDzl9dOiCIfi0CQQCsr1gFZqTh5XbgfXSu+FCriVf+mixrTNVjuLRC3gwW +bv9MTDiywu51+UFWXtqzqNavbXNMYj5HMhANy8fUTwfY +-----END RSA PRIVATE KEY----- http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/resources/certs/ca.pem ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/resources/certs/ca.pem b/components/camel-grpc/src/test/resources/certs/ca.pem new file mode 100644 index 0000000..8b4a8f4 --- /dev/null +++ b/components/camel-grpc/src/test/resources/certs/ca.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICSjCCAbOgAwIBAgIJALfhdwg6XCA6MA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMMBnRlc3RjYTAeFw0xNzA4MjUxMDEwMDNa +Fw0yNzA4MjMxMDEwMDNaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0 +YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMM +BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsaiRy8y70F3Ox1Zb +vITpIVyeHhZjMEBVPRe89bTwOW8Nf1ExbeaL9Cz5eunb2ZwX2dL5p6mZDDTL+nCF +e0eFujQ/sWWM1sNtHAguEhpgwfu8eiYBc/THg+d/YrY5p0sZhqy4JhfMgGQ8vvol +sFhJl/x3QnZ4Gulo/8xBhlYoEs8CAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAiWKmh6KzqpHaGszH6PNegdJL +ryuBpjkHNIoNsZD98lcd+d+yH2Ii9nQQZCiB5FPGev+7eXs0RtpWde/WVA9xhSVU +RK9zzy6tq0nMS7kWZndnRR/CLcHDjC7HmaV5RiBAf2mxbeu7VNUu9PStLqRMBRSK +dl0Huv54GYbcXuHLLsw= +-----END CERTIFICATE----- http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/resources/certs/client.key ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/resources/certs/client.key b/components/camel-grpc/src/test/resources/certs/client.key new file mode 100644 index 0000000..a4ce199 --- /dev/null +++ b/components/camel-grpc/src/test/resources/certs/client.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMKtFB05LD1e2ANn +8nTxRA/9bUMl/V7QEgfIKdIc7TNAg1d5CDb6VLdS0woV9+lHW2KAItA6snHCvWJp +cn8FhdCF4EF9gQ0kKkdHir1W/bT322KhSOjGZM0XkVLjY0fM+/fKgHAIsTbU7+9p +JxxSELpyWGTyLw8SkjBqtdzH2MWzAgMBAAECgYBfEGvJFXkwAteTWjhAuOxWrpej +ebKvkQWs/SbG7s85/t/kYDsNtdKWrwBVZYLpTKoogI//hRpMiR84Jmv98TF1Vi57 +YXTPq8hfxZXYrHzKAMnp1iQQ0zesXkHXr3oZKkYNeN+ms7tWVRItZr+IiBASabkv +JNidg80rKGsw4hKzaQJBAPdLnQ8nFPhc84SVGUu1PwbMLUofZQ1P3RMGoMWscbog +269f0Lb5Fj8zFp/Nq9qiYHHbxlVWelw/yjI/Pjz6gdUCQQDJh0+hqkPOqI7mfLzx +bP9S+pjoHgs8auB3vsubbJUBOUuEovUfxYiUdCdjQ3J4Nc0Sn9NJmYkyrDkj3Myf +v+VnAkEAzbWEbLph40fO+hbc9/FJAGqPsfzznmM0z0LQMh8Ea4QxumzFva7uJpxk +0YHQ1woDmDLthMdu+ZXGqI2bRDZOEQJAOR2eVgU5foKLLYvAyPPJUS0w1Ohe6tqn +j4iFkCEwAc7JNmgw7LZBRUG+QAXHlYY5/sNJUJyxI6ln8GANpmDulQJBAMfe5Rl7 +5e6JHoDv/qMOoG1+fK7Eic0aKk9HKOeCtB9eCC/BemiV56iPn/mevVD9MNc+1USO +5GnlZS6RI2KAGjs= +-----END PRIVATE KEY----- http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/resources/certs/client.pem ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/resources/certs/client.pem b/components/camel-grpc/src/test/resources/certs/client.pem new file mode 100644 index 0000000..ef8c697 --- /dev/null +++ b/components/camel-grpc/src/test/resources/certs/client.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICIzCCAYwCCQDxA0CVWlyyozANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTcwODI1MTAxODE4WhcNMzEw +NTA0MTAxODE4WjBWMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5 +MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMRIwEAYDVQQDDAlsb2NhbGhv +c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMKtFB05LD1e2ANn8nTxRA/9 +bUMl/V7QEgfIKdIc7TNAg1d5CDb6VLdS0woV9+lHW2KAItA6snHCvWJpcn8FhdCF +4EF9gQ0kKkdHir1W/bT322KhSOjGZM0XkVLjY0fM+/fKgHAIsTbU7+9pJxxSELpy +WGTyLw8SkjBqtdzH2MWzAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAnYNJQTg1h7nI +iQHV0anPiAOBi9dgtxY8uYeyeQdbK/6rkCgiOE/uOqK7synOJ8xb8neNnrY99ylx +7qvTlZPMChoPiOcjx4GSyfcSNXAGlD/ENzagQCueWitgDxhfudykmnzm5wQIhbe4 ++R8K/xD74ebqbTIM+lTc4RAbXB251LE= +-----END CERTIFICATE----- http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/resources/certs/server.key ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/resources/certs/server.key b/components/camel-grpc/src/test/resources/certs/server.key new file mode 100644 index 0000000..111f833 --- /dev/null +++ b/components/camel-grpc/src/test/resources/certs/server.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ45sv2cHQQjf8tO +aBfvnQdTyMooPhloYjG1gN7akKhyYmIcBQzL0KIx0Js/lgnPVaRWIZmiUWffbBec +QSMPiUhJgZPpq3CoCGmGg13dWjEYjCP4yxWi+fpUgn5qdf11Gtl3EDa90neZTyUW +sOaU5dzh7O6kgxI1X1HQ3HKjY//vAgMBAAECgYBphN1DmKsZKXt+YEm3PMsiKdQM +TY4sb5qcwAizlltGmxHVkA4mHH6EzGfsQRmUbTsWH4LE7KUResShcklWUnQgPrUg +NQE3PVSpkqOYBUyFJz3eVWOU+MVGAVavjxfiDsU3G/9yM3AY+wuTgksbTDEsMGeF +QwbewCZxmr49bIFqkQJBAM2HTmc1EmpZWMdZJYUUAod21u5Huf/0QfvfRGQVyIid +EO88d/jMB5ikYBfc3p8XN/Oe7wNw5M2DxePh+KgR9JUCQQDFFKXEnkpJqCMDklMA +ikDFzggU0o764XVwuwaKVTAv79B3S2W4sxjcyCiGFPS9lf1y/INzaBUFhJcbMY7I +VV1zAkEAidFTZ62U3a9v8qz6ldQnJgMweLOsK8/0dxrt11csEz+PXXzkzfaymU6Q +CTBYL8H4COroRxxqsMzN49NhVAJGSQJAWs0njw5rJcKc10FskpwgOcKygH1+uOJ1 +zImu+r9DI2L3hm8rn8yMkPR7j0NKe6sGihsDqYFz5gXv5OyRX4XNNwJATHJrMCY3 +H8KYABAXbzdav5n0hTCDf23y5gRKgfYXKwwtr9iveKucpQvo95raCWTRrpET4ha0 +/KcyCVQcco+JhA== +-----END PRIVATE KEY----- http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/components/camel-grpc/src/test/resources/certs/server.pem ---------------------------------------------------------------------- diff --git a/components/camel-grpc/src/test/resources/certs/server.pem b/components/camel-grpc/src/test/resources/certs/server.pem new file mode 100644 index 0000000..dce5fbc --- /dev/null +++ b/components/camel-grpc/src/test/resources/certs/server.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICIzCCAYwCCQDxA0CVWlyypDANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTcwODI4MTIzMDA2WhcNMzEw +NTA3MTIzMDA2WjBWMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5 +MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMRIwEAYDVQQDDAlsb2NhbGhv +c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ45sv2cHQQjf8tOaBfvnQdT +yMooPhloYjG1gN7akKhyYmIcBQzL0KIx0Js/lgnPVaRWIZmiUWffbBecQSMPiUhJ +gZPpq3CoCGmGg13dWjEYjCP4yxWi+fpUgn5qdf11Gtl3EDa90neZTyUWsOaU5dzh +7O6kgxI1X1HQ3HKjY//vAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAVveL1W1aeKxW +okRldjZ3uqmkfYmneNKtKbrzw/XbWcKXpst0i0CQaKPnWVYCmVbS/iFh/LMllj4A +Lmy59v+z/Fcj7lXFW51hiVCycyV7rN3ov6CruxHdFhosfdoixZ5dGvAT7NaU3Io0 +3nGbUOOrGI+yDR1v61pIldVcXS3ljzc= +-----END CERTIFICATE----- http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/parent/pom.xml ---------------------------------------------------------------------- diff --git a/parent/pom.xml b/parent/pom.xml index a9c71e33..d7ae4ab 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -264,8 +264,11 @@ v1-rev12-1.22.0 0.30 2.3.25 - 1.5.0 - 1.5.0_1 + 1.6.1 + 0.7.1 + 3.2.0 + 2.0.5.Final + 1.6.1_1 2.8.1 4.0 3.0 http://git-wip-us.apache.org/repos/asf/camel/blob/687ec7b5/platforms/spring-boot/components-starter/camel-grpc-starter/pom.xml ---------------------------------------------------------------------- diff --git a/platforms/spring-boot/components-starter/camel-grpc-starter/pom.xml b/platforms/spring-boot/components-starter/camel-grpc-starter/pom.xml index baeeace..adf3d24 100644 --- a/platforms/spring-boot/components-starter/camel-grpc-starter/pom.xml +++ b/platforms/spring-boot/components-starter/camel-grpc-starter/pom.xml @@ -38,6 +38,14 @@ org.apache.camel camel-grpc ${project.version} + + + + commons-logging + commons-logging + + +