diff options
-rw-r--r-- | BUILD | 2 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | build.json | 1 | ||||
-rw-r--r-- | include/grpc++/auth_metadata_processor.h | 67 | ||||
-rw-r--r-- | include/grpc++/server_credentials.h | 6 | ||||
-rw-r--r-- | include/grpc++/support/auth_context.h | 5 | ||||
-rw-r--r-- | include/grpc/grpc_security.h | 5 | ||||
-rw-r--r-- | src/core/security/server_auth_filter.c | 8 | ||||
-rw-r--r-- | src/cpp/common/secure_auth_context.cc | 12 | ||||
-rw-r--r-- | src/cpp/common/secure_auth_context.h | 6 | ||||
-rw-r--r-- | src/cpp/server/insecure_server_credentials.cc | 6 | ||||
-rw-r--r-- | src/cpp/server/secure_server_credentials.cc | 62 | ||||
-rw-r--r-- | src/cpp/server/secure_server_credentials.h | 29 | ||||
-rw-r--r-- | test/cpp/common/secure_auth_context_test.cc | 20 | ||||
-rw-r--r-- | tools/doxygen/Doxyfile.c++ | 3 | ||||
-rw-r--r-- | tools/doxygen/Doxyfile.c++.internal | 3 | ||||
-rw-r--r-- | tools/run_tests/sources_and_headers.json | 4 | ||||
-rw-r--r-- | vsprojects/grpc++/grpc++.vcxproj | 1 | ||||
-rw-r--r-- | vsprojects/grpc++/grpc++.vcxproj.filters | 3 | ||||
-rw-r--r-- | vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj | 1 | ||||
-rw-r--r-- | vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters | 3 |
21 files changed, 230 insertions, 19 deletions
@@ -714,6 +714,7 @@ cc_library( "src/cpp/util/time.cc", ], hdrs = [ + "include/grpc++/auth_metadata_processor.h", "include/grpc++/channel.h", "include/grpc++/client_context.h", "include/grpc++/completion_queue.h", @@ -803,6 +804,7 @@ cc_library( "src/cpp/util/time.cc", ], hdrs = [ + "include/grpc++/auth_metadata_processor.h", "include/grpc++/channel.h", "include/grpc++/client_context.h", "include/grpc++/completion_queue.h", @@ -4630,6 +4630,7 @@ LIBGRPC++_SRC = \ src/cpp/util/time.cc \ PUBLIC_HEADERS_CXX += \ + include/grpc++/auth_metadata_processor.h \ include/grpc++/channel.h \ include/grpc++/client_context.h \ include/grpc++/completion_queue.h \ @@ -4872,6 +4873,7 @@ LIBGRPC++_UNSECURE_SRC = \ src/cpp/util/time.cc \ PUBLIC_HEADERS_CXX += \ + include/grpc++/auth_metadata_processor.h \ include/grpc++/channel.h \ include/grpc++/client_context.h \ include/grpc++/completion_queue.h \ diff --git a/build.json b/build.json index 4f9017a0ad..90c6e05d85 100644 --- a/build.json +++ b/build.json @@ -30,6 +30,7 @@ { "name": "grpc++_base", "public_headers": [ + "include/grpc++/auth_metadata_processor.h", "include/grpc++/channel.h", "include/grpc++/client_context.h", "include/grpc++/completion_queue.h", diff --git a/include/grpc++/auth_metadata_processor.h b/include/grpc++/auth_metadata_processor.h new file mode 100644 index 0000000000..3caf3e84fd --- /dev/null +++ b/include/grpc++/auth_metadata_processor.h @@ -0,0 +1,67 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPCXX_AUTH_METADATA_PROCESSOR_H_ +#define GRPCXX_AUTH_METADATA_PROCESSOR_H_ + +#include <map> +#include <string> + +#include <grpc++/support/auth_context.h> + +namespace grpc { + +class AuthMetadataProcessor { + public: + virtual ~AuthMetadataProcessor() {} + + // If this method returns true, the Process function will be scheduled in + // a different thread from the one processing the call. + virtual bool IsBlocking() const { return true; } + + // context is read/write: it contains the properties of the channel peer and + // it is the job of the Process method to augment it with properties derived + // from the passed-in auth_metadata. + // consumed_auth_metadata needs to be filled with metadata that has been + // consumed by the processor and will be removed from the call. + // Returns true if successful. + virtual bool Process( + const std::multimap<grpc::string, grpc::string>& auth_metadata, + AuthContext* context, + std::multimap<grpc::string, grpc::string>* consumed_auth_metadata) = 0; +}; + +} // namespace grpc + +#endif // GRPCXX_AUTH_METADATA_PROCESSOR_H_ + diff --git a/include/grpc++/server_credentials.h b/include/grpc++/server_credentials.h index 16b78c08af..486c35c56b 100644 --- a/include/grpc++/server_credentials.h +++ b/include/grpc++/server_credentials.h @@ -38,6 +38,7 @@ #include <vector> #include <grpc++/support/config.h> +#include <grpc++/auth_metadata_processor.h> struct grpc_server; @@ -54,6 +55,11 @@ class ServerCredentials { virtual int AddPortToServer(const grpc::string& addr, grpc_server* server) = 0; + + // This method is not thread-safe and has to be called before the server is + // started. The last call to this function wins. + virtual void SetAuthMetadataProcessor( + const std::shared_ptr<AuthMetadataProcessor>& processor) = 0; }; // Options to create ServerCredentials with SSL diff --git a/include/grpc++/support/auth_context.h b/include/grpc++/support/auth_context.h index f4f2dcf5bb..e6b793972a 100644 --- a/include/grpc++/support/auth_context.h +++ b/include/grpc++/support/auth_context.h @@ -88,6 +88,11 @@ class AuthContext { // Iteration over all the properties. virtual AuthPropertyIterator begin() const = 0; virtual AuthPropertyIterator end() const = 0; + + // Mutation functions: should only be used by an AuthMetadataProcessor. + virtual void AddProperty(const grpc::string& key, + const grpc::string& value) = 0; + virtual bool SetPeerIdentityPropertyName(const grpc::string& name) = 0; }; } // namespace grpc diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 7f8f4d4a05..43861e5c3d 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -292,9 +292,10 @@ typedef void (*grpc_process_auth_metadata_done_cb)( typedef struct { /* The context object is read/write: it contains the properties of the channel peer and it is the job of the process function to augment it with - properties derived from the passed-in metadata. */ + properties derived from the passed-in metadata. + The lifetime of these objects is guaranteed until cb is invoked. */ void (*process)(void *state, grpc_auth_context *context, - const grpc_metadata *md, size_t md_count, + const grpc_metadata *md, size_t num_md, grpc_process_auth_metadata_done_cb cb, void *user_data); void *state; } grpc_auth_metadata_processor; diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c index 6e831431fa..57729be32c 100644 --- a/src/core/security/server_auth_filter.c +++ b/src/core/security/server_auth_filter.c @@ -50,6 +50,7 @@ typedef struct call_data { handling it. */ grpc_iomgr_closure auth_on_recv; grpc_transport_stream_op transport_op; + grpc_metadata_array md; const grpc_metadata *consumed_md; size_t num_consumed_md; grpc_stream_op *md_op; @@ -134,6 +135,7 @@ static void on_md_processing_done( grpc_transport_stream_op_add_close(&calld->transport_op, status, &message); grpc_call_next_op(elem, &calld->transport_op); } + grpc_metadata_array_destroy(&calld->md); } static void auth_on_recv(void *user_data, int success) { @@ -145,17 +147,15 @@ static void auth_on_recv(void *user_data, int success) { size_t nops = calld->recv_ops->nops; grpc_stream_op *ops = calld->recv_ops->ops; for (i = 0; i < nops; i++) { - grpc_metadata_array md_array; grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA || calld->got_client_metadata) continue; calld->got_client_metadata = 1; if (chand->processor.process == NULL) continue; calld->md_op = op; - md_array = metadata_batch_to_md_array(&op->data.metadata); + calld->md = metadata_batch_to_md_array(&op->data.metadata); chand->processor.process(chand->processor.state, calld->auth_context, - md_array.metadata, md_array.count, + calld->md.metadata, calld->md.count, on_md_processing_done, elem); - grpc_metadata_array_destroy(&md_array); return; } } diff --git a/src/cpp/common/secure_auth_context.cc b/src/cpp/common/secure_auth_context.cc index 87d7bab75c..dc41083a48 100644 --- a/src/cpp/common/secure_auth_context.cc +++ b/src/cpp/common/secure_auth_context.cc @@ -93,4 +93,16 @@ AuthPropertyIterator SecureAuthContext::end() const { return AuthPropertyIterator(); } +void SecureAuthContext::AddProperty(const grpc::string& key, + const grpc::string& value) { + if (!ctx_) return; + grpc_auth_context_add_property(ctx_, key.c_str(), value.data(), value.size()); +} + +bool SecureAuthContext::SetPeerIdentityPropertyName(const grpc::string& name) { + if (!ctx_) return false; + return grpc_auth_context_set_peer_identity_property_name(ctx_, + name.c_str()) != 0; +} + } // namespace grpc diff --git a/src/cpp/common/secure_auth_context.h b/src/cpp/common/secure_auth_context.h index 01b7126189..8a866eaaa9 100644 --- a/src/cpp/common/secure_auth_context.h +++ b/src/cpp/common/secure_auth_context.h @@ -57,6 +57,12 @@ class SecureAuthContext GRPC_FINAL : public AuthContext { AuthPropertyIterator end() const GRPC_OVERRIDE; + void AddProperty(const grpc::string& key, + const grpc::string& value) GRPC_OVERRIDE; + + virtual bool SetPeerIdentityPropertyName(const grpc::string& name) + GRPC_OVERRIDE; + private: grpc_auth_context* ctx_; }; diff --git a/src/cpp/server/insecure_server_credentials.cc b/src/cpp/server/insecure_server_credentials.cc index 800cd36caa..12807e70e7 100644 --- a/src/cpp/server/insecure_server_credentials.cc +++ b/src/cpp/server/insecure_server_credentials.cc @@ -34,6 +34,7 @@ #include <grpc++/server_credentials.h> #include <grpc/grpc.h> +#include <grpc/support/log.h> namespace grpc { namespace { @@ -43,6 +44,11 @@ class InsecureServerCredentialsImpl GRPC_FINAL : public ServerCredentials { grpc_server* server) GRPC_OVERRIDE { return grpc_server_add_insecure_http2_port(server, addr.c_str()); } + void SetAuthMetadataProcessor( + const std::shared_ptr<AuthMetadataProcessor>& processor) GRPC_OVERRIDE { + (void)processor; + GPR_ASSERT(0); // Should not be called on InsecureServerCredentials. + } }; } // namespace diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc index f203cf7f49..a7d11856a0 100644 --- a/src/cpp/server/secure_server_credentials.cc +++ b/src/cpp/server/secure_server_credentials.cc @@ -31,15 +31,77 @@ * */ +#include <functional> +#include <map> +#include <memory> + + +#include "src/cpp/common/secure_auth_context.h" #include "src/cpp/server/secure_server_credentials.h" +#include <grpc++/auth_metadata_processor.h> + namespace grpc { +void AuthMetadataProcessorAyncWrapper::Process( + void* wrapper, grpc_auth_context* context, const grpc_metadata* md, + size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data) { + auto* w = reinterpret_cast<AuthMetadataProcessorAyncWrapper*>(wrapper); + if (w->processor_ == nullptr) { + // Early exit. + cb(user_data, nullptr, 0, nullptr, 0, GRPC_STATUS_OK, nullptr); + return; + } + if (w->processor_->IsBlocking()) { + w->thread_pool_->Add( + std::bind(&AuthMetadataProcessorAyncWrapper::InvokeProcessor, w, + context, md, num_md, cb, user_data)); + } else { + // invoke directly. + w->InvokeProcessor(context, md, num_md, cb, user_data); + } +} + +void AuthMetadataProcessorAyncWrapper::InvokeProcessor( + grpc_auth_context* ctx, + const grpc_metadata* md, size_t num_md, + grpc_process_auth_metadata_done_cb cb, void* user_data) { + Metadata metadata; + for (size_t i = 0; i < num_md; i++) { + metadata.insert(std::make_pair( + md[i].key, grpc::string(md[i].value, md[i].value_length))); + } + SecureAuthContext context(ctx); + Metadata consumed_metadata; + bool ok = processor_->Process(metadata, &context, &consumed_metadata); + if (ok) { + std::vector<grpc_metadata> consumed_md(consumed_metadata.size()); + for (const auto& entry : consumed_metadata) { + consumed_md.push_back({entry.first.c_str(), + entry.second.data(), + entry.second.size(), + 0, + {{nullptr, nullptr, nullptr, nullptr}}}); + } + cb(user_data, &consumed_md[0], consumed_md.size(), nullptr, 0, + GRPC_STATUS_OK, nullptr); + } else { + cb(user_data, nullptr, 0, nullptr, 0, GRPC_STATUS_UNAUTHENTICATED, nullptr); + } +} + int SecureServerCredentials::AddPortToServer(const grpc::string& addr, grpc_server* server) { return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_); } +void SecureServerCredentials::SetAuthMetadataProcessor( + const std::shared_ptr<AuthMetadataProcessor>& processor) { + processor_.reset(new AuthMetadataProcessorAyncWrapper(processor)); + grpc_server_credentials_set_auth_metadata_processor( + creds_, {AuthMetadataProcessorAyncWrapper::Process, processor_.get()}); +} + std::shared_ptr<ServerCredentials> SslServerCredentials( const SslServerCredentialsOptions& options) { std::vector<grpc_ssl_pem_key_cert_pair> pem_key_cert_pairs; diff --git a/src/cpp/server/secure_server_credentials.h b/src/cpp/server/secure_server_credentials.h index d3d37b188d..e427280a37 100644 --- a/src/cpp/server/secure_server_credentials.h +++ b/src/cpp/server/secure_server_credentials.h @@ -34,12 +34,35 @@ #ifndef GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H #define GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H +#include <memory> + #include <grpc++/server_credentials.h> #include <grpc/grpc_security.h> +#include "src/cpp/server/thread_pool_interface.h" + namespace grpc { +class AuthMetadataProcessorAyncWrapper GRPC_FINAL { + public: + static void Process(void* wrapper, grpc_auth_context* context, + const grpc_metadata* md, size_t num_md, + grpc_process_auth_metadata_done_cb cb, void* user_data); + + AuthMetadataProcessorAyncWrapper( + const std::shared_ptr<AuthMetadataProcessor>& processor) + : thread_pool_(CreateDefaultThreadPool()), processor_(processor) {} + + private: + typedef std::multimap<grpc::string, grpc::string> Metadata; + void InvokeProcessor(grpc_auth_context* context, const grpc_metadata* md, + size_t num_md, grpc_process_auth_metadata_done_cb cb, + void* user_data); + std::unique_ptr<ThreadPoolInterface> thread_pool_; + std::shared_ptr<AuthMetadataProcessor> processor_; +}; + class SecureServerCredentials GRPC_FINAL : public ServerCredentials { public: explicit SecureServerCredentials(grpc_server_credentials* creds) @@ -51,8 +74,12 @@ class SecureServerCredentials GRPC_FINAL : public ServerCredentials { int AddPortToServer(const grpc::string& addr, grpc_server* server) GRPC_OVERRIDE; + void SetAuthMetadataProcessor( + const std::shared_ptr<AuthMetadataProcessor>& processor) GRPC_OVERRIDE; + private: - grpc_server_credentials* const creds_; + grpc_server_credentials* creds_; + std::unique_ptr<AuthMetadataProcessorAyncWrapper> processor_; }; } // namespace grpc diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc index c71ef58023..e1f6bf05ce 100644 --- a/test/cpp/common/secure_auth_context_test.cc +++ b/test/cpp/common/secure_auth_context_test.cc @@ -57,12 +57,12 @@ TEST_F(SecureAuthContextTest, EmptyContext) { TEST_F(SecureAuthContextTest, Properties) { grpc_auth_context* ctx = grpc_auth_context_create(NULL); - grpc_auth_context_add_cstring_property(ctx, "name", "chapi"); - grpc_auth_context_add_cstring_property(ctx, "name", "chapo"); - grpc_auth_context_add_cstring_property(ctx, "foo", "bar"); - EXPECT_EQ(1, grpc_auth_context_set_peer_identity_property_name(ctx, "name")); - SecureAuthContext context(ctx); + context.AddProperty("name", "chapi"); + context.AddProperty("name", "chapo"); + context.AddProperty("foo", "bar"); + EXPECT_TRUE(context.SetPeerIdentityPropertyName("name")); + std::vector<grpc::string> peer_identity = context.GetPeerIdentity(); EXPECT_EQ(2u, peer_identity.size()); EXPECT_EQ("chapi", peer_identity[0]); @@ -75,12 +75,12 @@ TEST_F(SecureAuthContextTest, Properties) { TEST_F(SecureAuthContextTest, Iterators) { grpc_auth_context* ctx = grpc_auth_context_create(NULL); - grpc_auth_context_add_cstring_property(ctx, "name", "chapi"); - grpc_auth_context_add_cstring_property(ctx, "name", "chapo"); - grpc_auth_context_add_cstring_property(ctx, "foo", "bar"); - EXPECT_EQ(1, grpc_auth_context_set_peer_identity_property_name(ctx, "name")); - SecureAuthContext context(ctx); + context.AddProperty("name", "chapi"); + context.AddProperty("name", "chapo"); + context.AddProperty("foo", "bar"); + EXPECT_TRUE(context.SetPeerIdentityPropertyName("name")); + AuthPropertyIterator iter = context.begin(); EXPECT_TRUE(context.end() != iter); AuthProperty p0 = *iter; diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 887f6169af..0cd6ddd020 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -760,7 +760,8 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = include/grpc++/channel.h \ +INPUT = include/grpc++/auth_metadata_processor.h \ +include/grpc++/channel.h \ include/grpc++/client_context.h \ include/grpc++/completion_queue.h \ include/grpc++/create_channel.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 84b13f94a7..b2ebb2d31e 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -760,7 +760,8 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = include/grpc++/channel.h \ +INPUT = include/grpc++/auth_metadata_processor.h \ +include/grpc++/channel.h \ include/grpc++/client_context.h \ include/grpc++/completion_queue.h \ include/grpc++/create_channel.h \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index a7fd884cd8..98851a9288 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -13112,6 +13112,7 @@ "grpc" ], "headers": [ + "include/grpc++/auth_metadata_processor.h", "include/grpc++/channel.h", "include/grpc++/client_context.h", "include/grpc++/completion_queue.h", @@ -13163,6 +13164,7 @@ "language": "c++", "name": "grpc++", "src": [ + "include/grpc++/auth_metadata_processor.h", "include/grpc++/channel.h", "include/grpc++/client_context.h", "include/grpc++/completion_queue.h", @@ -13289,6 +13291,7 @@ "grpc_unsecure" ], "headers": [ + "include/grpc++/auth_metadata_processor.h", "include/grpc++/channel.h", "include/grpc++/client_context.h", "include/grpc++/completion_queue.h", @@ -13337,6 +13340,7 @@ "language": "c++", "name": "grpc++_unsecure", "src": [ + "include/grpc++/auth_metadata_processor.h", "include/grpc++/channel.h", "include/grpc++/client_context.h", "include/grpc++/completion_queue.h", diff --git a/vsprojects/grpc++/grpc++.vcxproj b/vsprojects/grpc++/grpc++.vcxproj index 53930c1394..0d8cf1d6c3 100644 --- a/vsprojects/grpc++/grpc++.vcxproj +++ b/vsprojects/grpc++/grpc++.vcxproj @@ -213,6 +213,7 @@ </Link> </ItemDefinitionGroup> <ItemGroup> + <ClInclude Include="..\..\include\grpc++\auth_metadata_processor.h" /> <ClInclude Include="..\..\include\grpc++\channel.h" /> <ClInclude Include="..\..\include\grpc++\client_context.h" /> <ClInclude Include="..\..\include\grpc++\completion_queue.h" /> diff --git a/vsprojects/grpc++/grpc++.vcxproj.filters b/vsprojects/grpc++/grpc++.vcxproj.filters index 6bc9ed64d2..e38328b130 100644 --- a/vsprojects/grpc++/grpc++.vcxproj.filters +++ b/vsprojects/grpc++/grpc++.vcxproj.filters @@ -99,6 +99,9 @@ </ClCompile> </ItemGroup> <ItemGroup> + <ClInclude Include="..\..\include\grpc++\auth_metadata_processor.h"> + <Filter>include\grpc++</Filter> + </ClInclude> <ClInclude Include="..\..\include\grpc++\channel.h"> <Filter>include\grpc++</Filter> </ClInclude> diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj index 12fa1b781c..d5e44d64d4 100644 --- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj +++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj @@ -213,6 +213,7 @@ </Link> </ItemDefinitionGroup> <ItemGroup> + <ClInclude Include="..\..\include\grpc++\auth_metadata_processor.h" /> <ClInclude Include="..\..\include\grpc++\channel.h" /> <ClInclude Include="..\..\include\grpc++\client_context.h" /> <ClInclude Include="..\..\include\grpc++\completion_queue.h" /> diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters index 17d9d5332f..da7d87e173 100644 --- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters +++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters @@ -84,6 +84,9 @@ </ClCompile> </ItemGroup> <ItemGroup> + <ClInclude Include="..\..\include\grpc++\auth_metadata_processor.h"> + <Filter>include\grpc++</Filter> + </ClInclude> <ClInclude Include="..\..\include\grpc++\channel.h"> <Filter>include\grpc++</Filter> </ClInclude> |