def authenticate_2_0(self): reqbody = json.dumps({ 'auth': { 'passwordCredentials': { 'username': self.user_id, 'password': self.key } } }) resp = self.request('tokens/', data=reqbody, headers={'Content-Type': 'application/json'}, method='POST') if resp.status == httplib.UNAUTHORIZED: raise InvalidCredsError() elif resp.status not in [ httplib.OK, httplib.NON_AUTHORITATIVE_INFORMATION ]: raise MalformedResponseError('Malformed response', body='code: %s body: %s' % (resp.status, resp.body), driver=self.driver) else: try: body = json.loads(resp.body) except Exception, e: raise MalformedResponseError('Failed to parse JSON', e) try: self.auth_token = body['access']['token']['id'] self.urls = body['access']['serviceCatalog'] except KeyError, e: raise MalformedResponseError( 'Auth JSON response is missing required elements', e)
def parse_body(self): if self.status == httplib.NO_CONTENT or not self.body: return None if self.has_content_type('application/xml'): try: try: return ET.XML(self.body) except ValueError: # lxml wants a bytes and tests are basically hard-coded to str return ET.XML(self.body.encode('utf-8')) except: raise MalformedResponseError('Failed to parse XML', body=self.body, driver=self.node_driver) elif self.has_content_type('application/json'): try: return json.loads(self.body) except: raise MalformedResponseError('Failed to parse JSON', body=self.body, driver=self.node_driver) else: return self.body
def _authenticate_2_0_with_body(self, reqbody): resp = self.request('/v2.0/tokens', data=reqbody, headers={'Content-Type': 'application/json'}, method='POST') if resp.status == httplib.UNAUTHORIZED: raise InvalidCredsError() elif resp.status not in [ httplib.OK, httplib.NON_AUTHORITATIVE_INFORMATION ]: body = 'code: %s body: %s' % (resp.status, resp.body) raise MalformedResponseError('Malformed response', body=body, driver=self.driver) else: body = resp.object try: access = body['access'] expires = access['token']['expires'] self.auth_token = access['token']['id'] self.auth_token_expires = parse_date(expires) self.urls = access['serviceCatalog'] self.auth_user_info = access.get('user', {}) except KeyError: e = sys.exc_info()[1] raise MalformedResponseError( 'Auth JSON response is \ missing required elements', e) return self
def authenticate_1_1(self): reqbody = json.dumps( {'credentials': { 'username': self.user_id, 'key': self.key }}) resp = self.request("/auth", data=reqbody, headers={}, method='POST') if resp.status == httplib.UNAUTHORIZED: # HTTP UNAUTHORIZED (401): auth failed raise InvalidCredsError() elif resp.status != httplib.OK: raise MalformedResponseError('Malformed response', body='code: %s body:%s' % (resp.status, resp.body), driver=self.driver) else: try: body = json.loads(resp.body) except Exception, e: raise MalformedResponseError('Failed to parse JSON', e) try: self.auth_token = body['auth']['token']['id'] self.urls = body['auth']['serviceCatalog'] except KeyError, e: raise MalformedResponseError( 'Auth JSON response is missing required elements', e)
def authenticate_1_0(self): headers = { 'X-Auth-User': self.user_id, 'X-Auth-Key': self.key, } resp = self.request('/v1.0', headers=headers, method='GET') if resp.status == httplib.UNAUTHORIZED: # HTTP UNAUTHORIZED (401): auth failed raise InvalidCredsError() elif resp.status not in [httplib.NO_CONTENT, httplib.OK]: body = 'code: %s body:%s headers:%s' % (resp.status, resp.body, resp.headers) raise MalformedResponseError('Malformed response', body=body, driver=self.driver) else: headers = resp.headers # emulate the auth 1.1 URL list self.urls = {} self.urls['cloudServers'] = \ [{'publicURL': headers.get('x-server-management-url', None)}] self.urls['cloudFilesCDN'] = \ [{'publicURL': headers.get('x-cdn-management-url', None)}] self.urls['cloudFiles'] = \ [{'publicURL': headers.get('x-storage-url', None)}] self.auth_token = headers.get('x-auth-token', None) self.auth_user_info = None if not self.auth_token: raise MalformedResponseError('Missing X-Auth-Token in \ response headers') return self
def authenticate_2_0_with_body(self, reqbody): resp = self.request('/v2.0/tokens/', data=reqbody, headers={'Content-Type':'application/json'}, method='POST') if resp.status == httplib.UNAUTHORIZED: raise InvalidCredsError() elif resp.status not in [httplib.OK, httplib.NON_AUTHORITATIVE_INFORMATION]: raise MalformedResponseError('Malformed response', body='code: %s body: %s' % (resp.status, resp.body), driver=self.driver) else: try: body = json.loads(resp.body) except Exception: e = sys.exc_info()[1] raise MalformedResponseError('Failed to parse JSON', e) try: access = body['access'] token = access['token'] self.auth_token = token['id'] self.urls = access['serviceCatalog'] except KeyError: e = sys.exc_info()[1] raise MalformedResponseError('Auth JSON response is missing required elements', e)
def _populate_hosts_and_request_paths(self): """ Rackspace uses a separate host for API calls which is only provided after an initial authentication request. If we haven't made that request yet, do it here. Otherwise, just return the management host. """ if not self.auth_token: # Initial connection used for authentication conn = self.conn_classes[self.secure](self.auth_host, self.port[self.secure]) conn.request(method='GET', url='/%s' % (AUTH_API_VERSION), headers={ 'X-Auth-User': self.user_id, 'X-Auth-Key': self.key }) resp = conn.getresponse() if resp.status == httplib.NO_CONTENT: # HTTP NO CONTENT (204): auth successful headers = dict(resp.getheaders()) try: self.server_url = headers['x-server-management-url'] self.storage_url = headers['x-storage-url'] self.cdn_management_url = headers['x-cdn-management-url'] self.lb_url = self.server_url.replace( "servers", "ord.loadbalancers") self.auth_token = headers['x-auth-token'] except KeyError, e: # Returned 204 but has missing information in the header, something is wrong raise MalformedResponseError('Malformed response', body='Missing header: %s' % (str(e)), driver=self.driver) elif resp.status == httplib.UNAUTHORIZED: # HTTP UNAUTHORIZED (401): auth failed raise InvalidCredsError() else: # Any response code != 401 or 204, something is wrong raise MalformedResponseError( 'Malformed response', body='code: %s body:%s' % (resp.status, ''.join(resp.body.readlines())), driver=self.driver) for key in [ 'server_url', 'storage_url', 'cdn_management_url', 'lb_url' ]: scheme, server, request_path, param, query, fragment = ( urlparse.urlparse(getattr(self, key))) # Set host to where we want to make further requests to setattr(self, '__%s' % (key), server) setattr(self, '__request_path_%s' % (key), request_path) conn.close()
def parse_body(self): if not self.body: return None if 'content-type' in self.headers: key = 'content-type' elif 'Content-Type' in self.headers: key = 'Content-Type' else: raise LibcloudError('Missing content-type header', driver=OpenStackAuthConnection) content_type = self.headers[key] if content_type.find(';') != -1: content_type = content_type.split(';')[0] if content_type == 'application/json': try: data = json.loads(self.body) except: raise MalformedResponseError('Failed to parse JSON', body=self.body, driver=OpenStackAuthConnection) elif content_type == 'text/plain': data = self.body else: data = self.body return data
def authenticate(self, force=False): if not self._is_authentication_needed(force=force): return self reqbody = json.dumps( {'credentials': { 'username': self.user_id, 'key': self.key }}) resp = self.request('/v1.1/auth', data=reqbody, headers={}, method='POST') if resp.status == httplib.UNAUTHORIZED: # HTTP UNAUTHORIZED (401): auth failed raise InvalidCredsError() elif resp.status != httplib.OK: body = 'code: %s body:%s' % (resp.status, resp.body) raise MalformedResponseError('Malformed response', body=body, driver=self.driver) else: try: body = json.loads(resp.body) except Exception: e = sys.exc_info()[1] raise MalformedResponseError('Failed to parse JSON', e) try: expires = body['auth']['token']['expires'] self.auth_token = body['auth']['token']['id'] self.auth_token_expires = parse_date(expires) self.urls = body['auth']['serviceCatalog'] self.auth_user_info = None except KeyError: e = sys.exc_info()[1] raise MalformedResponseError( 'Auth JSON response is \ missing required elements', e) return self
def parse_body(self): if len(self.body) == 0 and not self.parse_zero_length_body: return self.body try: body = lxml_ET.XML(self.body) except Exception as e: raise MalformedResponseError('Failed to parse XML %s' % e, body=self.body, driver=self.connection.driver) return body
def _parse_url_headers(self, headers): try: self.server_url = headers['x-server-management-url'] self.storage_url = headers['x-storage-url'] self.cdn_management_url = headers['x-cdn-management-url'] self.lb_url = self.server_url.replace("servers", "ord.loadbalancers") self.auth_token = headers['x-auth-token'] except KeyError, e: # Returned 204 but has missing information in the header, something is wrong raise MalformedResponseError('Malformed response', body='Missing header: %s' % (str(e)), driver=self.driver)
def parse_body(self): if self.status == httplib.NO_CONTENT or not self.body: return None if self.has_content_type('application/xml'): try: return ET.XML(self.body) except: raise MalformedResponseError('Failed to parse XML', body=self.body, driver=self.node_driver) elif self.has_content_type('application/json'): try: return json.loads(self.body) except: raise MalformedResponseError('Failed to parse JSON', body=self.body, driver=self.node_driver) else: return self.body
def parse_body(self): # length of 1 can't be valid XML, but on destroy node, # slicehost returns a 1 byte response with a "Content-Type: # application/xml" header. booya. if not self.body or len(self.body) <= 1: return None try: body = ET.XML(self.body) except: raise MalformedResponseError( "Failed to parse XML", body=self.body, driver=SlicehostNodeDriver) return body
def parse_error(self): if self.status == 401: raise InvalidCredsError(self.body) try: body = ET.XML(self.body) except: raise MalformedResponseError( "Failed to parse XML", body=self.body, driver=SlicehostNodeDriver) try: return "; ".join([ err.text for err in body.findall('error') ]) except ExpatError: return self.body
def _auth(self): conn = None try: conn = self.conn_classes[self.secure]( self.auth_host, self.auth_port) conn.request( method='GET', url=self.auth_path, headers={ 'X-Auth-User': self.user_id, 'X-Auth-Key': self.key } ) resp = conn.getresponse() if resp.status == httplib.NO_CONTENT: # HTTP NO CONTENT (204): auth successful self._parse_url_headers(dict(resp.getheaders())) elif resp.status == httplib.UNAUTHORIZED: # HTTP UNAUTHORIZED (401): auth failed raise InvalidCredsError() else: # Any response code != 401 or 204, something is wrong raise MalformedResponseError('Malformed response', body='code: %s body:%s' % (resp.status, ''.join(resp.body.readlines())), driver=self.driver) for key in ['server_url', 'storage_url', 'cdn_management_url', 'lb_url']: url = getattr(self, key, None) if url: scheme, server, request_path, param, query, fragment = ( urlparse.urlparse(getattr(self, key))) # Set host to where we want to make further requests to setattr(self, '__%s' % (key), server) setattr(self, '__request_path_%s' % (key), request_path) finally: if conn: conn.close()
def authenticate_3_x_with_password(self): # TODO: Support for custom domain # TODO: Refactor and add a class per API version domain = 'Default' data = { 'auth': { 'identity': { 'methods': ['password'], 'password': { 'user': { 'domain': { 'name': domain }, 'name': self.user_id, 'password': self.key } } }, 'scope': { 'project': { 'domain': { 'name': domain }, 'name': self.tenant_name } } } } if self.tenant_name: data['auth']['scope'] = { 'project': { 'domain': { 'name': domain }, 'name': self.tenant_name } } data = json.dumps(data) response = self.request('/v3/auth/tokens', data=data, headers={'Content-Type': 'application/json'}, method='POST') if response.status == httplib.UNAUTHORIZED: # Invalid credentials raise InvalidCredsError() elif response.status in [httplib.OK, httplib.CREATED]: headers = response.headers try: body = json.loads(response.body) except Exception: e = sys.exc_info()[1] raise MalformedResponseError('Failed to parse JSON', e) try: expires = body['token']['expires_at'] self.auth_token = headers['x-subject-token'] self.auth_token_expires = parse_date(expires) self.urls = body['token']['catalog'] self.auth_user_info = None except KeyError: e = sys.exc_info()[1] raise MalformedResponseError( 'Auth JSON response is \ missing required elements', e) body = 'code: %s body:%s' % (response.status, response.body) else: raise MalformedResponseError('Malformed response', body=body, driver=self.driver) return self
def authenticate(self, force=False): """ Perform authentication. """ if not self._is_authentication_needed(force=force): return self data = { 'auth': { 'identity': { 'methods': ['password'], 'password': { 'user': { 'domain': { 'name': self.domain_name }, 'name': self.user_id, 'password': self.key } } } } } if self.token_scope == OpenStackIdentityTokenScope.PROJECT: # Scope token to project (tenant) data['auth']['scope'] = { 'project': { 'domain': { 'name': self.domain_name }, 'name': self.tenant_name } } elif self.token_scope == OpenStackIdentityTokenScope.DOMAIN: # Scope token to domain data['auth']['scope'] = {'domain': {'name': self.domain_name}} elif self.token_scope == OpenStackIdentityTokenScope.UNSCOPED: pass else: raise ValueError('Token needs to be scoped either to project or ' 'a domain') data = json.dumps(data) response = self.request('/v3/auth/tokens', data=data, headers={'Content-Type': 'application/json'}, method='POST') if response.status == httplib.UNAUTHORIZED: # Invalid credentials raise InvalidCredsError() elif response.status in [httplib.OK, httplib.CREATED]: headers = response.headers try: body = json.loads(response.body) except Exception: e = sys.exc_info()[1] raise MalformedResponseError('Failed to parse JSON', e) try: roles = self._to_roles(body['token']['roles']) except Exception: e = sys.exc_info()[1] roles = [] try: expires = body['token']['expires_at'] self.auth_token = headers['x-subject-token'] self.auth_token_expires = parse_date(expires) # Note: catalog is not returned for unscoped tokens self.urls = body['token'].get('catalog', None) self.auth_user_info = None self.auth_user_roles = roles except KeyError: e = sys.exc_info()[1] raise MalformedResponseError( 'Auth JSON response is \ missing required elements', e) body = 'code: %s body:%s' % (response.status, response.body) else: raise MalformedResponseError('Malformed response', body=body, driver=self.driver) return self