Merge branch 'master' of github.com:grpc/grpc into cpp_auth_md_processor
diff --git a/BUILD b/BUILD
index d612d9c..bc2136d 100644
--- a/BUILD
+++ b/BUILD
@@ -719,6 +719,7 @@
     "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",
@@ -808,6 +809,7 @@
     "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 543bc09..1015b2e 100644
--- a/Makefile
+++ b/Makefile
@@ -4631,6 +4631,7 @@
     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 \
@@ -4875,6 +4876,7 @@
     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 a5be837..cbb40a8 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 0000000..c0631bc
--- /dev/null
+++ b/include/grpc++/auth_metadata_processor.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * 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 <grpc++/support/auth_context.h>
+#include <grpc++/support/status.h>
+#include <grpc++/support/string_ref.h>
+
+namespace grpc {
+
+class AuthMetadataProcessor {
+ public:
+  typedef std::multimap<grpc::string_ref, grpc::string_ref> InputMetadata;
+  typedef std::multimap<grpc::string, grpc::string_ref> OutputMetadata;
+
+  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.
+  // TODO(jboeuf).
+  virtual Status Process(const InputMetadata& auth_metadata,
+                         AuthContext* context,
+                         OutputMetadata* consumed_auth_metadata,
+                         OutputMetadata* response_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 16b78c0..486c35c 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 @@
 
   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 67e3e66..5d5f8e8 100644
--- a/include/grpc++/support/auth_context.h
+++ b/include/grpc++/support/auth_context.h
@@ -89,6 +89,11 @@
   // 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 6ee6933..e2205ee 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -288,9 +288,10 @@
 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 6e83143..57729be 100644
--- a/src/core/security/server_auth_filter.c
+++ b/src/core/security/server_auth_filter.c
@@ -50,6 +50,7 @@
      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 @@
     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 @@
     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 b18a853..823ad8b 100644
--- a/src/cpp/common/secure_auth_context.cc
+++ b/src/cpp/common/secure_auth_context.cc
@@ -94,4 +94,16 @@
   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 7f622b8..cc09a29 100644
--- a/src/cpp/common/secure_auth_context.h
+++ b/src/cpp/common/secure_auth_context.h
@@ -57,6 +57,12 @@
 
   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 800cd36..12807e7 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 @@
                       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 5bce9ca..f8847b8 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -31,15 +31,89 @@
  *
  */
 
+#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) {
+  AuthMetadataProcessor::InputMetadata metadata;
+  for (size_t i = 0; i < num_md; i++) {
+    metadata.insert(std::make_pair(
+        md[i].key, grpc::string_ref(md[i].value, md[i].value_length)));
+  }
+  SecureAuthContext context(ctx);
+  AuthMetadataProcessor::OutputMetadata consumed_metadata;
+  AuthMetadataProcessor::OutputMetadata response_metadata;
+
+  Status status = processor_->Process(metadata, &context, &consumed_metadata,
+                                      &response_metadata);
+
+  std::vector<grpc_metadata> consumed_md(consumed_metadata.size());
+  for (auto it = consumed_metadata.begin(); it != consumed_metadata.end();
+       ++it) {
+    consumed_md.push_back({it->first.c_str(),
+                           it->second.data(),
+                           it->second.size(),
+                           0,
+                           {{nullptr, nullptr, nullptr, nullptr}}});
+  }
+
+  std::vector<grpc_metadata> response_md(response_metadata.size());
+  for (auto it = response_metadata.begin(); it != response_metadata.end();
+       ++it) {
+    response_md.push_back({it->first.c_str(),
+                           it->second.data(),
+                           it->second.size(),
+                           0,
+                           {{nullptr, nullptr, nullptr, nullptr}}});
+  }
+  cb(user_data, &consumed_md[0], consumed_md.size(), &response_md[0],
+     response_md.size(), static_cast<grpc_status_code>(status.error_code()),
+     status.error_message().c_str());
+}
+
 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 d3d37b1..d15b793 100644
--- a/src/cpp/server/secure_server_credentials.h
+++ b/src/cpp/server/secure_server_credentials.h
@@ -34,12 +34,34 @@
 #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:
+  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 +73,12 @@
   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 25538c1..4ab7fca 100644
--- a/test/cpp/common/secure_auth_context_test.cc
+++ b/test/cpp/common/secure_auth_context_test.cc
@@ -60,12 +60,12 @@
 
 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_ref> peer_identity = context.GetPeerIdentity();
   EXPECT_EQ(2u, peer_identity.size());
   EXPECT_EQ("chapi", ToString(peer_identity[0]));
@@ -78,12 +78,12 @@
 
 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 887f616..0cd6ddd 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -760,7 +760,8 @@
 # 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 84b13f9..b2ebb2d 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -760,7 +760,8 @@
 # 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 42942e4..7be6b34 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -13135,6 +13135,7 @@
       "grpc"
     ], 
     "headers": [
+      "include/grpc++/auth_metadata_processor.h", 
       "include/grpc++/channel.h", 
       "include/grpc++/client_context.h", 
       "include/grpc++/completion_queue.h", 
@@ -13186,6 +13187,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", 
@@ -13315,6 +13317,7 @@
       "grpc_unsecure"
     ], 
     "headers": [
+      "include/grpc++/auth_metadata_processor.h", 
       "include/grpc++/channel.h", 
       "include/grpc++/client_context.h", 
       "include/grpc++/completion_queue.h", 
@@ -13363,6 +13366,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 53930c1..0d8cf1d 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 6bc9ed6..e38328b 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 12fa1b7..d5e44d6 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 17d9d53..da7d87e 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>