Repository: pynamodb/PynamoDB

Issue:
There is no mechanism for passing a session token
Using STS, I should be able to assume a role and pass the `aws_access_key_id` `aws_secret_access_key` and `session_token` to my model. Currently there is no mechanism to pass the session_token to a Model (without mucking with env variables)

Discussion:
julienduchesne: Any update on this?
ikonst: @julienduchesne I'll try to get another reviewer today or tomorrow.
julienduchesne: Here you go @garrettheel

Patch:
diff --git a/docs/awsaccess.rst b/docs/awsaccess.rst
index 6a72c45..38e26ae 100644
--- a/docs/awsaccess.rst
+++ b/docs/awsaccess.rst
@@ -22,6 +22,7 @@ If for some reason you can't use conventional AWS configuration methods, you can
         class Meta:
             aws_access_key_id = 'my_access_key_id'
             aws_secret_access_key = 'my_secret_access_key'
+            aws_session_token = 'my_session_token' # Optional, only for temporary credentials like those received when assuming a role
 
 Finally, see the `AWS CLI documentation <http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-installing-credentials>`_
 for more details on how to pass credentials to botocore.
\ No newline at end of file
diff --git a/pynamodb/connection/table.py b/pynamodb/connection/table.py
index 9b6d5c4..a804136 100644
--- a/pynamodb/connection/table.py
+++ b/pynamodb/connection/table.py
@@ -22,7 +22,8 @@ class TableConnection(object):
                  max_pool_connections=None,
                  extra_headers=None,
                  aws_access_key_id=None,
-                 aws_secret_access_key=None):
+                 aws_secret_access_key=None,
+                 aws_session_token=None):
         self._hash_keyname = None
         self._range_keyname = None
         self.table_name = table_name
@@ -37,7 +38,8 @@ class TableConnection(object):
 
         if aws_access_key_id and aws_secret_access_key:
             self.connection.session.set_credentials(aws_access_key_id,
-                                                    aws_secret_access_key)
+                                                    aws_secret_access_key,
+                                                    aws_session_token)
 
     def get_meta_table(self, refresh=False):
         """
diff --git a/pynamodb/connection/table.pyi b/pynamodb/connection/table.pyi
index 2d1c7c1..c52576d 100644
--- a/pynamodb/connection/table.pyi
+++ b/pynamodb/connection/table.pyi
@@ -20,6 +20,7 @@ class TableConnection:
         extra_headers: Optional[MutableMapping[Text, Text]] = ...,
         aws_access_key_id: Optional[str] = ...,
         aws_secret_access_key: Optional[str] = ...,
+        aws_access_token: Optional[str] = ...,
     ) -> None: ...
 
     def get_operation_kwargs(
@@ -81,4 +82,3 @@ class TableConnection:
     def update_time_to_live(self, ttl_attr_name: Text): ...
     def update_table(self, read_capacity_units: Optional[Any] = ..., write_capacity_units: Optional[Any] = ..., global_secondary_index_updates: Optional[Any] = ...): ...
     def create_table(self, attribute_definitions: Optional[Any] = ..., key_schema: Optional[Any] = ..., read_capacity_units: Optional[Any] = ..., write_capacity_units: Optional[Any] = ..., global_secondary_indexes: Optional[Any] = ..., local_secondary_indexes: Optional[Any] = ..., stream_specification: Optional[Any] = ...): ...
-
diff --git a/pynamodb/models.py b/pynamodb/models.py
index 1481127..fe7a485 100644
--- a/pynamodb/models.py
+++ b/pynamodb/models.py
@@ -208,6 +208,8 @@ class MetaModel(AttributeContainerMeta):
                         setattr(attr_obj, 'aws_access_key_id', None)
                     if not hasattr(attr_obj, 'aws_secret_access_key'):
                         setattr(attr_obj, 'aws_secret_access_key', None)
+                    if not hasattr(attr_obj, 'aws_session_token'):
+                        setattr(attr_obj, 'aws_session_token', None)
                 elif isinstance(attr_obj, Index):
                     attr_obj.Meta.model = cls
                     if not hasattr(attr_obj.Meta, "index_name"):
@@ -1042,7 +1044,8 @@ class Model(AttributeContainer):
                                               max_pool_connections=cls.Meta.max_pool_connections,
                                               extra_headers=cls.Meta.extra_headers,
                                               aws_access_key_id=cls.Meta.aws_access_key_id,
-                                              aws_secret_access_key=cls.Meta.aws_secret_access_key)
+                                              aws_secret_access_key=cls.Meta.aws_secret_access_key,
+                                              aws_session_token=cls.Meta.aws_session_token)
         return cls._connection
 
     def _deserialize(self, attrs):


Test patch:
diff --git a/tests/test_table_connection.py b/tests/test_table_connection.py
index 73deeac..caab960 100644
--- a/tests/test_table_connection.py
+++ b/tests/test_table_connection.py
@@ -45,6 +45,19 @@ class ConnectionTestCase(TestCase):
         self.assertEqual(credentials.access_key, 'access_key_id')
         self.assertEqual(credentials.secret_key, 'secret_access_key')
 
+    def test_connection_session_set_credentials_with_session_token(self):
+        conn = TableConnection(
+            self.test_table_name,
+            aws_access_key_id='access_key_id',
+            aws_secret_access_key='secret_access_key',
+            aws_session_token='session_token')
+
+        credentials = conn.connection.session.get_credentials()
+
+        self.assertEqual(credentials.access_key, 'access_key_id')
+        self.assertEqual(credentials.secret_key, 'secret_access_key')
+        self.assertEqual(credentials.token, 'session_token')
+
     def test_create_table(self):
         """
         TableConnection.create_table