def is_service_up(self):
     pre_healthcheck.send(sender=self, request=self.request)
     status = not (general_config().health_check is not None and not general_config().health_check.get_service_status(self.cfg.get('name').lower()))
     if not status:
         self.analytics.increment("proxy.%s.service.fail" % self.cfg.get('name').lower())
         self.err = {"error": 500, "message": "service_failure"}
     post_healthcheck.send(sender=self, request=self.request, status=status, error=self.err)
     return status
    def handle(self, *args, **options):
        cfg_file_name = options['cfg_file']
        if cfg_file_name is None:
            cfg_file_name = settings.API_CONF_FILE

        cfg_file = os.path.abspath(os.path.join(os.path.dirname(cfg_dir), cfg_file_name))

        print("Validating configuration file: %s" % cfg_file)

        try:
            config = load_config(cfg_file)
        except IOError as e:
            print(colored("IOError: Could not open file for reading %s" % e, "red", None, ['bold']))
            sys.exit(-1)
        except Exception as e:
            print(colored("File doesn't seem to valid JSON %s" % e, "red", None, ['bold']))
            sys.exit(-1)

        print(colored("File Exists", "green"))
        print(colored("File is valid JSON", "green"))

        add_proxies_from_data(config)

        if general_config().errors_during_init:
            print(colored("JSON file has errors during init", "red", None, ['bold']))
            sys.exit(-1)
        else:
            print(colored("JSON file is verified correct", "green", None, ['bold']))
            sys.exit(0)
    def dispatch(self, request, *args, **kwargs):
        health_check_results = None
        if str2bool(request.GET.get('details', "False")):
            if general_config().health_check is not None:
                health_check_results = {}
                for endpoint_url in self.endpoints:
                    endpoint = self.endpoints.get(endpoint_url)
                    if endpoint is not None:
                        health_check_results[endpoint.get('name').lower()] = general_config().health_check.get_service_status(endpoint.get('name').lower())

        res = {"success": True,
           "number_of_endpoints": len(self.endpoints),
           "domain_name": self.domain_name,
           "version": __version__,
           "startup_time": self.startup_time }

        if health_check_results is not None:
            res['endpoint_statuses'] = health_check_results

        return HttpResponse(json.dumps(res, default=dthandler), content_type="application/json")
def add_proxies_from_data(config):
    urlpatterns = []
    init_global_config(config.get('general', {}))

    for key in config.get('endpoints').keys():
        endpoint_cfg = config.get('endpoints').get(key)
        endpoint_cfg['pattern'] = key
        urlpatterns += patterns('proxy.views',
                                url(key, ProxyView().as_view(cfg=endpoint_cfg))
        )
        general_config().cache.enable_caching_for_endpoint(key, endpoint_cfg)

    health_check_url = config.get('general', {}).get("self_health_check_url", "^proxy-check$")
    urlpatterns += patterns('proxy.views',
                            url(health_check_url, SimpleProxyHealthCheck().as_view(cfg=config)))

    invalidation_endpoint = general_config().cache.add_invalidation_endpoint()
    if invalidation_endpoint is not None:
        urlpatterns += invalidation_endpoint

    return urlpatterns
 def authorize(self, request, *args, **kwargs):
     cfg = general_config()
     application_object = cfg.application_object
     if application_object is None:
         logger.error("You are trying to use the proxy.authentication.AppKeyProvider with no application_object set!")
         return AuthenticationError(error_code=500, message="Internal error")
     else:
         try:
             obj = application_cache().get(request.REQUEST.get('client_id', "MISSING-CLIENT-ID-xyz"))
             if obj is None:
                 return AuthenticationError(error_code=401, message="Invalid client_id")
             return obj
         except Exception as e:
             return AuthenticationError(error_code=401, message="Invalid client_id")
         return AuthenticationError(error_code=401, message="Invalid client_id")
def invalidate_cache_view(request, application):
    if not application.super_application:
        return HttpResponse(json.dumps({"error": 403, "message": "auth_error"}), content_type="application/json", status=403)
    uncache_type = request.POST.get('uncache_type')
    if uncache_type == 'user_request':
        # user use case
        try:
            user_id = request.POST.get('user_id')
            u = general_config().user_provider.find(id=user_id, force_no_cache=True)
            if u is None:
                return HttpResponse(json.dumps({"error": 404, "message": "user not found with id " + user_id}), content_type="application/json", status=404)
            cache_key = UserCacheKeyMaker(u)
            cache_key.invalidate_with_key()
            return HttpResponse(json.dumps({"message": "OK"}), content_type="application/json", status=200)
        except Exception as e:
            logger.exception("Could not uncache", e)
            return HttpResponse(json.dumps({"error": "500"}), content_type="application/json", status=500)
    else:
        # TODO: Add the normal use case for API Caching (right now we only do user caching)
        pass

    return HttpResponse(json.dumps({"message": "OK"}), content_type="application/json", status=200)
 def get_with_key(self):
     for hash_key in self.build_key():
         result = general_config().cache.store.retrieve(hash_key)
         if result is not None:
             return result
 def as_view(cls, **initkwargs):
     initkwargs['endpoints'] = initkwargs.get('cfg').get('endpoints', [])
     initkwargs['domain_name'] = general_config().domain_name
     initkwargs['startup_time'] = datetime.datetime.now(tz=utc)
     view = super(SimpleProxyHealthCheck, cls).as_view(**initkwargs)
     return view
 def testCacheStartup(self):
     self.assertIsInstance(general_config().cache.store, SimpleInMemoryCacheStore)
    def dispatch(self, request, *args, **kwargs):
        self.request = request
        self.err = None

        custom_headers = {}
        if general_config().domain_name is not None:
            custom_headers = {'X_FORWARDED_HOST': general_config().domain_name}

        self.get_url_to_call()

        if not self.auth_flow(custom_headers, *args, **kwargs):
            return HttpResponse(json.dumps(self.err), content_type="application/json", status=self.err.get('error'))

        if not self.is_allowed():
            return HttpResponse(json.dumps(self.err), content_type="application/json", status=self.err.get('error'))

        if self.cached:
            cache_key_maker = CacheKeyMaker()
            cache_key_maker.set_request(self.request)

            for rule in self.cache_rules:
                rule.run_rule(cache_key_maker)

            cache_key = cache_key_maker.build_key()
            response = general_config().cache.store.retrieve(cache_key)
            if response is not None:
                logger.info("Cache HIT for %s" % cache_key)
                return response
            else:
                logger.info("Cache MISS for %s" % cache_key)

        if not self.is_service_up():
            return HttpResponse(json.dumps(self.err), content_type="application/json", status=self.err.get('error'))

        try:
            request.GET = request.GET.copy()  # make request objects mutable for the transformers
            for transformer in self.request_transformers:
                request = transformer.transform_request(request)

            if request.method.lower() in ['post', 'put']:
                self.web_call = partial(self.web_call, data=request.body, params=request.GET.lists())
            else:
                self.web_call = partial(self.web_call, params=request.GET.lists())

            if self.cfg.get('pass_headers', False):
                self.web_call = partial(self.web_call, headers=get_all_http_request_headers(request, custom_headers))
            else:
                self.web_call = partial(self.web_call, headers=get_content_request_headers_only(request, custom_headers))

            response = self.web_call(self.url_to_call, timeout=general_config().timeout)

            django_resp = HttpResponse(response.text, status=response.status_code)
            for header in response.headers.keys():
                if header not in hop_headers:
                    if header != "content-encoding":
                        django_resp[header] = response.headers.get(header)

            django_resp['content-length'] = len(response.content)
            
            for transformer in self.response_transformers:
                django_resp = transformer.transform_response(django_resp)

            self.analytics.increment("proxy.%s.dispatch.server.success" % (self.cfg.get('name').lower(),))

            if self.cached:
                general_config().cache.store.store(cache_key, django_resp)

            return django_resp
        except TransformerException as e:
            self.analytics.increment("proxy.%s.dispatch.server.transformer_exception.fail" % (self.cfg.get('name').lower(), ))
            err = e.to_dict()
            return HttpResponse(json.dumps(err, sort_keys=False), content_type="application/json", status=e.error_code)
        except FaceOffException as e:
            self.analytics.increment("proxy.%s.dispatch.server.faceoff_exception.fail" % (self.cfg.get('name').lower(), ))
            err = e.to_dict()
            return HttpResponse(json.dumps(err, sort_keys=False), content_type="application/json", status=e.error_code)
        except (SSLError, Timeout) as e: # Timeouts are SSLErrors if url is SSL
            err = OrderedDict({"error": "408", "message": "service_time_out"})
            self.analytics.increment("proxy.%s.dispatch.server.service_time_out.fail" % (self.cfg.get('name').lower(), ))
            logger.warning("Service timed out for %s" % self.cfg.get('name') )
            return HttpResponse(json.dumps(err, sort_keys=False), content_type="application/json", status=408)
        except ConnectionError as e:
            err = OrderedDict({"error": "1", "message": "connection_error"})
            self.analytics.increment("proxy.%s.dispatch.server.connection_error.fail" % (self.cfg.get('name').lower(), ))
            logger.warning("Service connection errored for %s" % self.cfg.get('name') )
            return HttpResponse(json.dumps(err, sort_keys=False), content_type="application/json", status=502)
        except Exception as e:
            err = OrderedDict({"error": "500", "message": "service_error"})
            self.analytics.increment("proxy.%s.dispatch.server.generic_service_exception.fail" % (self.cfg.get('name').lower(), ))

            return HttpResponse(json.dumps(err, sort_keys=False), content_type="application/json", status=500)
def init_global_config(general_json_config):
    if hasattr(general_config(), "configuration_complete"):
        return
    start = datetime.now()
    errors = "no"
    logger.info(colored("-------------------------------------------------", "green"))
    logger.info(colored("Face/Off Version %s" % proxy.__version__, "green"))
    logger.info(colored("I'd like to take his face... off.", "green"))
    logger.info(colored("-------------------------------------------------", "green"))

    global_faceoff_config = general_config()
    global_faceoff_config.domain_name = general_json_config.get('domain_name', None)
    env_domain = os.environ.get("FACEOFF_DOMAIN_NAME", None)
    overrode_domain_from_env = False
    if env_domain is not None:
        global_faceoff_config.domain_name = env_domain
        overrode_domain_from_env = True
    if global_faceoff_config.domain_name is None:
        logger.warning("No domain name in your config, which could cause problems with facaded APIs that need it")
    else:
        logger.info("Configuring Face/Off with domain name: %s, Overrode from FACEOFF_DOMAIN_NAME env variable: %s"
                    % (global_faceoff_config.domain_name, overrode_domain_from_env))

    global_faceoff_config.timeout = float(general_json_config.get('timeout', '.500'))
    logger.info("Configuring Face/Off with timeout of %s" % global_faceoff_config.timeout)
    application_object_name = general_json_config.get('application_object', None)
    if application_object_name is not None:
        try:
            application_object = load_class_from_name(application_object_name)
            global_faceoff_config.application_object = application_object
            logger.info("Configuring Face/Off with application object: %s " % application_object_name)
        except Exception as e:
            errors = "some"
            logger.error("Could not load application object with name %s" % (application_object_name,))
    else:
        global_faceoff_config.application_object = None
        logger.warning("No application object!  Can't use AppKeyProvider authentication handle")

    analytic_classes = general_json_config.get('analytics', [])
    analytics = ChainedAnalytics()
    for analytic_class in analytic_classes:
        if isinstance(analytic_class, dict):
            function = analytic_class.get('function')
            parameters = analytic_class.get('parameters')
        elif isinstance(analytic_class, str):
            function = analytic_class
            parameters = {}
        else:
            logger.error("Could not load analytics class with config %s" % (analytic_class,))
            errors = "some"
            continue
        try:
            analytics.add_analytic(load_class_from_name(function)(**parameters))
        except Exception as e:
            errors = "some"
            logger.error("Could not load analytics class with name %s because of %s" % (analytic_class, e))

    global_faceoff_config.analytics = analytics
    logger.info("Configuring Face/Off with analytics classes: %s", analytic_classes)

    try:
        user_provider_config = general_json_config.get('user_provider', {})
        user_function = user_provider_config.get('function')
        parameters = user_provider_config.get('parameters', {})
        global_faceoff_config.user_provider = load_class_from_name(user_function)(**parameters)
        logger.info("Configuring Face/Off with user provider config: %s", user_provider_config)

    except Exception as e:
        if general_json_config.get('user_provider') is None:
            logger.warning("There is no user provider class, this means Face/Off can't protect endpoints by consumer keys")
        else:
            errors = "some"
            logger.error("Could not load user provider class with config %s" % (general_json_config.get('user_provider')))

    user_provider_servers = general_json_config.get('user_provider_servers', [])
    global_faceoff_config.user_provider_servers = user_provider_servers

    health_check = general_json_config.get('health_check_storage', {}).get('implementation', None)
    if health_check is not None:
        redis_health_check_config = general_json_config.get('health_check_storage')
        global_faceoff_config.health_check = load_class_from_name(redis_health_check_config.get('implementation'))(**general_json_config.get('health_check_storage'))

    else:
        logger.warning("You have no healthcheck implementation.  This probably means you have no healthchecks!")
        global_faceoff_config.health_check = None

    health_check_url = general_json_config.get("self_health_check_url", "proxy-check")
    logger.info("Proxy self-check URL is %s", health_check_url)

    if "cache" in general_json_config:
        global_faceoff_config.cache = CacheManager(general_json_config.get('cache'))
    else:
        global_faceoff_config.cache = NoCacheManager()

    application_cache().load_from_db()  # fill application_cache
    logger.info("Application in memory cache loaded with %s applications" % (len(application_cache().all()),))
    stop = datetime.now()
    if errors == "some":
        color = "red"
    else:
        color = "green"

    global_faceoff_config.configuration_complete = True
    global_faceoff_config.errors_during_init = errors == "some"

    logger.info(colored("-------------------------------------------------", color))
    logger.info(colored("Face/Off started in %sms with %s errors" % ((stop - start).microseconds, errors), color))
    logger.info(colored("-------------------------------------------------", color))
 def init_analytics(cls, **initkwargs):
     initkwargs["analytics"] = general_config().analytics
     return initkwargs
def authorization(request):
    
    try:
        analytics = general_config().analytics

        client_id = request.GET.get('client_id')
        response_type = request.GET.get('response_type')
        state = request.GET.get('state', '')

        auth_failed = False
        
        try:
            provider = AppKeyProvider()
            a = provider.authorize(request)
            redirect_uri = request.GET.get('redirect_uri', None)
            if redirect_uri is not None:
                if redirect_uri != a.redirect_uri:
                    # require them to be equal for now
                    redirect_uri = None
        except Exception as e:
            logger.error("AUTH ERROR WAS %s" % e)
            auth_failed = True
        if isinstance(a, AuthenticationError):
            auth_failed = True
            
        if auth_failed:
            err = {"error": "4030", "message": "Client id not valid"}
            analytics.increment("proxy.access_tokens.views.authorization.client_id_not_valid.4030.fail")
            return HttpResponse(json.dumps(err), content_type="application/json", status=403)
            
        if response_type == "token":
            if 'facebook_access_token' in request.REQUEST or 'device_id' in request.REQUEST or 'ias_user_id' in request.REQUEST:
                user = None
                try:
                    user = general_config().user_provider.find(facebook_access_token=request.REQUEST.get('facebook_access_token'), device_id=request.REQUEST.get('device_id'), ias_user_id=request.REQUEST.get('ias_user_id'), headers=provider.get_headers(a))
                except Exception as e:
                    err = {"error": "500", "message": "connection error"}
                    analytics.increment("proxy.access_tokens.views.authorization.user_provider_connection_error.500.fail")
                    return HttpResponse(json.dumps(err), content_type="application/json", status=500)

                if user is None:
                    err = {"error": "4032", "message": "user not found"}
                    analytics.increment("proxy.access_tokens.views.authorization.user_not_found.4032.fail")
                    return HttpResponse(json.dumps(err), content_type="application/json", status=403)

                if 'facebook_access_token' in request.REQUEST:
                    analytics.increment("proxy.access_tokens.views.authorization.param.facebook_access_token")
                if 'device_id' in request.REQUEST:
                    analytics.increment("proxy.access_tokens.views.authorization.param.device_id")
                if 'ias_user_id' in request.REQUEST:
                    analytics.increment("proxy.access_tokens.views.authorization.param.ias_user_id")

                t = AccessToken()
                t.user = user.get('id')
                t.application = a
                t.is_active = True
                t.save()

                analytics.increment("proxy.access_tokens.views.authorization.token_created.success")

                if redirect_uri is not None:
                    return redirect("%s#access_token=%s&state=%s&token_type=bearer" % (redirect_uri, t.token, state))
                else:
                    resp_dict = {'access_token': t.token,
                                 'state': state,
                                 'token_type': 'bearer'}
                    return HttpResponse(json.dumps(resp_dict), content_type='application/json')
            else:
                analytics.increment("proxy.access_tokens.views.authorization.parameter_missing.422.fail")
                return HttpResponse("Required Parameter Missing", status=422)
        else:

            analytics.increment("proxy.access_tokens.views.authorization.token_auth_not_implmented.501.fail")

            err = {"error": "501", "message": "Token auth not implemented yet"}
            return HttpResponse(json.dumps(err), content_type="application/json", status=501)

    except Exception as e:
        analytics.increment("proxy.access_tokens.views.authorization.general_failure.%s.500.fail" % e.__class__.__name__)
        err = {"error": "500", "message": "Server Error"}
        return HttpResponse(json.dumps(err), content_type="application/json", status=500)
 def store_with_key(self, value):
     for hash_key in self.build_key():
         general_config().cache.store.store(hash_key, value)
 def testFaceoffCustomHeaders(self):
     response = self.client.get("/custom_headers")
     self.assertIn(b"HTTP_X_FORWARDED_HOST", response.content)
     self.assertEqual("HTTP_X_FORWARDED_HOST:%s" % general_config().domain_name, response.content.decode('utf-8'))
 def invalidate_with_key(self):
     general_config().cache.store.invalidate(self.build_key())
 def get_with_key(self):
     return general_config().cache.store.retrieve(self.build_key())
 def store_with_key(self, value):
     general_config().cache.store.store(self.build_key(), value)
 def invalidate_with_key(self):
     for hash_key in self.build_key():
         general_config().cache.store.invalidate(hash_key)