aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD2
-rw-r--r--Makefile2
-rw-r--r--build.json1
-rw-r--r--include/grpc++/auth_metadata_processor.h67
-rw-r--r--include/grpc++/server_credentials.h6
-rw-r--r--include/grpc++/support/auth_context.h5
-rw-r--r--include/grpc/grpc_security.h5
-rw-r--r--src/core/security/server_auth_filter.c8
-rw-r--r--src/cpp/common/secure_auth_context.cc12
-rw-r--r--src/cpp/common/secure_auth_context.h6
-rw-r--r--src/cpp/server/insecure_server_credentials.cc6
-rw-r--r--src/cpp/server/secure_server_credentials.cc62
-rw-r--r--src/cpp/server/secure_server_credentials.h29
-rw-r--r--test/cpp/common/secure_auth_context_test.cc20
-rw-r--r--tools/doxygen/Doxyfile.c++3
-rw-r--r--tools/doxygen/Doxyfile.c++.internal3
-rw-r--r--tools/run_tests/sources_and_headers.json4
-rw-r--r--vsprojects/grpc++/grpc++.vcxproj1
-rw-r--r--vsprojects/grpc++/grpc++.vcxproj.filters3
-rw-r--r--vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj1
-rw-r--r--vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters3
21 files changed, 230 insertions, 19 deletions
diff --git a/BUILD b/BUILD
index 0e244cabcd..aca61fbe8c 100644
--- a/BUILD
+++ b/BUILD
@@ -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",
diff --git a/Makefile b/Makefile
index 975633f998..2a2ffa7ce2 100644
--- a/Makefile
+++ b/Makefile
@@ -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>