def __call__(self, req): # Read request signature and access id. # If we find X-Auth-User in the headers we ignore a key error # here so that we can use both authentication methods. # Returning here just means the user didn't supply AWS # authentication and we'll let the app try native keystone next. logger.info("Checking AWS credentials..") signature = self._get_signature(req) if not signature: if 'X-Auth-User' in req.headers: return self.application else: logger.info("No AWS Signature found.") raise exception.HeatIncompleteSignatureError() access = self._get_access(req) if not access: if 'X-Auth-User' in req.headers: return self.application else: logger.info("No AWSAccessKeyId/Authorization Credential") raise exception.HeatMissingAuthenticationTokenError() logger.info("AWS credentials found, checking against keystone.") # Make a copy of args for authentication and signature verification. auth_params = dict(req.params) # 'Signature' param Not part of authentication args auth_params.pop('Signature', None) # Authenticate the request. # AWS v4 authentication requires a hash of the body body_hash = hashlib.sha256(req.body).hexdigest() creds = {'ec2Credentials': {'access': access, 'signature': signature, 'host': req.host, 'verb': req.method, 'path': req.path, 'params': auth_params, 'headers': req.headers, 'body_hash': body_hash }} creds_json = json.dumps(creds) headers = {'Content-Type': 'application/json'} # Disable 'has no x member' pylint error # for httplib and urlparse # pylint: disable-msg=E1101 keystone_ec2_uri = self._conf_get_keystone_ec2_uri() logger.info('Authenticating with %s' % keystone_ec2_uri) o = urlparse.urlparse(keystone_ec2_uri) if o.scheme == 'http': conn = httplib.HTTPConnection(o.netloc) else: conn = httplib.HTTPSConnection(o.netloc) conn.request('POST', o.path, body=creds_json, headers=headers) response = conn.getresponse().read() conn.close() # NOTE(vish): We could save a call to keystone by # having keystone return token, tenant, # user, and roles from this call. result = json.loads(response) try: token_id = result['access']['token']['id'] tenant = result['access']['token']['tenant']['name'] tenant_id = result['access']['token']['tenant']['id'] logger.info("AWS authentication successful.") except (AttributeError, KeyError): logger.info("AWS authentication failure.") # Try to extract the reason for failure so we can return the # appropriate AWS error via raising an exception try: reason = result['error']['message'] except KeyError: reason = None if reason == "EC2 access key not found.": raise exception.HeatInvalidClientTokenIdError() elif reason == "EC2 signature not supplied.": raise exception.HeatSignatureError() else: raise exception.HeatAccessDeniedError() # Authenticated! ec2_creds = {'ec2Credentials': {'access': access, 'signature': signature}} req.headers['X-Auth-EC2-Creds'] = json.dumps(ec2_creds) req.headers['X-Auth-Token'] = token_id req.headers['X-Tenant-Name'] = tenant req.headers['X-Tenant-Id'] = tenant_id req.headers['X-Auth-URL'] = self._conf_get('auth_uri') metadata = result['access'].get('metadata', {}) roles = metadata.get('roles', []) req.headers['X-Roles'] = ','.join(roles) return self.application
def _authorize(self, req, auth_uri): # Read request signature and access id. # If we find X-Auth-User in the headers we ignore a key error # here so that we can use both authentication methods. # Returning here just means the user didn't supply AWS # authentication and we'll let the app try native keystone next. logger.info(_("Checking AWS credentials..")) signature = self._get_signature(req) if not signature: if 'X-Auth-User' in req.headers: return self.application else: logger.info(_("No AWS Signature found.")) raise exception.HeatIncompleteSignatureError() access = self._get_access(req) if not access: if 'X-Auth-User' in req.headers: return self.application else: logger.info(_("No AWSAccessKeyId/Authorization Credential")) raise exception.HeatMissingAuthenticationTokenError() logger.info(_("AWS credentials found, checking against keystone.")) if not auth_uri: logger.error(_("Ec2Token authorization failed, no auth_uri " "specified in config file")) raise exception.HeatInternalFailureError(_('Service ' 'misconfigured')) # Make a copy of args for authentication and signature verification. auth_params = dict(req.params) # 'Signature' param Not part of authentication args auth_params.pop('Signature', None) # Authenticate the request. # AWS v4 authentication requires a hash of the body body_hash = hashlib.sha256(req.body).hexdigest() creds = {'ec2Credentials': {'access': access, 'signature': signature, 'host': req.host, 'verb': req.method, 'path': req.path, 'params': auth_params, 'headers': req.headers, 'body_hash': body_hash }} creds_json = json.dumps(creds) headers = {'Content-Type': 'application/json'} keystone_ec2_uri = self._conf_get_keystone_ec2_uri(auth_uri) logger.info(_('Authenticating with %s') % keystone_ec2_uri) response = requests.post(keystone_ec2_uri, data=creds_json, headers=headers) result = response.json() try: token_id = result['access']['token']['id'] tenant = result['access']['token']['tenant']['name'] tenant_id = result['access']['token']['tenant']['id'] logger.info(_("AWS authentication successful.")) except (AttributeError, KeyError): logger.info(_("AWS authentication failure.")) # Try to extract the reason for failure so we can return the # appropriate AWS error via raising an exception try: reason = result['error']['message'] except KeyError: reason = None if reason == "EC2 access key not found.": raise exception.HeatInvalidClientTokenIdError() elif reason == "EC2 signature not supplied.": raise exception.HeatSignatureError() else: raise exception.HeatAccessDeniedError() # Authenticated! ec2_creds = {'ec2Credentials': {'access': access, 'signature': signature}} req.headers['X-Auth-EC2-Creds'] = json.dumps(ec2_creds) req.headers['X-Auth-Token'] = token_id req.headers['X-Tenant-Name'] = tenant req.headers['X-Tenant-Id'] = tenant_id req.headers['X-Auth-URL'] = auth_uri metadata = result['access'].get('metadata', {}) roles = metadata.get('roles', []) req.headers['X-Roles'] = ','.join(roles) return self.application
def __call__(self, req): # Read request signature and access id. # If we find X-Auth-User in the headers we ignore a key error # here so that we can use both authentication methods. # Returning here just means the user didn't supply AWS # authentication and we'll let the app try native keystone next. logger.info("Checking AWS credentials..") try: signature = req.params['Signature'] except KeyError: logger.info("No AWS Signature found.") if 'X-Auth-User' in req.headers: return self.application else: raise exception.HeatIncompleteSignatureError() try: access = req.params['AWSAccessKeyId'] except KeyError: logger.info("No AWSAccessKeyId found.") if 'X-Auth-User' in req.headers: return self.application else: raise exception.HeatMissingAuthenticationTokenError() logger.info("AWS credentials found, checking against keystone.") # Make a copy of args for authentication and signature verification. auth_params = dict(req.params) # Not part of authentication args auth_params.pop('Signature') # Authenticate the request. creds = {'ec2Credentials': {'access': access, 'signature': signature, 'host': req.host, 'verb': req.method, 'path': req.path, 'params': auth_params, }} creds_json = None try: creds_json = json.dumps(creds) except TypeError: creds_json = json.dumps(json.to_primitive(creds)) headers = {'Content-Type': 'application/json'} # Disable 'has no x member' pylint error # for httplib and urlparse # pylint: disable-msg=E1101 logger.info('Authenticating with %s' % self.conf['keystone_ec2_uri']) o = urlparse.urlparse(self.conf['keystone_ec2_uri']) if o.scheme == 'http': conn = httplib.HTTPConnection(o.netloc) else: conn = httplib.HTTPSConnection(o.netloc) conn.request('POST', o.path, body=creds_json, headers=headers) response = conn.getresponse().read() conn.close() # NOTE(vish): We could save a call to keystone by # having keystone return token, tenant, # user, and roles from this call. result = json.loads(response) try: token_id = result['access']['token']['id'] logger.info("AWS authentication successful.") except (AttributeError, KeyError): logger.info("AWS authentication failure.") # Try to extract the reason for failure so we can return the # appropriate AWS error via raising an exception try: reason = result['error']['message'] except KeyError: reason = None if reason == "EC2 access key not found.": raise exception.HeatInvalidClientTokenIdError() elif reason == "EC2 signature not supplied.": raise exception.HeatSignatureError() else: raise exception.HeatAccessDeniedError() # Authenticated! ec2_creds = {'ec2Credentials': {'access': access, 'signature': signature}} req.headers['X-Auth-EC2-Creds'] = json.dumps(ec2_creds) req.headers['X-Auth-Token'] = token_id req.headers['X-Auth-URL'] = self.conf['auth_uri'] req.headers['X-Auth-EC2_URL'] = self.conf['keystone_ec2_uri'] return self.application