def __call__(self, env, start_response): self.logger.debug('In mauth middleware') identity = None # the identity we are trying to populate # Handle s3 connections first because s3 has a unique format/use for the 'HTTP_X_AUTH_TOKEN'. s3 = env.get('HTTP_AUTHORIZATION', None) if s3 and s3.startswith('AWS'): s3_apikey, s3_signature = s3.split(' ')[1].rsplit(':', 1)[:] if s3_apikey and s3_signature: # check if we have cached data to validate this request instead of hitting cloudstack. memcache_client = cache_from_env(env) memcache_result = memcache_client.get('mauth_s3_apikey/%s' % s3_apikey) valid_cache = False data = None if memcache_result and self.cache_timeout > 0: expires, data = memcache_result if expires > time(): valid_cache = True if valid_cache: self.logger.debug('Validating the S3 request via the cached identity') s3_token = base64.urlsafe_b64decode(env.get('HTTP_X_AUTH_TOKEN', '')).encode("utf-8") if s3_signature == base64.b64encode(hmac.new(data.get('secret', ''), s3_token, hashlib.sha1).digest()): self.logger.debug('Using cached S3 identity') identity = data.get('identity', None) # The swift3 middleware sets env['PATH_INFO'] to '/v1/<aws_secret_key>', we need to map it to the cloudstack account. env['PATH_INFO'] = env['PATH_INFO'].replace(s3_apikey, '%s' % (identity.get('account_url').split('/v1/')[-1])) else: # hit cloudstack and populate memcached if valid request secret_key = None try: identity, secret_key = self.get_s3_identity(env, start_response, s3_apikey, s3_signature) except self.MauthError as e: self.logger.debug(e.value) env['swift.authorize'] = self.denied_response return self.app(env, start_response) if identity: # The swift3 middleware sets env['PATH_INFO'] to '/v1/<aws_secret_key>', we need to map it to the cloudstack account. env['PATH_INFO'] = env['PATH_INFO'].replace(s3_apikey, '%s' % (identity.get('account_url').split('/v1/')[-1])) memcache_client = cache_from_env(env) if memcache_client: memcache_client.set('mauth_s3_apikey/%s' % s3_apikey, (identity.get('expires', time()), dict({'secret':secret_key, 'identity':identity})), time=int(env.get('HTTP_X_AUTH_TTL', self.cache_timeout))) memcache_client.set('mauth_token/%s' % token, (identity.get('expires', time()), identity), time=int(env.get('HTTP_X_AUTH_TTL', self.cache_timeout))) else: self.logger.debug('No identity for this request') env['swift.authorize'] = self.denied_response return self.app(env, start_response) else: self.logger.debug('Invalid credential format') env['swift.authorize'] = self.denied_response return self.app(env, start_response) # If it is not an S3 call, handle the request for authenication, otherwise, use the token. req = Request(env) if not s3: try: auth_url_piece, rest_of_url = split_path(req.path_info, minsegs=1, maxsegs=2, rest_with_last=True) except ValueError: return HTTPNotFound(request=req) # Check if the request is for authentication (to get a token). if auth_url_piece in ('auth', 'v1.0'): # valid auth urls auth_user = env.get('HTTP_X_AUTH_USER', None) auth_key = env.get('HTTP_X_AUTH_KEY', None) if auth_user and auth_key: # check if we have this user and key cached. memcache_client = cache_from_env(env) memcache_result = memcache_client.get('mauth_creds/%s/%s' % (auth_user, auth_key)) valid_cache = False data = None if memcache_result and self.cache_timeout > 0 and int(env.get('HTTP_X_AUTH_TTL', 1)) > 0: expires, data = memcache_result if expires > time(): valid_cache = True if valid_cache: self.logger.debug('Using cached identity via creds') identity = data self.logger.debug("Using identity: %r" % (identity)) req.response = Response(request=req, headers={'x-auth-token':identity.get('token', None), 'x-storage-token':identity.get('token', None), 'x-storage-url':identity.get('account_url', None)}) return req.response(env, start_response) else: # hit cloudstack for the details. try: identity = self.get_identity(env, start_response, auth_user, auth_key) except self.MauthError as e: self.logger.debug(e.value) env['swift.authorize'] = self.denied_response return self.app(env, start_response) if identity: self.logger.debug("Using identity: %r" % (identity)) # add to memcache so it can be referenced later memcache_client = cache_from_env(env) if memcache_client: memcache_client.set('mauth_creds/%s/%s' % (auth_user, auth_key), (identity.get('expires', time()), identity), time=int(env.get('HTTP_X_AUTH_TTL', self.cache_timeout))) memcache_client.set('mauth_token/%s' % identity.get('token', ''), (identity.get('expires', time()), identity), time=int(env.get('HTTP_X_AUTH_TTL', self.cache_timeout))) req.response = Response(request=req, headers={'x-auth-token':identity.get('token', None), 'x-storage-token':identity.get('token', None), 'x-storage-url':identity.get('account_url', None)}) return req.response(env, start_response) else: self.logger.debug('No identity for these credentials') env['swift.authorize'] = self.denied_response return self.app(env, start_response) else: self.logger.debug('Credentials missing') env['swift.authorize'] = self.denied_response return self.app(env, start_response) else: token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN', None)) if not token: qs = env.get('QUERY_STRING', None) if qs: parts = qs.split('&') for part in parts: param = part.split('=') if 'X-AUTH-TOKEN' in param[0].upper(): self.logger.debug("Found token '%s' in query string." % param[1]) token = param[1] if not identity and not token: # this is an anonymous request. pass it through for authorize to verify. self.logger.debug('Passing through anonymous request') env['swift.authorize'] = self.authorize env['swift.clean_acl'] = clean_acl return self.app(env, start_response) # setup a memcache client for the following. memcache_client = cache_from_env(env) if not identity: memcache_result = memcache_client.get('mauth_token/%s' % token) if memcache_result and self.cache_timeout > 0: expires, _identity = memcache_result if expires > time(): self.logger.debug('Using cached identity via token') identity = _identity if not identity: self.logger.debug("No cached identity, validate token via the extension.") try: identity = self.validate_token(token) except self.MauthError as e: self.logger.debug(e.value) env['swift.authorize'] = self.denied_response return self.app(env, start_response) if identity and memcache_client: memcache_client.set('mauth_token/%s' % identity.get('token', None), (identity.get('expires', time()), identity), time=int(env.get('HTTP_X_AUTH_TTL', self.cache_timeout))) else: # if we didn't get identity it means there was an error. self.logger.debug('No identity for this token'); env['swift.authorize'] = self.denied_response return self.app(env, start_response) if not identity: env['swift.authorize'] = self.denied_response return self.app(env, start_response) self.logger.debug("Using identity: %r" % (identity)) env['mauth.identity'] = identity env['REMOTE_USER'] = '******'.join(identity['roles']) env['swift.authorize'] = self.authorize env['swift.clean_acl'] = clean_acl return self.app(env, start_response)