def _v1_auth(self, token_url): creds = self.creds headers = {} headers['X-Auth-User'] = creds['username'] headers['X-Auth-Key'] = creds['password'] tenant = creds.get('tenant') if tenant: headers['X-Auth-Tenant'] = tenant resp, resp_body = self._do_request(token_url, 'GET', headers=headers) if resp.status in (200, 204): try: self.management_url = resp['x-server-management-url'] self.auth_token = resp['x-auth-token'] except KeyError: raise exception.AuthorizationFailure() elif resp.status == 305: raise exception.AuthorizationRedirect(resp['location']) elif resp.status == 400: raise exception.AuthBadRequest() elif resp.status == 401: raise exception.NotAuthorized() elif resp.status == 404: raise exception.AuthUrlNotFound(url=token_url) else: raise Exception(_('Unexpected response: %s' % resp.status))
def process_request(self, req): """ Extract any authentication information in the request and construct an appropriate context from it. A few scenarios exist: 1. If X-Auth-Token is passed in, then consult TENANT and ROLE headers to determine permissions. 2. An X-Auth-Token was passed in, but the Identity-Status is not confirmed. For now, just raising a NotAuthorized exception. 3. X-Auth-Token is omitted. If we were using Keystone, then the tokenauth middleware would have rejected the request, so we must be using NoAuth. In that case, assume that is_admin=True. """ # TODO(sirp): should we be using the tank_tokeauth shim from # Keystone here? If we do, we need to make sure it handles the NoAuth # case auth_tok = req.headers.get('X-Auth-Token', req.headers.get('X-Storage-Token')) if auth_tok: if req.headers.get('X-Identity-Status') == 'Confirmed': # 1. Auth-token is passed, check other headers user = req.headers.get('X-User') tenant = req.headers.get('X-Tenant') roles = [ r.strip() for r in req.headers.get('X-Role', '').split(',') ] is_admin = 'Admin' in roles else: # 2. Indentity-Status not confirmed # FIXME(sirp): not sure what the correct behavior in this case # is; just raising NotAuthorized for now raise exception.NotAuthorized() else: # 3. Auth-token is ommited, assume NoAuth user = None tenant = None roles = [] is_admin = True req.context = self.make_context(auth_tok=auth_tok, user=user, tenant=tenant, roles=roles, is_admin=is_admin)
def _v2_auth(self, token_url): creds = self.creds creds = { "auth": { "tenantName": creds['tenant'], "passwordCredentials": { "username": creds['username'], "password": creds['password'] } } } headers = {} headers['Content-Type'] = 'application/json' req_body = json.dumps(creds) resp, resp_body = self._do_request(token_url, 'POST', headers=headers, body=req_body) if resp.status == 200: resp_auth = json.loads(resp_body)['access'] # FIXME(sirp): for now just using the first endpoint we get back # from the service catalog for tank, and using the public url. for service in resp_auth['serviceCatalog']: if service['name'] == 'tank': tank_endpoint = service['endpoints'][0]['publicURL'] break else: raise exception.NoServiceEndpoint() self.management_url = tank_endpoint self.auth_token = resp_auth['token']['id'] elif resp.status == 305: raise exception.RedirectException(resp['location']) elif resp.status == 400: raise exception.AuthBadRequest() elif resp.status == 401: raise exception.NotAuthorized() elif resp.status == 404: raise exception.AuthUrlNotFound(url=token_url) else: raise Exception(_('Unexpected response: %s') % resp.status)
def image_member_get(context, member_id, session=None): """Get an image member or raise if it does not exist.""" session = session or get_session() try: query = session.query(models.ImageMember).\ options(joinedload(models.ImageMember.image)).\ filter_by(id=member_id) if not can_show_deleted(context): query = query.filter_by(deleted=False) member = query.one() except exc.NoResultFound: raise exception.NotFound("No membership found with ID %s" % member_id) # Make sure they can look at it if not context.is_image_visible(member.image): raise exception.NotAuthorized("Image not visible to you") return member
def delete(self, location): """ Takes a `tank.store.location.Location` object that indicates where to find the image file to delete :location `tank.store.location.Location` object, supplied from tank.store.location.get_location_from_uri() :raises NotFound if image does not exist :raises NotAuthorized if cannot delete because of permissions """ loc = location.store_location fn = loc.path if os.path.exists(fn): try: logger.debug(_("Deleting image at %(fn)s") % locals()) os.unlink(fn) except OSError: raise exception.NotAuthorized( _("You cannot delete file %s") % fn) else: raise exception.NotFound(_("Image file %s does not exist") % fn)
def image_get(context, image_id, session=None, force_show_deleted=False): """Get an image or raise if it does not exist.""" session = session or get_session() try: query = session.query(models.Image).\ options(joinedload(models.Image.properties)).\ options(joinedload(models.Image.members)).\ filter_by(id=image_id) # filter out deleted images if context disallows it if not force_show_deleted and not can_show_deleted(context): query = query.filter_by(deleted=False) image = query.one() except exc.NoResultFound: raise exception.NotFound("No image found with ID %s" % image_id) # Make sure they can look at it if not context.is_image_visible(image): raise exception.NotAuthorized("Image not visible to you") return image
def check_mutate_authorization(context, image_ref): if not context.is_image_mutable(image_ref): logger.info(_("Attempted to modify image user did not own.")) msg = _("You do not own this image") raise exception.NotAuthorized(msg)
def _do_request(self, method, url, body, headers): """ Connects to the server and issues a request. Handles converting any returned HTTP error status codes to X7/Tank exceptions and closing the server connection. Returns the result data, or raises an appropriate exception. :param method: HTTP method ("GET", "POST", "PUT", etc...) :param url: urlparse.ParsedResult object with URL information :param body: string of data to send, or None (default) :param headers: mapping of key/value pairs to add as headers :note If the body param has a read attribute, and method is either POST or PUT, this method will automatically conduct a chunked-transfer encoding and use the body as a file object, transferring chunks of data using the connection's send() method. This allows large objects to be transferred efficiently without buffering the entire body in memory. """ if url.query: path = url.path + "?" + url.query else: path = url.path try: connection_type = self.get_connection_type() headers = headers or {} if 'x-auth-token' not in headers and self.auth_tok: headers['x-auth-token'] = self.auth_tok c = connection_type(url.hostname, url.port, **self.connect_kwargs) # Do a simple request or a chunked request, depending # on whether the body param is a file-like object and # the method is PUT or POST if hasattr(body, 'read') and method.lower() in ('post', 'put'): # Chunk it, baby... c.putrequest(method, path) for header, value in headers.items(): c.putheader(header, value) c.putheader('Transfer-Encoding', 'chunked') c.endheaders() chunk = body.read(self.CHUNKSIZE) while chunk: c.send('%x\r\n%s\r\n' % (len(chunk), chunk)) chunk = body.read(self.CHUNKSIZE) c.send('0\r\n\r\n') else: # Simple request... c.request(method, path, body, headers) res = c.getresponse() status_code = self.get_status_code(res) if status_code in self.OK_RESPONSE_CODES: return res elif status_code in self.REDIRECT_RESPONSE_CODES: raise exception.RedirectException(res.getheader('Location')) elif status_code == httplib.UNAUTHORIZED: raise exception.NotAuthorized(res.read()) elif status_code == httplib.FORBIDDEN: raise exception.NotAuthorized(res.read()) elif status_code == httplib.NOT_FOUND: raise exception.NotFound(res.read()) elif status_code == httplib.CONFLICT: raise exception.Duplicate(res.read()) elif status_code == httplib.BAD_REQUEST: raise exception.Invalid(res.read()) elif status_code == httplib.MULTIPLE_CHOICES: raise exception.MultipleChoices(body=res.read()) elif status_code == httplib.INTERNAL_SERVER_ERROR: raise Exception("Internal Server error: %s" % res.read()) else: raise Exception("Unknown error occurred! %s" % res.read()) except (socket.error, IOError), e: raise exception.ClientConnectionError(e)