コード例 #1
0
ファイル: secrets.py プロジェクト: honghuac/custodia
    def _int_del_key(self, trail, request, response):
        try:
            name = '/'.join(trail)
            msg = self._parse_maybe_body(request, name)
        except Exception as e:
            raise HTTPError(406, str(e))
        key = self._db_key(trail)
        try:
            ret = self.root.store.cut(key)
        except CSStoreDenied:
            self.logger.exception(
                "Delete: Permission to perform this operation was denied")
            raise HTTPError(403)
        except CSStoreError:
            self.logger.exception('Delete: Internal Server Error')
            raise HTTPError(500)
        except CSStoreUnsupported:
            self.logger.exception('Delete: Unsupported operation')
            raise HTTPError(501)

        if ret is False:
            raise HTTPError(404)

        output = msg.reply(None)
        if output is None:
            response['code'] = 204
        else:
            response['headers'][
                'Content-Type'] = 'application/json; charset=utf-8'
            response['output'] = output
            response['code'] = 200
コード例 #2
0
    def _destroy(self, trail, request, response):
        try:
            name = '/'.join(trail)
            msg = self._parse_maybe_body(request, name)
        except Exception as e:
            raise HTTPError(406, str(e))
        basename = self._db_container_key(None, trail)
        try:
            keylist = self.root.store.list(basename)
            if keylist is None:
                raise HTTPError(404)
            if len(keylist) != 0:
                raise HTTPError(409)
            ret = self.root.store.cut(basename.rstrip('/'))
        except CSStoreError:
            raise HTTPError(500)

        if ret is False:
            raise HTTPError(404)

        output = msg.reply(None)
        if output is None:
            response['code'] = 204
        else:
            response['headers'][
                'Content-Type'] = 'application/json; charset=utf-8'
            response['output'] = output
            response['code'] = 200
コード例 #3
0
    def _create(self, trail, request, response):
        try:
            name = '/'.join(trail)
            msg = self._parse_maybe_body(request, name)
        except Exception as e:
            raise HTTPError(406, str(e))
        default = request.get('default_namespace', None)
        basename = self._db_container_key(None, trail)
        try:
            if len(trail) > 2:
                ok = self._parent_exists(default, trail[:-1])
                if not ok:
                    raise HTTPError(404)

            self.root.store.span(basename)
        except CSStoreExists:
            raise HTTPError(409)
        except CSStoreError:
            raise HTTPError(500)

        output = msg.reply(None)
        if output is not None:
            response['headers'][
                'Content-Type'] = 'application/json; charset=utf-8'
            response['output'] = output
        response['code'] = 201
コード例 #4
0
ファイル: secrets.py プロジェクト: honghuac/custodia
 def _list(self, trail, request, response):
     try:
         name = '/'.join(trail)
         msg = self._parse_query(request, name)
     except Exception as e:
         raise HTTPError(406, str(e))
     default = request.get('default_namespace', None)
     basename = self._db_container_key(default, trail)
     try:
         keylist = self.root.store.list(basename)
         self.logger.debug('list %s returned %r', basename, keylist)
         if keylist is None:
             raise HTTPError(404)
         response['headers'][
             'Content-Type'] = 'application/json; charset=utf-8'
         response['output'] = msg.reply(keylist)
     except CSStoreDenied:
         self.logger.exception(
             "List: Permission to perform this operation was denied")
         raise HTTPError(403)
     except CSStoreError:
         self.logger.exception('List: Internal server error')
         raise HTTPError(500)
     except CSStoreUnsupported:
         self.logger.exception('List: Unsupported operation')
         raise HTTPError(501)
コード例 #5
0
 def _db_container_key(self, default, trail):
     f = None
     if len(trail) > 1:
         f = self._db_key(trail)
     elif len(trail) == 1 and trail[0] != '':
         raise HTTPError(403)
     elif default is None:
         # No dfault namespace, fail
         raise HTTPError(403)
     else:
         # Use the default namespace
         f = self._db_key([default, ''])
     return f
コード例 #6
0
 def _int_get_key(self, trail, request, response):
     try:
         name = '/'.join(trail)
         handler = self._parse_query(request, name)
     except Exception as e:
         raise HTTPError(406, str(e))
     key = self._db_key(trail)
     try:
         output = self.root.store.get(key)
         if output is None:
             raise HTTPError(404)
         self._format_reply(request, response, handler, output)
     except CSStoreError:
         raise HTTPError(500)
コード例 #7
0
ファイル: secrets.py プロジェクト: honghuac/custodia
 def _db_container_key(self, default, trail):
     f = None
     if len(trail) > 1:
         f = self._db_key(trail)
     elif len(trail) == 1 and trail[0] != '':
         self.logger.debug(
             "Forbidden action: Wrong container path. Container names must "
             "end with '/'")
         raise HTTPError(403)
     elif default is None:
         self.logger.debug("Forbidden action: No default namespace")
         raise HTTPError(403)
     else:
         # Use the default namespace
         f = self._db_key([default, ''])
     return f
コード例 #8
0
ファイル: secrets.py プロジェクト: honghuac/custodia
 def _parse_bin_body(self, request, name):
     body = request.get('body')
     if body is None:
         raise HTTPError(400)
     value = b64encode(bytes(body)).decode('utf-8')
     payload = {'type': 'simple', 'value': value}
     return self._parse(request, payload, name)
コード例 #9
0
ファイル: secrets.py プロジェクト: honghuac/custodia
 def _db_key(self, trail):
     if len(trail) < 2:
         self.logger.debug(
             "Forbidden action: Operation only permitted within a "
             "container")
         raise HTTPError(403)
     return os.path.join('keys', *trail)
コード例 #10
0
ファイル: secrets.py プロジェクト: honghuac/custodia
 def DELETE(self, request, response):
     trail = request.get('trail', [])
     if len(trail) == 0:
         raise HTTPError(405)
     if trail[-1] == '':
         self._destroy(trail, request, response)
     else:
         self._del_key(trail, request, response)
コード例 #11
0
 def parse_body(self):
     length = int(self.headers.get('content-length', 0))
     if length > MAX_REQUEST_SIZE:
         raise HTTPError(413)
     if length == 0:
         self.body = None
     else:
         self.body = self.rfile.read(length)
コード例 #12
0
 def _list(self, trail, request, response):
     try:
         name = '/'.join(trail)
         msg = self._parse_query(request, name)
     except Exception as e:
         raise HTTPError(406, str(e))
     default = request.get('default_namespace', None)
     basename = self._db_container_key(default, trail)
     try:
         keylist = self.root.store.list(basename)
         self.logger.debug('list %s returned %r', basename, keylist)
         if keylist is None:
             raise HTTPError(404)
         response['headers'][
             'Content-Type'] = 'application/json; charset=utf-8'
         response['output'] = msg.reply(keylist)
     except CSStoreError:
         raise HTTPError(500)
コード例 #13
0
    def _find_handler(self, request):
        base = self
        command = request.get('command', 'GET')
        if command not in SUPPORTED_COMMANDS:
            raise HTTPError(501)
        trail = request.get('trail', None)
        if trail is not None:
            for comp in trail:
                subs = getattr(base, 'subs', {})
                if comp in subs:
                    base = subs[comp]
                    trail.pop(0)
                else:
                    break

        handler = getattr(base, command)
        if handler is None:
            raise HTTPError(400)

        return handler
コード例 #14
0
ファイル: secrets.py プロジェクト: honghuac/custodia
    def _int_set_key(self, trail, request, response):
        try:
            name = '/'.join(trail)

            content_type = request.get('headers', {}).get('Content-Type', '')
            content_type_value = content_type.split(';')[0].strip()
            if content_type_value == 'application/octet-stream':
                msg = self._parse_bin_body(request, name)
            elif content_type_value == 'application/json':
                msg = self._parse_body(request, name)
            else:
                raise ValueError('Invalid Content-Type')
        except UnknownMessageType as e:
            raise HTTPError(406, str(e))
        except UnallowedMessage as e:
            raise HTTPError(406, str(e))
        except Exception as e:
            raise HTTPError(400, str(e))

        # must _db_key first as access control is done here for now
        # otherwise users would e able to probe containers in namespaces
        # they do not have access to.
        key = self._db_key(trail)

        try:
            default = request.get('default_namespace', None)
            ok = self._parent_exists(default, trail)
            if not ok:
                raise HTTPError(404)

            ok = self.root.store.set(key, msg.payload)
        except CSStoreDenied:
            self.logger.exception(
                "Set: Permission to perform this operation was denied")
            raise HTTPError(403)
        except CSStoreExists:
            self.logger.exception('Set: Key already exist')
            raise HTTPError(409)
        except CSStoreError:
            self.logger.exception('Set: Internal Server Error')
            raise HTTPError(500)
        except CSStoreUnsupported:
            self.logger.exception('Set: Unsupported operation')
            raise HTTPError(501)

        output = msg.reply(None)
        if output is not None:
            response['headers'][
                'Content-Type'] = 'application/json; charset=utf-8'
            response['output'] = output
        response['code'] = 201
コード例 #15
0
 def _int_head_key(self, trail, request, response):
     try:
         name = '/'.join(trail)
         handler = self._parse_query(request, name)
     except Exception as e:
         raise HTTPError(406, str(e))
     key = self._db_key(trail)
     try:
         content = b64decode(self.root.store.get(key))
         if content is None:
             raise HTTPError(404)
         elif len(content) == 0:
             raise HTTPError(406)
         output = handler.reply(None)
         response['output'] = output
         response['code'] = 200
         response['headers']['Content-Length'] = str(len(content))
         response['headers']['Content-MD5'] = b64encode(
             hashlib.md5(content).digest())
     except CSStoreDenied:
         self.logger.exception(
             "Get: Permission to perform this operation was denied")
         raise HTTPError(403)
     except CSStoreError:
         self.logger.exception('Get: Internal server error')
         raise HTTPError(500)
     except CSStoreUnsupported:
         self.logger.exception('Get: Unsupported operation')
         raise HTTPError(501)
コード例 #16
0
ファイル: secrets.py プロジェクト: honghuac/custodia
    def _create(self, trail, request, response):
        try:
            name = '/'.join(trail)
            msg = self._parse_maybe_body(request, name)
        except Exception as e:
            raise HTTPError(406, str(e))
        default = request.get('default_namespace', None)
        basename = self._db_container_key(None, trail)
        try:
            if len(trail) > 2:
                ok = self._parent_exists(default, trail[:-1])
                if not ok:
                    raise HTTPError(404)

            self.root.store.span(basename)
        except CSStoreDenied:
            self.logger.exception(
                "Create: Permission to perform this operation was denied")
            raise HTTPError(403)
        except CSStoreExists:
            self.logger.exception('Create: Key already exists')
            raise HTTPError(409)
        except CSStoreError:
            self.logger.exception('Create: Internal server error')
            raise HTTPError(500)
        except CSStoreUnsupported:
            self.logger.exception('Create: Unsupported operation')
            raise HTTPError(501)

        output = msg.reply(None)
        if output is not None:
            response['headers'][
                'Content-Type'] = 'application/json; charset=utf-8'
            response['output'] = output
        response['code'] = 201
コード例 #17
0
    def _int_del_key(self, trail, request, response):
        try:
            name = '/'.join(trail)
            msg = self._parse_maybe_body(request, name)
        except Exception as e:
            raise HTTPError(406, str(e))
        key = self._db_key(trail)
        try:
            ret = self.root.store.cut(key)
        except CSStoreError:
            raise HTTPError(500)

        if ret is False:
            raise HTTPError(404)

        output = msg.reply(None)
        if output is None:
            response['code'] = 204
        else:
            response['headers'][
                'Content-Type'] = 'application/json; charset=utf-8'
            response['output'] = output
            response['code'] = 200
コード例 #18
0
ファイル: secrets.py プロジェクト: honghuac/custodia
    def _parent_exists(self, default, trail):
        # check that the containers exist
        basename = self._db_container_key(trail[0], trail[:-1] + [''])
        try:
            keylist = self.root.store.list(basename)
        except CSStoreError:
            raise HTTPError(500)

        self.logger.debug('parent_exists: %s (%s, %r) -> %r', basename,
                          default, trail, keylist)

        if keylist is not None:
            return True

        # create default namespace if it is the only missing piece
        if len(trail) == 2 and default == trail[0]:
            container = self._db_container_key(default, '')
            self.root.store.span(container)
            return True

        return False
コード例 #19
0
ファイル: secrets.py プロジェクト: honghuac/custodia
 def _int_get_key(self, trail, request, response):
     try:
         name = '/'.join(trail)
         handler = self._parse_query(request, name)
     except Exception as e:
         raise HTTPError(406, str(e))
     key = self._db_key(trail)
     try:
         output = self.root.store.get(key)
         if output is None:
             raise HTTPError(404)
         elif len(output) == 0:
             raise HTTPError(406)
         self._format_reply(request, response, handler, output)
     except CSStoreDenied:
         self.logger.exception(
             "Get: Permission to perform this operation was denied")
         raise HTTPError(403)
     except CSStoreError:
         self.logger.exception('Get: Internal server error')
         raise HTTPError(500)
     except CSStoreUnsupported:
         self.logger.exception('Get: Unsupported operation')
         raise HTTPError(501)
コード例 #20
0
ファイル: forwarder.py プロジェクト: honghuac/custodia
 def _request(self, cmd, request, response, path, **kwargs):
     if self.uuid in request['headers'].get('X-LOOP-CUSTODIA', ''):
         raise HTTPError(502, "Loop detected")
     reply = cmd(path, **kwargs)
     self._response(reply, response)
コード例 #21
0
ファイル: forwarder.py プロジェクト: honghuac/custodia
 def _response(self, reply, response):
     if reply.status_code < 200 or reply.status_code > 299:
         raise HTTPError(reply.status_code)
     response['code'] = reply.status_code
     if reply.content:
         response['output'] = reply.content
コード例 #22
0
ファイル: test_secrets.py プロジェクト: nkinder/custodia
 def check_authz(self, req):
     req['client_id'] = 'test'
     req['path'] = '/'.join([''] + req.get('trail', []))
     if self.authz.handle(req) is False:
         raise HTTPError(403)
コード例 #23
0
    def pipeline(self, config, request):
        """
        The pipeline() function handles authentication and invocation of
        the correct consumer based on the server configuration, that is
        provided at initialization time.

        When authentication is performed all the authenticators are
        executed. If any returns False, authentication fails and a 403
        error is raised. If none of them positively succeeds and they all
        return None then also authentication fails and a 403 error is
        raised. Authentication plugins can add attributes to the request
        object for use of authorization or other plugins.

        When authorization is performed and positive result will cause the
        operation to be accepted and any negative result will cause it to
        fail. If no authorization plugin returns a positive result a 403
        error is returned.

        Once authentication and authorization are successful the pipeline
        will parse the path component and find the consumer plugin that
        handles the provided path walking up the path component by
        component until a consumer is found.

        Paths are walked up from the leaf to the root, so if two consumers
        hang on the same tree, the one closer to the leaf will be used. If
        there is a trailing path when the conumer is selected then it will
        be stored in the request dicstionary named 'trail'. The 'trail' is
        an ordered list of the path components below the consumer entry
        point.
        """
        path_chain = request['path_chain']
        if not path_chain or path_chain[0] != '':
            # no path or not an absolute path
            raise HTTPError(400)

        # auth framework here
        authers = config.get('authenticators')
        if authers is None:
            raise HTTPError(403)
        valid_once = False
        for auth in authers:
            valid = authers[auth].handle(request)
            if valid is False:
                raise HTTPError(403)
            elif valid is True:
                valid_once = True
        if valid_once is not True:
            self.server.auditlog.svc_access(self.__class__.__name__,
                                            log.AUDIT_SVC_AUTH_FAIL,
                                            request['client_id'], 'No auth')
            raise HTTPError(403)

        # auhz framework here
        authzers = config.get('authorizers')
        if authzers is None:
            raise HTTPError(403)
        authz_ok = None
        for authz in authzers:
            valid = authzers[authz].handle(request)
            if valid is True:
                authz_ok = True
            elif valid is False:
                authz_ok = False
                break
        if authz_ok is not True:
            self.server.auditlog.svc_access(self.__class__.__name__,
                                            log.AUDIT_SVC_AUTHZ_FAIL,
                                            request['client_id'], path_chain)
            raise HTTPError(403)

        # Select consumer
        trail = []
        while path_chain:
            if path_chain in config['consumers']:
                con = config['consumers'][path_chain]
                if len(trail) != 0:
                    request['trail'] = trail
                return con.handle(request)
            trail.insert(0, path_chain[-1])
            path_chain = path_chain[:-1]

        raise HTTPError(404)
コード例 #24
0
    def handle_one_request(self):
        if self.request.family == socket.AF_UNIX:
            # Set a fake client address to make log functions happy
            self.client_address = ['127.0.0.1', 0]
        try:
            if not self.server.config:
                self.close_connection = 1
                return
            self.raw_requestline = self.rfile.readline(65537)
            if not self.raw_requestline:
                self.close_connection = 1
                return
            if len(self.raw_requestline) > 65536:
                self.requestline = ''
                self.request_version = ''
                self.command = ''
                self.send_error(414)
                self.wfile.flush()
                return
            if not self.parse_request():
                self.close_connection = 1
                return
            try:
                self.parse_body()
            except HTTPError as e:
                self.send_error(e.code, e.mesg)
                self.wfile.flush()
                return
            request = {
                'creds': self.peer_creds,
                'client_cert': self.peer_cert,
                'client_id': self.peer_info,
                'command': self.command,
                'path': self.path,
                'path_chain': self.path_chain,
                'query': self.query,
                'url': self.url,
                'version': self.request_version,
                'headers': self.headers,
                'body': self.body
            }
            logger.debug(
                "REQUEST: %s %s, query: %r, cred: %r, client_id: %s, "
                "headers: %r, body: %r", request['command'],
                request['path_chain'],
                request['query'], request['creds'], request['client_id'],
                dict(request['headers']), request['body'])
            try:
                response = self.pipeline(self.server.config, request)
                if response is None:
                    raise HTTPError(500)
            except HTTPError as e:
                self.send_error(e.code, e.mesg)
                self.wfile.flush()
                return
            except socket.timeout as e:
                self.log_error("Request timed out: %r", e)
                self.close_connection = 1
                return
            except Exception as e:  # pylint: disable=broad-except
                self.log_error("Handler failed: %r", e, exc_info=True)
                self.send_error(500)
                self.wfile.flush()
                return

            self.send_response(response.get('code', 200))
            for header, value in six.iteritems(response.get('headers', {})):
                self.send_header(header, value)
            self.end_headers()

            output = response.get('output', None)
            if hasattr(output, 'read'):
                shutil.copyfileobj(output, self.wfile)
                output.close()
            elif output is not None:
                self.wfile.write(output)
            else:
                self.close_connection = 1
            self.wfile.flush()
            return
        except socket.timeout as e:
            self.log_error("Request timed out: %r", e)
            self.close_connection = 1
            return
コード例 #25
0
 def _db_key(self, trail):
     if len(trail) < 2:
         raise HTTPError(403)
     return os.path.join('keys', *trail)
コード例 #26
0
ファイル: secrets.py プロジェクト: honghuac/custodia
 def _parse_body(self, request, name):
     body = request.get('body')
     if body is None:
         raise HTTPError(400)
     value = json.loads(bytes(body).decode('utf-8'))
     return self._parse(request, value, name)
コード例 #27
0
ファイル: secrets.py プロジェクト: honghuac/custodia
 def PUT(self, request, response):
     trail = request.get('trail', [])
     if len(trail) == 0 or trail[-1] == '':
         raise HTTPError(405)
     else:
         self._set_key(trail, request, response)
コード例 #28
0
ファイル: secrets.py プロジェクト: honghuac/custodia
 def POST(self, request, response):
     trail = request.get('trail', [])
     if len(trail) > 0 and trail[-1] == '':
         self._create(trail, request, response)
     else:
         raise HTTPError(405)