PageRenderTime 25ms CodeModel.GetById 17ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/boto-2.5.2/boto/sts/connection.py

#
Python | 134 lines | 95 code | 11 blank | 28 comment | 11 complexity | 24de7b4a29c68aed6dff212135ebef02 MD5 | raw file
  1# Copyright (c) 2011 Mitch Garnaat http://garnaat.org/
  2# Copyright (c) 2011, Eucalyptus Systems, Inc.
  3#
  4# Permission is hereby granted, free of charge, to any person obtaining a
  5# copy of this software and associated documentation files (the
  6# "Software"), to deal in the Software without restriction, including
  7# without limitation the rights to use, copy, modify, merge, publish, dis-
  8# tribute, sublicense, and/or sell copies of the Software, and to permit
  9# persons to whom the Software is furnished to do so, subject to the fol-
 10# lowing conditions:
 11#
 12# The above copyright notice and this permission notice shall be included
 13# in all copies or substantial portions of the Software.
 14#
 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 16# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 17# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 18# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 19# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21# IN THE SOFTWARE.
 22
 23from boto.connection import AWSQueryConnection
 24from boto.regioninfo import RegionInfo
 25from credentials import Credentials, FederationToken
 26import boto
 27import boto.utils
 28import datetime
 29import threading
 30
 31_session_token_cache = {}
 32
 33class STSConnection(AWSQueryConnection):
 34
 35    DefaultRegionName = 'us-east-1'
 36    DefaultRegionEndpoint = 'sts.amazonaws.com'
 37    APIVersion = '2011-06-15'
 38
 39    def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
 40                 is_secure=True, port=None, proxy=None, proxy_port=None,
 41                 proxy_user=None, proxy_pass=None, debug=0,
 42                 https_connection_factory=None, region=None, path='/',
 43                 converter=None):
 44        if not region:
 45            region = RegionInfo(self, self.DefaultRegionName,
 46                                self.DefaultRegionEndpoint,
 47                                connection_cls=STSConnection)
 48        self.region = region
 49        self._mutex = threading.Semaphore()
 50        AWSQueryConnection.__init__(self, aws_access_key_id,
 51                                    aws_secret_access_key,
 52                                    is_secure, port, proxy, proxy_port,
 53                                    proxy_user, proxy_pass,
 54                                    self.region.endpoint, debug,
 55                                    https_connection_factory, path)
 56
 57    def _required_auth_capability(self):
 58        return ['sign-v2']
 59
 60    def _check_token_cache(self, token_key, duration=None, window_seconds=60):
 61        token = _session_token_cache.get(token_key, None)
 62        if token:
 63            now = datetime.datetime.utcnow()
 64            expires = boto.utils.parse_ts(token.expiration)
 65            delta = expires - now
 66            if delta < datetime.timedelta(seconds=window_seconds):
 67                msg = 'Cached session token %s is expired' % token_key
 68                boto.log.debug(msg)
 69                token = None
 70        return token
 71
 72    def _get_session_token(self, duration=None):
 73        params = {}
 74        if duration:
 75            params['DurationSeconds'] = duration
 76        return self.get_object('GetSessionToken', params,
 77                                Credentials, verb='POST')
 78
 79    def get_session_token(self, duration=None, force_new=False):
 80        """
 81        Return a valid session token.  Because retrieving new tokens
 82        from the Secure Token Service is a fairly heavyweight operation
 83        this module caches previously retrieved tokens and returns
 84        them when appropriate.  Each token is cached with a key
 85        consisting of the region name of the STS endpoint
 86        concatenated with the requesting user's access id.  If there
 87        is a token in the cache meeting with this key, the session
 88        expiration is checked to make sure it is still valid and if
 89        so, the cached token is returned.  Otherwise, a new session
 90        token is requested from STS and it is placed into the cache
 91        and returned.
 92
 93        :type duration: int
 94        :param duration: The number of seconds the credentials should
 95            remain valid.
 96
 97        :type force_new: bool
 98        :param force_new: If this parameter is True, a new session token
 99            will be retrieved from the Secure Token Service regardless
100            of whether there is a valid cached token or not.
101        """
102        token_key = '%s:%s' % (self.region.name, self.provider.access_key)
103        token = self._check_token_cache(token_key, duration)
104        if force_new or not token:
105            boto.log.debug('fetching a new token for %s' % token_key)
106            self._mutex.acquire()
107            token = self._get_session_token(duration)
108            _session_token_cache[token_key] = token
109            self._mutex.release()
110        return token
111        
112    def get_federation_token(self, name, duration=None, policy=None):
113        """
114        :type name: str
115        :param name: The name of the Federated user associated with
116                     the credentials.
117                     
118        :type duration: int
119        :param duration: The number of seconds the credentials should
120                         remain valid.
121
122        :type policy: str
123        :param policy: A JSON policy to associate with these credentials.
124
125        """
126        params = {'Name' : name}
127        if duration:
128            params['DurationSeconds'] = duration
129        if policy:
130            params['Policy'] = policy
131        return self.get_object('GetFederationToken', params,
132                                FederationToken, verb='POST')
133        
134