コード例 #1
0
ファイル: test_models.py プロジェクト: chellygel/barbican
    def test_create_new_order_task(self):
        order = models.Order({
            'type':
            'certificate',
            'meta': {
                'email': '*****@*****.**'
            },
            'sub_status':
            'Pending',
            'sub_status_message':
            'Waiting for instructions...'
        })
        at = datetime.datetime.utcnow()
        order_retry_task = models.OrderRetryTask(
            order_id=order.id,
            retry_task="foobar",
            retry_at=at,
            retry_args=json.dumps(["one", "two"]),
            retry_kwargs=json.dumps({"three": "four"}),
        )

        self.assertEqual(order_retry_task.order_id, order.id)
        self.assertEqual(order_retry_task.retry_task, "foobar")
        self.assertEqual(order_retry_task.retry_at, at)
        self.assertEqual(
            order_retry_task.retry_args,
            json.dumps(["one", "two"]),
        )
        self.assertEqual(
            order_retry_task.retry_kwargs,
            json.dumps({"three": "four"}),
        )
コード例 #2
0
    def __call__(self, target, creds, enforcer):
        """Check http: rules by calling to a remote server.

        This example implementation simply verifies that the response
        is exactly 'True'.
        """

        url = ("http:" + self.match) % target
        data = {"target": jsonutils.dumps(target), "credentials": jsonutils.dumps(creds)}
        post_data = urlparse.urlencode(data)
        f = urlrequest.urlopen(url, post_data)
        return f.read() == "True"
コード例 #3
0
ファイル: test_models.py プロジェクト: chellygel/barbican
    def test_get_retry_params(self):
        order_retry_task = models.OrderRetryTask(
            retry_args=json.dumps(["one", "two"]),
            retry_kwargs=json.dumps({"three": "four"}),
        )

        self.assertEqual(
            order_retry_task.get_retry_params(),
            (["one", "two"], {
                "three": "four"
            }),
        )
コード例 #4
0
ファイル: policy.py プロジェクト: stanzikratel/barbican-2
    def __call__(self, target, creds, enforcer):
        """Check http: rules by calling to a remote server.

        This example implementation simply verifies that the response
        is exactly 'True'.
        """

        url = ('http:' + self.match) % target
        data = {'target': jsonutils.dumps(target),
                'credentials': jsonutils.dumps(creds)}
        post_data = urlparse.urlencode(data)
        f = urlrequest.urlopen(url, post_data)
        return f.read() == "True"
コード例 #5
0
ファイル: impl_qpid.py プロジェクト: bdacode/barbican
    def _pack_json_msg(self, msg):
        """Qpid cannot serialize dicts containing strings longer than 65535
           characters.  This function dumps the message content to a JSON
           string, which Qpid is able to handle.

        :param msg: May be either a Qpid Message object or a bare dict.
        :returns: A Qpid Message with its content field JSON encoded.
        """
        try:
            msg.content = jsonutils.dumps(msg.content)
        except AttributeError:
            # Need to have a Qpid message so we can set the content_type.
            msg = qpid_messaging.Message(jsonutils.dumps(msg))
        msg.content_type = JSON_CONTENT_TYPE
        return msg
コード例 #6
0
ファイル: p11_crypto.py プロジェクト: Neetuj/barbican
    def encrypt(self, encrypt_dto, kek_meta_dto, project_id):
        session = self._create_working_session()

        key = self._unwrap_key(kek_meta_dto.plugin_meta, session)
        iv = self._generate_random(16, session)
        ck_mechanism = self._build_gcm_mech(iv)

        rv = self.lib.C_EncryptInit(session, ck_mechanism.mech, key)
        self._check_error(rv)
        # GCM does not require padding, but sometimes HSMs don't seem to
        # know that and then you need to pad things for no reason.
        pt_padded = self._pad(encrypt_dto.unencrypted)
        pt_len = len(pt_padded)
        # The GCM mechanism adds a 16 byte tag to the front of the
        # cyphertext (which is the same length as the (annoyingly) padded
        # plaintext) so adding 16 bytes guarantees sufficient space.
        ct_len = self.ffi.new("CK_ULONG *", pt_len + 16)
        ct = self.ffi.new("CK_BYTE[{0}]".format(pt_len + 16))
        rv = self.lib.C_Encrypt(session, pt_padded, pt_len, ct, ct_len)
        self._check_error(rv)

        cyphertext = self.ffi.buffer(ct, ct_len[0])[:]
        kek_meta_extended = json.dumps({
            'iv': base64.b64encode(self.ffi.buffer(iv)[:])
        })

        self._close_session(session)

        return plugin.ResponseDTO(cyphertext, kek_meta_extended)
コード例 #7
0
ファイル: impl_qpid.py プロジェクト: bdacode/barbican
    def __init__(self, session, node_name, node_opts=None):
        """Init the Publisher class with the exchange_name, routing_key,
        and other options
        """
        self.sender = None
        self.session = session

        addr_opts = {
            "create": "always",
            "node": {
                "type": "topic",
                "x-declare": {
                    "durable": False,
                    # auto-delete isn't implemented for exchanges in qpid,
                    # but put in here anyway
                    "auto-delete": True,
                },
            },
        }
        if node_opts:
            addr_opts["node"]["x-declare"].update(node_opts)

        self.address = "%s ; %s" % (node_name, jsonutils.dumps(addr_opts))

        self.reconnect(session)
コード例 #8
0
ファイル: resources.py プロジェクト: docstack/barbican
    def on_get(self, req, resp, keystone_id):
        LOG.debug('Start containers on_get '
                  'for tenant-ID {0}:'.format(keystone_id))

        result = self.container_repo.get_by_create_date(
            keystone_id,
            offset_arg=req.get_param('offset'),
            limit_arg=req.get_param('limit'),
            suppress_exception=True
        )

        containers, offset, limit, total = result

        if not containers:
            resp_ctrs_overall = {'containers': [], 'total': total}
        else:
            resp_ctrs = [convert_to_hrefs(keystone_id,
                                          c.to_dict_fields())
                         for c in containers]
            resp_ctrs_overall = add_nav_hrefs('containers',
                                              keystone_id, offset,
                                              limit, total,
                                              {'containers': resp_ctrs})
            resp_ctrs_overall.update({'total': total})

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(resp_ctrs_overall,
                               default=json_handler)
コード例 #9
0
ファイル: resources.py プロジェクト: docstack/barbican
    def on_post(self, req, resp, keystone_id):

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

        data = api.load_body(req, resp, self.validator)
        LOG.debug('Start on_post...{0}'.format(data))

        new_container = models.Container(data)
        new_container.tenant_id = tenant.id

        #TODO: (hgedikli) performance optimizations
        for secret_ref in new_container.container_secrets:
            secret = self.secret_repo.get(entity_id=secret_ref.secret_id,
                                          keystone_id=keystone_id,
                                          suppress_exception=True)
            if not secret:
                api.abort(falcon.HTTP_404,
                          u._("Secret provided for '%s'"
                              " doesn't exist." % secret_ref.name),
                          req, resp)

        self.container_repo.create_from(new_container)

        resp.status = falcon.HTTP_202
        resp.set_header('Location',
                        '/{0}/containers/{1}'.format(keystone_id,
                                                     new_container.id))
        url = convert_container_to_href(keystone_id, new_container.id)
        resp.body = json.dumps({'container_ref': url})
コード例 #10
0
ファイル: resources.py プロジェクト: docstack/barbican
    def on_get(self, req, resp, keystone_id, secret_id):

        secret = self.repo.get(entity_id=secret_id, keystone_id=keystone_id,
                               suppress_exception=True)
        if not secret:
            _secret_not_found(req, resp)

        resp.status = falcon.HTTP_200

        if is_json_request_accept(req):
            # Metadata-only response, no decryption necessary.
            resp.set_header('Content-Type', 'application/json')
            secret_fields = mime_types.augment_fields_with_content_types(
                secret)
            resp.body = json.dumps(convert_to_hrefs(keystone_id,
                                                    secret_fields),
                                   default=json_handler)
        else:
            tenant = res.get_or_create_tenant(keystone_id, self.tenant_repo)
            resp.set_header('Content-Type', req.accept)

            resp.body = self.crypto_manager \
                            .decrypt(req.accept,
                                     secret,
                                     tenant)
コード例 #11
0
ファイル: common.py プロジェクト: crc32a/barbican
def serialize_remote_exception(failure_info, log_failure=True):
    """Prepares exception data to be sent over rpc.

    Failure_info should be a sys.exc_info() tuple.

    """
    tb = traceback.format_exception(*failure_info)
    failure = failure_info[1]
    if log_failure:
        LOG.error(_("Returning exception %s to caller"), unicode(failure))
        LOG.error(tb)

    kwargs = {}
    if hasattr(failure, 'kwargs'):
        kwargs = failure.kwargs

    data = {
        'class': str(failure.__class__.__name__),
        'module': str(failure.__class__.__module__),
        'message': unicode(failure),
        'tb': tb,
        'args': failure.args,
        'kwargs': kwargs
    }

    json_data = jsonutils.dumps(data)

    return json_data
コード例 #12
0
ファイル: common.py プロジェクト: douglassims/barbican
def serialize_remote_exception(failure_info, log_failure=True):
    """Prepares exception data to be sent over rpc.

    Failure_info should be a sys.exc_info() tuple.

    """
    tb = traceback.format_exception(*failure_info)
    failure = failure_info[1]
    if log_failure:
        LOG.error(_("Returning exception %s to caller"), unicode(failure))
        LOG.error(tb)

    kwargs = {}
    if hasattr(failure, 'kwargs'):
        kwargs = failure.kwargs

    data = {
        'class': str(failure.__class__.__name__),
        'module': str(failure.__class__.__module__),
        'message': unicode(failure),
        'tb': tb,
        'args': failure.args,
        'kwargs': kwargs
    }

    json_data = jsonutils.dumps(data)

    return json_data
コード例 #13
0
ファイル: securemessage.py プロジェクト: bdacode/barbican
    def encode(self, version, target, json_msg):
        """This is the main encoding function.

        It takes a target and a message and returns a tuple consisting of a
        JSON serialized metadata object, a JSON serialized (and optionally
        encrypted) message, and a signature.

        :param version: the current envelope version
        :param target: The name of the target service (usually with hostname)
        :param json_msg: a serialized json message object
        """
        ticket = self._get_ticket(target)

        metadata = jsonutils.dumps({'source': self._name,
                                    'destination': target,
                                    'timestamp': time.time(),
                                    'nonce': _get_nonce(),
                                    'esek': ticket.esek,
                                    'encryption': self._encrypt})

        message = json_msg
        if self._encrypt:
            message = self._crypto.encrypt(ticket.ekey, message)

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

        return (metadata, message, signature)
コード例 #14
0
    def encrypt(self, encrypt_dto, kek_meta_dto, project_id):
        key = self._unwrap_key(kek_meta_dto.plugin_meta)
        iv = self._generate_random(16)
        mech = self._build_gcm_mech(iv)
        with self.enc_sem:
            rv = self.lib.C_EncryptInit(self.session, mech, key)
            self._check_error(rv)
            # GCM does not require padding, but sometimes HSMs don't seem to
            # know that and then you need to pad things for no reason.
            pt_padded = self._pad(encrypt_dto.unencrypted)
            pt_len = len(pt_padded)
            # The GCM mechanism adds a 16 byte tag to the front of the
            # cyphertext (which is the same length as the (annoyingly) padded
            # plaintext) so adding 16 bytes guarantees sufficient space.
            ct_len = self.ffi.new("CK_ULONG *", pt_len + 16)
            ct = self.ffi.new("CK_BYTE[{0}]".format(pt_len + 16))
            rv = self.lib.C_Encrypt(self.session, pt_padded, pt_len, ct,
                                    ct_len)
            self._check_error(rv)

        cyphertext = self.ffi.buffer(ct, ct_len[0])[:]
        kek_meta_extended = json.dumps(
            {'iv': base64.b64encode(self.ffi.buffer(iv)[:])})

        return plugin.ResponseDTO(cyphertext, kek_meta_extended)
コード例 #15
0
ファイル: resources.py プロジェクト: douglassims/barbican
    def on_post(self, req, resp, keystone_id):

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

        body = api.load_body(req, resp, self.validator)
        LOG.debug('Start on_post...{0}'.format(body))

        if 'secret' not in body:
            _secret_not_in_order(req, resp)
        secret_info = body['secret']
        name = secret_info['name']
        LOG.debug('Secret to create is {0}'.format(name))

        new_order = models.Order()
        new_order.secret_name = secret_info['name']
        new_order.secret_algorithm = secret_info.get('algorithm', None)
        new_order.secret_bit_length = secret_info.get('bit_length', None)
        new_order.secret_cypher_type = secret_info.get('cypher_type', None)
        new_order.secret_mime_type = secret_info['mime_type']
        new_order.secret_expiration = secret_info.get('expiration', None)
        new_order.tenant_id = tenant.id
        self.order_repo.create_from(new_order)

        # Send to workers to process.
        self.queue.process_order(order_id=new_order.id,
                                 keystone_id=keystone_id)

        resp.status = falcon.HTTP_202
        resp.set_header('Location',
                        '/{0}/orders/{1}'.format(keystone_id, new_order.id))
        url = convert_order_to_href(keystone_id, new_order.id)
        resp.body = json.dumps({'order_ref': url})
コード例 #16
0
ファイル: resources.py プロジェクト: douglassims/barbican
    def on_get(self, req, resp, keystone_id, secret_id):

        secret = self.repo.get(entity_id=secret_id,
                               keystone_id=keystone_id,
                               suppress_exception=True)
        if not secret:
            _secret_not_found(req, resp)

        resp.status = falcon.HTTP_200

        if not req.accept or req.accept == 'application/json' \
           or req.accept == '*/*':
            # Metadata-only response, no decryption necessary.
            resp.set_header('Content-Type', 'application/json')
            secret_fields = augment_fields_with_content_types(secret)
            resp.body = json.dumps(convert_to_hrefs(keystone_id,
                                                    secret_fields),
                                   default=json_handler)
        else:
            tenant = res.get_or_create_tenant(keystone_id, self.tenant_repo)
            resp.set_header('Content-Type', req.accept)
            try:
                resp.body = self.crypto_manager.decrypt(
                    req.accept, secret, tenant)
            except em.CryptoAcceptNotSupportedException as canse:
                LOG.exception('Secret decryption failed - '
                              'accept not supported')
                _get_accept_not_supported(canse.accept, req, resp)
            except em.CryptoNoSecretOrDataException as cnsode:
                LOG.exception('Secret information of type {0} not '
                              'found for decryption.'.format(cnsode.mime_type))
                _get_secret_info_not_found(cnsode.mime_type, req, resp)
            except Exception as e:
                LOG.exception('Secret decryption failed - unknown')
                _failed_to_decrypt_data(req, resp)
コード例 #17
0
ファイル: resources.py プロジェクト: douglassims/barbican
    def on_get(self, req, resp, keystone_id):
        LOG.debug('Start secrets on_get '
                  'for tenant-ID {0}:'.format(keystone_id))

        params = req._params

        result = self.secret_repo \
                     .get_by_create_date(keystone_id,
                                         offset_arg=params.get('offset',
                                                               None),
                                         limit_arg=params.get('limit',
                                                              None),
                                         suppress_exception=True)
        secrets, offset, limit = result

        if not secrets:
            secrets_resp_overall = {'secrets': []}
        else:
            secret_fields = lambda s: augment_fields_with_content_types(s)
            secrets_resp = [
                convert_to_hrefs(keystone_id, secret_fields(s))
                for s in secrets
            ]
            secrets_resp_overall = add_nav_hrefs('secrets', keystone_id,
                                                 offset, limit, len(secrets),
                                                 {'secrets': secrets_resp})

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(secrets_resp_overall, default=json_handler)
コード例 #18
0
ファイル: resources.py プロジェクト: douglassims/barbican
    def on_post(self, req, resp, keystone_id):
        LOG.debug('Start on_post for tenant-ID {0}:...'.format(keystone_id))

        data = api.load_body(req, resp, self.validator)
        tenant = res.get_or_create_tenant(keystone_id, self.tenant_repo)

        try:
            new_secret = res.create_secret(data, tenant, self.crypto_manager,
                                           self.secret_repo,
                                           self.tenant_secret_repo,
                                           self.datum_repo)
        except em.CryptoMimeTypeNotSupportedException as cmtnse:
            LOG.exception('Secret creation failed - mime-type not supported')
            _secret_mime_type_not_supported(cmtnse.mime_type, req, resp)
        except exception.NoDataToProcess:
            LOG.exception('No secret data to process')
            _secret_plain_text_empty(req, resp)
        except exception.LimitExceeded:
            LOG.exception('Secret data too big to process')
            _secret_data_too_large(req, resp)
        except Exception as e:
            LOG.exception('Secret creation failed - unknown')
            _general_failure('Secret creation failed - unknown', req, resp)

        resp.status = falcon.HTTP_201
        resp.set_header('Location',
                        '/{0}/secrets/{1}'.format(keystone_id, new_secret.id))
        url = convert_secret_to_href(keystone_id, new_secret.id)
        LOG.debug('URI to secret is {0}'.format(url))
        resp.body = json.dumps({'secret_ref': url})
コード例 #19
0
ファイル: resources.py プロジェクト: douglassims/barbican
    def on_get(self, req, resp, keystone_id):
        LOG.debug('Start orders on_get '
                  'for tenant-ID {0}:'.format(keystone_id))

        params = req._params

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

        if not orders:
            orders_resp_overall = {'orders': []}
        else:
            orders_resp = [
                convert_to_hrefs(keystone_id, o.to_dict_fields())
                for o in orders
            ]
            orders_resp_overall = add_nav_hrefs('orders', keystone_id, offset,
                                                limit, len(orders),
                                                {'orders': orders_resp})

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(orders_resp_overall, default=json_handler)
コード例 #20
0
ファイル: resources.py プロジェクト: jfwood/barbican-1
    def on_get(self, req, resp, keystone_id):
        LOG.debug('Start verifications on_get '
                  'for tenant-ID {0}:'.format(keystone_id))

        result = self.verification_repo.get_by_create_date(
            keystone_id,
            offset_arg=req.get_param('offset'),
            limit_arg=req.get_param('limit'),
            suppress_exception=True
        )

        verifications, offset, limit, total = result

        if not verifications:
            resp_overall = {'verifications': [], 'total': total}
        else:
            resp = [convert_to_hrefs(keystone_id, v.to_dict_fields()) for
                    v in verifications]
            resp_overall = add_nav_hrefs('verifications', keystone_id,
                                         offset, limit, total,
                                         {'verifications': resp})
            resp_overall.update({'total': total})

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(resp_overall,
                               default=json_handler)
コード例 #21
0
ファイル: resources.py プロジェクト: kaitlin-farr/barbican
    def on_post(self, req, resp, keystone_id):

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

        data = api.load_body(req, resp, self.validator)
        LOG.debug('Start on_post...{0}'.format(data))

        new_container = models.Container(data)
        new_container.tenant_id = tenant.id

        #TODO: (hgedikli) performance optimizations
        for secret_ref in new_container.container_secrets:
            secret = self.secret_repo.get(entity_id=secret_ref.secret_id,
                                          keystone_id=keystone_id,
                                          suppress_exception=True)
            if not secret:
                api.abort(falcon.HTTP_404,
                          u._("Secret provided for '%s'"
                              " doesn't exist." % secret_ref.name),
                          req, resp)

        self.container_repo.create_from(new_container)

        resp.status = falcon.HTTP_202
        resp.set_header('Location',
                        '/{0}/containers/{1}'.format(keystone_id,
                                                     new_container.id))
        url = convert_container_to_href(keystone_id, new_container.id)
        resp.body = json.dumps({'container_ref': url})
コード例 #22
0
ファイル: resources.py プロジェクト: crc32a/barbican
 def on_get(self, req, resp, tenant_id, order_id):
     #TODO: Use a falcon exception here
     order = self.repo.get(entity_id=order_id)
     resp.status = falcon.HTTP_200
     resp.body = json.dumps(convert_to_hrefs(order.tenant_id,
                                             order.to_dict_fields()),
                            default=json_handler)
コード例 #23
0
ファイル: resources.py プロジェクト: bdacode/barbican
    def on_get(self, req, resp, keystone_id, secret_id):

        secret = self.repo.get(entity_id=secret_id, keystone_id=keystone_id,
                               suppress_exception=True)
        if not secret:
            _secret_not_found(req, resp)

        resp.status = falcon.HTTP_200

        if is_json_request_accept(req):
            # Metadata-only response, no decryption necessary.
            resp.set_header('Content-Type', 'application/json')
            secret_fields = mime_types.augment_fields_with_content_types(
                secret)
            resp.body = json.dumps(convert_to_hrefs(keystone_id,
                                                    secret_fields),
                                   default=json_handler)
        else:
            tenant = res.get_or_create_tenant(keystone_id, self.tenant_repo)
            resp.set_header('Content-Type', req.accept)

            resp.body = self.crypto_manager \
                            .decrypt(req.accept,
                                     secret,
                                     tenant)
コード例 #24
0
ファイル: log.py プロジェクト: aelkikhia/barbican
    def format(self, record):
        message = {'message': record.getMessage(),
                   'asctime': self.formatTime(record, self.datefmt),
                   'name': record.name,
                   'msg': record.msg,
                   'args': record.args,
                   'levelname': record.levelname,
                   'levelno': record.levelno,
                   'pathname': record.pathname,
                   'filename': record.filename,
                   'module': record.module,
                   'lineno': record.lineno,
                   'funcname': record.funcName,
                   'created': record.created,
                   'msecs': record.msecs,
                   'relative_created': record.relativeCreated,
                   'thread': record.thread,
                   'thread_name': record.threadName,
                   'process_name': record.processName,
                   'process': record.process,
                   'traceback': None}

        if hasattr(record, 'extra'):
            message['extra'] = record.extra

        if record.exc_info:
            message['traceback'] = self.formatException(record.exc_info)

        return jsonutils.dumps(message)
コード例 #25
0
ファイル: resources.py プロジェクト: jfwood/barbican
    def on_post(self, req, resp, keystone_id):
        LOG.debug('Start on_post for tenant-ID {0}:...'.format(keystone_id))

        data = api.load_body(req, resp, self.validator)
        tenant = res.get_or_create_tenant(keystone_id, self.tenant_repo)

        try:
            new_secret = res.create_secret(data, tenant, self.crypto_manager,
                                           self.secret_repo,
                                           self.tenant_secret_repo,
                                           self.datum_repo)
        except em.CryptoMimeTypeNotSupportedException as cmtnse:
            LOG.exception('Secret creation failed - mime-type not supported')
            _secret_mime_type_not_supported(cmtnse.mime_type, req, resp)
        except exception.NoDataToProcess:
            LOG.exception('No secret data to process')
            _secret_plain_text_empty(req, resp)
        except exception.LimitExceeded:
            LOG.exception('Secret data too big to process')
            _secret_data_too_large(req, resp)
        except Exception as e:
            LOG.exception('Secret creation failed - unknown')
            _general_failure('Secret creation failed - unknown', req, resp)

        resp.status = falcon.HTTP_201
        resp.set_header('Location', '/{0}/secrets/{1}'.format(keystone_id,
                                                              new_secret.id))
        url = convert_secret_to_href(keystone_id, new_secret.id)
        LOG.debug('URI to secret is {0}'.format(url))
        resp.body = json.dumps({'secret_ref': url})
コード例 #26
0
ファイル: resources.py プロジェクト: jfwood/barbican
    def on_get(self, req, resp, keystone_id, secret_id):

        secret = self.repo.get(entity_id=secret_id, keystone_id=keystone_id,
                               suppress_exception=True)
        if not secret:
            _secret_not_found(req, resp)

        resp.status = falcon.HTTP_200

        if not req.accept or req.accept == 'application/json' \
                or req.accept == '*/*':
            # Metadata-only response, no decryption necessary.
            resp.set_header('Content-Type', 'application/json')
            secret_fields = augment_fields_with_content_types(secret)
            resp.body = json.dumps(convert_to_hrefs(keystone_id,
                                                    secret_fields),
                                   default=json_handler)
        else:
            tenant = res.get_or_create_tenant(keystone_id, self.tenant_repo)
            resp.set_header('Content-Type', req.accept)
            try:
                resp.body = self.crypto_manager.decrypt(req.accept, secret,
                                                        tenant)
            except em.CryptoAcceptNotSupportedException as canse:
                LOG.exception('Secret decryption failed - '
                              'accept not supported')
                _get_accept_not_supported(canse.accept, req, resp)
            except em.CryptoNoSecretOrDataException as cnsode:
                LOG.exception('Secret information of type {0} not '
                              'found for decryption.'.format(cnsode.mime_type))
                _get_secret_info_not_found(cnsode.mime_type, req, resp)
            except Exception as e:
                LOG.exception('Secret decryption failed - unknown')
                _failed_to_decrypt_data(req, resp)
コード例 #27
0
ファイル: log.py プロジェクト: kaitlin-farr/barbican
    def format(self, record):
        message = {
            "message": record.getMessage(),
            "asctime": self.formatTime(record, self.datefmt),
            "name": record.name,
            "msg": record.msg,
            "args": record.args,
            "levelname": record.levelname,
            "levelno": record.levelno,
            "pathname": record.pathname,
            "filename": record.filename,
            "module": record.module,
            "lineno": record.lineno,
            "funcname": record.funcName,
            "created": record.created,
            "msecs": record.msecs,
            "relative_created": record.relativeCreated,
            "thread": record.thread,
            "thread_name": record.threadName,
            "process_name": record.processName,
            "process": record.process,
            "traceback": None,
        }

        if hasattr(record, "extra"):
            message["extra"] = record.extra

        if record.exc_info:
            message["traceback"] = self.formatException(record.exc_info)

        return jsonutils.dumps(message)
コード例 #28
0
ファイル: resources.py プロジェクト: bdacode/barbican
    def on_post(self, req, resp, keystone_id):

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

        body = api.load_body(req, resp, self.validator)
        LOG.debug('Start on_post...{0}'.format(body))

        if 'secret' not in body:
            _secret_not_in_order(req, resp)
        secret_info = body['secret']
        name = secret_info.get('name')
        LOG.debug('Secret to create is {0}'.format(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.
        self.queue.process_order(order_id=new_order.id,
                                 keystone_id=keystone_id)

        resp.status = falcon.HTTP_202
        resp.set_header('Location', '/{0}/orders/{1}'.format(keystone_id,
                                                             new_order.id))
        url = convert_order_to_href(keystone_id, new_order.id)
        resp.body = json.dumps({'order_ref': url})
コード例 #29
0
ファイル: securemessage.py プロジェクト: bdacode/barbican
    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']
コード例 #30
0
ファイル: resources.py プロジェクト: bdacode/barbican
    def on_get(self, req, resp, keystone_id):
        LOG.debug('Start orders on_get '
                  'for tenant-ID {0}:'.format(keystone_id))

        params = req._params

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

        if not orders:
            orders_resp_overall = {'orders': [],
                                   'total': total}
        else:
            orders_resp = [convert_to_hrefs(keystone_id, o.to_dict_fields())
                           for o in orders]
            orders_resp_overall = add_nav_hrefs('orders', keystone_id,
                                                offset, limit, total,
                                                {'orders': orders_resp})
            orders_resp_overall.update({'total': total})

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(orders_resp_overall,
                               default=json_handler)
コード例 #31
0
ファイル: common.py プロジェクト: bdacode/barbican
def serialize_msg(raw_msg):
    # NOTE(russellb) See the docstring for _RPC_ENVELOPE_VERSION for more
    # information about this format.
    msg = {_VERSION_KEY: _RPC_ENVELOPE_VERSION,
           _MESSAGE_KEY: jsonutils.dumps(raw_msg)}

    return msg
コード例 #32
0
ファイル: resources.py プロジェクト: bdacode/barbican
    def on_get(self, req, resp, keystone_id):
        LOG.debug('Start secrets on_get '
                  'for tenant-ID {0}:'.format(keystone_id))

        result = self.secret_repo.get_by_create_date(
            keystone_id,
            offset_arg=req.get_param('offset'),
            limit_arg=req.get_param('limit'),
            suppress_exception=True
        )

        secrets, offset, limit, total = result

        if not secrets:
            secrets_resp_overall = {'secrets': [],
                                    'total': total}
        else:
            secret_fields = lambda s: mime_types\
                .augment_fields_with_content_types(s)
            secrets_resp = [convert_to_hrefs(keystone_id, secret_fields(s)) for
                            s in secrets]
            secrets_resp_overall = add_nav_hrefs('secrets', keystone_id,
                                                 offset, limit, total,
                                                 {'secrets': secrets_resp})
            secrets_resp_overall.update({'total': total})

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(secrets_resp_overall,
                               default=json_handler)
コード例 #33
0
ファイル: impl_qpid.py プロジェクト: douglassims/barbican
    def __init__(self, session, node_name, node_opts=None):
        """Init the Publisher class with the exchange_name, routing_key,
        and other options
        """
        self.sender = None
        self.session = session

        addr_opts = {
            "create": "always",
            "node": {
                "type": "topic",
                "x-declare": {
                    "durable": False,
                    # auto-delete isn't implemented for exchanges in qpid,
                    # but put in here anyway
                    "auto-delete": True,
                },
            },
        }
        if node_opts:
            addr_opts["node"]["x-declare"].update(node_opts)

        self.address = "%s ; %s" % (node_name, jsonutils.dumps(addr_opts))

        self.reconnect(session)
コード例 #34
0
    def format(self, record):
        message = {
            'message': record.getMessage(),
            'asctime': self.formatTime(record, self.datefmt),
            'name': record.name,
            'msg': record.msg,
            'args': record.args,
            'levelname': record.levelname,
            'levelno': record.levelno,
            'pathname': record.pathname,
            'filename': record.filename,
            'module': record.module,
            'lineno': record.lineno,
            'funcname': record.funcName,
            'created': record.created,
            'msecs': record.msecs,
            'relative_created': record.relativeCreated,
            'thread': record.thread,
            'thread_name': record.threadName,
            'process_name': record.processName,
            'process': record.process,
            'traceback': None
        }

        if hasattr(record, 'extra'):
            message['extra'] = record.extra

        if record.exc_info:
            message['traceback'] = self.formatException(record.exc_info)

        return jsonutils.dumps(message)
コード例 #35
0
 def on_error(self, state, exc):
     if isinstance(exc, webob_exc.HTTPError):
         exc.body = json.dumps({
             'code': exc.status_int,
             'title': exc.title,
             'description': exc.detail
         })
         state.response.content_type = "application/json"
         return exc.body
コード例 #36
0
ファイル: hooks.py プロジェクト: Banno/barbican
 def on_error(self, state, exc):
     if isinstance(exc, webob.exc.HTTPError):
         exc.body = jsonutils.dumps({
             'code': exc.status_int,
             'title': exc.title,
             'description': exc.detail
         })
         state.response.content_type = "application/json"
         return exc.body
コード例 #37
0
ファイル: common.py プロジェクト: douglassims/barbican
def serialize_msg(raw_msg):
    # NOTE(russellb) See the docstring for _RPC_ENVELOPE_VERSION for more
    # information about this format.
    msg = {
        _VERSION_KEY: _RPC_ENVELOPE_VERSION,
        _MESSAGE_KEY: jsonutils.dumps(raw_msg)
    }

    return msg
コード例 #38
0
ファイル: log_notifier.py プロジェクト: douglassims/barbican
def notify(_context, message):
    """Notifies the recipient of the desired event given the model.
    Log notifications using openstack's default logging system"""

    priority = message.get('priority', CONF.default_notification_level)
    priority = priority.lower()
    logger = logging.getLogger('barbican.openstack.common.notification.%s' %
                               message['event_type'])
    getattr(logger, priority)(jsonutils.dumps(message))
コード例 #39
0
ファイル: resources.py プロジェクト: bdacode/barbican
    def on_get(self, req, resp, keystone_id, order_id):
        order = self.repo.get(entity_id=order_id, keystone_id=keystone_id,
                              suppress_exception=True)
        if not order:
            _order_not_found(req, resp)

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(convert_to_hrefs(keystone_id,
                                                order.to_dict_fields()),
                               default=json_handler)
コード例 #40
0
ファイル: resources.py プロジェクト: docstack/barbican
    def on_get(self, req, resp, keystone_id, order_id):
        order = self.repo.get(entity_id=order_id, keystone_id=keystone_id,
                              suppress_exception=True)
        if not order:
            _order_not_found(req, resp)

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(convert_to_hrefs(keystone_id,
                                                order.to_dict_fields()),
                               default=json_handler)
コード例 #41
0
ファイル: impl_zmq.py プロジェクト: douglassims/barbican
def _serialize(data):
    """
    Serialization wrapper
    We prefer using JSON, but it cannot encode all types.
    Error if a developer passes us bad data.
    """
    try:
        return jsonutils.dumps(data, ensure_ascii=True)
    except TypeError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("JSON serialization failed."))
コード例 #42
0
ファイル: resources.py プロジェクト: docstack/barbican
    def on_get(self, req, resp, keystone_id, verification_id):
        verif = self.repo.get(entity_id=verification_id,
                              keystone_id=keystone_id,
                              suppress_exception=True)
        if not verif:
            _verification_not_found(req, resp)

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(convert_to_hrefs(keystone_id,
                                                verif.to_dict_fields()),
                               default=json_handler)
コード例 #43
0
ファイル: log_notifier.py プロジェクト: crc32a/barbican
def notify(_context, message):
    """Notifies the recipient of the desired event given the model.
    Log notifications using openstack's default logging system"""

    priority = message.get('priority',
                           CONF.default_notification_level)
    priority = priority.lower()
    logger = logging.getLogger(
        'barbican.openstack.common.notification.%s' %
        message['event_type'])
    getattr(logger, priority)(jsonutils.dumps(message))
コード例 #44
0
ファイル: resources.py プロジェクト: jfwood/barbican-1
    def on_get(self, req, resp, keystone_id, verification_id):
        verif = self.repo.get(entity_id=verification_id,
                              keystone_id=keystone_id,
                              suppress_exception=True)
        if not verif:
            _verification_not_found(req, resp)

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(convert_to_hrefs(keystone_id,
                                                verif.to_dict_fields()),
                               default=json_handler)
コード例 #45
0
    def bind_kek_metadata(self, kek_meta_dto):
        # Enforce idempotency: If we've already generated a key leave now.
        if not kek_meta_dto.plugin_meta:
            kek_length = 32
            kek_meta_dto.plugin_meta = json.dumps(
                self._generate_wrapped_kek(kek_meta_dto.kek_label, kek_length))
            # To be persisted by Barbican:
            kek_meta_dto.algorithm = 'AES'
            kek_meta_dto.bit_length = kek_length * 8
            kek_meta_dto.mode = 'CBC'

        return kek_meta_dto
コード例 #46
0
ファイル: p11_crypto.py プロジェクト: stanzikratel/barbican-2
    def encrypt(self, encrypt_dto, kek_meta_dto, keystone_id):
        key = self._get_key_by_label(kek_meta_dto.kek_label)
        iv = self._generate_iv()
        gcm = self._build_gcm_params(iv)
        mech = PyKCS11.Mechanism(self.algorithm, gcm)
        encrypted = self.session.encrypt(key, encrypt_dto.unencrypted, mech)
        cyphertext = b''.join(chr(i) for i in encrypted)
        kek_meta_extended = json.dumps({
            'iv': base64.b64encode(iv)
        })

        return plugin.ResponseDTO(cyphertext, kek_meta_extended)
コード例 #47
0
ファイル: p11_crypto.py プロジェクト: frumioj/barbican
    def encrypt(self, encrypt_dto, kek_meta_dto, keystone_id):
        key = self._get_key_by_label(kek_meta_dto.kek_label)
        iv = self._generate_iv()
        gcm = self._build_gcm_params(iv)
        mech = PyKCS11.Mechanism(self.algorithm, gcm)
        encrypted = self.session.encrypt(key, encrypt_dto.unencrypted, mech)
        cyphertext = b''.join(chr(i) for i in encrypted)
        kek_meta_extended = json.dumps({
            'iv': base64.b64encode(iv)
        })

        return plugin.ResponseDTO(cyphertext, kek_meta_extended)
コード例 #48
0
ファイル: policy.py プロジェクト: andersonvom/barbican
    def __str__(self):
        """Dumps a string representation of the rules."""

        # Start by building the canonical strings for the rules
        out_rules = {}
        for key, value in self.items():
            # Use empty string for singleton TrueCheck instances
            if isinstance(value, TrueCheck):
                out_rules[key] = ''
            else:
                out_rules[key] = str(value)

        # Dump a pretty-printed JSON representation
        return jsonutils.dumps(out_rules, indent=4)
コード例 #49
0
ファイル: p11_crypto.py プロジェクト: divya-csekar/barbican
    def bind_kek_metadata(self, kek_meta_dto):
        # Enforce idempotency: If we've already generated a key leave now.
        if not kek_meta_dto.plugin_meta:
            kek_meta_dto.plugin_meta = json.dumps(
                self._generate_wrapped_kek(
                    kek_meta_dto.kek_label, 32
                )
            )
            # To be persisted by Barbican:
            kek_meta_dto.algorithm = 'AES'
            kek_meta_dto.bit_length = 32 * 8
            kek_meta_dto.mode = 'CBC'

        return kek_meta_dto
コード例 #50
0
ファイル: policy.py プロジェクト: chellygel/barbican
    def __str__(self):
        """Dumps a string representation of the rules."""

        # Start by building the canonical strings for the rules
        out_rules = {}
        for key, value in self.items():
            # Use empty string for singleton TrueCheck instances
            if isinstance(value, TrueCheck):
                out_rules[key] = ''
            else:
                out_rules[key] = str(value)

        # Dump a pretty-printed JSON representation
        return jsonutils.dumps(out_rules, indent=4)
コード例 #51
0
ファイル: resources.py プロジェクト: crc32a/barbican
    def on_post(self, req, resp, tenant_id):

        # Retrieve Tenant, or else create new Tenant
        #   if this is a request from a new tenant.
        tenant = self.tenant_repo.get(tenant_id, suppress_exception=True)
        if not tenant:
            tenant = Tenant()
            tenant.keystone_id = tenant_id
            tenant.status = States.ACTIVE
            self.tenant_repo.create_from(tenant)

        body = load_body(req)
        LOG.debug('Start on_post...{0}'.format(body))

        if 'secret' not in body:
            _secret_not_in_order()
        secret_info = body['secret']
        name = secret_info['name']
        LOG.debug('Secret to create is {0}'.format(name))

        # TODO: What criteria to restrict multiple concurrent Order
        #      requests per tenant?
        # order = self.order_repo.find_by_name(name=secret_name,
        #                                  suppress_exception=True)
        # if order:
        #    abort(falcon.HTTP_400, 'Order with username {0} '
        #                           'already exists'.format(username))

        # TODO: Encrypt fields as needed

        new_order = Order()
        new_order.secret_name = secret_info['name']
        new_order.secret_algorithm = secret_info.get('algorithm', None)
        new_order.secret_bit_length = secret_info.get('bit_length', None)
        new_order.secret_cypher_type = secret_info.get('cypher_type', None)
        new_order.secret_mime_type = secret_info['mime_type']
        new_order.secret_expiration = secret_info.get('expiration', None)

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

        # Send to workers to process.
        self.queue.process_order(order_id=new_order.id)

        resp.status = falcon.HTTP_202
        resp.set_header('Location', '/{0}/orders/{1}'.format(tenant_id,
                                                             new_order.id))
        url = convert_order_to_href(tenant_id, new_order.id)
        resp.body = json.dumps({'order_ref': url})
コード例 #52
0
    def encrypt(self, unencrypted, tenant):
        if not isinstance(unencrypted, str):
            raise ValueError('Unencrypted data must be a byte type, '
                             'but was {0}'.format(type(unencrypted)))
        padded_data = self._pad(unencrypted)
        iv = Random.get_random_bytes(self.block_size)
        encryptor = AES.new(self.kek, AES.MODE_CBC, iv)

        cyphertext = iv + encryptor.encrypt(padded_data)
        kek_metadata = json.dumps({
            'plugin': 'SimpleCryptoPlugin',
            'encryption': 'aes-128-cbc',
            'kek': 'kek_id'
        })

        return cyphertext, kek_metadata
コード例 #53
0
ファイル: resources.py プロジェクト: crc32a/barbican
    def on_get(self, req, resp, tenant_id, secret_id):

        secret = self.repo.get(entity_id=secret_id, suppress_exception=True)
        if not secret:
            _secret_not_found()

        resp.status = falcon.HTTP_200

        if not req.accept or req.accept == 'application/json':
            # Metadata-only response, no decryption necessary.
            resp.set_header('Content-Type', 'application/json')
            resp.body = json.dumps(augment_fields_with_content_types(secret),
                                   default=json_handler)
        else:
            resp.set_header('Content-Type', req.accept)
            resp.body = generate_response_for(req.accept, secret)
コード例 #54
0
ファイル: securemessage.py プロジェクト: bdacode/barbican
    def _do_get(self, url, request):
        req_kwargs = dict()
        req_kwargs['headers'] = dict()
        req_kwargs['headers']['User-Agent'] = self.USER_AGENT
        req_kwargs['headers']['Content-Type'] = 'application/json'
        req_kwargs['data'] = jsonutils.dumps({'request': request})
        if self.timeout is not None:
            req_kwargs['timeout'] = self.timeout

        try:
            resp = requests.get(url, **req_kwargs)
        except requests.ConnectionError as e:
            err = "Unable to establish connection. %s" % e
            raise CommunicationError(url, err)

        return resp
コード例 #55
0
ファイル: resources.py プロジェクト: docstack/barbican
    def on_post(self, req, resp, keystone_id):
        LOG.debug('Start on_post for tenant-ID {0}:...'.format(keystone_id))

        data = api.load_body(req, resp, self.validator)
        tenant = res.get_or_create_tenant(keystone_id, self.tenant_repo)

        new_secret = res.create_secret(data, tenant, self.crypto_manager,
                                       self.secret_repo,
                                       self.tenant_secret_repo,
                                       self.datum_repo,
                                       self.kek_repo)

        resp.status = falcon.HTTP_201
        resp.set_header('Location', '/{0}/secrets/{1}'.format(keystone_id,
                                                              new_secret.id))
        url = convert_secret_to_href(keystone_id, new_secret.id)
        LOG.debug('URI to secret is {0}'.format(url))
        resp.body = json.dumps({'secret_ref': url})
コード例 #56
0
ファイル: resources.py プロジェクト: docstack/barbican
    def on_get(self, req, resp, keystone_id, container_id):
        container = self.container_repo.get(entity_id=container_id,
                                            keystone_id=keystone_id,
                                            suppress_exception=True)
        if not container:
            _container_not_found(req, resp)

        resp.status = falcon.HTTP_200

        dict_fields = container.to_dict_fields()

        for secret_ref in dict_fields['secret_refs']:
                convert_to_hrefs(keystone_id, secret_ref)

        resp.body = json.dumps(
            convert_to_hrefs(keystone_id,
                             convert_to_hrefs(keystone_id, dict_fields)),
            default=json_handler)
コード例 #57
0
ファイル: impl_qpid.py プロジェクト: douglassims/barbican
    def __init__(self, session, callback, node_name, node_opts, link_name,
                 link_opts):
        """Declare a queue on an amqp session.

        'session' is the amqp session to use
        'callback' is the callback to call when messages are received
        'node_name' is the first part of the Qpid address string, before ';'
        'node_opts' will be applied to the "x-declare" section of "node"
                    in the address string.
        'link_name' goes into the "name" field of the "link" in the address
                    string
        'link_opts' will be applied to the "x-declare" section of "link"
                    in the address string.
        """
        self.callback = callback
        self.receiver = None
        self.session = None

        addr_opts = {
            "create": "always",
            "node": {
                "type": "topic",
                "x-declare": {
                    "durable": True,
                    "auto-delete": True,
                },
            },
            "link": {
                "name": link_name,
                "durable": True,
                "x-declare": {
                    "durable": False,
                    "auto-delete": True,
                    "exclusive": False,
                },
            },
        }
        addr_opts["node"]["x-declare"].update(node_opts)
        addr_opts["link"]["x-declare"].update(link_opts)

        self.address = "%s ; %s" % (node_name, jsonutils.dumps(addr_opts))

        self.reconnect(session)
コード例 #58
0
ファイル: resources.py プロジェクト: docstack/barbican
    def on_post(self, req, resp, keystone_id):
        LOG.debug('Start on_post for tenant-ID {0}:...'.format(keystone_id))

        data = api.load_body(req, resp, self.validator)
        tenant = res.get_or_create_tenant(keystone_id, self.tenant_repo)

        new_verification = models.Verification(data)
        new_verification.tenant_id = tenant.id
        self.verification_repo.create_from(new_verification)

        # Send to workers to process.
        self.queue.process_verification(verification_id=new_verification.id,
                                        keystone_id=keystone_id)

        resp.status = falcon.HTTP_202
        resp.set_header('Location',
                        '/{0}/verifications/{1}'.format(keystone_id,
                                                        new_verification.id))
        url = convert_verification_to_href(keystone_id, new_verification.id)
        LOG.debug('URI to verification is {0}'.format(url))
        resp.body = json.dumps({'verification_ref': url})
コード例 #59
0
ファイル: resources.py プロジェクト: docstack/barbican
    def on_get(self, req, resp, keystone_id):
        LOG.debug('Start secrets on_get '
                  'for tenant-ID {0}:'.format(keystone_id))

        name = req.get_param('name')
        if name:
            name = urllib.unquote_plus(name)

        result = self.secret_repo.get_by_create_date(
            keystone_id,
            offset_arg=req.get_param('offset'),
            limit_arg=req.get_param('limit'),
            name=name,
            alg=req.get_param('alg'),
            mode=req.get_param('mode'),
            bits=req.get_param('bits'),
            suppress_exception=True
        )

        secrets, offset, limit, total = result

        if not secrets:
            secrets_resp_overall = {'secrets': [],
                                    'total': total}
        else:
            secret_fields = lambda s: mime_types\
                .augment_fields_with_content_types(s)
            secrets_resp = [convert_to_hrefs(keystone_id, secret_fields(s)) for
                            s in secrets]
            secrets_resp_overall = add_nav_hrefs('secrets', keystone_id,
                                                 offset, limit, total,
                                                 {'secrets': secrets_resp})
            secrets_resp_overall.update({'total': total})

        resp.status = falcon.HTTP_200
        resp.body = json.dumps(secrets_resp_overall,
                               default=json_handler)