Ejemplo n.º 1
0
    def get_ticket(self, source, target, crypto, key):

        # prepare metadata
        md = {'requestor': source,
              'target': target,
              'timestamp': time.time(),
              'nonce': struct.unpack('Q', os.urandom(8))[0]}
        metadata = base64.b64encode(jsonutils.dumps(md))

        # sign metadata
        signature = crypto.sign(key, metadata)

        # HTTP request
        reply = self._get_ticket({'metadata': metadata,
                                  'signature': signature})

        # verify reply
        signature = crypto.sign(key, (reply['metadata'] + reply['ticket']))
        if signature != reply['signature']:
            raise InvalidEncryptedTicket(md['source'], md['destination'])
        md = jsonutils.loads(base64.b64decode(reply['metadata']))
        if ((md['source'] != source or
             md['destination'] != target or
             md['expiration'] < time.time())):
            raise InvalidEncryptedTicket(md['source'], md['destination'])

        # return ticket data
        tkt = jsonutils.loads(crypto.decrypt(key, reply['ticket']))

        return tkt, md['expiration']
Ejemplo n.º 2
0
    def decrypt(self, decrypt_dto, kek_meta_dto, kek_meta_extended,
                project_id):
        session = self._create_working_session()

        key = self._unwrap_key(kek_meta_dto.plugin_meta, session)
        meta_extended = json.loads(kek_meta_extended)
        iv = base64.b64decode(meta_extended['iv'])
        iv = self.ffi.new("CK_BYTE[]", iv)
        ck_mechanism = self._build_gcm_mech(iv)

        rv = self.lib.C_DecryptInit(session, ck_mechanism.mech, key)
        self._check_error(rv)
        pt = self.ffi.new(
            "CK_BYTE[{0}]".format(len(decrypt_dto.encrypted))
        )
        pt_len = self.ffi.new("CK_ULONG *", len(decrypt_dto.encrypted))
        rv = self.lib.C_Decrypt(
            session,
            decrypt_dto.encrypted,
            len(decrypt_dto.encrypted),
            pt,
            pt_len
        )
        self._check_error(rv)

        self._close_session(session)
        return self._unpad(self.ffi.buffer(pt, pt_len[0])[:])
Ejemplo n.º 3
0
    def test_should_get_list_orders(self):
        self.resource.on_get(self.req, self.resp, self.keystone_id)

        self.order_repo.get_by_create_date \
            .assert_called_once_with(self.keystone_id,
                                     offset_arg=self.params.get('offset',
                                                                self.offset),
                                     limit_arg=self.params.get('limit',
                                                               self.limit),
                                     suppress_exception=True)

        resp_body = jsonutils.loads(self.resp.body)
        self.assertTrue('previous' in resp_body)
        self.assertTrue('next' in resp_body)

        url_nav_next = self._create_url(self.keystone_id,
                                        self.offset + self.limit, self.limit)
        self.assertTrue(self.resp.body.count(url_nav_next) == 1)

        url_nav_prev = self._create_url(self.keystone_id,
                                        0, self.limit)
        self.assertTrue(self.resp.body.count(url_nav_prev) == 1)

        url_hrefs = self._create_url(self.keystone_id)
        self.assertTrue(self.resp.body.count(url_hrefs) ==
                        (self.num_orders + 2))
Ejemplo n.º 4
0
    def load_json(cls, data, default_rule=None):
        """Allow loading of JSON rule data."""

        # Suck in the JSON data and parse the rules
        rules = dict((k, parse_rule(v)) for k, v in jsonutils.loads(data).items())

        return cls(rules, default_rule)
Ejemplo n.º 5
0
def load_body(req, resp=None, validator=None):
    """
    Helper function for loading an HTTP request body from JSON into a
    Python dictionary
    """
    try:
        raw_json = req.stream.read(MAX_BYTES_REQUEST_INPUT_ACCEPTED)
    except IOError:
        LOG.exception("Problem reading request JSON stream.")
        abort(falcon.HTTP_500, 'Read Error', req, resp)

    try:
        #TODO: Investigate how to get UTF8 format via openstack jsonutils:
        #     parsed_body = json.loads(raw_json, 'utf-8')
        parsed_body = json.loads(raw_json)
    except ValueError:
        LOG.exception("Problem loading request JSON.")
        abort(falcon.HTTP_400, 'Malformed JSON', req, resp)

    if validator:
        try:
            parsed_body = validator.validate(parsed_body)
        except exception.InvalidObject as e:
            LOG.exception("Failed to validate JSON information")
            abort(falcon.HTTP_400, str(e), req, resp)
        except exception.UnsupportedField as e:
            LOG.exception("Provided field value is not supported")
            abort(falcon.HTTP_400, str(e), req, resp)
        except exception.LimitExceeded as e:
            LOG.exception("Data limit exceeded")
            abort(falcon.HTTP_413, str(e), req, resp)

    return parsed_body
Ejemplo n.º 6
0
    def _decode_esek(self, key, source, target, timestamp, esek):
        """This function decrypts the esek buffer passed in and returns a
        KeyStore to be used to check and decrypt the received message.

        :param key: The key to use to decrypt the ticket (esek)
        :param source: The name of the source service
        :param traget: The name of the target service
        :param timestamp: The incoming message timestamp
        :param esek: a base64 encoded encrypted block containing a JSON string
        """
        rkey = None

        try:
            s = self._crypto.decrypt(key, esek)
            j = jsonutils.loads(s)

            rkey = base64.b64decode(j['key'])
            expiration = j['timestamp'] + j['ttl']
            if j['timestamp'] > timestamp or timestamp > expiration:
                raise InvalidExpiredTicket(source, target)

        except Exception:
            raise InvalidEncryptedTicket(source, target)

        info = '%s,%s,%s' % (source, target, str(j['timestamp']))

        sek = self._hkdf.expand(rkey, info, len(key) * 2)

        return self._split_key(sek, len(key))
Ejemplo n.º 7
0
def load_body(req, resp=None, validator=None):
    """
    Helper function for loading an HTTP request body from JSON into a
    Python dictionary
    """
    try:
        raw_json = req.stream.read(MAX_BYTES_REQUEST_INPUT_ACCEPTED)
    except IOError:
        LOG.exception("Problem reading request JSON stream.")
        abort(falcon.HTTP_500, 'Read Error', req, resp)

    try:
        #TODO: Investigate how to get UTF8 format via openstack jsonutils:
        #     parsed_body = json.loads(raw_json, 'utf-8')
        parsed_body = json.loads(raw_json)
    except ValueError:
        LOG.exception("Problem loading request JSON.")
        abort(falcon.HTTP_400, 'Malformed JSON', req, resp)

    if validator:
        try:
            parsed_body = validator.validate(parsed_body)
        except exception.InvalidObject as e:
            LOG.exception("Failed to validate JSON information")
            abort(falcon.HTTP_400, str(e), req, resp)
        except exception.LimitExceeded as e:
            LOG.exception("Data limit exceeded")
            abort(falcon.HTTP_413, str(e), req, resp)

    return parsed_body
Ejemplo n.º 8
0
    def _get_authenticated_context(self, req):
        # NOTE(bcwaldon): X-Roles is a csv string, but we need to parse
        # it into a list to be useful
        roles_header = req.headers.get('X-Roles', '')
        roles = [r.strip().lower() for r in roles_header.split(',')]

        # NOTE(bcwaldon): This header is deprecated in favor of X-Auth-Token
        # NOTE(mkbhanda): keeping this just-in-case for swift
        deprecated_token = req.headers.get('X-Storage-Token')

        service_catalog = None
        if req.headers.get('X-Service-Catalog') is not None:
            try:
                catalog_header = req.headers.get('X-Service-Catalog')
                service_catalog = json.loads(catalog_header)
            except ValueError:
                msg = u._('Problem processing X-Service-Catalog')
                LOG.exception(msg)
                raise webob.exc.HTTPInternalServerError(msg)

        kwargs = {
            'user': req.headers.get('X-User-Id'),
            'project': req.headers.get('X-Project-Id'),
            'roles': roles,
            'is_admin': CONF.admin_role.strip().lower() in roles,
            'auth_tok': req.headers.get('X-Auth-Token', deprecated_token),
            'owner_is_project': CONF.owner_is_project,
            'service_catalog': service_catalog,
            'policy_enforcer': self.policy_enforcer,
        }

        return barbican.context.RequestContext(**kwargs)
Ejemplo n.º 9
0
    def test_should_get_list_orders(self):
        self.resource.on_get(self.req, self.resp, self.keystone_id)

        self.order_repo.get_by_create_date \
            .assert_called_once_with(self.keystone_id,
                                     offset_arg=self.params.get('offset',
                                                                self.offset),
                                     limit_arg=self.params.get('limit',
                                                               self.limit),
                                     suppress_exception=True)

        resp_body = jsonutils.loads(self.resp.body)
        self.assertTrue('previous' in resp_body)
        self.assertTrue('next' in resp_body)

        url_nav_next = self._create_url(self.keystone_id,
                                        self.offset + self.limit, self.limit)
        self.assertTrue(self.resp.body.count(url_nav_next) == 1)

        url_nav_prev = self._create_url(self.keystone_id, 0, self.limit)
        self.assertTrue(self.resp.body.count(url_nav_prev) == 1)

        url_hrefs = self._create_url(self.keystone_id)
        self.assertTrue(
            self.resp.body.count(url_hrefs) == (self.num_orders + 2))
Ejemplo n.º 10
0
def load_body(req, resp=None, validator=None):
    """Helper function for loading an HTTP request body from JSON.

    This body is placed into into a Python dictionary.

    :param req: The HTTP request instance to load the body from.
    :param resp: The HTTP response instance.
    :param validator: The JSON validator to enforce.
    :return: A dict of values from the JSON request.
    """
    try:
        body = req.body_file.read(CONF.max_allowed_request_size_in_bytes)
        req.body_file.seek(0)
    except IOError:
        LOG.exception(u._LE("Problem reading request JSON stream."))
        pecan.abort(500, u._('Read Error'))

    try:
        # TODO(jwood): Investigate how to get UTF8 format via openstack
        # jsonutils:
        #     parsed_body = json.loads(raw_json, 'utf-8')
        parsed_body = json.loads(body)
        strip_whitespace(parsed_body)
    except ValueError:
        LOG.exception(u._LE("Problem loading request JSON."))
        pecan.abort(400, u._('Malformed JSON'))

    if validator:
        try:
            parsed_body = validator.validate(parsed_body)
        except exception.BarbicanHTTPException as e:
            LOG.exception(e.message)
            pecan.abort(e.status_code, e.client_message)

    return parsed_body
Ejemplo n.º 11
0
    def _get_authenticated_context(self, req):
        # NOTE(bcwaldon): X-Roles is a csv string, but we need to parse
        # it into a list to be useful
        roles_header = req.headers.get('X-Roles', '')
        roles = [r.strip().lower() for r in roles_header.split(',')]

        # NOTE(bcwaldon): This header is deprecated in favor of X-Auth-Token
        # NOTE(mkbhanda): keeping this just-in-case for swift
        deprecated_token = req.headers.get('X-Storage-Token')

        service_catalog = None
        if req.headers.get('X-Service-Catalog') is not None:
            try:
                catalog_header = req.headers.get('X-Service-Catalog')
                service_catalog = json.loads(catalog_header)
            except ValueError:
                msg = u._('Problem processing X-Service-Catalog')
                LOG.exception(msg)
                raise webob.exc.HTTPInternalServerError(msg)

        kwargs = {
            'user': req.headers.get('X-User-Id'),
            'project': req.headers.get('X-Tenant-Id'),
            'roles': roles,
            'is_admin': CONF.admin_role.strip().lower() in roles,
            'auth_tok': req.headers.get('X-Auth-Token', deprecated_token),
            'owner_is_project': CONF.owner_is_project,
            'service_catalog': service_catalog,
            'policy_enforcer': self.policy_enforcer,
        }

        return barbican.context.RequestContext(**kwargs)
Ejemplo n.º 12
0
    def load_json(cls, data, default_rule=None):
        """Allow loading of JSON rule data."""

        # Suck in the JSON data and parse the rules
        rules = dict(
            (k, parse_rule(v)) for k, v in jsonutils.loads(data).items())

        return cls(rules, default_rule)
Ejemplo n.º 13
0
 def decrypt(self, encrypted, kek_meta_dto, kek_meta_extended, keystone_id):
     key = self._get_key_by_label(kek_meta_dto.kek_label)
     meta_extended = json.loads(kek_meta_extended)
     iv = base64.b64decode(meta_extended['iv'])
     gcm = self._build_gcm_params(iv)
     mech = PyKCS11.Mechanism(self.algorithm, gcm)
     decrypted = self.session.decrypt(key, encrypted, mech)
     secret = b''.join(chr(i) for i in decrypted)
     return secret
Ejemplo n.º 14
0
 def decrypt(self, decrypt_dto, kek_meta_dto, kek_meta_extended,
             keystone_id):
     key = self._get_key_by_label(kek_meta_dto.kek_label)
     meta_extended = json.loads(kek_meta_extended)
     iv = base64.b64decode(meta_extended['iv'])
     gcm = self._build_gcm_params(iv)
     mech = PyKCS11.Mechanism(self.algorithm, gcm)
     decrypted = self.session.decrypt(key, decrypt_dto.encrypted, mech)
     secret = b''.join(chr(i) for i in decrypted)
     return secret
Ejemplo n.º 15
0
    def _unwrap_key(self, plugin_meta):
        """Unwraps byte string to key handle in HSM.

        :param plugin_meta: kek_meta_dto plugin meta (json string)
        :returns: Key handle from HSM. No unencrypted bytes.
        """
        meta = json.loads(plugin_meta)
        iv = base64.b64decode(meta['iv'])
        hmac = base64.b64decode(meta['hmac'])
        wrapped_key = base64.b64decode(meta['wrapped_key'])
        mkek = self._get_key_handle(meta['mkek_label'])
        hmac_key = self._get_key_handle(meta['hmac_label'])
        LOG.debug("Unwrapping key with %s mkek label", meta['mkek_label'])

        hmac_bytelist = PyKCS11.ckbytelist()
        hmac_bytelist.reserve(len(hmac))
        for x in hmac:
            hmac_bytelist.append(ord(x))
        wrapped_bytelist = PyKCS11.ckbytelist()
        wrapped_bytelist.reserve(len(wrapped_key))
        for x in wrapped_key:
            wrapped_bytelist.append(ord(x))

        LOG.debug("Verifying key with %s hmac label", meta['hmac_label'])
        self._verify_hmac(hmac_key, hmac_bytelist, wrapped_bytelist)

        unwrapped = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
        m = PyKCS11.LowLevel.CK_MECHANISM()
        m.mechanism = PyKCS11.LowLevel.CKM_AES_CBC_PAD
        m.pParameter = iv

        template = (
            (PyKCS11.CKA_CLASS, PyKCS11.CKO_SECRET_KEY),
            (PyKCS11.CKA_KEY_TYPE, PyKCS11.CKK_AES),
            (PyKCS11.CKA_ENCRYPT, True),
            (PyKCS11.CKA_DECRYPT, True),
            (PyKCS11.CKA_TOKEN, False),
            (PyKCS11.CKA_WRAP, True),
            (PyKCS11.CKA_UNWRAP, True),
            (PyKCS11.CKA_EXTRACTABLE, True)
        )
        ckattr = self.session._template2ckattrlist(template)

        self._check_error(
            self.pkcs11.lib.C_UnwrapKey(
                self.rw_session.session,
                m,
                mkek,
                wrapped_bytelist,
                ckattr,
                unwrapped
            )
        )

        return unwrapped
Ejemplo n.º 16
0
    def test_should_get_secret_as_json(self):
        self.resource.on_get(self.req, self.resp, self.tenant_id,
                             self.secret.id)

        self.secret_repo.get.assert_called_once_with(entity_id=self.secret.id,
                                                     suppress_exception=True)

        self.assertEquals(self.resp.status, falcon.HTTP_200)

        resp_body = jsonutils.loads(self.resp.body)
        self.assertTrue('content_types' in resp_body)
        self.assertTrue(self.datum.mime_type in
                        resp_body['content_types'].itervalues())
Ejemplo n.º 17
0
    def _get_reply(self, url, resp):
        if resp.text:
            try:
                body = jsonutils.loads(resp.text)
                reply = body['reply']
            except (KeyError, TypeError, ValueError):
                msg = "Failed to decode reply: %s" % resp.text
                raise CommunicationError(url, msg)
        else:
            msg = "No reply data was returned."
            raise CommunicationError(url, msg)

        return reply
Ejemplo n.º 18
0
    def test_should_handle_no_secrets(self):

        del self.secrets[:]

        self.resource.on_get(self.req, self.resp, self.keystone_id)

        self.secret_repo.get_by_create_date \
            .assert_called_once_with(self.keystone_id,
                                     offset_arg=self.offset,
                                     limit_arg=self.limit,
                                     suppress_exception=True)

        resp_body = jsonutils.loads(self.resp.body)
        self.assertFalse('previous' in resp_body)
        self.assertFalse('next' in resp_body)
Ejemplo n.º 19
0
    def test_should_get_secret_as_json(self):
        self.resource.on_get(self.req, self.resp, self.keystone_id,
                             self.secret.id)

        self.secret_repo\
            .get.assert_called_once_with(entity_id=self.secret.id,
                                         keystone_id=self.keystone_id,
                                         suppress_exception=True)

        self.assertEquals(self.resp.status, falcon.HTTP_200)

        resp_body = jsonutils.loads(self.resp.body)
        self.assertTrue('content_types' in resp_body)
        self.assertTrue(
            self.datum.mime_type in resp_body['content_types'].itervalues())
Ejemplo n.º 20
0
    def _unpack_json_msg(self, msg):
        """Load the JSON data in msg if msg.content_type indicates that it
           is necessary.  Put the loaded data back into msg.content and
           update msg.content_type appropriately.

        A Qpid Message containing a dict will have a content_type of
        'amqp/map', whereas one containing a string that needs to be converted
        back from JSON will have a content_type of JSON_CONTENT_TYPE.

        :param msg: a Qpid Message object
        :returns: None
        """
        if msg.content_type == JSON_CONTENT_TYPE:
            msg.content = jsonutils.loads(msg.content)
            msg.content_type = 'amqp/map'
Ejemplo n.º 21
0
    def test_should_handle_no_orders(self):

        del self.orders[:]

        self.resource.on_get(self.req, self.resp, self.keystone_id)

        self.order_repo.get_by_create_date \
            .assert_called_once_with(self.keystone_id,
                                     offset_arg=self.params.get('offset',
                                                                self.offset),
                                     limit_arg=self.params.get('limit',
                                                               self.limit),
                                     suppress_exception=True)

        resp_body = jsonutils.loads(self.resp.body)
        self.assertFalse('previous' in resp_body)
        self.assertFalse('next' in resp_body)
Ejemplo n.º 22
0
    def test_should_get_secret_as_json(self):
        self.resource.on_get(self.req, self.resp, self.keystone_id,
                             self.secret.id)

        self.secret_repo \
            .get.assert_called_once_with(entity_id=self.secret.id,
                                         keystone_id=self.keystone_id,
                                         suppress_exception=True)

        self.assertEquals(self.resp.status, falcon.HTTP_200)

        resp_body = jsonutils.loads(self.resp.body)
        self.assertNotIn('content_encodings', resp_body)
        self.assertIn('content_types', resp_body)
        self.assertIn(self.datum.content_type,
                      resp_body['content_types'].itervalues())
        self.assertNotIn('mime_type', resp_body)
Ejemplo n.º 23
0
    def decode(self, version, metadata, message, signature):
        """This is the main decoding function.

        It takes a version, metadata, message and signature strings and
        returns a tuple with a (decrypted) message and metadata or raises
        an exception in case of error.

        :param version: the current envelope version
        :param metadata: a JSON serialized object with metadata for validation
        :param message: a JSON serialized (base64 encoded encrypted) message
        :param signature: a base64 encoded signature
        """
        md = jsonutils.loads(metadata)

        check_args = ('source', 'destination', 'timestamp',
                      'nonce', 'esek', 'encryption')
        for arg in check_args:
            if arg not in md:
                raise InvalidMetadata('Missing metadata "%s"' % arg)

        if md['destination'] != self._name:
            # TODO(simo) handle group keys by checking target
            raise UnknownDestinationName(md['destination'])

        try:
            skey, ekey = self._decode_esek(self._key,
                                           md['source'], md['destination'],
                                           md['timestamp'], md['esek'])
        except InvalidExpiredTicket:
            raise
        except Exception:
            raise InvalidMetadata('Failed to decode ESEK for %s/%s' % (
                                  md['source'], md['destination']))

        sig = self._crypto.sign(skey, version + metadata + message)

        if sig != signature:
            raise InvalidSignature(md['source'], md['destination'])

        if md['encryption'] is True:
            msg = self._crypto.decrypt(ekey, message)
        else:
            msg = message

        return (md, msg)
Ejemplo n.º 24
0
    def decrypt(self, decrypt_dto, kek_meta_dto, kek_meta_extended,
                project_id):
        key = self._unwrap_key(kek_meta_dto.plugin_meta)
        meta_extended = json.loads(kek_meta_extended)
        iv = base64.b64decode(meta_extended['iv'])
        iv = self.ffi.new("CK_BYTE[]", iv)
        mech = self._build_gcm_mech(iv)
        with self.dec_sem:
            rv = self.lib.C_DecryptInit(self.session, mech, key)
            self._check_error(rv)
            pt = self.ffi.new("CK_BYTE[{0}]".format(len(
                decrypt_dto.encrypted)))
            pt_len = self.ffi.new("CK_ULONG *", len(decrypt_dto.encrypted))
            rv = self.lib.C_Decrypt(self.session, decrypt_dto.encrypted,
                                    len(decrypt_dto.encrypted), pt, pt_len)
            self._check_error(rv)

        return self._unpad(self.ffi.buffer(pt, pt_len[0])[:])
Ejemplo n.º 25
0
def load_body(req):
    """
    Helper function for loading an HTTP request body from JSON into a
    Python dictionary
    """
    try:
        raw_json = req.stream.read()
    except IOError:
        abort(falcon.HTTP_500, 'Read Error')

    try:
        #TODO: Investigate how to get UTF8 format via openstack jsonutils:
        #     parsed_body = json.loads(raw_json, 'utf-8')
        parsed_body = json.loads(raw_json)
    except ValueError:
        abort(falcon.HTTP_400, 'Malformed JSON')

    return parsed_body
Ejemplo n.º 26
0
    def test_should_abort_with_validation_unsupported_field(
            self, mock_pecan_abort):
        mock_pecan_abort.side_effect = ValueError('Abort!')

        body = json.dumps({'key1': 'value1'})

        req = mock.MagicMock()
        req.body_file = mock.MagicMock()
        req.body_file.read.return_value = body

        validator = mock.MagicMock()
        validator.validate.side_effect = exception.UnsupportedField('Field')

        exception_result = self.assertRaises(
            ValueError, api.load_body, req, validator=validator)

        self.assertEqual('Abort!', exception_result.message)
        validator.validate.assert_called_once_with(json.loads(body))
Ejemplo n.º 27
0
    def unwrap_key(self, plugin_meta, session):
        """Unwraps byte string to key handle in HSM.

        :param plugin_meta: kek_meta_dto plugin meta (json string)
        :returns: Key handle from HSM. No unencrypted bytes.
        """
        meta = json.loads(plugin_meta)
        iv = base64.b64decode(meta['iv'])
        hmac = base64.b64decode(meta['hmac'])
        wrapped_key = base64.b64decode(meta['wrapped_key'])
        mkek = self.get_key_handle(meta['mkek_label'], session)
        hmac_key = self.get_key_handle(meta['hmac_label'], session)
        LOG.debug("Unwrapping key with %s mkek label", meta['mkek_label'])

        LOG.debug("Verifying key with %s hmac label", meta['hmac_label'])
        self.verify_hmac(hmac_key, hmac, wrapped_key, session)

        unwrapped = self.ffi.new("CK_OBJECT_HANDLE *")
        mech = self.ffi.new("CK_MECHANISM *")
        mech.mechanism = CKM_AES_CBC_PAD
        iv = self.ffi.new("CK_BYTE[]", iv)
        mech.parameter = iv
        mech.parameter_len = 16

        ck_attributes = self.build_attributes([
            Attribute(CKA_CLASS, CKO_SECRET_KEY),
            Attribute(CKA_KEY_TYPE, CKK_AES),
            Attribute(CKA_ENCRYPT, True),
            Attribute(CKA_DECRYPT, True),
            Attribute(CKA_TOKEN, False),
            Attribute(CKA_WRAP, True),
            Attribute(CKA_UNWRAP, True),
            Attribute(CKA_EXTRACTABLE, True)
        ])

        rv = self.lib.C_UnwrapKey(
            session, mech, mkek, wrapped_key, len(wrapped_key),
            ck_attributes.template, len(ck_attributes.template), unwrapped
        )
        self.check_error(rv)

        return unwrapped[0]
Ejemplo n.º 28
0
def deserialize_msg(msg):
    # NOTE(russellb): Hang on to your hats, this road is about to
    # get a little bumpy.
    #
    # Robustness Principle:
    #    "Be strict in what you send, liberal in what you accept."
    #
    # At this point we have to do a bit of guessing about what it
    # is we just received.  Here is the set of possibilities:
    #
    # 1) We received a dict.  This could be 2 things:
    #
    #   a) Inspect it to see if it looks like a standard message envelope.
    #      If so, great!
    #
    #   b) If it doesn't look like a standard message envelope, it could either
    #      be a notification, or a message from before we added a message
    #      envelope (referred to as version 1.0).
    #      Just return the message as-is.
    #
    # 2) It's any other non-dict type.  Just return it and hope for the best.
    #    This case covers return values from rpc.call() from before message
    #    envelopes were used.  (messages to call a method were always a dict)

    if not isinstance(msg, dict):
        # See #2 above.
        return msg

    base_envelope_keys = (_VERSION_KEY, _MESSAGE_KEY)
    if not all(map(lambda key: key in msg, base_envelope_keys)):
        #  See #1.b above.
        return msg

    # At this point we think we have the message envelope
    # format we were expecting. (#1.a above)

    if not version_is_compatible(_RPC_ENVELOPE_VERSION, msg[_VERSION_KEY]):
        raise UnsupportedRpcEnvelopeVersion(version=msg[_VERSION_KEY])

    raw_msg = jsonutils.loads(msg[_MESSAGE_KEY])

    return raw_msg
Ejemplo n.º 29
0
def deserialize_msg(msg):
    # NOTE(russellb): Hang on to your hats, this road is about to
    # get a little bumpy.
    #
    # Robustness Principle:
    #    "Be strict in what you send, liberal in what you accept."
    #
    # At this point we have to do a bit of guessing about what it
    # is we just received.  Here is the set of possibilities:
    #
    # 1) We received a dict.  This could be 2 things:
    #
    #   a) Inspect it to see if it looks like a standard message envelope.
    #      If so, great!
    #
    #   b) If it doesn't look like a standard message envelope, it could either
    #      be a notification, or a message from before we added a message
    #      envelope (referred to as version 1.0).
    #      Just return the message as-is.
    #
    # 2) It's any other non-dict type.  Just return it and hope for the best.
    #    This case covers return values from rpc.call() from before message
    #    envelopes were used.  (messages to call a method were always a dict)

    if not isinstance(msg, dict):
        # See #2 above.
        return msg

    base_envelope_keys = (_VERSION_KEY, _MESSAGE_KEY)
    if not all(map(lambda key: key in msg, base_envelope_keys)):
        #  See #1.b above.
        return msg

    # At this point we think we have the message envelope
    # format we were expecting. (#1.a above)

    if not version_is_compatible(_RPC_ENVELOPE_VERSION, msg[_VERSION_KEY]):
        raise UnsupportedRpcEnvelopeVersion(version=msg[_VERSION_KEY])

    raw_msg = jsonutils.loads(msg[_MESSAGE_KEY])

    return raw_msg
Ejemplo n.º 30
0
    def test_should_get_secret_meta_for_binary(self):
        self.req.accept = 'application/json'
        self.datum.content_type = "application/octet-stream"
        self.datum.cypher_text = 'aaaa'

        self.resource.on_get(self.req, self.resp, self.keystone_id,
                             self.secret.id)

        self.secret_repo \
            .get.assert_called_once_with(entity_id=self.secret.id,
                                         keystone_id=self.keystone_id,
                                         suppress_exception=True)

        self.assertEquals(self.resp.status, falcon.HTTP_200)

        resp_body = jsonutils.loads(self.resp.body)
        self.assertIsNotNone(resp_body)
        self.assertIn('content_types', resp_body)
        self.assertIn(self.datum.content_type,
                      resp_body['content_types'].itervalues())
Ejemplo n.º 31
0
def load_body(req, resp=None, validator=None):
    """Helper function for loading an HTTP request body from JSON.

    This body is placed into into a Python dictionary.

    :param req: The HTTP request instance to load the body from.
    :param resp: The HTTP response instance.
    :param validator: The JSON validator to enforce.
    :return: A dict of values from the JSON request.
    """
    try:
        body = req.body_file.read(CONF.max_allowed_request_size_in_bytes)
        req.body_file.seek(0)
    except IOError:
        LOG.exception(u._LE("Problem reading request JSON stream."))
        pecan.abort(500, u._('Read Error'))

    try:
        # TODO(jwood): Investigate how to get UTF8 format via openstack
        # jsonutils:
        #     parsed_body = json.loads(raw_json, 'utf-8')
        parsed_body = json.loads(body)
        strip_whitespace(parsed_body)
    except ValueError:
        LOG.exception(u._LE("Problem loading request JSON."))
        pecan.abort(400, u._('Malformed JSON'))

    if validator:
        try:
            parsed_body = validator.validate(parsed_body)
        except exception.InvalidObject as e:
            LOG.exception(u._LE("Failed to validate JSON information"))
            pecan.abort(400, str(e))
        except exception.UnsupportedField as e:
            LOG.exception(u._LE("Provided field value is not supported"))
            pecan.abort(400, str(e))
        except exception.LimitExceeded as e:
            LOG.exception(u._LE("Data limit exceeded"))
            pecan.abort(413, str(e))

    return parsed_body
Ejemplo n.º 32
0
    def _unwrap_key(self, plugin_meta):
        """Unwraps byte string to key handle in HSM.

        :param plugin_meta: kek_meta_dto plugin meta (json string)
        :returns: Key handle from HSM. No unencrypted bytes.
        """
        meta = json.loads(plugin_meta)
        iv = base64.b64decode(meta['iv'])
        hmac = base64.b64decode(meta['hmac'])
        wrapped_key = base64.b64decode(meta['wrapped_key'])
        mkek = self._get_key_handle(meta['mkek_label'])
        hmac_key = self._get_key_handle(meta['hmac_label'])
        LOG.debug("Unwrapping key with %s mkek label", meta['mkek_label'])

        LOG.debug("Verifying key with %s hmac label", meta['hmac_label'])
        self._verify_hmac(hmac_key, hmac, wrapped_key)

        unwrapped = self.ffi.new("CK_OBJECT_HANDLE *")
        mech = self.ffi.new("CK_MECHANISM *")
        mech.mechanism = CKM_AES_CBC_PAD
        iv = self.ffi.new("CK_BYTE[]", iv)
        mech.parameter = iv
        mech.parameter_len = 16

        template, val_list = self._build_attributes([
            Attribute(CKA_CLASS, CKO_SECRET_KEY),
            Attribute(CKA_KEY_TYPE, CKK_AES),
            Attribute(CKA_ENCRYPT, True),
            Attribute(CKA_DECRYPT, True),
            Attribute(CKA_TOKEN, False),
            Attribute(CKA_WRAP, True),
            Attribute(CKA_UNWRAP, True),
            Attribute(CKA_EXTRACTABLE, True)
        ])

        rv = self.lib.C_UnwrapKey(self.rw_session, mech, mkek, wrapped_key,
                                  len(wrapped_key), template, len(template),
                                  unwrapped)
        self._check_error(rv)

        return unwrapped[0]
Ejemplo n.º 33
0
def deserialize_remote_exception(conf, data):
    failure = jsonutils.loads(str(data))

    trace = failure.get('tb', [])
    message = failure.get('message', "") + "\n" + "\n".join(trace)
    name = failure.get('class')
    module = failure.get('module')

    # NOTE(ameade): We DO NOT want to allow just any module to be imported, in
    # order to prevent arbitrary code execution.
    if module not in conf.allowed_rpc_exception_modules:
        return RemoteError(name, failure.get('message'), trace)

    try:
        mod = importutils.import_module(module)
        klass = getattr(mod, name)
        if not issubclass(klass, Exception):
            raise TypeError("Can only deserialize Exceptions")

        failure = klass(*failure.get('args', []), **failure.get('kwargs', {}))
    except (AttributeError, TypeError, ImportError):
        return RemoteError(name, failure.get('message'), trace)

    ex_type = type(failure)
    str_override = lambda self: message
    new_ex_type = type(ex_type.__name__ + "_Remote", (ex_type, ), {
        '__str__': str_override,
        '__unicode__': str_override
    })
    try:
        # NOTE(ameade): Dynamically create a new exception type and swap it in
        # as the new type for the exception. This only works on user defined
        # Exceptions and not core python exceptions. This is important because
        # we cannot necessarily change an exception message so we must override
        # the __str__ method.
        failure.__class__ = new_ex_type
    except TypeError:
        # NOTE(ameade): If a core exception then just add the traceback to the
        # first exception argument.
        failure.args = (message, ) + failure.args[1:]
    return failure
Ejemplo n.º 34
0
def deserialize_remote_exception(conf, data):
    failure = jsonutils.loads(str(data))

    trace = failure.get('tb', [])
    message = failure.get('message', "") + "\n" + "\n".join(trace)
    name = failure.get('class')
    module = failure.get('module')

    # NOTE(ameade): We DO NOT want to allow just any module to be imported, in
    # order to prevent arbitrary code execution.
    if module not in conf.allowed_rpc_exception_modules:
        return RemoteError(name, failure.get('message'), trace)

    try:
        mod = importutils.import_module(module)
        klass = getattr(mod, name)
        if not issubclass(klass, Exception):
            raise TypeError("Can only deserialize Exceptions")

        failure = klass(*failure.get('args', []), **failure.get('kwargs', {}))
    except (AttributeError, TypeError, ImportError):
        return RemoteError(name, failure.get('message'), trace)

    ex_type = type(failure)
    str_override = lambda self: message
    new_ex_type = type(ex_type.__name__ + _REMOTE_POSTFIX, (ex_type,),
                       {'__str__': str_override, '__unicode__': str_override})
    new_ex_type.__module__ = '%s%s' % (module, _REMOTE_POSTFIX)
    try:
        # NOTE(ameade): Dynamically create a new exception type and swap it in
        # as the new type for the exception. This only works on user defined
        # Exceptions and not core python exceptions. This is important because
        # we cannot necessarily change an exception message so we must override
        # the __str__ method.
        failure.__class__ = new_ex_type
    except TypeError:
        # NOTE(ameade): If a core exception then just add the traceback to the
        # first exception argument.
        failure.args = (message,) + failure.args[1:]
    return failure
Ejemplo n.º 35
0
def load_body(req, resp=None, validator=None):
    """Helper function for loading an HTTP request body from JSON.

    This body is placed into into a Python dictionary.

    :param req: The HTTP request instance to load the body from.
    :param resp: The HTTP response instance.
    :param validator: The JSON validator to enforce.
    :return: A dict of values from the JSON request.
    """
    try:
        body = req.body_file.read(CONF.max_allowed_request_size_in_bytes)
    except IOError:
        LOG.exception("Problem reading request JSON stream.")
        pecan.abort(500, 'Read Error')

    try:
        # TODO(jwood): Investigate how to get UTF8 format via openstack
        # jsonutils:
        #     parsed_body = json.loads(raw_json, 'utf-8')
        parsed_body = json.loads(body)
        strip_whitespace(parsed_body)
    except ValueError:
        LOG.exception("Problem loading request JSON.")
        pecan.abort(400, 'Malformed JSON')

    if validator:
        try:
            parsed_body = validator.validate(parsed_body)
        except exception.InvalidObject as e:
            LOG.exception("Failed to validate JSON information")
            pecan.abort(400, str(e))
        except exception.UnsupportedField as e:
            LOG.exception("Provided field value is not supported")
            pecan.abort(400, str(e))
        except exception.LimitExceeded as e:
            LOG.exception("Data limit exceeded")
            pecan.abort(413, str(e))

    return parsed_body
Ejemplo n.º 36
0
def load_body(req, resp=None, validator=None):
    """Helper function for loading an HTTP request body from JSON.
    This body is placed into into a Python dictionary.

    :param req: The HTTP request instance to load the body from.
    :param resp: The HTTP response instance.
    :param validator: The JSON validator to enforce.
    :return: A dict of values from the JSON request.
    """
    try:
        raw_json = req.stream.read(MAX_BYTES_REQUEST_INPUT_ACCEPTED)
    except IOError:
        LOG.exception("Problem reading request JSON stream.")
        abort(falcon.HTTP_500, 'Read Error', req, resp)

    try:
        #TODO(jwood): Investigate how to get UTF8 format via openstack
        # jsonutils:
        #     parsed_body = json.loads(raw_json, 'utf-8')
        parsed_body = json.loads(raw_json)
        strip_whitespace(parsed_body)
    except ValueError:
        LOG.exception("Problem loading request JSON.")
        abort(falcon.HTTP_400, 'Malformed JSON', req, resp)

    if validator:
        try:
            parsed_body = validator.validate(parsed_body)
        except exception.InvalidObject as e:
            LOG.exception("Failed to validate JSON information")
            abort(falcon.HTTP_400, str(e), req, resp)
        except exception.UnsupportedField as e:
            LOG.exception("Provided field value is not supported")
            abort(falcon.HTTP_400, str(e), req, resp)
        except exception.LimitExceeded as e:
            LOG.exception("Data limit exceeded")
            abort(falcon.HTTP_413, str(e), req, resp)

    return parsed_body
Ejemplo n.º 37
0
    def on_put(self, keystone_id, **kwargs):
        raw_body = pecan.request.body
        order_type = None
        if raw_body:
            order_type = json.loads(raw_body).get('type')

        if not order_type:
            _order_type_not_in_order()

        order_model = self.order_repo.get(entity_id=self.order_id,
                                          keystone_id=keystone_id,
                                          suppress_exception=True)

        if not order_model:
            _order_not_found()

        if order_model.type != order_type:
            order_cannot_modify_order_type()

        if models.OrderType.CERTIFICATE != order_model.type:
            _order_update_not_supported_for_type(order_type)

        if models.States.PENDING != order_model.status:
            _order_cannot_be_updated_if_not_pending(order_model.status)

        body = api.load_body(pecan.request,
                             validator=self.type_order_validator)

        updated_meta = body.get('meta')

        if not updated_meta:
            _order_meta_not_in_update()

        # TODO(chellygel): Put updated_meta into a separate order association
        # entity.
        self.queue.update_order(order_id=self.order_id,
                                keystone_id=keystone_id,
                                updated_meta=updated_meta)
Ejemplo n.º 38
0
    def on_post(self, keystone_id, **kwargs):

        tenant = res.get_or_create_tenant(keystone_id, self.tenant_repo)

        #Note(atiwari): trying to preserve backward compatibility
        #This will be removed as part of bug1335171
        raw_body = pecan.request.body
        order_type = None
        if raw_body:
            order_type = json.loads(raw_body).get('type')

        if order_type:
            body = api.load_body(pecan.request,
                                 validator=self.type_order_validator)
            LOG.debug('Processing order type %s', order_type)
            new_order = models.Order()
            new_order.meta = body.get('meta')
            new_order.type = order_type

            #TODO(john-wood-w) These are required attributes currently, but
            #   will eventually be removed once we drop the legacy orders
            #   request.
            new_order.secret_name = 'N/A'
            new_order.secret_algorithm = 'N/A'
            new_order.secret_bit_length = 0
            new_order.secret_mode = 'N/A'
            new_order.secret_payload_content_type = 'N/A'
        else:
            body = api.load_body(pecan.request, validator=self.validator)
            LOG.debug('Start on_post...%s', body)

            if 'secret' not in body:
                _secret_not_in_order()
            secret_info = body['secret']
            name = secret_info.get('name')
            LOG.debug('Secret to create is %s', name)

            new_order = models.Order()
            new_order.secret_name = secret_info.get('name')
            new_order.secret_algorithm = secret_info.get('algorithm')
            new_order.secret_bit_length = secret_info.get('bit_length', 0)
            new_order.secret_mode = secret_info.get('mode')
            new_order.secret_payload_content_type = secret_info.get(
                'payload_content_type')

            new_order.secret_expiration = secret_info.get('expiration')

        new_order.tenant_id = tenant.id
        self.order_repo.create_from(new_order)

        # Send to workers to process.
        #TODO(atiwari) - bug 1335171
        if order_type:
            self.queue.process_type_order(order_id=new_order.id,
                                          keystone_id=keystone_id)
        else:
            self.queue.process_order(order_id=new_order.id,
                                     keystone_id=keystone_id)

        pecan.response.status = 202
        pecan.response.headers['Location'] = '/{0}/orders/{1}'.format(
            keystone_id, new_order.id
        )
        url = hrefs.convert_order_to_href(new_order.id)
        return {'order_ref': url}
Ejemplo n.º 39
0
def _deserialize(data):
    """
    Deserialization wrapper
    """
    LOG.debug(_("Deserializing: %s"), data)
    return jsonutils.loads(data)
Ejemplo n.º 40
0
 def process_result_value(self, value, dialect):
     if value is not None:
         value = json.loads(value)
     return value
Ejemplo n.º 41
0
 def test_response_should_include_total(self):
     self.resource.on_get(self.req, self.resp, self.keystone_id)
     resp_body = jsonutils.loads(self.resp.body)
     self.assertIn('total', resp_body)
     self.assertEqual(resp_body['total'], self.total)