Example #1
0
    def __call__(self, env, start_response):
        """
        这是 proxy server 的入口,上层 middleware 将参数传到这里进入 proxy server 的处理流程。
+       最终返回的时候调用的是 swift.common.swob.Response。
+       在 Response 里会调用 start_response 函数(返回 head),并返回(body)。

        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        try:
            if self.memcache is None:
                self.memcache = cache_from_env(env, True)
            req = self.update_request(Request(env))
            # 下列返回的值中,self.handle_request(req)为一个Response类的实例。
            # Response类包含方法 __call__(evn,start_response)
            return self.handle_request(req)(env, start_response)
        except UnicodeError:
            err = HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')
            return err(env, start_response)
        except (Exception, Timeout):
            start_response('500 Server Error',
                           [('Content-Type', 'text/plain')])
            return ['Internal server error.\n']
Example #2
0
File: mac.py Project: hbhdytf/mac2
 def __init__(self, path, req):
     # Database defination
     #self.conn = MySQLdb.connect(host="127.0.0.1", user="******", passwd='root', db="auth", charset="utf8")
     #self.cur = self.conn.cursor()
     self.mc_meta = cache_from_env(req.environ)
     obj = self.get_conobj_from_path(path)
     #obj = self.get_objname_from_path(path)
     if self.mc_meta.get(path):
         self.object_id, self.object_name, self.parent_secl_id, self.seclevel, self.path, self.response = self.mc_meta.get(path).split(',')
     else:
         meta = self.get_metadata_from_objname(obj)
         if meta:
             self.object_id = meta['object_id']
             self.object_name = meta['object_name'].encode("utf8")
             self.parent_secl_id = meta['parent_secl_id']
             self.seclevel = meta['obj_seclevel']
             self.author = meta['author'].encode("utf8") if meta['author'] else None
             self.path = meta['path'].encode("utf8")
             self.subject = meta['subject'].encode("utf8") if meta['subject'] else None
             self.description = meta['description'].encode("utf8") if meta['description'] else None
             self.source = meta['source'].encode("utf8") if meta['source'] else None
             self.response = 'True'
             self.mc_meta.set(self.path, (('%s,%s,%s,%s,%s,%s') % (self.object_id, self.object_name, self.parent_secl_id, self.seclevel, self.path, self.response)))
         elif not self.response:
             self.response = ['Forbidden']
Example #3
0
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        try:
            if self.memcache is None:
                self.memcache = cache_from_env(env)
            # Remove any x-backend-* headers since those are reserved for use
            # by backends communicating with each other; no end user should be
            # able to send those into the cluster.
            for key in list(k for k in env if k.startswith('HTTP_X_BACKEND_')):
                del env[key]
            req = self.update_request(Request(env))
            return self.handle_request(req)(env, start_response)
        except UnicodeError:
            err = HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')
            return err(env, start_response)
        except (Exception, Timeout):
            start_response('500 Server Error',
                           [('Content-Type', 'text/plain')])
            return ['Internal server error.\n']
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        try:
            if self.memcache is None:
                self.memcache = cache_from_env(env, True)

            #更新headers的x-auth-token部分
            req = self.update_request(Request(env))

            #根据path的不同请求返回不同的controller
            #最终会调用swob.Response.__call__方法处理这个wsig
            return self.handle_request(req)(env, start_response)
        except UnicodeError:
            err = HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')
            return err(env, start_response)
        except (Exception, Timeout):
            start_response('500 Server Error',
                           [('Content-Type', 'text/plain')])
            return ['Internal server error.\n']
Example #5
0
    def __init__(self, request, conf, app, logger):
        super(VertigoProxyHandler, self).__init__(request, conf, app, logger)

        self.mc_container = self.conf["mc_container"]
        self.memcache = None
        self.request.headers['mc-enabled'] = True
        self.memcache = cache_from_env(self.request.environ)
Example #6
0
File: server.py Project: LJ-hust/HS
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        #try:
        #    if self.memcache is None:
        #        self.memcache = cache_from_env(env, True)
        #    req = self.update_request(Request(env))
        #    if req.headers['Stop']:
        #        res = HTTPOk(request=req,body='')
        #        return res(env, start_response)
        #except:
        #    pass
        try:
            if self.memcache is None:
                self.memcache = cache_from_env(env, True)
            req = self.update_request(Request(env))
            return self.handle_request(req)(env, start_response)
        except UnicodeError:
            err = HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')
            return err(env, start_response)
        except (Exception, Timeout):
            start_response('500 Server Error',
                           [('Content-Type', 'text/plain')])
            return ['Internal server error.\n']
Example #7
0
def get_container_info(env, app, swift_source=None):
    """
    Get the info structure for a container, based on env and app.
    This is useful to middlewares.
    """
    cache = cache_from_env(env)
    if not cache:
        return None
    (version, account, container, obj) = \
        split_path(env['PATH_INFO'], 2, 4, True)
    cache_key = get_container_memcache_key(account, container)
    # Use a unique environment cache key per container.  If you copy this env
    # to make a new request, it won't accidentally reuse the old container info
    env_key = 'swift.%s' % cache_key
    if env_key not in env:
        container_info = cache.get(cache_key)
        if not container_info:
            resp = make_pre_authed_request(
                env, 'HEAD', '/%s/%s/%s' % (version, account, container),
                swift_source=swift_source,
            ).get_response(app)
            container_info = headers_to_container_info(
                resp.headers, resp.status_int)
        env[env_key] = container_info
    return env[env_key]
Example #8
0
    def _get_container_info(self, env):
        """
        Retrieves x-container-meta-web-index, x-container-meta-web-error,
        x-container-meta-web-listings, and x-container-meta-web-listings-css
        from memcache or from the cluster and stores the result in memcache and
        in self._index, self._error, self._listings, and self._listings_css.

        :param env: The WSGI environment dict.
        """
        self._index = self._error = self._listings = self._listings_css = None
        memcache_client = cache_from_env(env)
        if memcache_client:
            memcache_key = "/staticweb/%s/%s/%s" % (self.version, self.account, self.container)
            cached_data = memcache_client.get(memcache_key)
            if cached_data:
                (self._index, self._error, self._listings, self._listings_css) = cached_data
                return
        resp = make_pre_authed_request(
            env, "HEAD", "/%s/%s/%s" % (self.version, self.account, self.container), agent=self.agent
        ).get_response(self.app)
        if is_success(resp.status_int):
            self._index = resp.headers.get("x-container-meta-web-index", "").strip()
            self._error = resp.headers.get("x-container-meta-web-error", "").strip()
            self._listings = resp.headers.get("x-container-meta-web-listings", "").strip()
            self._listings_css = resp.headers.get("x-container-meta-web-listings-css", "").strip()
            if memcache_client:
                memcache_client.set(
                    memcache_key,
                    (self._index, self._error, self._listings, self._listings_css),
                    timeout=self.cache_timeout,
                )
Example #9
0
 def __call__(self, env, start_response):
     if self.enable_caching:
         self.memcache = cache_from_env(env)
     else:
         self.memcache = None
     start_time = time.time()
     req = Request(env)
     self.logger.txn_id = req.headers.get('x-trans-id', None)
     if not check_utf8(req.path_info):
         res = HTTPPreconditionFailed(body='Invalid UTF8')
     else:
         try:
             if hasattr(self, req.method):
                 res = getattr(self, req.method)(req)
             else:
                 res = HTTPMethodNotAllowed()
         except Exception:
             self.logger.exception(_('ERROR __call__ error with %(method)s'
                 ' %(path)s '), {'method': req.method, 'path': req.path})
             res = HTTPInternalServerError(body=traceback.format_exc())
     trans_time = '%.4f' % (time.time() - start_time)
     log_message = '%s - - [%s] "%s %s" %s %s "%s" "%s" "%s" %s' % (
         req.remote_addr,
         time.strftime('%d/%b/%Y:%H:%M:%S +0000',
                       time.gmtime()),
         req.method, req.path,
         res.status.split()[0], res.content_length or '-',
         req.headers.get('x-trans-id', '-'),
         req.referer or '-', req.user_agent or '-',
         trans_time)
     if req.method.upper() == 'REPLICATE':
         self.logger.debug(log_message)
     else:
         self.logger.info(log_message)
     return res(env, start_response)
Example #10
0
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.
        
        WSGI的入口点.
        一个server在PasteDeplot中, 就是一个App, 并调用类的__call__方法.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        try:
            if self.memcache is None:
                self.memcache = cache_from_env(env)
            req = self.update_request(Request(env))
            
            # 开始处理请求
            return self.handle_request(req)(env, start_response)
        except UnicodeError:
            err = HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')
            return err(env, start_response)
        except (Exception, Timeout):
            start_response('500 Server Error',
                           [('Content-Type', 'text/plain')])
            return ['Internal server error.\n']
Example #11
0
    def __call__(self, env, start_response):
        """
        Main hook into the WSGI paste.deploy filter/app pipeline.

        :param env: The WSGI environment dict.
        :param start_response: The WSGI start_response hook.
        """
        env['staticweb.start_time'] = time.time()
        try:
            (self.version, self.account, self.container, self.obj) = \
                split_path(env['PATH_INFO'], 2, 4, True)
        except ValueError:
            return self.app(env, start_response)
        memcache_client = cache_from_env(env)
        if memcache_client:
            if env['REQUEST_METHOD'] in ('PUT', 'POST'):
                if not self.obj and self.container:
                    memcache_key = '/staticweb/%s/%s/%s' % \
                        (self.version, self.account, self.container)
                    memcache_client.delete(memcache_key)
                return self.app(env, start_response)
        if (env['REQUEST_METHOD'] not in ('HEAD', 'GET') or
            (env.get('REMOTE_USER') and
             env.get('HTTP_X_WEB_MODE', 'f').lower() not in TRUE_VALUES) or
            (not env.get('REMOTE_USER') and
             env.get('HTTP_X_WEB_MODE', 't').lower() not in TRUE_VALUES)):
            return self.app(env, start_response)
        if self.obj:
            return self._handle_object(env, start_response)
        elif self.container:
            return self._handle_container(env, start_response)
        return self.app(env, start_response)
Example #12
0
    def _get_details(self, req, access_key):
        """Get access key details.

        :return: (secret_key, account) as tuple or (None, None) if not found.
        """
        memcache_client = cache_from_env(req.environ)
        if memcache_client:
            memcache_key = MEMCACHE_KEY_FORMAT % (self.reseller_prefix,
                                                  access_key)
            data = memcache_client.get(memcache_key)
            if data:
                return data[0], data[1]

        path = quote(self.akd_container_url + access_key)
        resp = make_pre_authed_request(req.environ, 'GET',
                                       path).get_response(self.app)
        if resp.status_int // 100 == 2:
            data = json.loads(resp.body)
            secret_key, account = data['secret_key'], data['account']
            if memcache_client:
                memcache_client.set(memcache_key, (secret_key, account),
                                    time=self.cache_time)
            return secret_key, account
        elif resp.status_int // 100 == 4:
            return None, None
        else:
            raise Exception('Could not GET access key details: {} {}'.format(
                path, resp.status_int))
Example #13
0
def get_account_info(env, app, swift_source=None):
    """
    Get the info structure for an account, based on env and app.
    This is useful to middlewares.
    Note: This call bypasses auth. Success does not imply that the
          request has authorization to the account_info.
    """
    cache = cache_from_env(env)
    if not cache:
        return None
    (version, account, container, _) = \
        split_path(env['PATH_INFO'], 2, 4, True)
    cache_key = get_account_memcache_key(account)
    # Use a unique environment cache key per account.  If you copy this env
    # to make a new request, it won't accidentally reuse the old account info
    env_key = 'swift.%s' % cache_key
    if env_key not in env:
        account_info = cache.get(cache_key)
        if not account_info:
            resp = make_pre_authed_request(
                env,
                'HEAD',
                '/%s/%s' % (version, account),
                swift_source=swift_source,
            ).get_response(app)
            account_info = headers_to_account_info(resp.headers,
                                                   resp.status_int)
        env[env_key] = account_info
    return env[env_key]
Example #14
0
    def __call__(self, env, start_response):
        """
        Main hook into the WSGI paste.deploy filter/app pipeline.

        :param env: The WSGI environment dict.
        :param start_response: The WSGI start_response hook.
        """
        env['staticweb.start_time'] = time.time()
        try:
            (self.version, self.account, self.container, self.obj) = \
                split_path(env['PATH_INFO'], 2, 4, True)
        except ValueError:
            return self.app(env, start_response)
        memcache_client = cache_from_env(env)
        if memcache_client:
            if env['REQUEST_METHOD'] in ('PUT', 'POST'):
                if not self.obj and self.container:
                    memcache_key = '/staticweb/%s/%s/%s' % \
                        (self.version, self.account, self.container)
                    memcache_client.delete(memcache_key)
                return self.app(env, start_response)
        if (env['REQUEST_METHOD'] not in ('HEAD', 'GET') or
            (env.get('REMOTE_USER')
             and env.get('HTTP_X_WEB_MODE', 'f').lower() not in TRUE_VALUES) or
            (not env.get('REMOTE_USER')
             and env.get('HTTP_X_WEB_MODE', 't').lower() not in TRUE_VALUES)):
            return self.app(env, start_response)
        if self.obj:
            return self._handle_object(env, start_response)
        elif self.container:
            return self._handle_container(env, start_response)
        return self.app(env, start_response)
Example #15
0
    def __call__(self, env, start_response):
        """
        Main hook into the WSGI paste.deploy filter/app pipeline.

        :param env: The WSGI environment dict.
        :param start_response: The WSGI start_response hook.
        """
        env['staticweb.start_time'] = time.time()
        try:
            (version, account, container, obj) = \
                split_path(env['PATH_INFO'], 2, 4, True)
        except ValueError:
            return self.app(env, start_response)
        if env['REQUEST_METHOD'] in ('PUT', 'POST') and container and not obj:
            memcache_client = cache_from_env(env)
            if memcache_client:
                memcache_key = \
                    '/staticweb/%s/%s/%s' % (version, account, container)
                memcache_client.delete(memcache_key)
            return self.app(env, start_response)
        if env['REQUEST_METHOD'] not in ('HEAD', 'GET'):
            return self.app(env, start_response)
        if env.get('REMOTE_USER') and \
                not config_true_value(env.get('HTTP_X_WEB_MODE', 'f')):
            return self.app(env, start_response)
        if not container:
            return self.app(env, start_response)
        context = _StaticWebContext(self, version, account, container, obj)
        if obj:
            return context.handle_object(env, start_response)
        return context.handle_container(env, start_response)
Example #16
0
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        req = Request(env)
        if self.memcache_client is None:
            # 在pipline中memcache middleware应该在前面
            # memcache为每一个请求建立一个memcache client,并把这个client放入env中
            self.memcache_client = cache_from_env(env)
        if not self.memcache_client:
            self.logger.warning(
                _('Warning: Cannot ratelimit without a memcached client'))
            return self.app(env, start_response)
        try:
            version, account, container, obj = req.split_path(1, 4, True)
        except ValueError:
            return self.app(env, start_response)
        ratelimit_resp = self.handle_ratelimit(req, account, container, obj)
        # ratelimit_resp 为 None 或者 Response 对象,Response 对象是可调用的。
        # ratelimit 操作正常执行,或者不需要执行,返回 None,接着向下调用。
        if ratelimit_resp is None:
            return self.app(env, start_response)
        else:
            # ratelimit 执行失败,或者需要返回错误信息,返回 Response 对象。
            # 不用向下调用,直接返回。
            return ratelimit_resp(env, start_response)
    def __call__(self, env, start_response):
        """
        Main hook into the WSGI paste.deploy filter/app pipeline.

        :param env: The WSGI environment dict.
        :param start_response: The WSGI start_response hook.
        """
        try:
            (version, account, container, obj) = \
                split_path(env['PATH_INFO'], 2, 4, True)
        except ValueError:
            return self.app(env, start_response)

        if not self._cache:
            self._cache = cache_from_env(env)

        # Don't handle non-GET requests.
        if env['REQUEST_METHOD'] not in ('HEAD', 'GET'):

            # flush cache if we expect the container metadata being changed.
            if container and not obj and self._cache:
                memcache_key = 'better_static/%s/%s' % (account, container)
                self._cache.delete(memcache_key)

            return self.app(env, start_response)

        # If non-html was explicitly requested, don't bother trying to format
        # the html
        params = urlparse.parse_qs(env.get('QUERY_STRING', ''))

        if 'format' in params and params['format'] != ['html']:
            return self.app(env, start_response)

        context = Context(self, env, account, container, obj)
        return context(env, start_response)
Example #18
0
    def handle_quota_object(self, env, start_response, version, account,
                            container, obj):
        """ Handle quota of container usage and object count. """
        memcache_client = cache_from_env(env)
        object_size = int(env.get('CONTENT_LENGTH') or 0)
        container_count, quota_level = self._get_account_meta(
            env, version, account, memcache_client)
        try:
            container_usage_quota = self.container_usage[quota_level]
            object_count_quota = self.object_count[quota_level]
        except Exception:
            self.logger.warn('Invalid quota_leve %s/%s quota_level[%s].' % (
                account, container, quota_level))
            container_usage_quota = None
            object_count_quota = None
        container_usage, object_count = self._get_container_meta(
            env, version, account, container, memcache_client)
        if container_usage_quota and container_usage >= container_usage_quota:
            self.logger.notice("Container usage over quota, "
                               "request[PUT %s/%s/%s], container_usage[%s] "
                               "object_size[%s] quota[%s]" % (
                                   account, container, obj, container_usage,
                                   object_size, container_usage_quota))
            return HTTPForbidden(body="The usage of container is over quota")(
                env, start_response)
        elif container_usage_quota and (container_usage + object_size >
                                        container_usage_quota):
            self.logger.notice("Container usage over quota, "
                               "request[PUT %s/%s/%s], container_usage[%s] "
                               "object_size[%s] quota[%s]" % (
                                   account, container, obj, container_usage,
                                   object_size, container_usage_quota))
            return HTTPForbidden(body="The usage of container is over quota")(
                env, start_response)
        elif object_count_quota and object_count + 1 > object_count_quota:
            self.logger.notice("Object count over quota, request[PUT %s/%s/%s],"
                               "object_count[%s] quota[%s]" % (
                                   account, container, obj, object_count + 1,
                                   object_count_quota))
            return HTTPForbidden(body="The count of object is over quota")(
                env, start_response)
        elif self.precise_mode and memcache_client:
            res = [None, None, None]
            result_code = None

            def _start_response(response_status, response_headers,
                                exc_info=None):
                res[0] = response_status
                res[1] = response_headers
                res[2] = exc_info

            resp = self.app(env, _start_response)
            result_code = self._get_status_int(res[0])
            if is_success(result_code):
                memcache_client.delete(
                    get_container_memcache_key(account, container))
            start_response(res[0], res[1], res[2])
            return resp
        else:
            return self.app(env, start_response)
Example #19
0
def get_account_info(env, app, swift_source=None):
    """
    Get the info structure for an account, based on env and app.
    This is useful to middlewares.
    Note: This call bypasses auth. Success does not imply that the
          request has authorization to the account_info.
    """
    cache = cache_from_env(env)
    if not cache:
        return None
    (version, account, _junk, _junk) = \
        split_path(env['PATH_INFO'], 2, 4, True)
    cache_key = get_account_memcache_key(account)
    # Use a unique environment cache key per account.  If you copy this env
    # to make a new request, it won't accidentally reuse the old account info
    env_key = 'swift.%s' % cache_key
    if env_key not in env:
        account_info = cache.get(cache_key)
        if not account_info:
            resp = make_pre_authed_request(
                env, 'HEAD', '/%s/%s' % (version, account),
                swift_source=swift_source,
            ).get_response(app)
            account_info = headers_to_account_info(
                resp.headers, resp.status_int)
        env[env_key] = account_info
    return env[env_key]
Example #20
0
    def handle_delete(self, env, start_response, version, account, container,
                      obj):
        """ Handle delete request. """
        memcache_client = cache_from_env(env)
        if not memcache_client:
            return self.app(env, start_response)

        res = [None, None, None]
        result_code = None

        def _start_response(response_status, response_headers, exc_info=None):
            res[0] = response_status
            res[1] = response_headers
            res[2] = exc_info

        resp = self.app(env, _start_response)
        result_code = self._get_status_int(res[0])
        try:
            if is_success(result_code):
                if obj:
                    memcache_client.delete(
                        get_container_memcache_key(account, container))
                else:
                    memcache_client.delete(get_account_memcache_key(account))
        except Exception, err:
            self.logger.error(
                'Error in [Quota] delete cache: %s' % (err.message))
Example #21
0
    def __call__(self, env, start_response):
        """
        Main hook into the WSGI paste.deploy filter/app pipeline.

        :param env: The WSGI environment dict.
        :param start_response: The WSGI start_response hook.
        """
        env["staticweb.start_time"] = time.time()
        try:
            (version, account, container, obj) = split_path(env["PATH_INFO"], 2, 4, True)
        except ValueError:
            return self.app(env, start_response)
        if env["REQUEST_METHOD"] in ("PUT", "POST") and container and not obj:
            memcache_client = cache_from_env(env)
            if memcache_client:
                memcache_key = "/staticweb/%s/%s/%s" % (version, account, container)
                memcache_client.delete(memcache_key)
            return self.app(env, start_response)
        if env["REQUEST_METHOD"] not in ("HEAD", "GET"):
            return self.app(env, start_response)
        if env.get("REMOTE_USER") and env.get("HTTP_X_WEB_MODE", "f").lower() not in TRUE_VALUES:
            return self.app(env, start_response)
        if not container:
            return self.app(env, start_response)
        context = _StaticWebContext(self, version, account, container, obj)
        if obj:
            return context.handle_object(env, start_response)
        return context.handle_container(env, start_response)
Example #22
0
File: mac.py Project: hbhdytf/mac2
 def __init__(self, token=None, username=None, request=None):
     # Database defination
     self.mc_user = cache_from_env(request.environ)
     # Initialze user information by token or usernames
     if token is None and username is None:
         self.denied_response('token')
     # TO DO: get user from db (web update user, not read from cache , temparily )
     if self.mc_user.get(username) and False:
         self.tu_id, self.username, self.seclevel, self.login_name, self.response = self.mc_user.get(username).split(',')
     else:
         if token:
             info = self.get_user_info_from_token(token=token)
         elif username:
             info = self.get_user_info_from_db(user_name=username)
         if info:
             # set each info
             self.tu_id = info['tu_id']
             self.username = info['username']
             self.login_name = info['login_name']
             self.seclevel = info['seclevel']
             self.email = info['email']
             self.password = info['password']
             self.mobile = info['mobile']
             self.response = 'True'
             self.mc_user.set(self.username, (('%s,%s,%s,%s,%s')%(self.tu_id, self.username, self.seclevel,self.login_name,self.response)))
         elif not self.response:
             self.response = ['Forbidden']
Example #23
0
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        try:
            if self.memcache is None:
                self.memcache = cache_from_env(env)
            # Remove any x-backend-* headers since those are reserved for use
            # by backends communicating with each other; no end user should be
            # able to send those into the cluster.
            for key in list(k for k in env if k.startswith('HTTP_X_BACKEND_')):
                del env[key]
            req = self.update_request(Request(env))
            return self.handle_request(req)(env, start_response)
        except UnicodeError:
            err = HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')
            return err(env, start_response)
        except (Exception, Timeout):
            start_response('500 Server Error',
                           [('Content-Type', 'text/plain')])
            return ['Internal server error.\n']
Example #24
0
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
	print '**** in __call__ of proxy server start *********'
	print 'env',env
	print 'start_response',start_response
        try:
            if self.memcache is None:
                self.memcache = cache_from_env(env, True)
            req = self.update_request(Request(env))
	    print '**** in __call__ of proxy server end by returning self.handle_request(req)(env, start_response) *********'
            return self.handle_request(req)(env, start_response)
        except UnicodeError:
            err = HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')
            return err(env, start_response)
        except (Exception, Timeout):
            start_response('500 Server Error',
                           [('Content-Type', 'text/plain')])
            return ['Internal server error.\n']
Example #25
0
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        req = Request(env)
        if self.memcache_client is None:
            self.memcache_client = cache_from_env(env)
        if not self.memcache_client:
            self.logger.warning(
                _('Warning: Cannot ratelimit without a memcached client'))
            return self.app(env, start_response)
        try:
            version, account, container, obj = req.split_path(1, 4, True)
        except ValueError:
            return self.app(env, start_response)
        if not valid_api_version(version):
            return self.app(env, start_response)
        ratelimit_resp = self.handle_ratelimit(req, account, container, obj)
        if ratelimit_resp is None:
            return self.app(env, start_response)
        else:
            return ratelimit_resp(env, start_response)
Example #26
0
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        try:
            if self.memcache is None:
                self.memcache = cache_from_env(env)
            req = self.update_request(Request(env))
            return self.handle_request(req)(env, start_response)
        except UnicodeError:
            err = HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')
            return err(env, start_response)
        except (Exception, Timeout):
            # P3
            fp = open("/tmp/dump","a")
            fp.write("====== status 500 in __call__\n")
            fp.write(traceback.format_exc())
            fp.write("====== done\n")
            fp.close()
            start_response('500 Server Error',
                           [('Content-Type', 'text/plain')])
            return ['Internal server error.\n']
Example #27
0
 def __call__(self, env, start_response):
     if not self.storage_domain:
         return self.app(env, start_response)
     given_domain = env['HTTP_HOST']
     port = ''
     if ':' in given_domain:
         given_domain, port = given_domain.rsplit(':', 1)
     if given_domain == self.storage_domain[1:]:  # strip initial '.'
         return self.app(env, start_response)
     a_domain = given_domain
     if not a_domain.endswith(self.storage_domain):
         if self.memcache is None:
             self.memcache = cache_from_env(env)
         error = True
         for tries in xrange(self.lookup_depth):
             found_domain = None
             if self.memcache:
                 memcache_key = ''.join(['cname-', a_domain])
                 found_domain = self.memcache.get(memcache_key)
             if not found_domain:
                 ttl, found_domain = lookup_cname(a_domain)
                 if self.memcache:
                     memcache_key = ''.join(['cname-', given_domain])
                     self.memcache.set(memcache_key, found_domain,
                                       timeout=ttl)
             if found_domain is None or found_domain == a_domain:
                 # no CNAME records or we're at the last lookup
                 error = True
                 found_domain = None
                 break
             elif found_domain.endswith(self.storage_domain):
                 # Found it!
                 self.logger.info(
                     _('Mapped %(given_domain)s to %(found_domain)s') %
                     {'given_domain': given_domain,
                      'found_domain': found_domain})
                 if port:
                     env['HTTP_HOST'] = ':'.join([found_domain, port])
                 else:
                     env['HTTP_HOST'] = found_domain
                 error = False
                 break
             else:
                 # try one more deep in the chain
                 self.logger.debug(
                     _('Following CNAME chain for  '
                       '%(given_domain)s to %(found_domain)s') %
                     {'given_domain': given_domain,
                      'found_domain': found_domain})
                 a_domain = found_domain
         if error:
             if found_domain:
                 msg = 'CNAME lookup failed after %d tries' % \
                     self.lookup_depth
             else:
                 msg = 'CNAME lookup failed to resolve to a valid domain'
             resp = HTTPBadRequest(request=Request(env), body=msg,
                                   content_type='text/plain')
             return resp(env, start_response)
     return self.app(env, start_response)
Example #28
0
File: mac.py Project: hbhdytf/mac2
 def __init__(self, token=None, username=None, request=None):
     # Database defination
     self.conn = MySQLdb.connect(host="127.0.0.1", user="******", passwd="root", db="auth", charset="utf8")
     self.cur = self.conn.cursor()
     self.mc_user = cache_from_env(request.environ)
     # Initialze user information by token or usernames
     if token is None and username is None:
         self.denied_response("token")
     # TO DO: get user from db (web update user, not read from cache , temparily )
     if self.mc_user.get(username) and False:
         self.tu_id, self.username, self.seclevel, self.login_name, self.response = self.mc_user.get(username).split(
             ","
         )
     else:
         if token:
             info = self.get_user_info_from_token(token=token)
         elif username:
             info = self.get_user_info_from_db(user_name=username)
         if info:
             # set each info
             self.tu_id = info["tu_id"]
             self.username = info["username"]
             self.login_name = info["login_name"]
             self.seclevel = info["seclevel"]
             self.email = info["email"]
             self.password = info["password"]
             self.mobile = info["mobile"]
             self.response = "True"
             self.mc_user.set(
                 self.username,
                 (("%s,%s,%s,%s,%s") % (self.tu_id, self.username, self.seclevel, self.login_name, self.response)),
             )
         elif not self.response:
             self.response = ["Forbidden"]
Example #29
0
 def __call__(self, env, start_response):
     if not self.storage_domain:
         return self.app(env, start_response)
     given_domain = env['HTTP_HOST']
     port = ''
     if ':' in given_domain:
         given_domain, port = given_domain.rsplit(':', 1)
     if given_domain == self.storage_domain[1:]:  # strip initial '.'
         return self.app(env, start_response)
     a_domain = given_domain
     if not a_domain.endswith(self.storage_domain):
         if self.memcache is None:
             self.memcache = cache_from_env(env)
         error = True
         for tries in xrange(self.lookup_depth):
             found_domain = None
             if self.memcache:
                 memcache_key = ''.join(['cname-', a_domain])
                 found_domain = self.memcache.get(memcache_key)
             if not found_domain:
                 ttl, found_domain = lookup_cname(a_domain)
                 if self.memcache:
                     memcache_key = ''.join(['cname-', given_domain])
                     self.memcache.set(memcache_key, found_domain,
                                       timeout=ttl)
             if found_domain is None or found_domain == a_domain:
                 # no CNAME records or we're at the last lookup
                 error = True
                 found_domain = None
                 break
             elif found_domain.endswith(self.storage_domain):
                 # Found it!
                 self.logger.info(
                     _('Mapped %(given_domain)s to %(found_domain)s') %
                     {'given_domain': given_domain,
                      'found_domain': found_domain})
                 if port:
                     env['HTTP_HOST'] = ':'.join([found_domain, port])
                 else:
                     env['HTTP_HOST'] = found_domain
                 error = False
                 break
             else:
                 # try one more deep in the chain
                 self.logger.debug(_('Following CNAME chain for  ' \
                         '%(given_domain)s to %(found_domain)s') %
                         {'given_domain': given_domain,
                          'found_domain': found_domain})
                 a_domain = found_domain
         if error:
             if found_domain:
                 msg = 'CNAME lookup failed after %d tries' % \
                         self.lookup_depth
             else:
                 msg = 'CNAME lookup failed to resolve to a valid domain'
             resp = HTTPBadRequest(request=Request(env), body=msg,
                                   content_type='text/plain')
             return resp(env, start_response)
     return self.app(env, start_response)
 def __call__(self, env, start_response):
     if not self.storage_domain:
         return self.app(env, start_response)
     if "HTTP_HOST" in env:
         given_domain = env["HTTP_HOST"]
     else:
         given_domain = env["SERVER_NAME"]
     port = ""
     if ":" in given_domain:
         given_domain, port = given_domain.rsplit(":", 1)
     if is_ip(given_domain):
         return self.app(env, start_response)
     a_domain = given_domain
     if not self._domain_endswith_in_storage_domain(a_domain):
         if self.memcache is None:
             self.memcache = cache_from_env(env)
         error = True
         for tries in xrange(self.lookup_depth):
             found_domain = None
             if self.memcache:
                 memcache_key = "".join(["cname-", a_domain])
                 found_domain = self.memcache.get(memcache_key)
             if not found_domain:
                 ttl, found_domain = lookup_cname(a_domain)
                 if self.memcache:
                     memcache_key = "".join(["cname-", given_domain])
                     self.memcache.set(memcache_key, found_domain, time=ttl)
             if found_domain is None or found_domain == a_domain:
                 # no CNAME records or we're at the last lookup
                 error = True
                 found_domain = None
                 break
             elif self._domain_endswith_in_storage_domain(found_domain):
                 # Found it!
                 self.logger.info(
                     _("Mapped %(given_domain)s to %(found_domain)s")
                     % {"given_domain": given_domain, "found_domain": found_domain}
                 )
                 if port:
                     env["HTTP_HOST"] = ":".join([found_domain, port])
                 else:
                     env["HTTP_HOST"] = found_domain
                 error = False
                 break
             else:
                 # try one more deep in the chain
                 self.logger.debug(
                     _("Following CNAME chain for  " "%(given_domain)s to %(found_domain)s")
                     % {"given_domain": given_domain, "found_domain": found_domain}
                 )
                 a_domain = found_domain
         if error:
             if found_domain:
                 msg = "CNAME lookup failed after %d tries" % self.lookup_depth
             else:
                 msg = "CNAME lookup failed to resolve to a valid domain"
             resp = HTTPBadRequest(request=Request(env), body=msg, content_type="text/plain")
             return resp(env, start_response)
     return self.app(env, start_response)
Example #31
0
    def __init__(self, request, conf, app, logger):
        super(VertigoProxyHandler, self).__init__(
            request, conf, app, logger)

        self.mc_container = self.conf["mc_container"]
        self.memcache = None
        self.request.headers['mc-enabled'] = True
        self.memcache = cache_from_env(self.request.environ)
    def __call__(self, environ, start_response):
        self.logger.debug('Initialise keystone middleware')

        req = Request(environ)
        token = environ.get('HTTP_X_AUTH_TOKEN',
                            environ.get('HTTP_X_STORAGE_TOKEN'))
        if not token:
            self.logger.debug('No token: exiting')
            environ['swift.authorize'] = self.denied_response
            return self.app(environ, start_response)

        self.logger.debug('Got token: %s' % (token))

        identity = None
        memcache_client = cache_from_env(environ)
        memcache_key = 'tokens/%s' % (token)
        candidate_cache = memcache_client.get(memcache_key)
        if candidate_cache:
            expires, _identity = candidate_cache
            if expires > time():
                self.logger.debug('getting identity info from memcache')
                identity = _identity

        if not identity:
            if environ.get('HTTP_AUTHORIZATION'):
                identity = self._keystone_validate_s3token(req, token)
                if 'tenant' in identity:
                    print identity
                    environ['PATH_INFO'] = '/v1/AUTH_%s' % \
                        identity['tenant'][0]
            else:
                identity = self._keystone_validate_token(token)

            if identity and memcache_client:
                expires = identity['expires']
                if expires:
                    memcache_client.set(memcache_key,
                                        (expires, identity),
                                        timeout=expires - time())
                    ts = str(datetime.fromtimestamp(expires))
                    self.logger.debug('setting memcache expiration to %s' % ts)
            else:  # if we didn't get identity it means there was an error.
                return HTTPBadRequest(request=req)

        self.logger.debug("Using identity: %r" % (identity))

        if not identity:
            #TODO: non authenticated access allow via refer
            environ['swift.authorize'] = self.denied_response
            return self.app(environ, start_response)

        self.logger.debug("Using identity: %r" % (identity))
        environ['keystone.identity'] = identity
        environ['REMOTE_USER'] = identity.get('tenant')
        environ['swift.authorize'] = self.authorize
        environ['swift.clean_acl'] = clean_acl

        return self.app(environ, start_response)
Example #33
0
    def _set_hash_data(self, env, cdn_obj_path, new_hash_data,
                       update_listings=True):
        """
        Actually sets the data in the .origin account. If not successful on
        any of the several updates this has to do, will raise a OriginDbFailure
        """
        cdn_obj_data = new_hash_data.get_json_str()
        cdn_obj_etag = md5(cdn_obj_data).hexdigest()
        # this is always a PUT because a POST needs to update the file
        cdn_obj_resp = make_pre_authed_request(
            env, 'PUT', cdn_obj_path, body=cdn_obj_data,
            headers={'Etag': cdn_obj_etag},
            agent='SwiftOrigin', swift_source='SOS').get_response(self.app)

        if cdn_obj_resp.status_int // 100 != 2:
            raise OriginDbFailure(
                'Could not PUT .hash obj in origin '
                'db: %s %s' % (cdn_obj_path, cdn_obj_resp.status_int))

        memcache_client = utils.cache_from_env(env)
        if memcache_client:
            memcache_key = self.cdn_data_memcache_key(cdn_obj_path)
            memcache_client.delete(memcache_key)

        if not update_listings:
            return

        listing_cont_path = quote('/v1/%s/%s' % (self.origin_account,
                                                 new_hash_data.account))
        resp = make_pre_authed_request(
            env, 'HEAD', listing_cont_path,
            agent='SwiftOrigin', swift_source='SOS').get_response(self.app)
        if resp.status_int == 404:
            # create new container for listings
            resp = make_pre_authed_request(
                env, 'PUT', listing_cont_path,
                agent='SwiftOrigin', swift_source='SOS').get_response(self.app)
            if resp.status_int // 100 != 2:
                raise OriginDbFailure(
                    'Could not create listing container '
                    'in origin db: %s %s' % (listing_cont_path, resp.status))

        cdn_list_path = quote('/v1/%s/%s/%s' % (
            self.origin_account, new_hash_data.account.encode('utf-8'),
            new_hash_data.container.encode('utf-8')))

        listing_content_type = new_hash_data.gen_listing_content_type()

        cdn_list_resp = make_pre_authed_request(
            env, 'PUT', cdn_list_path,
            headers={'Content-Type': listing_content_type,
                     'Content-Length': 0},
            agent='SwiftOrigin', swift_source='SOS').get_response(self.app)

        if cdn_list_resp.status_int // 100 != 2:
            raise OriginDbFailure(
                'Could not PUT/POST to cdn listing in '
                'origin db: %s %s' % (cdn_list_path, cdn_list_resp.status_int))
Example #34
0
    def origin_db_delete(self, env, req):
        """
        Handles DELETEs in the Origin database.
        This is not really a delete- it will remove the object from the
        container listing and set cdn_enabled=false and a deleted flag in the
        .hash_* obj that says that the obj is deleted. This way the container
        won't show up in the listings, HEAD to the object will return 404s but
        behind the scenes lookups to the object will be able to determine
        the account and container from a container_hash.
        """
        try:
            vsn, account, container = split_path(req.path, 3, 3)
        except ValueError:
            return HTTPBadRequest(
                'Invalid request. '
                'URI format: /<api version>/<account>/<container>')
        if self.extra_header_for_deletes and not req.headers.get(
                self.extra_header_for_deletes, 'f').lower() in TRUE_VALUES:
            # only do delete if header is set (assuming you want the header)
            return HTTPMethodNotAllowed(request=req)
        hsh = self.hash_path(account, container)
        cdn_obj_path = self.get_hsh_obj_path(hsh)

        # Remove memcache entry
        memcache_client = utils.cache_from_env(env)
        if memcache_client:
            memcache_key = self.cdn_data_memcache_key(cdn_obj_path)
            memcache_client.delete(memcache_key)

        ref_hash_data = HashData(account,
                                 container,
                                 self.default_ttl,
                                 False,
                                 False,
                                 deleted=True)
        self._set_hash_data(env,
                            cdn_obj_path,
                            ref_hash_data,
                            update_listings=False)

        cdn_list_path = quote('/v1/%s/%s/%s' %
                              (self.origin_account, account, container))
        list_resp = make_pre_authed_request(env,
                                            'DELETE',
                                            cdn_list_path,
                                            agent='SwiftOrigin',
                                            swift_source='SOS').get_response(
                                                self.app)

        if list_resp.status_int // 100 != 2 and list_resp.status_int != 404:
            raise OriginDbFailure('Could not DELETE listing path in origin '
                                  'db: %s %s' %
                                  (cdn_list_path, list_resp.status_int))

        # Return 404 if container didn't exist
        if list_resp.status_int == 404:
            return HTTPNotFound(request=req)
        return HTTPNoContent(request=req)
Example #35
0
    def __call__(self, environ, start_response):
        self.logger.debug('Initialise keystone middleware')

        req = Request(environ)
        token = environ.get('HTTP_X_AUTH_TOKEN',
                            environ.get('HTTP_X_STORAGE_TOKEN'))
        if not token:
            self.logger.debug('No token: exiting')
            environ['swift.authorize'] = self.denied_response
            return self.app(environ, start_response)

        self.logger.debug('Got token: %s' % (token))

        identity = None
        memcache_client = cache_from_env(environ)
        memcache_key = 'tokens/%s' % (token)
        candidate_cache = memcache_client.get(memcache_key)
        if candidate_cache:
            expires, _identity = candidate_cache
            if expires > time():
                self.logger.debug('getting identity info from memcache')
                identity = _identity

        if not identity:
            if environ.get('HTTP_AUTHORIZATION'):
                identity = self._keystone_validate_s3token(req, token)
                if 'tenant' in identity:
                    print identity
                    environ['PATH_INFO'] = '/v1/AUTH_%s' % \
                        identity['tenant'][0]
            else:
                identity = self._keystone_validate_token(token)

            if identity and memcache_client:
                expires = identity['expires']
                if expires:
                    memcache_client.set(memcache_key, (expires, identity),
                                        timeout=expires - time())
                    ts = str(datetime.fromtimestamp(expires))
                    self.logger.debug('setting memcache expiration to %s' % ts)
            else:  # if we didn't get identity it means there was an error.
                return HTTPBadRequest(request=req)

        self.logger.debug("Using identity: %r" % (identity))

        if not identity:
            #TODO: non authenticated access allow via refer
            environ['swift.authorize'] = self.denied_response
            return self.app(environ, start_response)

        self.logger.debug("Using identity: %r" % (identity))
        environ['keystone.identity'] = identity
        environ['REMOTE_USER'] = identity.get('tenant')
        environ['swift.authorize'] = self.authorize
        environ['swift.clean_acl'] = clean_acl

        return self.app(environ, start_response)
Example #36
0
    def __init__(self, request, conf, app, logger):
        super(VertigoProxyHandler, self).__init__(request, conf, app, logger)

        self.mc_container = self.conf["mc_container"]
        self.memcache = None
        self.request.headers['mc-enabled'] = True
        self.memcache = cache_from_env(self.request.environ)

        self.redis = redis.StrictRedis(conf['redis_host'], conf['redis_port'],
                                       conf['redis_db'])
Example #37
0
    def _get_container_info(self, env):
        """
        Retrieves x-container-meta-web-index, x-container-meta-web-error,
        x-container-meta-web-listings, x-container-meta-web-listings-css,
        and x-container-meta-web-directory-type from memcache or from the
        cluster and stores the result in memcache and in self._index,
        self._error, self._listings, self._listings_css and self._dir_type.

        :param env: The WSGI environment dict.
        """
        self._index = self._error = self._listings = self._listings_css = \
            self._dir_type = None
        memcache_client = cache_from_env(env)
        if memcache_client:
            cached_data = memcache_client.get(
                get_memcache_key(self.version, self.account, self.container))
            if cached_data:
                (self._index, self._error, self._listings, self._listings_css,
                 self._dir_type) = cached_data
                return
            else:
                cached_data = memcache_client.get(
                    get_compat_memcache_key(
                        self.version, self.account, self.container))
                if cached_data:
                    (self._index, self._error, self._listings,
                     self._listings_css) = cached_data
                    self._dir_type = ''
                    return
        resp = make_pre_authed_request(
            env, 'HEAD', '/%s/%s/%s' % (
                self.version, self.account, self.container),
            agent=self.agent, swift_source='SW').get_response(self.app)
        if is_success(resp.status_int):
            self._index = \
                resp.headers.get('x-container-meta-web-index', '').strip()
            self._error = \
                resp.headers.get('x-container-meta-web-error', '').strip()
            self._listings = \
                resp.headers.get('x-container-meta-web-listings', '').strip()
            self._listings_css = \
                resp.headers.get('x-container-meta-web-listings-css',
                                 '').strip()
            self._dir_type = \
                resp.headers.get('x-container-meta-web-directory-type',
                                 '').strip()
            if memcache_client:
                memcache_client.set(
                    get_memcache_key(
                        self.version, self.account, self.container),
                    (self._index, self._error, self._listings,
                     self._listings_css, self._dir_type),
                    time=self.cache_timeout)
    def list_containers_iter(self, *args, **kwargs):
        """ Returns a list of containers the user has access to """
        
        try:
            version, account = self.request.split_path(2, 2)
        except ValueError:
            pass

        path = "/%s/%s?format=json" % (version, account)
        
        for key in ('limit', 'marker', 'end_marker', 'prefix', 'delimiter'):
            value = self.request.params.get(key)
            if value:
                path+= '&%s=%s' % (key, value)

        if self.memcache_client is None:
            self.memcache_client = cache_from_env(self.request.environ)

        memcache_key = 'containerlist%s%s' % (path, str(self.groups))
        containers = self.memcache_client.get(memcache_key)
        if containers is not None:
            return containers
        
        req = make_pre_authed_request(self.request.environ, 'GET', path)
        resp = req.get_response(self.app)
        tmp_containers = json.loads(resp.body)
    
        # No cached result? -> ratelimit request to prevent abuse
        memcache_key_sleep = 'containerlist_sleep/%s' % self.account
        last_request_time = self.memcache_client.get(memcache_key_sleep)
        if last_request_time and len(tmp_containers) > 0:
            last_request = time.time() - last_request_time
            if last_request < self.min_sleep:
                eventlet.sleep(self.min_sleep - last_request)


        containers = []
        for container in tmp_containers:
            tmp_env = copy.copy(self.request.environ)
            container_name = container['name'].encode("utf8")
            path_info = "/%s/%s/%s" % (version, account, container_name)
            tmp_env['PATH_INFO'] = path_info
            container_info = get_container_info(tmp_env, self.app)
            acl = (container_info.get('read_acl') or '').split(',')
            if (list(set(self.groups) & set(acl))):
                containers.append((container['name'],
                                  container['count'],
                                  container['bytes'],
                                  0))

        self.memcache_client.set(memcache_key, containers, time=60)
        self.memcache_client.set(memcache_key_sleep, time.time()) 
        return containers
Example #39
0
    def get_cdn_data(self, env, cdn_obj_path):
        """
        Retrieves HashData object from memcache or by doing a GET
        of the cdn_obj_path which should be what is returned from
        get_hsh_obj_path. Will return None if the HashData is "deleted"

        :returns: HashData object or None.
        """
        memcache_client = utils.cache_from_env(env)
        memcache_key = self.cdn_data_memcache_key(cdn_obj_path)
        if memcache_client:
            cached_cdn_data = memcache_client.get(memcache_key)
            if cached_cdn_data == '404':
                return None
            if cached_cdn_data:
                try:
                    hash_data = HashData.create_from_json(cached_cdn_data)
                    if hash_data.deleted:
                        return None
                    else:
                        return hash_data
                except ValueError:
                    pass

        resp = make_pre_authed_request(env,
                                       'GET',
                                       cdn_obj_path,
                                       agent='SwiftOrigin',
                                       swift_source='SOS').get_response(
                                           self.app)
        if resp.status_int // 100 == 2:
            try:
                if memcache_client:
                    memcache_client.set(memcache_key,
                                        resp.body,
                                        serialize=False,
                                        time=MEMCACHE_TIMEOUT)

                hash_data = HashData.create_from_json(resp.body)
                if not hash_data.deleted:
                    return hash_data
            except ValueError:
                self.logger.warn('Invalid HashData json: %s' % cdn_obj_path)
        if resp.status_int == 404:
            if memcache_client:
                # only memcache for 30 secs in case adding container to swift
                memcache_client.set(memcache_key,
                                    '404',
                                    serialize=False,
                                    time=CACHE_404)

        return None
    def get_groups(self, env, token):
        """
        Get groups for the given token.

        :param env: The current WSGI environment dictionary.
        :param token: Token to validate and return a group string for.

        :returns: None if the token is invalid or a string containing a comma
                  separated list of groups the authenticated user is a member
                  of. The first group in the list is also considered a unique
                  identifier for that user.
        """
        groups = None
        memcache_client = cache_from_env(env)
        if not memcache_client:
            raise Exception('Memcache required')
        memcache_token_key = '%s/token/%s' % (self.reseller_prefix, token)
        cached_auth_data = memcache_client.get(memcache_token_key)
        if cached_auth_data:
            expires, groups = cached_auth_data
            if expires < time():
                groups = None

        if env.get('HTTP_AUTHORIZATION'):
            account_user, sign = \
                env['HTTP_AUTHORIZATION'].split(' ')[1].rsplit(':', 1)
            account, user = account_user.split(':', 1)
            h_account = md5(account).hexdigest()
            h_user = md5(user).hexdigest()
            h_account_user = h_account +':'+h_user
            if h_account_user not in self.users:
                return None

            # account_id = url.rsplit('/', 1)[-1]
            account_id = self.reseller_prefix + account 
            path = env['PATH_INFO']
            env['PATH_INFO'] = path.replace(account_user, account_id, 1)
            msg = base64.urlsafe_b64decode(unquote(token))
            key = self.users[account_user]['key']
            s = base64.encodestring(hmac.new(key, msg, sha1).digest()).strip()
            if s != sign:
                return None
            groups = [account, account_user]
            groups.extend(self.users[h_account_user]['groups'])
            if '.admin' in groups:
                groups.remove('.admin')
                groups.append(account_id)
            groups = ','.join(groups)

        return groups
Example #41
0
    def origin_db_delete(self, env, req):
        """ Handles DELETEs in the Origin database """
        if not self.delete_enabled:
            return HTTPMethodNotAllowed(request=req)
        try:
            vsn, account, container = split_path(req.path, 3, 3)
        except ValueError:
            return HTTPBadRequest(
                'Invalid request. '
                'URI format: /<api version>/<account>/<container>')
        hsh = self.hash_path(account, container)
        cdn_obj_path = self.get_hsh_obj_path(hsh)

        # Remove memcache entry
        memcache_client = utils.cache_from_env(env)
        if memcache_client:
            memcache_key = self.cdn_data_memcache_key(cdn_obj_path)
            memcache_client.delete(memcache_key)

        resp = make_pre_authed_request(env,
                                       'DELETE',
                                       cdn_obj_path,
                                       agent='SwiftOrigin',
                                       swift_source='SOS').get_response(
                                           self.app)

        # A 404 means it's already deleted, which is okay
        if resp.status_int // 100 != 2 and resp.status_int != 404:
            raise OriginDbFailure('Could not DELETE .hash obj in origin '
                                  'db: %s %s' %
                                  (cdn_obj_path, resp.status_int))

        cdn_list_path = quote('/v1/%s/%s/%s' %
                              (self.origin_account, account, container))
        list_resp = make_pre_authed_request(env,
                                            'DELETE',
                                            cdn_list_path,
                                            agent='SwiftOrigin',
                                            swift_source='SOS').get_response(
                                                self.app)

        if list_resp.status_int // 100 != 2 and list_resp.status_int != 404:
            raise OriginDbFailure('Could not DELETE listing path in origin '
                                  'db: %s %s' %
                                  (cdn_list_path, list_resp.status_int))

        # Return 404 if container didn't exist
        if resp.status_int == 404 and list_resp.status_int == 404:
            return HTTPNotFound(request=req)
        return HTTPNoContent(request=req)
Example #42
0
    def get_groups(self, env, token):
        """
        Get groups for the given token.

        :param env: The current WSGI environment dictionary.
        :param token: Token to validate and return a group string for.
        :returns: None if the token is invalid or a string containing a comma
                  separated list of groups the authenticated user is a member
                  of. The first group in the list is also considered a unique
                  identifier for that user.
        """
        groups = None
        memcache_client = cache_from_env(env)
        if not memcache_client:
            raise Exception('Memcache required')
        memcache_token_key = '%s/token/%s' % (self.reseller_prefix, token)
        cached_auth_data = memcache_client.get(memcache_token_key)
        if cached_auth_data:
            expires, groups = cached_auth_data
            info = self.users.get(groups, {}).get('url')
            if not info:
                account_id = self.admins[groups]['url'].rsplit('/', 1)[-1]
            else:
                account_id = info.rsplit('/', 1)[-1]
            # account_id = self.users.get(groups).get('url').rsplit('/', 1)[-1]
            groups = groups + ',' + account_id + ',admin,.admin'
            # groups=sun
            if expires < time():
                groups = None

        if env.get('HTTP_AUTHORIZATION'):
            account_user, sign = \
                env['HTTP_AUTHORIZATION'].split(' ')[1].rsplit(':', 1)
            if account_user not in self.users and account_user not in self.admins:
                return None
            account, user = account_user.split(':', 1)
            account_id = self.users[account_user]['url'].rsplit('/', 1)[-1]
            if not account_id:
                account_id = self.admins[user]['url'].rsplit('/', 1)[-1]
            path = env['PATH_INFO']
            env['PATH_INFO'] = path.replace(account_user, account_id, 1)
            msg = base64.urlsafe_b64decode(unquote(token))
            key = self.users[account_user]['key']
            s = base64.encodestring(hmac.new(key, msg, sha1).digest()).strip()
            if s != sign:
                return None
            groups = self._get_user_groups(account, account_user, account_id)
        # account_id = self.users[groups]['url'].rsplit('/', 1)[-1]
        # groups=groups + ',' + account_id + ',admin,.admin'
        return groups
Example #43
0
    def __call__(self, env, start_response):
        request = Request(env)

        if request.method not in ("POST", "PUT"):
            return self.app(env, start_response)

        try:
            (version, account) = split_path(request.path_info, 1, 2, True)

        except ValueError:
            return self.app(env, start_response)

        reseller = self.reseller_request(env)

        # deny quota set for non-resellers
        val = request.headers.get('X-Account-Meta-Quota-Bytes')
        if val is not None and not reseller:
            return HTTPForbidden()(env, start_response)
        # verify new quota headers are properly formatted
        if val and not val.isdigit():
            return HTTPBadRequest()(env, start_response)

        #Pass early if request is from reseller
        if reseller:
            return self.app(env, start_response)

        memcache_client = cache_from_env(env)
        quota_exceeded = None

        if memcache_client:
            memcache_key = "quota_exceeded_%s" % (account, )
            quota_exceeded = memcache_client.get(memcache_key)

        if quota_exceeded is None:
            quota_exceeded = False

            (used_bytes, quota) = self.get_quota(env, version, account)

            if 0 <= quota < used_bytes:
                quota_exceeded = True

            if memcache_client:
                memcache_client.set(
                    memcache_key,
                    quota_exceeded,
                    timeout=float(self.conf.get('cache_timeout', 60)))

        if quota_exceeded:
            return HTTPRequestEntityTooLarge()(env, start_response)
        return self.app(env, start_response)
    def _accession_by_auth_token(self, env, auth_token):
        """
        add by colony.
        """
        req = Request(env)
        memcache_client = cache_from_env(env)

        #get memcache
        if memcache_client:
            memcache_key = 'auth/%s' % auth_token
            cached_auth_data = memcache_client.get(memcache_key)
            if cached_auth_data:
                expires, tenant, username, roles, storage_url = cached_auth_data
                if expires > time():
                    if not self.across_account and not self.valid_account_owner(
                            req, tenant):
                        return None
                    return tenant, username, roles, storage_url

        token = {'auth': {'token': {'id': auth_token}, 'tenantId': ''}}
        req_headers = {
            'Content-type': 'application/json',
            'Accept': 'text/json'
        }
        connect = httplib.HTTPConnection if self.auth_protocol == 'http' else httplib.HTTPSConnection
        conn = connect('%s' % self.auth_netloc, timeout=10)
        conn.request('POST', '/v2.0/tokens', json.dumps(token), req_headers)
        resp = conn.getresponse()
        if resp.status == 200:
            data = resp.read()
        else:
            return None
        auth_resp = json.loads(data)
        verified_auth_token, tenant, username, roles, storage_url = \
            self._get_swift_info(auth_resp, self.region_name)
        if auth_token != verified_auth_token:
            return None

        # set memcache
        if memcache_client:
            memcache_client.set(memcache_key,
                                (time() + self.memcache_expire, tenant,
                                 username, roles, storage_url),
                                timeout=self.memcache_expire)

        if not self.across_account and not self.valid_account_owner(
                req, tenant):
            return None
        return tenant, username, roles, storage_url
Example #45
0
    def get_groups(self, env, token):
        """
        Get groups for the given token.

        :param env: The current WSGI environment dictionary.
        :param token: Token to validate and return a group string for.
        :returns: None if the token is invalid or a string containing a comma
                  separated list of groups the authenticated user is a member
                  of. The first group in the list is also considered a unique
                  identifier for that user.
        """
        groups = None
        memcache_client = cache_from_env(env)
        if not memcache_client:
            raise Exception('Memcache required')
        memcache_token_key = '%s/token/%s' % (self.reseller_prefix, token)
        cached_auth_data = memcache_client.get(memcache_token_key)
        if cached_auth_data:
            expires, groups = cached_auth_data
            if expires < time():
                groups = None

        s3_auth_details = env.get('swift3.auth_details')
        if s3_auth_details:
            account_user = s3_auth_details['access_key']
            signature_from_user = s3_auth_details['signature']
            if account_user not in self.users:
                return None
            account, user = account_user.split(':', 1)
            account_id = self.users[account_user]['url'].rsplit('/', 1)[-1]
            path = env['PATH_INFO']
            env['PATH_INFO'] = path.replace(account_user, account_id, 1)
            if 'check_signature' in s3_auth_details:
                if not s3_auth_details['check_signature'](
                        self.users[account_user]['key']):
                    return None
            else:
                valid_signature = base64.encodestring(hmac.new(
                    self.users[account_user]['key'],
                    s3_auth_details['string_to_sign'],
                    sha1).digest()).strip()
                if signature_from_user != valid_signature:
                    return None
            groups = self._get_user_groups(account, account_user, account_id)

        return groups
Example #46
0
    def get_groups(self, env, token):
        """
        Get groups for the given token.

        :param env: The current WSGI environment dictionary.
        :param token: Token to validate and return a group string for.
        :returns: None if the token is invalid or a string containing a comma
                  separated list of groups the authenticated user is a member
                  of. The first group in the list is also considered a unique
                  identifier for that user.
        """
        groups = None
        memcache_client = cache_from_env(env)
        if not memcache_client:
            raise Exception('Memcache required')
        memcache_token_key = '%s/token/%s' % (self.reseller_prefix, token)
        cached_auth_data = memcache_client.get(memcache_token_key)
        if cached_auth_data:
            expires, groups = cached_auth_data
            if expires < time():
                groups = None
            elif six.PY2:
                groups = groups.encode('utf8')

        s3_auth_details = env.get('s3api.auth_details') or\
            env.get('swift3.auth_details')
        if s3_auth_details:
            if 'check_signature' not in s3_auth_details:
                self.logger.warning(
                    'Swift3 did not provide a check_signature function; '
                    'upgrade Swift3 if you want to use it with tempauth')
                return None
            account_user = s3_auth_details['access_key']
            if account_user not in self.users:
                return None
            user = self.users[account_user]
            account = account_user.split(':', 1)[0]
            account_id = user['url'].rsplit('/', 1)[-1]
            if not s3_auth_details['check_signature'](user['key']):
                return None
            env['PATH_INFO'] = env['PATH_INFO'].replace(
                account_user, account_id, 1)
            groups = self._get_user_groups(account, account_user, account_id)

        return groups
Example #47
0
def set_container_metadata(vertigo, metadata):
    """
    Sets the swift metadata to the container

    :param metadata: metadata dictionary
    """
    memcache = cache_from_env(vertigo.request.environ)
    dest_path = os.path.join('/', vertigo.api_version, vertigo.account, vertigo.container)
    for key in metadata.keys():
        if not key.startswith(SYSMETA_CONTAINER_HEADER):
            del metadata[key]
    # We store the Vertigo metadata in the memcached server (only 10 minutes)
    memcache.set("vertigo_"+dest_path, metadata, time=600)
    new_env = dict(vertigo.request.environ)
    auth_token = vertigo.request.headers.get('X-Auth-Token')
    metadata.update({'X-Auth-Token': auth_token})
    sub_req = make_subrequest(new_env, 'POST', dest_path,
                              headers=metadata,
                              swift_source='Vertigo')
    sub_req.get_response(vertigo.app)
Example #48
0
    def _set_details(self, req, access_key, secret_key, account):
        """Set access key details."""
        path = quote(self.akd_container_url + access_key)
        resp = make_pre_authed_request(
            env=req.environ,
            method='PUT',
            path=path,
            body=json.dumps({'secret_key': secret_key, 'account': account})).\
            get_response(self.app)

        if resp.status_int // 100 == 2:
            # Remove old data from cache.
            memcache_client = cache_from_env(req.environ)
            if memcache_client:
                memcache_key = MEMCACHE_KEY_FORMAT % (self.reseller_prefix,
                                                      access_key)
                memcache_client.delete(memcache_key)
        else:
            raise Exception('Could not PUT access key details: {} {}'.format(
                path, resp.status_int))
Example #49
0
    def _get_container_info(self, env, start_response):
        """
        Retrieves x-container-meta-web-index, x-container-meta-web-error,
        x-container-meta-web-listings, and x-container-meta-web-listings-css
        from memcache or from the cluster and stores the result in memcache and
        in self._index, self._error, self._listings, and self._listings_css.

        :param env: The WSGI environment dict.
        :param start_response: The WSGI start_response hook.
        """
        self._index = self._error = self._listings = self._listings_css = None
        memcache_client = cache_from_env(env)
        if memcache_client:
            memcache_key = '/staticweb/%s/%s/%s' % (self.version, self.account,
                                                    self.container)
            cached_data = memcache_client.get(memcache_key)
            if cached_data:
                (self._index, self._error, self._listings,
                 self._listings_css) = cached_data
                return
        tmp_env = self._get_escalated_env(env)
        tmp_env['REQUEST_METHOD'] = 'HEAD'
        req = Request.blank('/%s/%s/%s' %
                            (self.version, self.account, self.container),
                            environ=tmp_env)
        resp = req.get_response(self.app)
        if resp.status_int // 100 == 2:
            self._index = \
                resp.headers.get('x-container-meta-web-index', '').strip()
            self._error = \
                resp.headers.get('x-container-meta-web-error', '').strip()
            self._listings = \
                resp.headers.get('x-container-meta-web-listings', '').strip()
            self._listings_css = \
                resp.headers.get('x-container-meta-web-listings-css',
                                 '').strip()
            if memcache_client:
                memcache_client.set(memcache_key,
                                    (self._index, self._error, self._listings,
                                     self._listings_css),
                                    timeout=self.cache_timeout)
Example #50
0
    def _get_container_info(self, env):
        """
        Retrieves x-container-meta-web-index, x-container-meta-web-error,
        x-container-meta-web-listings, and x-container-meta-web-listings-css
        from memcache or from the cluster and stores the result in memcache and
        in self._index, self._error, self._listings, and self._listings_css.

        :param env: The WSGI environment dict.
        """
        self._index = self._error = self._listings = self._listings_css = None
        memcache_client = cache_from_env(env)
        if memcache_client:
            memcache_key = '/staticweb/%s/%s/%s' % (self.version, self.account,
                                                    self.container)
            cached_data = memcache_client.get(memcache_key)
            if cached_data:
                (self._index, self._error, self._listings,
                 self._listings_css) = cached_data
                return
        resp = make_pre_authed_request(
            env,
            'HEAD',
            '/%s/%s/%s' % (self.version, self.account, self.container),
            agent=self.agent,
            swift_source='SW').get_response(self.app)
        if is_success(resp.status_int):
            self._index = \
                resp.headers.get('x-container-meta-web-index', '').strip()
            self._error = \
                resp.headers.get('x-container-meta-web-error', '').strip()
            self._listings = \
                resp.headers.get('x-container-meta-web-listings', '').strip()
            self._listings_css = \
                resp.headers.get('x-container-meta-web-listings-css',
                                 '').strip()
            if memcache_client:
                memcache_client.set(memcache_key,
                                    (self._index, self._error, self._listings,
                                     self._listings_css),
                                    time=self.cache_timeout)
Example #51
0
    def set_container_metadata(self, container, metadata):
        """
        Sets the swift metadata to the container

        :param metadata: metadata dictionary
        """
        for key in metadata.keys():
            if not key.startswith(MICROCONTROLLERS_CONT_HEADER):
                del metadata[key]
        dest_path = os.path.join('/', self.api_version, self.account, container)
        # We store the micro-controller execution list in a memcached server (only 10 minutes)
        memcache = cache_from_env(self.request.environ)
        memcache.set("vertigo_"+dest_path, metadata, time=600)
        new_env = dict(self.request.environ)
        auth_token = self.request.headers.get('X-Auth-Token')
        metadata.update({'X-Auth-Token': auth_token})
        sub_req = make_subrequest(new_env, 'POST', dest_path,
                                  headers=metadata,
                                  swift_source='micro-controllers_middleware')
        response = sub_req.get_response(self.app)
        if response.status_int != 202:
            raise
Example #52
0
    def handle_delete_access_key(self, req, access_key):
        """Delete access key.

        Required headers:
         - `x-s3auth-admin-key`: admin key
        """
        path = quote(self.akd_container_url + access_key)
        resp = make_pre_authed_request(req.environ, 'DELETE',
                                       path).get_response(self.app)

        if resp.status_int // 100 == 2:
            memcache_client = cache_from_env(req.environ)
            if memcache_client:
                memcache_key = MEMCACHE_KEY_FORMAT % (self.reseller_prefix,
                                                      access_key)
                memcache_client.delete(memcache_key)
            return HTTPNoContent(request=req)
        elif resp.status_int // 100 == 4:
            return HTTPNotFound(request=req)
        else:
            raise Exception(
                'Could not DELETE access key details: {} {}'.format(
                    path, resp.status_int))
Example #53
0
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        try:
            if self.memcache is None:
                self.memcache = cache_from_env(env, True)
            #将env包装为一个swob的请求,并传递给请求处理方法
            req = self.update_request(Request(env))
            #调用处理请求的方法,处理请求
            return self.handle_request(req)(env, start_response)
        except UnicodeError:
            err = HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')
            return err(env, start_response)
        except (Exception, Timeout):
            start_response('500 Server Error',
                           [('Content-Type', 'text/plain')])
            return ['Internal server error.\n']
Example #54
0
    def get_groups(self, env, token):
        """
        Get groups for the given token.

        :param env: The current WSGI environment dictionary.
        :param token: Token to validate and return a group string for.

        :returns: None if the token is invalid or a string containing a comma
                  separated list of groups the authenticated user is a member
                  of. The first group in the list is also considered a unique
                  identifier for that user.
        """
        groups = None
        memcache_client = cache_from_env(env)
        if not memcache_client:
            raise Exception('Memcache required')
        memcache_token_key = '%s/token/%s' % (self.reseller_prefix, token)
        cached_auth_data = memcache_client.get(memcache_token_key)
        if cached_auth_data:
            expires, groups = cached_auth_data
            if expires < time():
                groups = None

        return groups
Example #55
0
    def __call__(self, env, start_response):
        """
        WSGI entry point.
        Wraps env in swob.Request object and passes it down.

        :param env: WSGI environment dictionary
        :param start_response: WSGI callable
        """
        req = Request(env)
        if self.memcache_client is None:
            self.memcache_client = cache_from_env(env)
        if not self.memcache_client:
            self.logger.warning(
                _('Warning: Cannot ratelimit without a memcached client'))
            return self.app(env, start_response)
        try:
            version, account, container, obj = req.split_path(1, 4, True)
        except ValueError:
            return self.app(env, start_response)
        ratelimit_resp = self.handle_ratelimit(req, account, container, obj)
        if ratelimit_resp is None:
            return self.app(env, start_response)
        else:
            return ratelimit_resp(env, start_response)
Example #56
0
    def GETorHEAD(self, req):
        """Handler for HTTP GET/HEAD requests."""
        ai = self.account_info(self.account_name, req)
        auto_account = self.account_name.startswith(
            self.app.auto_create_account_prefix)
        if not (auto_account or ai[1]):
            if 'swift.authorize' in req.environ:
                aresp = req.environ['swift.authorize'](req)
                if aresp:
                    # Don't cache this. It doesn't reflect the state of the
                    # container, just that the user can't access it.
                    return aresp
            # Don't cache this. The lack of account will be cached, and that
            # is sufficient.
            return HTTPNotFound(request=req)

        # The read-modify-write of params here is because the Request.params
        # getter dynamically generates a dict of params from the query string;
        # the setter must be called for new params to update the query string.
        params = req.params
        params['format'] = 'json'
        # x-backend-record-type may be sent via internal client e.g. from
        # the sharder or in probe tests
        record_type = req.headers.get('X-Backend-Record-Type', '').lower()
        if not record_type:
            record_type = 'auto'
            req.headers['X-Backend-Record-Type'] = 'auto'
            params['states'] = 'listing'
        req.params = params

        memcache = cache_from_env(req.environ, True)
        if (req.method == 'GET' and record_type != 'object'
                and self.app.recheck_listing_shard_ranges > 0 and memcache
                and get_param(req, 'states') == 'listing'
                and not config_true_value(
                    req.headers.get('x-backend-include-deleted', False))):
            # This GET might be served from cache or might populate cache.
            # 'x-backend-include-deleted' is not usually expected in requests
            # to the proxy (it is used from sharder to container servers) but
            # it is included in the conditions just in case because we don't
            # cache deleted shard ranges.
            resp = self._GET_using_cache(req)
        else:
            resp = self._GETorHEAD_from_backend(req)

        resp_record_type = resp.headers.get('X-Backend-Record-Type', '')
        if all((req.method == "GET", record_type == 'auto',
                resp_record_type.lower() == 'shard')):
            resp = self._get_from_shards(req, resp)

        if not config_true_value(resp.headers.get('X-Backend-Cached-Results')):
            # Cache container metadata. We just made a request to a storage
            # node and got up-to-date information for the container.
            resp.headers['X-Backend-Recheck-Container-Existence'] = str(
                self.app.recheck_container_existence)
            set_info_cache(self.app, req.environ, self.account_name,
                           self.container_name, resp)
        if 'swift.authorize' in req.environ:
            req.acl = resp.headers.get('x-container-read')
            aresp = req.environ['swift.authorize'](req)
            if aresp:
                # Don't cache this. It doesn't reflect the state of the
                # container, just that the user can't access it.
                return aresp
        if not req.environ.get('swift_owner', False):
            for key in self.app.swift_owner_headers:
                if key in resp.headers:
                    del resp.headers[key]
        # Expose sharding state in reseller requests
        if req.environ.get('reseller_request', False):
            resp.headers['X-Container-Sharding'] = config_true_value(
                resp.headers.get(
                    get_sys_meta_prefix('container') + 'Sharding', 'False'))
        return resp
Example #57
0
    def __call__(self, env, start_response):
        self.logger.debug('In cs_auth middleware')
        identity = None  # the identity we are trying to populate

        # Handle s3 connections first because s3 has a unique format/use for the 'HTTP_X_AUTH_TOKEN'.
        s3 = env.get('HTTP_AUTHORIZATION', None)
        if s3 and s3.startswith('AWS'):
            s3_apikey, s3_signature = s3.split(' ')[1].rsplit(':', 1)[:]
            if s3_apikey and s3_signature:
                # check if we have cached data to validate this request instead of hitting cloudstack.
                memcache_client = cache_from_env(env)
                memcache_result = memcache_client.get('cs_s3_auth/%s' %
                                                      s3_apikey)
                valid_cache = False
                data = None
                if memcache_result and self.cs_cache_timeout > 0:
                    expires, data = memcache_result
                    if expires > time():
                        valid_cache = True
                if valid_cache:
                    self.logger.debug(
                        'Validating the S3 request via the cached identity')
                    s3_token = base64.urlsafe_b64decode(
                        env.get('HTTP_X_AUTH_TOKEN', '')).encode("utf-8")
                    if s3_signature == base64.b64encode(
                            hmac.new(data.get('secret', ''), s3_token,
                                     hashlib.sha1).digest()):
                        self.logger.debug('Using cached S3 identity')
                        identity = data.get('identity', None)
                        token = identity.get(
                            'token', None
                        )  # this just simplifies the logical flow, its not really used in this case.

                        # The swift3 middleware sets env['PATH_INFO'] to '/v1/<aws_secret_key>', we need to map it to the cloudstack account.
                        if self.reseller_prefix != '':
                            env['PATH_INFO'] = env['PATH_INFO'].replace(
                                s3_apikey,
                                '%s_%s' % (self.reseller_prefix,
                                           identity.get('account', '')))
                        else:
                            env['PATH_INFO'] = env['PATH_INFO'].replace(
                                s3_apikey,
                                '%s' % (identity.get('account', '')))
                else:  # hit cloudstack and populate memcached if valid request
                    user_list = self.cs_api.request(
                        dict({'command': 'listUsers'}))
                    if user_list:
                        for user in user_list['user']:
                            if user['state'] == 'enabled' and 'apikey' in user and user[
                                    'apikey'] == s3_apikey:
                                # At this point we have found a matching user.  Authenticate them.
                                s3_token = base64.urlsafe_b64decode(
                                    env.get('HTTP_X_AUTH_TOKEN',
                                            '')).encode("utf-8")
                                if s3_signature == base64.b64encode(
                                        hmac.new(user['secretkey'], s3_token,
                                                 hashlib.sha1).digest()):
                                    expires = time() + self.cs_cache_timeout
                                    timeout = self.cs_cache_timeout
                                    token = hashlib.sha224(
                                        '%s%s' % (user['secretkey'],
                                                  user['apikey'])).hexdigest()
                                    if self.reseller_prefix != '':
                                        account_url = '%s/v1/%s_%s' % (
                                            self.storage_url,
                                            self.reseller_prefix,
                                            quote(user['account']))
                                    else:
                                        account_url = '%s/v1/%s' % (
                                            self.storage_url,
                                            quote(user['account']))
                                    identity = dict({
                                        'username':
                                        user['username'],
                                        'account':
                                        user['account'],
                                        'token':
                                        token,
                                        'account_url':
                                        account_url,
                                        'domain':
                                        dict({
                                            'id': user['domainid'],
                                            'name': user['domain']
                                        }),
                                        'roles': [
                                            self.cs_roles[user['accounttype']],
                                            user['account']
                                        ],
                                        'expires':
                                        expires
                                    })
                                    self.logger.debug('Creating S3 identity')
                                    # The swift3 middleware sets env['PATH_INFO'] to '/v1/<aws_secret_key>', we need to map it to the cloudstack account.
                                    if self.reseller_prefix != '':
                                        env['PATH_INFO'] = env[
                                            'PATH_INFO'].replace(
                                                s3_apikey, '%s_%s' %
                                                (self.reseller_prefix,
                                                 user['account']))
                                    else:
                                        env['PATH_INFO'] = env[
                                            'PATH_INFO'].replace(
                                                s3_apikey,
                                                '%s' % (user['account']))
                                    memcache_client = cache_from_env(env)
                                    if memcache_client:
                                        memcache_client.set(
                                            'cs_s3_auth/%s' % s3_apikey,
                                            (expires,
                                             dict({
                                                 'secret': user['secretkey'],
                                                 'identity': identity
                                             })),
                                            timeout=timeout)
                                        memcache_client.set(
                                            'cs_token/%s' % token,
                                            (expires, identity),
                                            timeout=timeout)
                                else:
                                    self.logger.debug(
                                        'S3 credentials are not valid')
                                    env['swift.authorize'] = self.denied_response
                                    return self.app(env, start_response)
                    else:
                        self.logger.debug('Errors: %s' % self.cs_api.errors)
                        env['swift.authorize'] = self.denied_response
                        return self.app(env, start_response)
            else:
                self.logger.debug('Invalid credential format')
                env['swift.authorize'] = self.denied_response
                return self.app(env, start_response)

        # If it is not an S3 call, handle the request for authenication, otherwise, use the token.
        req = Request(env)
        if not s3:
            try:
                auth_url_piece, rest_of_url = split_path(req.path_info,
                                                         minsegs=1,
                                                         maxsegs=2,
                                                         rest_with_last=True)
            except ValueError:
                return HTTPNotFound(request=req)

            # Check if the request is for authentication (to get a token).
            if auth_url_piece in ('auth', 'v1.0'):  # valid auth urls
                auth_user = env.get('HTTP_X_AUTH_USER', None)
                auth_key = env.get('HTTP_X_AUTH_KEY', None)
                if auth_user and auth_key:
                    # check if we have this user and key cached.
                    memcache_client = cache_from_env(env)
                    memcache_result = memcache_client.get(
                        'cs_auth/%s/%s' % (auth_user, auth_key))
                    valid_cache = False
                    data = None
                    if memcache_result and self.cs_cache_timeout > 0 and env.get(
                            'HTTP_X_AUTH_TTL', 1) > 0:
                        expires, data = memcache_result
                        if expires > time():
                            valid_cache = True
                    if valid_cache:
                        self.logger.debug('Using cached identity via creds')
                        identity = data
                        self.logger.debug("Using identity: %r" % (identity))
                        token = identity.get('token', None)
                        req.response = Response(request=req,
                                                headers={
                                                    'x-auth-token':
                                                    token,
                                                    'x-storage-token':
                                                    token,
                                                    'x-storage-url':
                                                    identity.get(
                                                        'account_url', None)
                                                })
                        return req.response(env, start_response)
                    else:  # hit cloudstack for the details.
                        user_list = self.cs_api.request(
                            dict({
                                'command': 'listUsers',
                                'username': auth_user
                            }))
                        if user_list:
                            for user in user_list['user']:
                                if user['state'] == 'enabled' and 'apikey' in user and user[
                                        'apikey'] == auth_key:
                                    token = hashlib.sha224(
                                        '%s%s' % (user['secretkey'],
                                                  user['apikey'])).hexdigest()
                                    if env.get('HTTP_X_AUTH_TTL', None):
                                        expires = time() + int(
                                            env.get('HTTP_X_AUTH_TTL'))
                                        timeout = int(
                                            env.get('HTTP_X_AUTH_TTL'))
                                    else:
                                        expires = time(
                                        ) + self.cs_cache_timeout
                                        timeout = self.cs_cache_timeout
                                    if self.reseller_prefix != '':
                                        account_url = '%s/v1/%s_%s' % (
                                            self.storage_url,
                                            self.reseller_prefix,
                                            quote(user['account']))
                                    else:
                                        account_url = '%s/v1/%s' % (
                                            self.storage_url,
                                            quote(user['account']))
                                    identity = dict({
                                        'username':
                                        user['username'],
                                        'account':
                                        user['account'],
                                        'token':
                                        token,
                                        'account_url':
                                        account_url,
                                        'domain':
                                        dict({
                                            'id': user['domainid'],
                                            'name': user['domain']
                                        }),
                                        'roles': [
                                            self.cs_roles[user['accounttype']],
                                            user['account']
                                        ],
                                        'expires':
                                        expires
                                    })
                                    self.logger.debug('Created identity: %s' %
                                                      identity)
                                    # add to memcache so it can be referenced later
                                    memcache_client = cache_from_env(env)
                                    if memcache_client:
                                        memcache_client.set(
                                            'cs_auth/%s/%s' %
                                            (auth_user, auth_key),
                                            (expires, identity),
                                            timeout=timeout)
                                        memcache_client.set(
                                            'cs_token/%s' % token,
                                            (expires, identity),
                                            timeout=timeout)
                                    req.response = Response(
                                        request=req,
                                        headers={
                                            'x-auth-token': token,
                                            'x-storage-token': token,
                                            'x-storage-url': account_url
                                        })
                                    return req.response(env, start_response)

                            # if we get here the user was not valid, so fail...
                            self.logger.debug('Not a valid user and key pair')
                            env['swift.authorize'] = self.denied_response
                            return self.app(env, start_response)
                        else:
                            self.logger.debug('Errors: %s' %
                                              self.cs_api.errors)
                            env['swift.authorize'] = self.denied_response
                            return self.app(env, start_response)
                else:
                    self.logger.debug('Credentials missing')
                    env['swift.authorize'] = self.denied_response
                    return self.app(env, start_response)
            else:
                token = env.get('HTTP_X_AUTH_TOKEN',
                                env.get('HTTP_X_STORAGE_TOKEN'))

        if not identity and not env.get('HTTP_X_AUTH_TOKEN',
                                        env.get('HTTP_X_STORAGE_TOKEN', None)):
            # this is an anonymous request.  pass it through for authorize to verify.
            self.logger.debug('Passing through anonymous request')
            env['swift.authorize'] = self.authorize
            env['swift.clean_acl'] = clean_acl
            return self.app(env, start_response)

        # setup a memcache client for the following.
        memcache_client = cache_from_env(env)

        if not identity:
            memcache_result = memcache_client.get('cs_token/%s' % token)
            if memcache_result and self.cs_cache_timeout > 0:
                expires, _identity = memcache_result
                if expires > time():
                    self.logger.debug('Using cached identity via token')
                    identity = _identity

        if not identity:
            self.logger.debug(
                "No cached identity, validate token via cloudstack")
            identity = self._cloudstack_validate_token(token)
            if identity and memcache_client:
                expires = identity['expires']
                memcache_client.set('cs_token/%s' % token, (expires, identity),
                                    timeout=expires - time())
                ts = str(datetime.fromtimestamp(expires))
                self.logger.debug('Setting memcache expiration to %s' % ts)
            else:  # if we didn't get identity it means there was an error.
                self.logger.debug('No identity for this token')
                env['swift.authorize'] = self.denied_response
                return self.app(env, start_response)

        if not identity:
            env['swift.authorize'] = self.denied_response
            return self.app(env, start_response)

        self.logger.debug("Using identity: %r" % (identity))
        env['cloudstack.identity'] = identity
        env['REMOTE_USER'] = '******'.join(identity['roles'])
        env['swift.authorize'] = self.authorize
        env['swift.clean_acl'] = clean_acl
        return self.app(env, start_response)
Example #58
0
    def __call__(self, req):
        if not self.memcache:
            self.memcache = cache_from_env(req.environ)
        login_path = '%s/%s' % (self.page_path, 'login')
        token = None
        storage_url = None
        # favicon
        if req.path == '/favicon.ico':
            return self.pass_file(req, 'images/favicon.ico',
                                  'image/vnd.microsoft.icon')
        # not taylor
        if not req.path.startswith(self.page_path):
            return self.app

        # image
        if req.path.startswith(join(self.page_path, 'image')):
            return self.pass_file(req, join('images', basename(req.path)))
        # css
        if req.path.startswith(join(self.page_path, 'css')):
            return self.pass_file(req, join('css', basename(req.path)))
        # js
        if req.path.startswith(join(self.page_path, 'js')):
            return self.pass_file(req, join('js', basename(req.path)))
        # get token from cookie and query memcache
        token = req.cookies('_token')
        if self.memcache and token:
            cache_val = self.memcache.get('%s_%s' % (self.title, token))
            if cache_val:
                self.token_bank[token] = cache_val
        status = self.token_bank.get(token, None)
        if status:
            storage_url = status.get('url', None)
        # login page
        if req.path == login_path:
            return self.page_login(req)
        if not token or not storage_url:
            return HTTPFound(location=login_path)
        self.token_bank[token].update({'last': time()})
        # clean up token bank
        for tok, val in self.token_bank.items():
            last = val.get('last', 0)
            if (time() - last) >= self.cookie_max_age:
                del (self.token_bank[tok])
        if 'X-PJAX' in req.headers:
            return self.pass_file(req, 'images/test.html', 'text/html')
            # return self.page_cont_list(req, storage_url, token,
            #                            template_name='containers.tmpl')
            # return self.page_obj_list(req, storage_url, token,
            #                           template_name='objectss.tmpl')
        # ajax action
        if '_ajax' in req.params_alt():
            if req.params_alt()['_action'].endswith('_meta_list'):
                status, headers = self.action_routine(req, storage_url, token)
                return Response(status=status, body=headers)
            return Response(
                status=self.action_routine(req, storage_url, token))
        # after action
        if '_action' in req.params_alt():
            if req.params_alt()['_action'] == 'logout':
                del self.token_bank[token]
                self.memcache.delete('%s_%s' % (self.title, token))
                return HTTPFound(location=login_path)
            return self.page_after_action(req, storage_url, token)
        # construct main pages
        return self.page_main(req, storage_url, token)
Example #59
0
    def handle_get_token(self, req):
        """
        Handles the various `request for token and service end point(s)` calls.
        There are various formats to support the various auth servers in the
        past. Examples::

            GET <auth-prefix>/v1/<act>/auth
                X-Auth-User: <act>:<usr>  or  X-Storage-User: <usr>
                X-Auth-Key: <key>         or  X-Storage-Pass: <key>
            GET <auth-prefix>/auth
                X-Auth-User: <act>:<usr>  or  X-Storage-User: <act>:<usr>
                X-Auth-Key: <key>         or  X-Storage-Pass: <key>
            GET <auth-prefix>/v1.0
                X-Auth-User: <act>:<usr>  or  X-Storage-User: <act>:<usr>
                X-Auth-Key: <key>         or  X-Storage-Pass: <key>

        On successful authentication, the response will have X-Auth-Token and
        X-Storage-Token set to the token to use with Swift and X-Storage-URL
        set to the URL to the default Swift cluster to use.

        :param req: The swob.Request to process.
        :returns: swob.Response, 2xx on success with data set as explained
                  above.
        """
        # Validate the request info
        try:
            pathsegs = split_path(req.path_info, 1, 3, True)
        except ValueError:
            self.logger.increment('errors')
            return HTTPNotFound(request=req)
        if pathsegs[0] == 'v1' and pathsegs[2] == 'auth':
            account = pathsegs[1]
            user = req.headers.get('x-storage-user')
            if not user:
                user = req.headers.get('x-auth-user')
                if not user or ':' not in user:
                    self.logger.increment('token_denied')
                    auth = 'Swift realm="%s"' % account
                    return HTTPUnauthorized(request=req,
                                            headers={'Www-Authenticate': auth})
                account2, user = user.split(':', 1)
                if account != account2:
                    self.logger.increment('token_denied')
                    auth = 'Swift realm="%s"' % account
                    return HTTPUnauthorized(request=req,
                                            headers={'Www-Authenticate': auth})
            key = req.headers.get('x-storage-pass')
            if not key:
                key = req.headers.get('x-auth-key')
        elif pathsegs[0] in ('auth', 'v1.0'):
            user = req.headers.get('x-auth-user')
            if not user:
                user = req.headers.get('x-storage-user')
            if not user or ':' not in user:
                self.logger.increment('token_denied')
                auth = 'Swift realm="unknown"'
                return HTTPUnauthorized(request=req,
                                        headers={'Www-Authenticate': auth})
            account, user = user.split(':', 1)
            key = req.headers.get('x-auth-key')
            if not key:
                key = req.headers.get('x-storage-pass')
        else:
            return HTTPBadRequest(request=req)
        if not all((account, user, key)):
            self.logger.increment('token_denied')
            realm = account or 'unknown'
            return HTTPUnauthorized(request=req, headers={'Www-Authenticate':
                                                          'Swift realm="%s"' %
                                                          realm})
        # Authenticate user
        account_user = account + ':' + user
        if account_user not in self.users:
            self.logger.increment('token_denied')
            auth = 'Swift realm="%s"' % account
            return HTTPUnauthorized(request=req,
                                    headers={'Www-Authenticate': auth})
        if self.users[account_user]['key'] != key:
            self.logger.increment('token_denied')
            auth = 'Swift realm="unknown"'
            return HTTPUnauthorized(request=req,
                                    headers={'Www-Authenticate': auth})
        account_id = self.users[account_user]['url'].rsplit('/', 1)[-1]
        # Get memcache client
        memcache_client = cache_from_env(req.environ)
        if not memcache_client:
            raise Exception('Memcache required')
        # See if a token already exists and hasn't expired
        token = None
        memcache_user_key = '%s/user/%s' % (self.reseller_prefix, account_user)
        candidate_token = memcache_client.get(memcache_user_key)
        if candidate_token:
            memcache_token_key = \
                '%s/token/%s' % (self.reseller_prefix, candidate_token)
            cached_auth_data = memcache_client.get(memcache_token_key)
            if cached_auth_data:
                expires, old_groups = cached_auth_data
                old_groups = old_groups.split(',')
                new_groups = self._get_user_groups(account, account_user,
                                                   account_id)

                if expires > time() and \
                        set(old_groups) == set(new_groups.split(',')):
                    token = candidate_token
        # Create a new token if one didn't exist
        if not token:
            # Generate new token
            token = '%stk%s' % (self.reseller_prefix, uuid4().hex)
            expires = time() + self.token_life
            groups = self._get_user_groups(account, account_user, account_id)
            # Save token
            memcache_token_key = '%s/token/%s' % (self.reseller_prefix, token)
            memcache_client.set(memcache_token_key, (expires, groups),
                                time=float(expires - time()))
            # Record the token with the user info for future use.
            memcache_user_key = \
                '%s/user/%s' % (self.reseller_prefix, account_user)
            memcache_client.set(memcache_user_key, token,
                                time=float(expires - time()))
        resp = Response(request=req, headers={
            'x-auth-token': token, 'x-storage-token': token})
        url = self.users[account_user]['url'].replace('$HOST', resp.host_url)
        if self.storage_url_scheme != 'default':
            url = self.storage_url_scheme + ':' + url.split(':', 1)[1]
        resp.headers['x-storage-url'] = url
        return resp
Example #60
0
    def _GET_using_cache(self, req):
        # It may be possible to fulfil the request from cache: we only reach
        # here if request record_type is 'shard' or 'auto', so if the container
        # state is 'sharded' then look for cached shard ranges. However, if
        # X-Newest is true then we always fetch from the backend servers.
        get_newest = config_true_value(req.headers.get('x-newest', False))
        if get_newest:
            self.app.logger.debug(
                'Skipping shard cache lookup (x-newest) for %s', req.path_qs)
            info = None
        else:
            info = _get_info_from_caches(self.app, req.environ,
                                         self.account_name,
                                         self.container_name)
        if (info and is_success(info['status'])
                and info.get('sharding_state') == 'sharded'):
            # container is sharded so we may have the shard ranges cached
            headers = headers_from_container_info(info)
            if headers:
                # only use cached values if all required headers available
                infocache = req.environ.setdefault('swift.infocache', {})
                memcache = cache_from_env(req.environ, True)
                cache_key = get_cache_key(self.account_name,
                                          self.container_name,
                                          shard='listing')
                cached_ranges = infocache.get(cache_key)
                if cached_ranges is None and memcache:
                    cached_ranges = memcache.get(cache_key)
                if cached_ranges is not None:
                    infocache[cache_key] = tuple(cached_ranges)
                    # shard ranges can be returned from cache
                    self.app.logger.debug('Found %d shards in cache for %s',
                                          len(cached_ranges), req.path_qs)
                    headers.update({
                        'x-backend-record-type': 'shard',
                        'x-backend-cached-results': 'true'
                    })
                    shard_range_body = self._filter_resp_shard_ranges(
                        req, cached_ranges)
                    # mimic GetOrHeadHandler.get_working_response...
                    # note: server sets charset with content_type but proxy
                    # GETorHEAD_base does not, so don't set it here either
                    resp = Response(request=req, body=shard_range_body)
                    update_headers(resp, headers)
                    resp.last_modified = math.ceil(
                        float(headers['x-put-timestamp']))
                    resp.environ['swift_x_timestamp'] = headers.get(
                        'x-timestamp')
                    resp.accept_ranges = 'bytes'
                    resp.content_type = 'application/json'
                    return resp

        # The request was not fulfilled from cache so send to the backend
        # server, but instruct the backend server to ignore name constraints in
        # request params if returning shard ranges so that the response can
        # potentially be cached. Only do this if the container state is
        # 'sharded'. We don't attempt to cache shard ranges for a 'sharding'
        # container as they may include the container itself as a 'gap filler'
        # for shard ranges that have not yet cleaved; listings from 'gap
        # filler' shard ranges are likely to become stale as the container
        # continues to cleave objects to its shards and caching them is
        # therefore more likely to result in stale or incomplete listings on
        # subsequent container GETs.
        req.headers['x-backend-override-shard-name-filter'] = 'sharded'
        resp = self._GETorHEAD_from_backend(req)

        sharding_state = resp.headers.get('x-backend-sharding-state',
                                          '').lower()
        resp_record_type = resp.headers.get('x-backend-record-type',
                                            '').lower()
        complete_listing = config_true_value(
            resp.headers.pop('x-backend-override-shard-name-filter', False))
        # given that we sent 'x-backend-override-shard-name-filter=sharded' we
        # should only receive back 'x-backend-override-shard-name-filter=true'
        # if the sharding state is 'sharded', but check them both anyway...
        if (resp_record_type == 'shard' and sharding_state == 'sharded'
                and complete_listing):
            # backend returned unfiltered listing state shard ranges so parse
            # them and replace response body with filtered listing
            cache_key = get_cache_key(self.account_name,
                                      self.container_name,
                                      shard='listing')
            data = self._parse_listing_response(req, resp)
            backend_shard_ranges = self._parse_shard_ranges(req, data, resp)
            if backend_shard_ranges is not None:
                cached_ranges = [dict(sr) for sr in backend_shard_ranges]
                if resp.headers.get('x-backend-sharding-state') == 'sharded':
                    # cache in infocache even if no shard ranges returned; this
                    # is unexpected but use that result for this request
                    infocache = req.environ.setdefault('swift.infocache', {})
                    infocache[cache_key] = tuple(cached_ranges)
                    memcache = cache_from_env(req.environ, True)
                    if memcache and cached_ranges:
                        # cache in memcache only if shard ranges as expected
                        self.app.logger.debug('Caching %d shards for %s',
                                              len(cached_ranges), req.path_qs)
                        memcache.set(
                            cache_key,
                            cached_ranges,
                            time=self.app.recheck_listing_shard_ranges)

                # filter returned shard ranges according to request constraints
                resp.body = self._filter_resp_shard_ranges(req, cached_ranges)

        return resp