Composition of arbitrarily many CallCredentials
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index b3eeaad..0efd233 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -1091,37 +1091,41 @@
       _auth.AccessTokenCallCredentials(access_token))
 
 
-def composite_call_credentials(call_credentials, additional_call_credentials):
-  """Compose two CallCredentials to make a new one.
+def composite_call_credentials(*call_credentials):
+  """Compose multiple CallCredentials to make a new CallCredentials.
 
   Args:
-    call_credentials: A CallCredentials object.
-    additional_call_credentials: Another CallCredentials object to compose on
-      top of call_credentials.
+    *call_credentials: At least two CallCredentials objects.
 
   Returns:
-    A new CallCredentials composed of the two given CallCredentials.
+    A CallCredentials object composed of the given CallCredentials objects.
   """
+  from grpc import _credential_composition
+  cygrpc_call_credentials = tuple(
+      single_call_credentials._credentials
+      for single_call_credentials in call_credentials)
   return CallCredentials(
-      _cygrpc.call_credentials_composite(
-          call_credentials._credentials,
-          additional_call_credentials._credentials))
+      _credential_composition.call(cygrpc_call_credentials))
 
 
-def composite_channel_credentials(channel_credentials, call_credentials):
-  """Compose a ChannelCredentials and a CallCredentials.
+def composite_channel_credentials(channel_credentials, *call_credentials):
+  """Compose a ChannelCredentials and one or more CallCredentials objects.
 
   Args:
     channel_credentials: A ChannelCredentials.
-    call_credentials: A CallCredentials.
+    *call_credentials: One or more CallCredentials objects.
 
   Returns:
     A ChannelCredentials composed of the given ChannelCredentials and
-      CallCredentials.
+      CallCredentials objects.
   """
+  from grpc import _credential_composition
+  cygrpc_call_credentials = tuple(
+      single_call_credentials._credentials
+      for single_call_credentials in call_credentials)
   return ChannelCredentials(
-      _cygrpc.channel_credentials_composite(
-          channel_credentials._credentials, call_credentials._credentials))
+      _credential_composition.channel(
+          channel_credentials._credentials, cygrpc_call_credentials))
 
 
 def ssl_server_credentials(
diff --git a/src/python/grpcio/grpc/_credential_composition.py b/src/python/grpcio/grpc/_credential_composition.py
new file mode 100644
index 0000000..9cb5508
--- /dev/null
+++ b/src/python/grpcio/grpc/_credential_composition.py
@@ -0,0 +1,48 @@
+# Copyright 2016, 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.
+
+from grpc._cython import cygrpc
+
+
+def _call(call_credentialses):
+  call_credentials_iterator = iter(call_credentialses)
+  composition = next(call_credentials_iterator)
+  for additional_call_credentials in call_credentials_iterator:
+    composition = cygrpc.call_credentials_composite(
+        composition, additional_call_credentials)
+  return composition
+
+
+def call(call_credentialses):
+  return _call(call_credentialses)
+
+
+def channel(channel_credentials, call_credentialses):
+  return cygrpc.channel_credentials_composite(
+      channel_credentials, _call(call_credentialses))
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index 45eb75b..dcaef0d 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -12,6 +12,7 @@
   "_channel_test.ChannelTest", 
   "_compression_test.CompressionTest",
   "_connectivity_channel_test.ConnectivityStatesTest",
+  "_credentials_test.CredentialsTest",
   "_empty_message_test.EmptyMessageTest",
   "_exit_test.ExitTest",
   "_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
diff --git a/src/python/grpcio_tests/tests/unit/_credentials_test.py b/src/python/grpcio_tests/tests/unit/_credentials_test.py
new file mode 100644
index 0000000..87af85a
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_credentials_test.py
@@ -0,0 +1,72 @@
+# Copyright 2016, 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.
+
+"""Tests of credentials."""
+
+import unittest
+
+import grpc
+
+
+class CredentialsTest(unittest.TestCase):
+
+  def test_call_credentials_composition(self):
+    first = grpc.access_token_call_credentials('abc')
+    second = grpc.access_token_call_credentials('def')
+    third = grpc.access_token_call_credentials('ghi')
+
+    first_and_second = grpc.composite_call_credentials(first, second)
+    first_second_and_third = grpc.composite_call_credentials(
+        first, second, third)
+    
+    self.assertIsInstance(first_and_second, grpc.CallCredentials)
+    self.assertIsInstance(first_second_and_third, grpc.CallCredentials)
+
+  def test_channel_credentials_composition(self):
+    first_call_credentials = grpc.access_token_call_credentials('abc')
+    second_call_credentials = grpc.access_token_call_credentials('def')
+    third_call_credentials = grpc.access_token_call_credentials('ghi')
+    channel_credentials = grpc.ssl_channel_credentials()
+
+    channel_and_first = grpc.composite_channel_credentials(
+        channel_credentials, first_call_credentials)
+    channel_first_and_second = grpc.composite_channel_credentials(
+        channel_credentials, first_call_credentials, second_call_credentials)
+    channel_first_second_and_third = grpc.composite_channel_credentials(
+        channel_credentials, first_call_credentials, second_call_credentials,
+        third_call_credentials)
+
+    self.assertIsInstance(channel_and_first, grpc.ChannelCredentials)
+    self.assertIsInstance(channel_first_and_second, grpc.ChannelCredentials)
+    self.assertIsInstance(
+        channel_first_second_and_third, grpc.ChannelCredentials)
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)