Beispiel #1
0
    def list(self, req):
        params = req.params.copy()
        marker = params.pop('marker', None)
        query_params = {}
        # step 1 - apply marker to query if exists
        if marker is not None:
            query_params['marker'] = marker

        # step 2 - apply limit (if exists OR setup default limit)
        limit = params.pop('limit', CONF.default_api_limit)
        try:
            limit = int(limit)
        except ValueError:
            msg = _("Limit param must be an integer.")
            raise exc.BadRequest(message=msg)
        if limit < 0:
            msg = _("Limit param must be positive.")
            raise exc.BadRequest(message=msg)
        query_params['limit'] = min(CONF.max_api_limit, limit)

        # step 3 - parse sort parameters
        if 'sort' in params:
            sort = []
            for sort_param in params.pop('sort').strip().split(','):
                key, _sep, direction = sort_param.partition(':')
                if direction and direction not in ('asc', 'desc'):
                    raise exc.BadRequest('Sort direction must be one of '
                                         '["asc", "desc"]. Got %s direction' %
                                         direction)
                sort.append((key, direction or 'desc'))
            query_params['sort'] = sort

        query_params['filters'] = params
        return query_params
Beispiel #2
0
    def list(self, req):
        params = req.params.copy()
        marker = params.pop('marker', None)
        query_params = {}
        # step 1 - apply marker to query if exists
        if marker is not None:
            query_params['marker'] = marker

        # step 2 - apply limit (if exists OR setup default limit)
        limit = params.pop('limit', CONF.default_api_limit)
        try:
            limit = int(limit)
        except ValueError:
            msg = _("Limit param must be an integer.")
            raise exc.BadRequest(message=msg)
        if limit < 0:
            msg = _("Limit param must be positive.")
            raise exc.BadRequest(message=msg)
        query_params['limit'] = min(CONF.max_api_limit, limit)

        # step 3 - parse sort parameters
        if 'sort' in params:
            sort = []
            for sort_param in params.pop('sort').strip().split(','):
                key, _sep, direction = sort_param.partition(':')
                if direction and direction not in ('asc', 'desc'):
                    raise exc.BadRequest('Sort direction must be one of '
                                         '["asc", "desc"]. Got %s direction'
                                         % direction)
                sort.append((key, direction or 'desc'))
            query_params['sort'] = sort

        query_params['filters'] = params
        return query_params
Beispiel #3
0
    def process_request(req):
        auth_token = req.headers.get('X-Auth-Token')
        if not auth_token:
            msg = _("Auth token must be provided")
            raise exception.Unauthorized(msg)
        try:
            user, tenant, roles = auth_token.strip().split(':', 3)
        except ValueError:
            msg = _("Wrong auth token format. It must be 'user:tenant:roles'")
            raise exception.Unauthorized(msg)
        if not tenant:
            msg = _("Tenant must be specified in auth token. "
                    "Format of the token is 'user:tenant:roles'")
            raise exception.Unauthorized(msg)
        elif tenant.lower() == 'none':
            tenant = None
            req.headers['X-Identity-Status'] = 'Nope'
        else:
            req.headers['X-Identity-Status'] = 'Confirmed'

        req.headers['X-User-Id'] = user
        req.headers['X-Tenant-Id'] = tenant
        req.headers['X-Roles'] = roles

        if req.headers.get('X-Identity-Status') == 'Confirmed':
            kwargs = {'request_id': req.environ.get(request_id.ENV_REQUEST_ID)}
            req.context = RequestContext.from_environ(req.environ, **kwargs)
        elif CONF.allow_anonymous_access:
            req.context = RequestContext(read_only=True, is_admin=False)
        else:
            raise exception.Unauthorized()
Beispiel #4
0
 def coerce(obj, attr, value):
     # to remove the existing link user sets its value to None,
     # we have to consider this case.
     if value is None:
         return value
     # check that value is string
     if not isinstance(value, six.string_types):
         raise ValueError(
             _('A string is required in field %(attr)s, '
               'not a %(type)s') % {
                   'attr': attr,
                   'type': type(value).__name__
               })
     # determine if link is external or internal
     external = LinkFieldType.is_external(value)
     # validate link itself
     if external:
         link = urlparse.urlparse(value)
         if link.scheme not in ('http', 'https'):
             raise ValueError(
                 _('Only http and https requests '
                   'are allowed in url %s') % value)
     else:
         result = value.split('/')
         if len(result) != 4 or result[1] != 'artifacts':
             raise ValueError(
                 _('Link %(link)s is not valid in field '
                   '%(attr)s. The link must be either valid url or '
                   'reference to artifact. Example: '
                   '/artifacts/<artifact_type>/<artifact_id>') % {
                       'link': value,
                       'attr': attr
                   })
     return value
Beispiel #5
0
    def create(cls, context, values):
        """Create new Artifact in Glare repo

        :param context: user context
        :param values: Dict with specified artifact properties
        :return: definition of create Artifact
        """
        if context.tenant is None or context.read_only:
            msg = _("It's forbidden to anonymous users to create artifacts.")
            raise exception.Forbidden(msg)
        else:
            with cls.lock_engine.acquire(
                    context, cls._get_versioning_scope(context, values)):
                ver = values.setdefault(
                    'version', cls.DEFAULT_ARTIFACT_VERSION)
                cls._validate_versioning(context, values.get('name'), ver)
                # validate other values
                cls._validate_input_values(context, values)
                # validate visibility
                if 'visibility' in values:
                    msg = _("visibility is not allowed in a request "
                            "for artifact create.")
                    raise exception.BadRequest(msg)
                values['id'] = str(uuid.uuid4())
                values['owner'] = context.tenant
                values['created_at'] = timeutils.utcnow()
                values['updated_at'] = values['created_at']
                af = cls._init_artifact(context, values)
                LOG.info(_LI("Parameters validation for artifact creation "
                             "passed for request %s."), context.request_id)
                af_vals = cls.db_api.create(context,
                                            af.obj_changes_to_primitive())
                return cls._init_artifact(context, af_vals)
Beispiel #6
0
        def get_updates(af_dict, patch_with_upd):
            """Get updated values for artifact and json patch

            :param af_dict: current artifact definition as dict
            :param patch_with_upd: json-patch
            :return: dict of updated attributes and their values
            """

            try:
                af_dict_patched = patch_with_upd.apply(af_dict)
                diff = utils.DictDiffer(af_dict_patched, af_dict)

                # we mustn't add or remove attributes from artifact
                if diff.added() or diff.removed():
                    msg = _(
                        "Forbidden to add or remove attributes from artifact. "
                        "Added attributes %(added)s. "
                        "Removed attributes %(removed)s") % {
                            'added': diff.added(),
                            'removed': diff.removed()
                        }
                    raise exception.BadRequest(message=msg)

                return {key: af_dict_patched[key] for key in diff.changed()}

            except (jsonpatch.JsonPatchException,
                    jsonpatch.JsonPointerException, KeyError) as e:
                raise exception.BadRequest(message=str(e))
            except TypeError as e:
                msg = _("Incorrect type of the element. Reason: %s") % str(e)
                raise exception.BadRequest(msg)
Beispiel #7
0
    def __call__(self, request):
        if 'X-Auth-Token' not in request.headers:
            msg = _("Auth token must be provided in 'X-Auth-Token' header.")
            LOG.error(msg)
            raise exception.Unauthorized()
        access_token = request.headers.get('X-Auth-Token')
        try:
            decoded = jwt.decode(access_token, algorithms=['RS256'],
                                 verify=False)
        except Exception as e:
            msg = _("Token can't be decoded because of wrong format %s")\
                % str(e)
            LOG.error(msg)
            raise exception.Unauthorized()

        # Get user realm from parsed token
        # Format is "iss": "http://<host>:<port>/auth/realms/<realm_name>",
        __, __, realm_name = decoded['iss'].strip().rpartition('/realms/')

        # Get roles from from parsed token
        roles = ','.join(decoded['realm_access']['roles']) \
            if 'realm_access' in decoded else ''

        self.authenticate(access_token, realm_name)

        request.headers["X-Identity-Status"] = "Confirmed"
        request.headers["X-Project-Id"] = realm_name
        request.headers["X-Roles"] = roles
        return request.get_response(self.application)
Beispiel #8
0
    def download_blob_dict(cls, context, af, field_name, blob_key):
        """Download binary data from Glare Artifact.

        :param context: user context
        :param af: Artifact definition in Glare repo
        :param blob_key: name of blob key in dict
        :param field_name: name of blob dict field
        :return: file iterator for requested file
        """
        if not cls.is_blob_dict(field_name):
            msg = _("%s is not a blob dict") % field_name
            raise exception.BadRequest(msg)

        if af.status == cls.STATUS.DEACTIVATED and not context.is_admin:
            msg = _("Only admin is allowed to download image data "
                    "when it's deactivated")
            raise exception.Forbidden(message=msg)
        try:
            blob = getattr(af, field_name)[blob_key]
        except KeyError:
            msg = _("Blob with name %(blob_name)s is not found in blob "
                    "dictionary %(blob_dict)s") % (blob_key, field_name)
            raise exception.NotFound(message=msg)
        if blob is None or blob['status'] != BlobStatus.ACTIVE:
            msg = _("Blob %(blob_name)s from blob dictionary %(blob_dict)s "
                    "is not ready for download") % (blob_key, field_name)
            LOG.error(msg)
            raise exception.BadRequest(message=msg)
        data = store_api.load_from_store(uri=blob['url'], context=context)
        meta = {'size': blob['size'], 'checksum': blob['checksum'],
                'content_type': blob['content_type']}
        return data, meta
Beispiel #9
0
 def coerce(obj, attr, value):
     # to remove the existing dependency user sets its value to None,
     # we have to consider this case.
     if value is None:
         return value
     # check that value is string
     if not isinstance(value, six.string_types):
         raise ValueError(_('A string is required in field %(attr)s, '
                            'not a %(type)s') %
                          {'attr': attr, 'type': type(value).__name__})
     # determine if link is external or internal
     external = DependencyFieldType.is_external(value)
     # validate link itself
     if external:
         link = urlparse.urlparse(value)
         if link.scheme not in ('http', 'https'):
             raise ValueError(_('Only http and https requests '
                                'are allowed in url %s') % value)
     else:
         result = value.split('/')
         if len(result) != 4 or result[1] != 'artifacts':
             raise ValueError(
                 _('Dependency link %(link)s is not valid in field '
                   '%(attr)s. The link must be either valid url or '
                   'reference to artifact. Example: '
                   '/artifacts/<artifact_type>/<artifact_id>'
                   ) % {'link': value, 'attr': attr})
     return value
Beispiel #10
0
def validate_key_cert(key_file, cert_file):
    try:
        error_key_name = "private key"
        error_filename = key_file
        with open(key_file, 'r') as keyfile:
            key_str = keyfile.read()
        key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_str)

        error_key_name = "certificate"
        error_filename = cert_file
        with open(cert_file, 'r') as certfile:
            cert_str = certfile.read()
        cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_str)
    except IOError as ioe:
        raise RuntimeError(
            _("There is a problem with your %(error_key_name)s "
              "%(error_filename)s.  Please verify it."
              "  Error: %(ioe)s") % {
                  'error_key_name': error_key_name,
                  'error_filename': error_filename,
                  'ioe': ioe
              })
    except crypto.Error as ce:
        raise RuntimeError(
            _("There is a problem with your %(error_key_name)s "
              "%(error_filename)s.  Please verify it. OpenSSL"
              " error: %(ce)s") % {
                  'error_key_name': error_key_name,
                  'error_filename': error_filename,
                  'ce': ce
              })

    try:
        data = str(uuid.uuid4())
        # On Python 3, explicitly encode to UTF-8 to call crypto.sign() which
        # requires bytes. Otherwise, it raises a deprecation warning (and
        # will raise an error later).
        data = encodeutils.to_utf8(data)
        digest = CONF.digest_algorithm
        if digest == 'sha1':
            LOG.warn(
                _LW('The FIPS (FEDERAL INFORMATION PROCESSING STANDARDS)'
                    ' state that the SHA-1 is not suitable for'
                    ' general-purpose digital signature applications (as'
                    ' specified in FIPS 186-3) that require 112 bits of'
                    ' security. The default value is sha1 in Kilo for a'
                    ' smooth upgrade process, and it will be updated'
                    ' with sha256 in next release(L).'))
        out = crypto.sign(key, data, digest)
        crypto.verify(cert, out, data, digest)
    except crypto.Error as ce:
        raise RuntimeError(
            _("There is a problem with your key pair.  "
              "Please verify that cert %(cert_file)s and "
              "key %(key_file)s belong together.  OpenSSL "
              "error %(ce)s") % {
                  'cert_file': cert_file,
                  'key_file': key_file,
                  'ce': ce
              })
Beispiel #11
0
    def delete_external_blob(self,
                             context,
                             type_name,
                             artifact_id,
                             field_name,
                             blob_key=None):
        """Delete artifact blob with external location.

        :param context: user context
        :param type_name: name of artifact type
        :param artifact_id: id of artifact with the blob to delete
        :param field_name: name of blob or blob dict field
        :param blob_key: if field_name is blob dict it specifies key
         in this dictionary
        """
        af = self._show_artifact(context, type_name, artifact_id)
        action_name = 'artifact:delete_blob'
        policy.authorize(action_name, af.to_dict(), context)

        blob_name = self._generate_blob_name(field_name, blob_key)

        blob = self._get_blob_info(af, field_name, blob_key)
        if blob is None:
            msg = _("Blob %s wasn't found for artifact") % blob_name
            raise exception.NotFound(message=msg)
        if not blob['external']:
            msg = _("Blob %s is not external") % blob_name
            raise exception.Forbidden(message=msg)

        af = self._save_blob_info(context, af, field_name, blob_key, None)

        Notifier.notify(context, action_name, af)
        return af.to_dict()
Beispiel #12
0
    def activate(cls, context, af, values):
        """Activate Artifact and make it available for users

        :param context: User Context
        :param af: current Artifact definition in Glare
        :return: definition of activated Artifact
        """
        # validate that came to artifact as updates
        if values != {'status': cls.STATUS.ACTIVE}:
            msg = _("Only {'status': %s} is allowed in a request "
                    "for activation.") % cls.STATUS.ACTIVE
            raise exception.BadRequest(msg)

        for name, type_obj in six.iteritems(af.fields):
            if type_obj.required_on_activate and getattr(af, name) is None:
                msg = _("'%s' attribute must be set before activation") % name
                raise exception.BadRequest(msg)

        cls.validate_activate(context, af)
        if af.status != cls.STATUS.QUEUED:
            raise exception.InvalidStatusTransition(
                orig=af.status, new=cls.STATUS.ACTIVE
            )
        LOG.info(_LI("Parameters validation for artifact %(artifact)s "
                     "activate passed for request %(request)s."),
                 {'artifact': af.id, 'request': context.request_id})
        active_af = cls.db_api.update(context, af.id, values)
        return cls._init_artifact(context, active_af)
Beispiel #13
0
    def publish(cls, context, af, values):
        """Make Artifact available for everyone

        :param context: user context
        :param af: definition of published Artifact
        :return: definition of active Artifact
        """
        if values != {'visibility': 'public'}:
            msg = _("Only {'visibility': 'public'} is allowed in a request "
                    "for artifact publish.")
            raise exception.BadRequest(msg)

        with cls.lock_engine.acquire(context, cls._get_versioning_scope(
                context, values, af)):
            if af.status != cls.STATUS.ACTIVE:
                msg = _("Cannot publish non-active artifact")
                raise exception.BadRequest(msg)

            cls._validate_versioning(context, af.name, af.version,
                                     is_public=True)
            cls.validate_publish(context, af)
            LOG.info(_LI("Parameters validation for artifact %(artifact)s "
                         "publish passed for request %(request)s."),
                     {'artifact': af.id, 'request': context.request_id})
            af = cls.db_api.update(context, af.id, values)
            return cls._init_artifact(context, af)
Beispiel #14
0
    def coerce(obj, field, value):
        # to remove the existing link user sets its value to None,
        # we have to consider this case.
        if value is None:
            return value
        # check that value is string
        if not isinstance(value, six.string_types):
            raise ValueError(
                _('A string is required in field %(field)s, '
                  'not a %(type)s') % {
                      'field': field,
                      'type': type(value).__name__
                  })
        # determine if link is external or internal
        external = LinkFieldType.is_external(value)
        # validate link itself
        if external:
            link = urlparse.urlparse(value)
            if link.scheme not in ('http', 'https'):
                raise ValueError(
                    _('Only http and https requests '
                      'are allowed in url %s') % value)
            try:
                with urlrequest.urlopen(value) as data:
                    data.read(1)
            except Exception:
                raise ValueError(
                    _('Link %(link)s is not valid in field '
                      '%(field)s. The link must be either valid url or '
                      'reference to artifact. Example: '
                      'http://glarehost:9494/artifacts/<artifact_type>/'
                      '<artifact_id>') % {
                          'link': value,
                          'field': field
                      })
        else:
            result = value.split('/')
            if len(result) != 4 or result[1] != 'artifacts':
                raise ValueError(
                    _('Link %(link)s is not valid in field '
                      '%(field)s. The link must be either valid url or '
                      'reference to artifact. Example: '
                      '/artifacts/<artifact_type>/<artifact_id>') % {
                          'link': value,
                          'field': field
                      })
            # try to find the referenced artifact
            try:
                obj.db_api.get(obj.obj_context, None, result[3])
            except exception.NotFound:
                raise ValueError(
                    _("Link %(link)s is not valid in field %(field)s, because "
                      "artifact with id %(art_id)s doesn't exist") % {
                          'link': value,
                          'field': field,
                          'art_id': result[3]
                      })

        return value
Beispiel #15
0
def verify_uploaded_data_amount(context, type_name, data_amount=None):
    """Verify if user can upload data based on his quota limits.

    :param context: user context
    :param type_name: name of artifact type
    :param data_amount: number of bytes user wants to upload. Value None means
     that user hasn't specified data amount. In this case don't raise an
     exception, but just return the amount of data he is able to upload.
    :return: number of bytes user can upload if data_amount isn't specified
    """
    global_limit = CONF.max_uploaded_data
    type_limit = getattr(CONF, 'artifact_type:' + type_name).max_uploaded_data

    # update limits if they were reassigned for project
    project_id = context.project_id
    quotas = list_quotas(project_id).get(project_id, {})
    if 'max_uploaded_data' in quotas:
        global_limit = quotas['max_uploaded_data']
    if 'max_uploaded_data:' + type_name in quotas:
        type_limit = quotas['max_uploaded_data:' + type_name]

    session = api.get_session()
    res = -1

    if global_limit != -1:
        # the whole amount of created artifacts
        whole_number = api.calculate_uploaded_data(context, session)
        if data_amount is None:
            res = global_limit - whole_number
        elif whole_number + data_amount > global_limit:
            msg = _("Can't upload %(data_amount)d byte(s) because of global "
                    "quota limit: %(global_limit)d. "
                    "You have %(whole_number)d bytes uploaded.") % {
                        'data_amount': data_amount,
                        'global_limit': global_limit,
                        'whole_number': whole_number
                    }
            raise exception.RequestEntityTooLarge(msg)

    if type_limit != -1:
        # the amount of artifacts for specific type
        type_number = api.calculate_uploaded_data(context, session, type_name)
        if data_amount is None:
            available = type_limit - type_number
            res = available if res == -1 else min(res, available)
        elif type_number + data_amount > type_limit:
            msg = _("Can't upload %(data_amount)d byte(s) because of "
                    "quota limit for artifact type '%(type_name)s': "
                    "%(type_limit)d. You have %(type_number)d bytes "
                    "uploaded for this type.") % {
                        'data_amount': data_amount,
                        'type_name': type_name,
                        'type_limit': type_limit,
                        'type_number': type_number
                    }
            raise exception.RequestEntityTooLarge(msg)
    return res
Beispiel #16
0
    def delete(cls, context, af):
        """Delete Artifact and all blobs from Glare.

        :param context: user context
        :param af: definition of artifact targeted to delete
        """
        if af.visibility == 'public' and not context.is_admin:
            msg = _("Only admins are allowed to delete public images")
            raise exception.Forbidden(msg)
        # marking all blobs as pending delete
        blobs = {}
        for name, field in six.iteritems(af.fields):
            if cls.is_blob(name):
                b = getattr(af, name)
                if b:
                    if b['status'] == BlobStatus.PENDING_DELETE:
                        msg = _('Blob %(name)s is already deleting '
                                'for artifact %(id)s') % {'name': name,
                                                          'id': af.id}
                        raise exception.Conflict(msg)
                    else:
                        b['status'] = BlobStatus.PENDING_DELETE
                        blobs[name] = b
            elif cls.is_blob_dict(name):
                bd = getattr(af, name)
                if bd:
                    for key, b in six.iteritems(bd):
                        if b['status'] == BlobStatus.PENDING_DELETE:
                            msg = _('Blob %(name)s is already deleting '
                                    'for artifact %(id)s') % {'name': name,
                                                              'id': af.id}
                            raise exception.Conflict(msg)
                        else:
                            b['status'] = BlobStatus.PENDING_DELETE
                    blobs[name] = bd
        if blobs:
            LOG.debug("Marked all blobs %(blobs) for artifact %(artifact)s "
                      "as pending delete. Start blobs delete.",
                      {'blobs': blobs, 'artifact': af.id})
            cls.db_api.update(context, af.id, blobs)
            # delete blobs one by one
            if not CONF.delayed_blob_delete:
                for name, blob in six.iteritems(blobs):
                    if cls.is_blob(name):
                        store_api.delete_blob(blob['url'], context=context)
                        cls.db_api.update(context, af.id, {name: None})
                    elif cls.is_blob_dict(name):
                        upd_blob = deepcopy(blob)
                        for key, val in six.iteritems(blob):
                            store_api.delete_blob(val['url'], context=context)
                            del upd_blob[key]
                            cls.db_api.update(context, af.id, {name: upd_blob})

            LOG.info(_LI("Blobs successfully deleted for artifact %s"), af.id)
        # delete artifact itself
        cls.db_api.delete(context, af.id)
Beispiel #17
0
 def from_json(self, datastring):
     try:
         jsondata = jsonutils.loads(datastring, object_hook=self._sanitizer)
         if not isinstance(jsondata, (dict, list)):
             msg = _('Unexpected body type. Expected list/dict.')
             raise webob.exc.HTTPBadRequest(explanation=msg)
         return jsondata
     except ValueError:
         msg = _('Malformed JSON in request body.')
         raise webob.exc.HTTPBadRequest(explanation=msg)
Beispiel #18
0
 def from_json(self, datastring):
     try:
         jsondata = jsonutils.loads(datastring, object_hook=self._sanitizer)
         if not isinstance(jsondata, (dict, list)):
             msg = _('Unexpected body type. Expected list/dict.')
             raise webob.exc.HTTPBadRequest(explanation=msg)
         return jsondata
     except ValueError:
         msg = _('Malformed JSON in request body.')
         raise webob.exc.HTTPBadRequest(explanation=msg)
Beispiel #19
0
 def _get_blob_info(af, field_name, blob_key=None):
     """Return requested blob info."""
     if blob_key:
         if not af.is_blob_dict(field_name):
             msg = _("%s is not a blob dict") % field_name
             raise exception.BadRequest(msg)
         return getattr(af, field_name).get(blob_key)
     else:
         if not af.is_blob(field_name):
             msg = _("%s is not a blob") % field_name
             raise exception.BadRequest(msg)
         return getattr(af, field_name, None)
Beispiel #20
0
def validate_key_cert(key_file, cert_file):
    try:
        error_key_name = "private key"
        error_filename = key_file
        with open(key_file, 'r') as keyfile:
            key_str = keyfile.read()
        key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_str)

        error_key_name = "certificate"
        error_filename = cert_file
        with open(cert_file, 'r') as certfile:
            cert_str = certfile.read()
        cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_str)
    except IOError as ioe:
        raise RuntimeError(_("There is a problem with your %(error_key_name)s "
                             "%(error_filename)s.  Please verify it."
                             "  Error: %(ioe)s") %
                           {'error_key_name': error_key_name,
                            'error_filename': error_filename,
                            'ioe': ioe})
    except crypto.Error as ce:
        raise RuntimeError(_("There is a problem with your %(error_key_name)s "
                             "%(error_filename)s.  Please verify it. OpenSSL"
                             " error: %(ce)s") %
                           {'error_key_name': error_key_name,
                            'error_filename': error_filename,
                            'ce': ce})

    try:
        data = str(uuid.uuid4())
        # On Python 3, explicitly encode to UTF-8 to call crypto.sign() which
        # requires bytes. Otherwise, it raises a deprecation warning (and
        # will raise an error later).
        data = encodeutils.to_utf8(data)
        digest = CONF.digest_algorithm
        if digest == 'sha1':
            LOG.warn(
                _LW('The FIPS (FEDERAL INFORMATION PROCESSING STANDARDS)'
                    ' state that the SHA-1 is not suitable for'
                    ' general-purpose digital signature applications (as'
                    ' specified in FIPS 186-3) that require 112 bits of'
                    ' security. The default value is sha1 in Kilo for a'
                    ' smooth upgrade process, and it will be updated'
                    ' with sha256 in next release(L).'))
        out = crypto.sign(key, data, digest)
        crypto.verify(cert, out, data, digest)
    except crypto.Error as ce:
        raise RuntimeError(_("There is a problem with your key pair.  "
                             "Please verify that cert %(cert_file)s and "
                             "key %(key_file)s belong together.  OpenSSL "
                             "error %(ce)s") % {'cert_file': cert_file,
                                                'key_file': key_file,
                                                'ce': ce})
Beispiel #21
0
def get_location_info(url, context, max_size, calc_checksum=True):
    """Validate location and get information about external blob

    :param url: blob url
    :param context: user context
    :param calc_checksum: define if checksum must be calculated
    :return: blob size and checksum
    """
    # validate uri
    scheme = urlparse.urlparse(url).scheme
    if scheme not in ('http', 'https'):
        msg = _("Location %s is invalid.") % url
        raise exception.BadRequest(message=msg)

    res = urllib.urlopen(url)
    http_message = res.info()
    content_type = getattr(http_message, 'type') or 'application/octet-stream'

    # calculate blob checksum to ensure that location blob won't be changed
    # in future
    # TODO(kairat) need to support external location signatures
    checksum = None
    size = 0
    if calc_checksum:
        checksum = hashlib.md5()
        blob_data = load_from_store(url, context)
        for buf in blob_data:
            checksum.update(buf)
            size += len(buf)
            if size > max_size:
                msg = _("External blob size %(size)d exceeds maximum allowed "
                        "size %(max)d."), {
                            'size': size,
                            'max': max_size
                        }
                raise exception.BadRequest(message=msg)
        checksum = checksum.hexdigest()
    else:
        # request blob size
        size = get_blob_size(url, context=context)
        if size < 0 or size > max_size:
            msg = _("Invalid blob size %d.") % size
            raise exception.BadRequest(message=msg)

    LOG.debug(
        "Checksum %(checksum)s and size %(size)s calculated "
        "successfully for location %(location)s", {
            'checksum': str(checksum),
            'size': str(size),
            'location': url
        })

    return size, checksum, content_type
Beispiel #22
0
 def _check_dict(data_dict):
     # a dict of dicts has to be checked recursively
     for key, value in six.iteritems(data_dict):
         if isinstance(value, dict):
             _check_dict(value)
         else:
             if _is_match(key):
                 msg = _("Property names can't contain 4 byte unicode.")
                 raise exception.Invalid(msg)
             if _is_match(value):
                 msg = (_("%s can't contain 4 byte unicode characters.")
                        % key.title())
                 raise exception.Invalid(msg)
Beispiel #23
0
 def _check_dict(data_dict):
     # a dict of dicts has to be checked recursively
     for key, value in data_dict.items():
         if isinstance(value, dict):
             _check_dict(value)
         else:
             if _is_match(key):
                 msg = _("Property names can't contain 4 byte unicode.")
                 raise exception.BadRequest(msg)
             if _is_match(value):
                 msg = (_("%s can't contain 4 byte unicode characters.")
                        % key.title())
                 raise exception.BadRequest(msg)
Beispiel #24
0
def validate_visibility_transition(af, from_visibility, to_visibility):
    if to_visibility == 'private':
        if from_visibility != 'private':
            msg = _("Cannot make artifact private again.")
            raise exception.Forbidden()
    elif to_visibility == 'public':
        if af.status != 'active':
            msg = _("Cannot change visibility to 'public' if artifact"
                    " is not active.")
            raise exception.Forbidden(msg)
    else:
        msg = _("Unknown artifact visibility: %s.") % to_visibility
        raise exception.BadRequest(msg)
Beispiel #25
0
 def _parse_sort_values(cls, sort):
     new_sort = []
     for key, direction in sort:
         if key not in cls.fields:
             msg = _("The field %s doesn't exist.") % key
             raise exception.BadRequest(msg)
         # check if field can be sorted
         if not cls.fields[key].sortable:
             msg = _("The field %s is not sortable.") % key
             raise exception.BadRequest(msg)
         new_sort.append((key, direction, cls._get_field_type(
             cls.fields.get(key))))
     return new_sort
Beispiel #26
0
    def __call__(self, request):
        """WSGI method that controls (de)serialization and method dispatch."""
        action_args = self.get_action_args(request.environ)
        action = action_args.pop('action', None)
        body_reject = strutils.bool_from_string(
            action_args.pop('body_reject', None))

        try:
            if body_reject and self.deserializer.has_body(request):
                msg = _('A body is not expected with this request.')
                raise webob.exc.HTTPBadRequest(explanation=msg)
            deserialized_request = self.dispatch(self.deserializer,
                                                 action, request)
            action_args.update(deserialized_request)
            action_result = self.dispatch(self.controller, action,
                                          request, **action_args)
        except webob.exc.WSGIHTTPException as e:
            exc_info = sys.exc_info()
            e = translate_exception(request, e)
            six.reraise(type(e), e, exc_info[2])
        except glare_exc.GlareException:
            raise
        except UnicodeDecodeError:
            msg = _("Error decoding your request. Either the URL or the "
                    "request body contained characters that could not be "
                    "decoded by Glare")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except Exception as e:
            LOG.exception(_LE("Caught error: %s"),
                          encodeutils.exception_to_unicode(e))
            response = webob.exc.HTTPInternalServerError(explanation=str(e))
            return response

        try:
            response = webob.Response(request=request)
            self.dispatch(self.serializer, action, response, action_result)
            # encode all headers in response to utf-8 to prevent unicode errors
            for name, value in list(response.headers.items()):
                if six.PY2 and isinstance(value, six.text_type):
                    response.headers[name] = encodeutils.safe_encode(value)
            return response
        except webob.exc.WSGIHTTPException as e:
            return translate_exception(request, e)
        except webob.exc.HTTPException as e:
            return e
        except glare_exc.GlareException:
            raise
        # return unserializable result (typically a webob exc)
        except Exception:
            return action_result
Beispiel #27
0
    def _get_content_type(req, expected=None):
        """Determine content type of the request body."""
        if "Content-Type" not in req.headers:
            msg = _("Content-Type must be specified.")
            LOG.error(msg)
            raise exc.BadRequest(msg)

        content_type = req.content_type
        if expected is not None and content_type not in expected:
            msg = (_('Invalid content type: %(ct)s. Expected: %(exp)s') %
                   {'ct': content_type, 'exp': ', '.join(expected)})
            raise exc.UnsupportedMediaType(message=msg)

        return content_type
Beispiel #28
0
def get_socket(default_port):
    """
    Bind socket to bind ip:port in conf

    note: Mostly comes from Swift with a few small changes...

    :param default_port: port to bind to if none is specified in conf

    :returns: a socket object as returned from socket.listen or
               ssl.wrap_socket if conf specifies cert_file
    """
    bind_addr = get_bind_addr(default_port)

    # TODO(jaypipes): eventlet's greened socket module does not actually
    # support IPv6 in getaddrinfo(). We need to get around this in the
    # future or monitor upstream for a fix
    address_family = [
        addr[0] for addr in socket.getaddrinfo(
            bind_addr[0], bind_addr[1], socket.AF_UNSPEC, socket.SOCK_STREAM)
        if addr[0] in (socket.AF_INET, socket.AF_INET6)
    ][0]

    use_ssl = CONF.key_file or CONF.cert_file
    if use_ssl and (not CONF.key_file or not CONF.cert_file):
        raise RuntimeError(
            _("When running server in SSL mode, you must "
              "specify both a cert_file and key_file "
              "option value in your configuration file"))

    sock = utils.get_test_suite_socket()
    retry_until = time.time() + 30

    while not sock and time.time() < retry_until:
        try:
            sock = eventlet.listen(bind_addr,
                                   backlog=CONF.backlog,
                                   family=address_family)
        except socket.error as err:
            if err.args[0] != errno.EADDRINUSE:
                raise
            eventlet.sleep(0.1)
    if not sock:
        raise RuntimeError(
            _("Could not bind to %(host)s:%(port)s after"
              " trying for 30 seconds") % {
                  'host': bind_addr[0],
                  'port': bind_addr[1]
              })

    return sock
Beispiel #29
0
    def __call__(self, request):
        """WSGI method that controls (de)serialization and method dispatch."""
        action_args = self.get_action_args(request.environ)
        action = action_args.pop('action', None)
        body_reject = strutils.bool_from_string(
            action_args.pop('body_reject', None))

        try:
            if body_reject and self.deserializer.has_body(request):
                msg = _('A body is not expected with this request.')
                raise webob.exc.HTTPBadRequest(explanation=msg)
            deserialized_request = self.dispatch(self.deserializer,
                                                 action, request)
            action_args.update(deserialized_request)
            action_result = self.dispatch(self.controller, action,
                                          request, **action_args)
        except webob.exc.WSGIHTTPException as e:
            exc_info = sys.exc_info()
            e = translate_exception(request, e)
            six.reraise(type(e), e, exc_info[2])
        except glare_exc.GlareException:
            raise
        except UnicodeDecodeError:
            msg = _("Error decoding your request. Either the URL or the "
                    "request body contained characters that could not be "
                    "decoded by Glance")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except Exception as e:
            LOG.exception(_LE("Caught error: %s"),
                          encodeutils.exception_to_unicode(e))
            response = webob.exc.HTTPInternalServerError()
            return response

        try:
            response = webob.Response(request=request)
            self.dispatch(self.serializer, action, response, action_result)
            # encode all headers in response to utf-8 to prevent unicode errors
            for name, value in list(response.headers.items()):
                if six.PY2 and isinstance(value, six.text_type):
                    response.headers[name] = encodeutils.safe_encode(value)
            return response
        except webob.exc.WSGIHTTPException as e:
            return translate_exception(request, e)
        except webob.exc.HTTPException as e:
            return e
        except glare_exc.GlareException:
            raise
        # return unserializable result (typically a webob exc)
        except Exception:
            return action_result
Beispiel #30
0
 def _parse_sort_values(cls, sort):
     """Prepare sorting parameters for database."""
     new_sort = []
     for key, direction in sort:
         if key not in cls.fields:
             msg = _("The field %s doesn't exist.") % key
             raise exception.BadRequest(msg)
         # check if field can be sorted
         if not cls.fields[key].sortable:
             msg = _("The field %s is not sortable.") % key
             raise exception.BadRequest(msg)
         new_sort.append(
             (key, direction, cls._get_field_type(cls.fields.get(key))))
     return new_sort
Beispiel #31
0
def get_socket(default_port):
    """
    Bind socket to bind ip:port in conf

    note: Mostly comes from Swift with a few small changes...

    :param default_port: port to bind to if none is specified in conf

    :returns: a socket object as returned from socket.listen or
               ssl.wrap_socket if conf specifies cert_file
    """
    bind_addr = get_bind_addr(default_port)

    # TODO(jaypipes): eventlet's greened socket module does not actually
    # support IPv6 in getaddrinfo(). We need to get around this in the
    # future or monitor upstream for a fix
    address_family = [
        addr[0] for addr in socket.getaddrinfo(bind_addr[0],
                                               bind_addr[1],
                                               socket.AF_UNSPEC,
                                               socket.SOCK_STREAM)
        if addr[0] in (socket.AF_INET, socket.AF_INET6)
    ][0]

    use_ssl = CONF.key_file or CONF.cert_file
    if use_ssl and (not CONF.key_file or not CONF.cert_file):
        raise RuntimeError(_("When running server in SSL mode, you must "
                             "specify both a cert_file and key_file "
                             "option value in your configuration file"))

    sock = utils.get_test_suite_socket()
    retry_until = time.time() + 30

    while not sock and time.time() < retry_until:
        try:
            sock = eventlet.listen(bind_addr,
                                   backlog=CONF.backlog,
                                   family=address_family)
        except socket.error as err:
            if err.args[0] != errno.EADDRINUSE:
                raise
            eventlet.sleep(0.1)
    if not sock:
        raise RuntimeError(_("Could not bind to %(host)s:%(port)s after"
                             " trying for 30 seconds") %
                           {'host': bind_addr[0],
                            'port': bind_addr[1]})

    return sock
Beispiel #32
0
 def validate(self, value):
     for fc in self.forbidden_chars:
         if fc in value:
             raise ValueError(
                 _("Forbidden character %(char) found in string "
                   "%(string)s")
                 % {"char": fc, "string": value})
Beispiel #33
0
 def validate(self, value):
     l = len(value)
     if l > self.size:
         raise ValueError(
             _("Number of items must be less than  "
               "%(size)s. Current size: %(cur)s") %
             {'size': self.size, 'cur': l})
Beispiel #34
0
        def version_select(*args, **kwargs):
            """Look for the method which matches the name supplied and version
            constraints and calls it with the supplied arguments.
            :returns: Returns the result of the method called
            :raises: VersionNotFoundForAPIMethod if there is no method which
                 matches the name and version constraints
            """
            # versioning is used in 3 classes: request deserializer and
            # controller have request as first argument
            # response serializer has response as first argument
            # we must respect all three cases
            if hasattr(args[0], 'api_version_request'):
                ver = args[0].api_version_request
            elif hasattr(args[0], 'request'):
                ver = args[0].request.api_version_request
            else:
                raise exc.VersionNotFoundForAPIMethod(
                    message=_("Api version not found in the request."))

            func_list = self.versioned_methods[key]
            for func in func_list:
                if ver.matches(func.start_version, func.end_version):
                    # Update the version_select wrapper function so
                    # other decorator attributes like wsgi.response
                    # are still respected.
                    functools.update_wrapper(version_select, func.func)
                    return func.func(self, *args, **kwargs)

            # No version match
            raise exc.VersionNotFoundForAPIMethod(version=ver)
Beispiel #35
0
 def validate(self, value):
     for item in value:
         if item not in self.allowed_items:
             raise ValueError(_("Key %(item)s is not allowed in dict. "
                                "Allowed key values: %(allowed)s") %
                              {"item": item,
                               "allowed": ', '.join(self.allowed_items)})
Beispiel #36
0
 def validate(self, value):
     for item in self.required_items:
         if item not in value:
             raise ValueError(_("Key %(item)s is required in dict. "
                                "Required key values: %(required)s") %
                              {"item": item,
                               "required": ', '.join(self.required_items)})
Beispiel #37
0
 def validate(self, value):
     l = len(value)
     if l > self.size:
         raise ValueError(
             _("String length must be less than  %(size)s. "
               "Current size: %(cur)s") % {'size': self.size,
                                           'cur': l})
Beispiel #38
0
 def show_type_schema(cls, context, type_name):
     policy.authorize("artifact:type_list", {}, context)
     schemas = cls._get_schemas(cls.registry)
     if type_name not in schemas:
         msg = _("Artifact type %s does not exist") % type_name
         raise exception.NotFound(message=msg)
     return schemas[type_name]
Beispiel #39
0
def evaluate_filter_op(value, operator, threshold):
    """Evaluate a comparison operator.
    Designed for use on a comparative-filtering query field.

    :param value: evaluated against the operator, as left side of expression
    :param operator: any supported filter operation
    :param threshold: to compare value against, as right side of expression

    :raises: InvalidFilterOperatorValue if an unknown operator is provided

    :returns: boolean result of applied comparison

    """
    if operator == 'gt':
        return value > threshold
    elif operator == 'gte':
        return value >= threshold
    elif operator == 'lt':
        return value < threshold
    elif operator == 'lte':
        return value <= threshold
    elif operator == 'neq':
        return value != threshold
    elif operator == 'eq':
        return value == threshold

    msg = _("Unable to filter on a unknown operator.")
    raise exception.InvalidFilterOperatorValue(msg)
Beispiel #40
0
        def version_select(*args, **kwargs):
            """Look for the method which matches the name supplied and version
            constraints and calls it with the supplied arguments.
            :returns: Returns the result of the method called
            :raises: VersionNotFoundForAPIMethod if there is no method which
                 matches the name and version constraints
            """
            # versioning is used in 3 classes: request deserializer and
            # controller have request as first argument
            # response serializer has response as first argument
            # we must respect all three cases
            if hasattr(args[0], 'api_version_request'):
                ver = args[0].api_version_request
            elif hasattr(args[0], 'request'):
                ver = args[0].request.api_version_request
            else:
                raise exc.VersionNotFoundForAPIMethod(
                    message=_("Api version not found in the request."))

            func_list = self.versioned_methods[key]
            for func in func_list:
                if ver.matches(func.start_version, func.end_version):
                    # Update the version_select wrapper function so
                    # other decorator attributes like wsgi.response
                    # are still respected.
                    functools.update_wrapper(version_select, func.func)
                    return func.func(self, *args, **kwargs)

            # No version match
            raise exc.VersionNotFoundForAPIMethod(version=ver)
Beispiel #41
0
    def wrapper(*args, **kwargs):

        def _is_match(some_str):
            return (isinstance(some_str, six.text_type) and
                    REGEX_4BYTE_UNICODE.findall(some_str) != [])

        def _check_dict(data_dict):
            # a dict of dicts has to be checked recursively
            for key, value in six.iteritems(data_dict):
                if isinstance(value, dict):
                    _check_dict(value)
                else:
                    if _is_match(key):
                        msg = _("Property names can't contain 4 byte unicode.")
                        raise exception.Invalid(msg)
                    if _is_match(value):
                        msg = (_("%s can't contain 4 byte unicode characters.")
                               % key.title())
                        raise exception.Invalid(msg)

        for data_dict in [arg for arg in args if isinstance(arg, dict)]:
            _check_dict(data_dict)
        # now check args for str values
        for arg in args:
            if _is_match(arg):
                msg = _("Param values can't contain 4 byte unicode.")
                raise exception.Invalid(msg)
        # check kwargs as well, as params are passed as kwargs via
        # registry calls
        _check_dict(kwargs)
        return f(*args, **kwargs)
Beispiel #42
0
 def _validate_versioning(cls, context, name, version, is_public=False):
     if version is not None and name not in (None, ""):
         filters = {'name': name, 'version': version,
                    'status': 'neq:deleted'}
         if is_public is False:
             filters.update({'owner': context.tenant,
                             'visibility': 'private'})
         else:
             filters.update({'visibility': 'public'})
         if len(cls.list(context, MultiDict(filters))) > 0:
             msg = _("Artifact with this name and version is already "
                     "exists for this owner.")
             raise exception.Conflict(msg)
     else:
         msg = _("Cannot set artifact version without name and version.")
         raise exception.BadRequest(msg)
Beispiel #43
0
 def validate(self, value):
     for item in value:
         if item not in self.allowed_items:
             raise ValueError(_("Key %(item)s is not allowed in dict. "
                                "Allowed key values: %(allowed)s") %
                              {"item": item,
                               "allowed": ', '.join(self.allowed_items)})
Beispiel #44
0
    def _create_scoped_lock(self,
                            context,
                            type_name,
                            name,
                            version,
                            owner,
                            visibility='private'):
        """Create scoped lock for artifact."""
        # validate that artifact doesn't exist for the scope
        filters = [('name', 'eq:' + name), ('version', 'eq:' + version)]
        if visibility == 'public':
            filters.extend([('visibility', 'public')])
        elif visibility == 'private':
            filters.extend([('owner', 'eq:' + owner),
                            ('visibility', 'private')])

        scope_id = "%s:%s:%s" % (type_name, name, version)
        if visibility != 'public':
            scope_id += ':%s' % owner
        lock = self.lock_engine.acquire(context, scope_id)

        try:
            if self.list(context, type_name, filters).get("total_count") > 0:
                msg = _("Artifact with this name and version is already "
                        "exists for this scope.")
                raise exception.Conflict(msg)
        except Exception:
            with excutils.save_and_reraise_exception(logger=LOG):
                self.lock_engine.release(lock)

        return lock
Beispiel #45
0
 def __call__(self, value):
     l = len(value)
     if l < self.size:
         raise ValueError(
             _("Number of items must be greater than  "
               "%(size)d. Current size: %(cur)d") %
             {'size': self.size, 'cur': l})
Beispiel #46
0
 def validate(self, value):
     l = len(value)
     if l > self.size:
         raise ValueError(
             _("Number of items must be less than  "
               "%(size)s. Current size: %(cur)s") %
             {'size': self.size, 'cur': l})
Beispiel #47
0
 def validate(self, value):
     l = len(value)
     if l < self.size:
         raise ValueError(
             _("String length must be more than  %(size)s. "
               "Current size: %(cur)s") % {'size': self.size,
                                           'cur': l})
Beispiel #48
0
 def validate(self, value):
     for fc in self.forbidden_chars:
         if fc in value:
             raise ValueError(
                 _("Forbidden character %(char) found in string "
                   "%(string)s")
                 % {"char": fc, "string": value})
Beispiel #49
0
    def _get_content_type(req, expected=None):
        """Determine content type of the request body."""
        if "Content-Type" not in req.headers:
            msg = _("Content-Type must be specified.")
            LOG.error(msg)
            raise exc.BadRequest(msg)

        content_type = req.content_type
        if expected is not None and content_type not in expected:
            msg = (_('Invalid content type: %(ct)s. Expected: %(exp)s') % {
                'ct': content_type,
                'exp': ', '.join(expected)
            })
            raise exc.UnsupportedMediaType(message=msg)

        return content_type
Beispiel #50
0
 def create(self, req):
     self._get_content_type(req, expected=['application/json'])
     body = self._get_request_body(req)
     if not isinstance(body, dict):
         msg = _("Dictionary expected as body value. Got %s.") % type(body)
         raise exc.BadRequest(msg)
     return {'values': body}
Beispiel #51
0
    def wrapper(*args, **kwargs):
        def _is_match(some_str):
            return (isinstance(some_str, six.text_type)
                    and REGEX_4BYTE_UNICODE.findall(some_str) != [])

        def _check_dict(data_dict):
            # a dict of dicts has to be checked recursively
            for key, value in six.iteritems(data_dict):
                if isinstance(value, dict):
                    _check_dict(value)
                else:
                    if _is_match(key):
                        msg = _("Property names can't contain 4 byte unicode.")
                        raise exception.Invalid(msg)
                    if _is_match(value):
                        msg = (
                            _("%s can't contain 4 byte unicode characters.") %
                            key.title())
                        raise exception.Invalid(msg)

        for data_dict in [arg for arg in args if isinstance(arg, dict)]:
            _check_dict(data_dict)
        # now check args for str values
        for arg in args:
            if _is_match(arg):
                msg = _("Param values can't contain 4 byte unicode.")
                raise exception.Invalid(msg)
        # check kwargs as well, as params are passed as kwargs via
        # registry calls
        _check_dict(kwargs)
        return f(*args, **kwargs)
Beispiel #52
0
def evaluate_filter_op(value, operator, threshold):
    """Evaluate a comparison operator.
    Designed for use on a comparative-filtering query field.

    :param value: evaluated against the operator, as left side of expression
    :param operator: any supported filter operation
    :param threshold: to compare value against, as right side of expression

    :raises: InvalidFilterOperatorValue if an unknown operator is provided

    :returns: boolean result of applied comparison

    """
    if operator == 'gt':
        return value > threshold
    elif operator == 'gte':
        return value >= threshold
    elif operator == 'lt':
        return value < threshold
    elif operator == 'lte':
        return value <= threshold
    elif operator == 'neq':
        return value != threshold
    elif operator == 'eq':
        return value == threshold

    msg = _("Unable to filter on a unknown operator.")
    raise exception.InvalidFilterOperatorValue(msg)
Beispiel #53
0
 def get_type_name(link):
     url = link.split('/')
     if len(url) == 4:
         return url[2]
     else:
         raise ValueError(_("It is not possible to "
                            "extract type_name from link %s"), link)
Beispiel #54
0
 def create(self, req):
     self._get_content_type(req, expected=['application/json'])
     body = self._get_request_body(req)
     if not isinstance(body, dict):
         msg = _("Dictionary expected as body value. Got %s.") % type(body)
         raise exc.BadRequest(msg)
     return {'values': body}
Beispiel #55
0
    def deactivate(cls, context, af, values):
        """Deny Artifact downloading due to security concerns

        If user uploaded suspicious Artifact then Cloud Admins(or other users -
        it depends on policy configurations) can deny Artifact download by
        users by making Artifact de-activated. After additional investigation
        Artifact can be re-activated or deleted from Glare.

        :param context: user context
        :param af: Artifact definition in Glare
        :return: definition of de-activated Artifact
        """
        if values != {'status': cls.STATUS.DEACTIVATED}:
            msg = _("Only {'status': %s} is allowed in a request "
                    "for deactivation.") % cls.STATUS.DEACTIVATED
            raise exception.BadRequest(msg)

        if af.status != cls.STATUS.ACTIVE:
            raise exception.InvalidStatusTransition(
                orig=af.status, new=cls.STATUS.ACTIVE
            )
        LOG.info(_LI("Parameters validation for artifact %(artifact)s "
                     "deactivate passed for request %(request)s."),
                 {'artifact': af.id, 'request': context.request_id})
        af = cls.db_api.update(context, af.id, values)
        return cls._init_artifact(context, af)
Beispiel #56
0
 def show_type_schema(cls, context, type_name):
     policy.authorize("artifact:type_get", {}, context)
     schemas = cls._get_schemas(cls.registry)
     if type_name not in schemas:
         msg = _("Artifact type %s does not exist") % type_name
         raise exception.NotFound(message=msg)
     return schemas[type_name]
Beispiel #57
0
 def __call__(self, value):
     l = len(value)
     if l < self.size:
         raise ValueError(
             _("String length must be more than  %(size)d. "
               "Current length: %(cur)d") % {'size': self.size,
                                             'cur': l})
Beispiel #58
0
def get_location_info(url, context, max_size, calc_checksum=True):
    """Validate location and get information about external blob

    :param url: blob url
    :param context: user context
    :param calc_checksum: define if checksum must be calculated
    :return: blob size and checksum
    """
    # validate uri
    scheme = urlparse.urlparse(url).scheme
    if scheme not in ('http', 'https'):
        msg = _("Location %s is invalid.") % url
        raise exception.BadRequest(message=msg)

    res = urllib.urlopen(url)
    http_message = res.info()
    content_type = getattr(http_message, 'type') or 'application/octet-stream'

    # calculate blob checksum to ensure that location blob won't be changed
    # in future
    # TODO(kairat) need to support external location signatures
    checksum = None
    size = 0
    if calc_checksum:
        checksum = hashlib.md5()
        blob_data = load_from_store(url, context)
        for buf in blob_data:
            checksum.update(buf)
            size += len(buf)
            if size > max_size:
                msg = _("External blob size %(size)d exceeds maximum allowed "
                        "size %(max)d."), {'size': size, 'max': max_size}
                raise exception.BadRequest(message=msg)
        checksum = checksum.hexdigest()
    else:
        # request blob size
        size = get_blob_size(url, context=context)
        if size < 0 or size > max_size:
            msg = _("Invalid blob size %d.") % size
            raise exception.BadRequest(message=msg)

    LOG.debug("Checksum %(checksum)s and size %(size)s calculated "
              "successfully for location %(location)s",
              {'checksum': str(checksum), 'size': str(size),
               'location': url})

    return size, checksum, content_type
Beispiel #59
0
 def _validate_input_values(cls, context, values):
     # validate that we are not specifying any system attribute
     # and that we do not upload blobs or add locations here
     for field_name in values:
         if field_name in cls.fields:
             if cls.fields[field_name].system is True:
                 msg = _("Cannot specify system property %s. It is not "
                         "available for modifying by users.") % field_name
                 raise exception.Forbidden(msg)
             elif cls.is_blob(field_name) or cls.is_blob_dict(field_name):
                 msg = _("Cannot add blob %s with this request. "
                         "Use special Blob API for that.") % field_name
                 raise exception.BadRequest(msg)
         else:
             msg = (_("Cannot add non-existing property %s to artifact. ")
                    % field_name)
             raise exception.BadRequest(msg)
Beispiel #60
0
 def _validate_filter_ops(cls, filter_name, op):
     field = cls.fields.get(filter_name)
     if op not in field.filter_ops:
         msg = (_("Unsupported filter type '%s(key)'."
                  "The following filters are supported "
                  "%(filters)s") % {
             'key': op, 'filters': str(field.filter_ops)})
         raise exception.BadRequest(message=msg)