Work towards invocation-side security.
diff --git a/src/python/src/grpc/_adapter/_c_test.py b/src/python/src/grpc/_adapter/_c_test.py
index 44aff44..d81c63e 100644
--- a/src/python/src/grpc/_adapter/_c_test.py
+++ b/src/python/src/grpc/_adapter/_c_test.py
@@ -70,7 +70,7 @@
   def testChannel(self):
     _c.init()
 
-    channel = _c.Channel('test host:12345')
+    channel = _c.Channel('test host:12345', None)
     del channel
 
     _c.shut_down()
@@ -81,7 +81,7 @@
 
     _c.init()
 
-    channel = _c.Channel('%s:%d' % (host, 12345))
+    channel = _c.Channel('%s:%d' % (host, 12345), None)
     call = _c.Call(channel, method, host, time.time() + _TIMEOUT)
     del call
     del channel
diff --git a/src/python/src/grpc/_adapter/_channel.c b/src/python/src/grpc/_adapter/_channel.c
index 3ba943e..9cf580b 100644
--- a/src/python/src/grpc/_adapter/_channel.c
+++ b/src/python/src/grpc/_adapter/_channel.c
@@ -35,18 +35,28 @@
 
 #include <Python.h>
 #include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+
+#include "grpc/_adapter/_client_credentials.h"
 
 static int pygrpc_channel_init(Channel *self, PyObject *args, PyObject *kwds) {
   const char *hostport;
-  static char *kwlist[] = {"hostport", NULL};
+  PyObject *client_credentials;
+  static char *kwlist[] = {"hostport", "client_credentials", NULL};
 
-  if (!(PyArg_ParseTupleAndKeywords(args, kwds, "s:Channel", kwlist,
-                                    &hostport))) {
+  if (!(PyArg_ParseTupleAndKeywords(args, kwds, "sO:Channel", kwlist,
+                                    &hostport, &client_credentials))) {
     return -1;
   }
-
-  self->c_channel = grpc_channel_create(hostport, NULL);
-  return 0;
+  if (client_credentials == Py_None) {
+    self->c_channel = grpc_channel_create(hostport, NULL);
+    return 0;
+  } else {
+    self->c_channel = grpc_secure_channel_create(
+        ((ClientCredentials *)client_credentials)->c_client_credentials,
+        hostport, NULL);
+    return 0;
+  }
 }
 
 static void pygrpc_channel_dealloc(Channel *self) {
diff --git a/src/python/src/grpc/_adapter/_client_credentials.c b/src/python/src/grpc/_adapter/_client_credentials.c
index b970c86..e8ccff8 100644
--- a/src/python/src/grpc/_adapter/_client_credentials.c
+++ b/src/python/src/grpc/_adapter/_client_credentials.c
@@ -58,6 +58,7 @@
     self->c_client_credentials =
         grpc_ssl_credentials_create(root_certificates, NULL);
   }
+  return 0;
 }
 
 static void pygrpc_client_credentials_dealloc(ClientCredentials *self) {
diff --git a/src/python/src/grpc/_adapter/_face_test_case.py b/src/python/src/grpc/_adapter/_face_test_case.py
index 8cce322..475d780 100644
--- a/src/python/src/grpc/_adapter/_face_test_case.py
+++ b/src/python/src/grpc/_adapter/_face_test_case.py
@@ -85,7 +85,8 @@
     port = fore_link.port()
     rear_link = rear.RearLink(
         'localhost', port, pool,
-        serialization.request_serializers, serialization.response_deserializers)
+        serialization.request_serializers,
+        serialization.response_deserializers, False, None, None, None)
     rear_link.start()
     front = tickets_implementations.front(pool, pool, pool)
     back = tickets_implementations.back(
diff --git a/src/python/src/grpc/_adapter/_links_test.py b/src/python/src/grpc/_adapter/_links_test.py
index 6b3bcee..5d7e677 100644
--- a/src/python/src/grpc/_adapter/_links_test.py
+++ b/src/python/src/grpc/_adapter/_links_test.py
@@ -75,7 +75,7 @@
 
     rear_link = rear.RearLink(
         'localhost', port, self.rear_link_pool, {test_method: None},
-        {test_method: None})
+        {test_method: None}, False, None, None, None)
     rear_link.join_fore_link(test_fore_link)
     test_fore_link.join_rear_link(rear_link)
     rear_link.start()
@@ -129,7 +129,7 @@
 
     rear_link = rear.RearLink(
         'localhost', port, self.rear_link_pool, {test_method: _IDENTITY},
-        {test_method: _IDENTITY})
+        {test_method: _IDENTITY}, False, None, None, None)
     rear_link.join_fore_link(test_fore_link)
     test_fore_link.join_rear_link(rear_link)
     rear_link.start()
@@ -193,7 +193,7 @@
     rear_link = rear.RearLink(
         'localhost', port, self.rear_link_pool,
         {test_method: scenario.serialize_request},
-        {test_method: scenario.deserialize_response})
+        {test_method: scenario.deserialize_response}, False, None, None, None)
     rear_link.join_fore_link(test_fore_link)
     test_fore_link.join_rear_link(rear_link)
     rear_link.start()
diff --git a/src/python/src/grpc/_adapter/_lonely_rear_link_test.py b/src/python/src/grpc/_adapter/_lonely_rear_link_test.py
index 9a13309..77821ba 100644
--- a/src/python/src/grpc/_adapter/_lonely_rear_link_test.py
+++ b/src/python/src/grpc/_adapter/_lonely_rear_link_test.py
@@ -50,7 +50,8 @@
     self.pool.shutdown(wait=True)
 
   def testUpAndDown(self):
-    rear_link = rear.RearLink('nonexistent', 54321, self.pool, {}, {})
+    rear_link = rear.RearLink(
+        'nonexistent', 54321, self.pool, {}, {}, False, None, None, None)
 
     rear_link.start()
     rear_link.stop()
@@ -63,7 +64,7 @@
 
     rear_link = rear.RearLink(
         'nonexistent', 54321, self.pool, {test_method: None},
-        {test_method: None})
+        {test_method: None}, False, None, None, None)
     rear_link.join_fore_link(fore_link)
     rear_link.start()
 
diff --git a/src/python/src/grpc/_adapter/_low_test.py b/src/python/src/grpc/_adapter/_low_test.py
index 898c62c..03e3f47 100644
--- a/src/python/src/grpc/_adapter/_low_test.py
+++ b/src/python/src/grpc/_adapter/_low_test.py
@@ -56,7 +56,7 @@
     finish_tag = object()
 
     completion_queue = _low.CompletionQueue()
-    channel = _low.Channel('%s:%d' % (host, port))
+    channel = _low.Channel('%s:%d' % (host, port), None)
     client_call = _low.Call(channel, method, host, deadline)
 
     client_call.invoke(completion_queue, metadata_tag, finish_tag)
@@ -87,7 +87,7 @@
     self.server.start()
 
     self.client_completion_queue = _low.CompletionQueue()
-    self.channel = _low.Channel('%s:%d' % (self.host, port))
+    self.channel = _low.Channel('%s:%d' % (self.host, port), None)
 
   def tearDown(self):
     self.server.stop()
@@ -265,7 +265,7 @@
     self.server.start()
 
     self.client_completion_queue = _low.CompletionQueue()
-    self.channel = _low.Channel('%s:%d' % (self.host, port))
+    self.channel = _low.Channel('%s:%d' % (self.host, port), None)
 
   def tearDown(self):
     self.server.stop()
diff --git a/src/python/src/grpc/_adapter/rear.py b/src/python/src/grpc/_adapter/rear.py
index 94ff66f..bfde5f5 100644
--- a/src/python/src/grpc/_adapter/rear.py
+++ b/src/python/src/grpc/_adapter/rear.py
@@ -92,7 +92,8 @@
   """An invocation-side bridge between RPC Framework and the C-ish _low code."""
 
   def __init__(
-      self, host, port, pool, request_serializers, response_deserializers):
+      self, host, port, pool, request_serializers, response_deserializers,
+      secure, root_certificates, private_key, certificate_chain):
     """Constructor.
 
     Args:
@@ -103,6 +104,13 @@
         serializer behaviors.
       response_deserializers: A dict from RPC method names to response object
         deserializer behaviors.
+      secure: A boolean indicating whether or not to use a secure connection.
+      root_certificates: The PEM-encoded root certificates or None to ask for
+        them to be retrieved from a default location.
+      private_key: The PEM-encoded private key to use or None if no private
+        key should be used.
+      certificate_chain: The PEM-encoded certificate chain to use or None if
+        no certificate chain should be used.
     """
     self._condition = threading.Condition()
     self._host = host
@@ -116,6 +124,14 @@
     self._channel = None
     self._rpc_states = {}
     self._spinning = False
+    if secure:
+      self._client_credentials = _low.ClientCredentials(
+          root_certificates, private_key, certificate_chain)
+    else:
+      self._client_credentials = None
+    self._root_certificates = root_certificates
+    self._private_key = private_key
+    self._certificate_chain = certificate_chain
 
   def _on_write_event(self, operation_id, event, rpc_state):
     if event.write_accepted:
@@ -310,7 +326,8 @@
     """
     with self._condition:
       self._completion_queue = _low.CompletionQueue()
-      self._channel = _low.Channel('%s:%d' % (self._host, self._port))
+      self._channel = _low.Channel(
+          '%s:%d' % (self._host, self._port), self._client_credentials)
     return self
 
   def _stop(self):
@@ -369,11 +386,17 @@
 
 class _ActivatedRearLink(ticket_interfaces.RearLink, activated.Activated):
 
-  def __init__(self, host, port, request_serializers, response_deserializers):
+  def __init__(
+      self, host, port, request_serializers, response_deserializers, secure,
+      root_certificates, private_key, certificate_chain):
     self._host = host
     self._port = port
     self._request_serializers = request_serializers
     self._response_deserializers = response_deserializers
+    self._secure = secure
+    self._root_certificates = root_certificates
+    self._private_key = private_key
+    self._certificate_chain = certificate_chain
 
     self._lock = threading.Lock()
     self._pool = None
@@ -391,7 +414,8 @@
       self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
       self._rear_link = RearLink(
           self._host, self._port, self._pool, self._request_serializers,
-          self._response_deserializers)
+          self._response_deserializers, self._secure, self._root_certificates,
+          self._private_key, self._certificate_chain)
       self._rear_link.join_fore_link(self._fore_link)
       self._rear_link.start()
     return self
@@ -422,6 +446,7 @@
         self._rear_link.accept_front_to_back_ticket(ticket)
 
 
+# TODO(issue 726): reconcile these two creation functions.
 def activated_rear_link(
     host, port, request_serializers, response_deserializers):
   """Creates a RearLink that is also an activated.Activated.
@@ -436,6 +461,42 @@
       serializer behavior.
     response_deserializers: A dictionary from RPC method name to response
       object deserializer behavior.
+    secure: A boolean indicating whether or not to use a secure connection.
+    root_certificates: The PEM-encoded root certificates or None to ask for
+      them to be retrieved from a default location.
+    private_key: The PEM-encoded private key to use or None if no private key
+      should be used.
+    certificate_chain: The PEM-encoded certificate chain to use or None if no
+      certificate chain should be used.
   """
   return _ActivatedRearLink(
-      host, port, request_serializers, response_deserializers)
+      host, port, request_serializers, response_deserializers, False, None,
+      None, None)
+
+
+
+def secure_activated_rear_link(
+    host, port, request_serializers, response_deserializers, root_certificates,
+    private_key, certificate_chain):
+  """Creates a RearLink that is also an activated.Activated.
+
+  The returned object is only valid for use between calls to its start and stop
+  methods (or in context when used as a context manager).
+
+  Args:
+    host: The host to which to connect for RPC service.
+    port: The port to which to connect for RPC service.
+    request_serializers: A dictionary from RPC method name to request object
+      serializer behavior.
+    response_deserializers: A dictionary from RPC method name to response
+      object deserializer behavior.
+    root_certificates: The PEM-encoded root certificates or None to ask for
+      them to be retrieved from a default location.
+    private_key: The PEM-encoded private key to use or None if no private key
+      should be used.
+    certificate_chain: The PEM-encoded certificate chain to use or None if no
+      certificate chain should be used.
+  """
+  return _ActivatedRearLink(
+      host, port, request_serializers, response_deserializers, True,
+      root_certificates, private_key, certificate_chain)
diff --git a/src/python/src/grpc/early_adopter/_reexport.py b/src/python/src/grpc/early_adopter/_reexport.py
index 35855bc..35f4e85 100644
--- a/src/python/src/grpc/early_adopter/_reexport.py
+++ b/src/python/src/grpc/early_adopter/_reexport.py
@@ -27,9 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-import abc
-import collections
-
 from grpc.framework.face import exceptions as face_exceptions
 from grpc.framework.face import interfaces as face_interfaces
 from grpc.framework.foundation import future
@@ -186,6 +183,14 @@
   def __getattr__(self, attr):
     underlying_attr = self._assembly_stub.__getattr__(attr)
     cardinality = self._cardinalities.get(attr)
+    # TODO(nathaniel): unify this trick with its other occurrence in the code.
+    if cardinality is None:
+      for name, cardinality in self._cardinalities.iteritems():
+        last_slash_index = name.rfind('/')
+        if 0 <= last_slash_index and name[last_slash_index + 1:] == attr:
+          break
+      else:
+        raise AttributeError(attr)
     if cardinality is interfaces.Cardinality.UNARY_UNARY:
       return _UnaryUnarySyncAsync(underlying_attr)
     elif cardinality is interfaces.Cardinality.UNARY_STREAM:
diff --git a/src/python/src/grpc/early_adopter/implementations.py b/src/python/src/grpc/early_adopter/implementations.py
index 241ed7d..6195958 100644
--- a/src/python/src/grpc/early_adopter/implementations.py
+++ b/src/python/src/grpc/early_adopter/implementations.py
@@ -93,13 +93,7 @@
     with self._lock:
       return self._fore_link.port()
 
-def _build_stub(
-    methods, host, port, root_certificates, private_key, certificate_chain):
-  breakdown = _assembly_utilities.break_down_invocation(methods)
-  # TODO(nathaniel): pass security values.
-  activated_rear_link = _rear.activated_rear_link(
-      host, port, breakdown.request_serializers,
-      breakdown.response_deserializers)
+def _build_stub(breakdown, activated_rear_link):
   assembly_stub = _assembly_implementations.assemble_dynamic_inline_stub(
       breakdown.implementations, activated_rear_link)
   return _reexport.stub(assembly_stub, breakdown.cardinalities)
@@ -123,7 +117,11 @@
   Returns:
     An interfaces.Stub affording RPC invocation.
   """
-  return _build_stub(methods, host, port, None, None, None)
+  breakdown = _assembly_utilities.break_down_invocation(methods)
+  activated_rear_link = _rear.activated_rear_link(
+      host, port, breakdown.request_serializers,
+      breakdown.response_deserializers)
+  return _build_stub(breakdown, activated_rear_link)
 
 
 def secure_stub(
@@ -146,8 +144,12 @@
   Returns:
     An interfaces.Stub affording RPC invocation.
   """
-  return _build_stub(
-      methods, host, port, root_certificates, private_key, certificate_chain)
+  breakdown = _assembly_utilities.break_down_invocation(methods)
+  activated_rear_link = _rear.secure_activated_rear_link(
+      host, port, breakdown.request_serializers,
+      breakdown.response_deserializers, root_certificates, private_key,
+      certificate_chain)
+  return _build_stub(breakdown, activated_rear_link)
 
 
 def insecure_server(methods, port):
diff --git a/src/python/src/grpc/framework/assembly/implementations.py b/src/python/src/grpc/framework/assembly/implementations.py
index b9d3148..f7166ed 100644
--- a/src/python/src/grpc/framework/assembly/implementations.py
+++ b/src/python/src/grpc/framework/assembly/implementations.py
@@ -31,16 +31,18 @@
 
 import threading
 
+# tickets_interfaces, face_interfaces, and activated are referenced from
+# specification in this module.
 from grpc.framework.assembly import interfaces
 from grpc.framework.base import util as base_utilities
 from grpc.framework.base.packets import implementations as tickets_implementations
-from grpc.framework.base.packets import interfaces as tickets_interfaces
+from grpc.framework.base.packets import interfaces as tickets_interfaces  # pylint: disable=unused-import
 from grpc.framework.common import cardinality
 from grpc.framework.common import style
 from grpc.framework.face import implementations as face_implementations
-from grpc.framework.face import interfaces as face_interfaces
+from grpc.framework.face import interfaces as face_interfaces  # pylint: disable=unused-import
 from grpc.framework.face import utilities as face_utilities
-from grpc.framework.foundation import activated
+from grpc.framework.foundation import activated  # pylint: disable=unused-import
 from grpc.framework.foundation import logging_pool
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
@@ -138,7 +140,13 @@
     with self._lock:
       behavior = self._behaviors.get(attr)
       if behavior is None:
-        raise AttributeError(attr)
+        for name, behavior in self._behaviors.iteritems():
+          last_slash_index = name.rfind('/')
+          if 0 <= last_slash_index and name[last_slash_index + 1:] == attr:
+            return behavior
+        else:
+          raise AttributeError(
+              '_DynamicInlineStub instance has no attribute "%s"!' % attr)
       else:
         return behavior