def _handle_old_since_redirect(request): """ In order to limit the number of possible combinations of `_since` and `_expected` querystring parameters, and thus maximize the effect of caching, we redirect the clients that arrive here with a very old `_since` value. This simply means that these clients will have to iterate and compare the local timestamps of the whole list of changes instead of a filtered subset. https://searchfox.org/mozilla-central/rev/b58ca450/services/settings/remote-settings.js#299 See https://bugzilla.mozilla.org/show_bug.cgi?id=1529685 and https://bugzilla.mozilla.org/show_bug.cgi?id=1665319#c2 """ try: # request.validated is not populated yet (resource was not instantiated yet, # we want to bypass storage). qs_since_str = request.GET.get("_since", "") qs_since = int(qs_since_str.strip('"')) except ValueError: # Will fail later during resource querystring validation. return settings = request.registry.settings max_age_since = int(settings.get("changes.since_max_age_days", 21)) if max_age_since < 0: # Redirect is disabled. return min_since_dt = datetime.now() - timedelta(days=max_age_since) min_since = min_since_dt.timestamp() * 1000 if qs_since >= min_since: # Since value is recent. No redirect. return http_scheme = settings.get("http_scheme") or "https" http_host = settings.get("changes.http_host", request.registry.settings.get("http_host")) host_uri = f"{http_scheme}://{http_host}" redirect = host_uri + request.matched_route.generate(request.matchdict) queryparams = request.GET.copy() del queryparams["_since"] if queryparams: redirect += "?" + urlencode(queryparams) # Serve a redirection, with optional cache control headers. response = httpexceptions.HTTPTemporaryRedirect(redirect) cache_seconds = int( settings.get("changes.since_max_age_redirect_ttl_seconds", 86400)) if cache_seconds >= 0: response.cache_expires(cache_seconds) raise response
def get_login(request): """Initiates to login dance for the specified scopes and callback URI using appropriate redirections.""" # Settings. provider = request.matchdict["provider"] settings_prefix = "multiauth.policy.%s." % provider issuer = request.registry.settings[settings_prefix + "issuer"] client_id = request.registry.settings[settings_prefix + "client_id"] userid_field = request.registry.settings.get(settings_prefix + "userid_field") state_ttl = int( request.registry.settings.get(settings_prefix + "state_ttl_seconds", DEFAULT_STATE_TTL_SECONDS)) state_length = int( request.registry.settings.get(settings_prefix + "state_length", DEFAULT_STATE_LENGTH)) # Read OpenID configuration (cached by issuer) oid_config = fetch_openid_config(issuer) auth_endpoint = oid_config["authorization_endpoint"] scope = request.GET["scope"] callback = request.GET["callback"] prompt = request.GET.get("prompt") # Check that email scope is requested if userid field is configured as email. if userid_field == "email" and "email" not in scope: error_details = { "name": "scope", "description": "Provider %s requires 'email' scope" % provider, } raise_invalid(request, **error_details) # Generate a random string as state. # And save it until code is traded. state = random_bytes_hex(state_length) request.registry.cache.set("openid:state:" + state, callback, ttl=state_ttl) # Redirect the client to the Identity Provider that will eventually redirect # to the OpenID token endpoint. token_uri = request.route_url("openid_token", provider=provider) + "?" params = dict(client_id=client_id, response_type="code", scope=scope, redirect_uri=token_uri, state=state) if prompt: # The 'prompt' parameter is optional. params["prompt"] = prompt redirect = "{}?{}".format(auth_endpoint, urllib.parse.urlencode(params)) raise httpexceptions.HTTPTemporaryRedirect(redirect)
def handle_redir(request): rlogger = request.registry.get('logger') storage = request.registry.get('storage') counter = request.registry.get('counter') data = storage.resolve(request.matchdict.get('token')) if data is None: raise http.HTTPNotFound counter.redir(data) rlogger.log(type='redirect', severity=LOG.INFORMATIONAL, msg='redirect', fields=data) raise http.HTTPTemporaryRedirect(location=data['dest_url'])
def get_login(request): """Initiates to login dance for the specified scopes and callback URI using appropriate redirections.""" # Settings. provider = request.matchdict['provider'] settings_prefix = 'multiauth.policy.%s.' % provider issuer = request.registry.settings[settings_prefix + 'issuer'] client_id = request.registry.settings[settings_prefix + 'client_id'] userid_field = request.registry.settings.get(settings_prefix + 'userid_field') state_ttl = int( request.registry.settings.get(settings_prefix + 'state_ttl_seconds', DEFAULT_STATE_TTL_SECONDS)) state_length = int( request.registry.settings.get(settings_prefix + 'state_length', DEFAULT_STATE_LENGTH)) # Read OpenID configuration (cached by issuer) oid_config = fetch_openid_config(issuer) auth_endpoint = oid_config['authorization_endpoint'] scope = request.GET['scope'] callback = request.GET['callback'] # Check that email scope is requested if userid field is configured as email. if userid_field == 'email' and 'email' not in scope: error_details = { 'name': 'scope', 'description': "Provider %s requires 'email' scope" % provider, } raise_invalid(request, **error_details) # Generate a random string as state. # And save it until code is traded. state = random_bytes_hex(state_length) request.registry.cache.set('openid:state:' + state, callback, ttl=state_ttl) # Redirect the client to the Identity Provider that will eventually redirect # to the OpenID token endpoint. token_uri = request.route_url('openid_token', provider=provider) + '?' params = dict(client_id=client_id, response_type='code', scope=scope, redirect_uri=token_uri, state=state) redirect = '{}?{}'.format(auth_endpoint, urllib.parse.urlencode(params)) raise httpexceptions.HTTPTemporaryRedirect(redirect)
def get_token(request): """Trades the specified code and state against access and ID tokens. The client is redirected to the original ``callback`` URI with the result in querystring.""" # Settings. provider = request.matchdict["provider"] settings_prefix = "multiauth.policy.%s." % provider issuer = request.registry.settings[settings_prefix + "issuer"] client_id = request.registry.settings[settings_prefix + "client_id"] client_secret = request.registry.settings[settings_prefix + "client_secret"] # Read OpenID configuration (cached by issuer) oid_config = fetch_openid_config(issuer) token_endpoint = oid_config["token_endpoint"] code = request.GET["code"] state = request.GET["state"] # State can be used only once. callback = request.registry.cache.delete("openid:state:" + state) if callback is None: error_details = { "name": "state", "description": "Invalid state", "errno": ERRORS.INVALID_AUTH_TOKEN.value, } raise_invalid(request, **error_details) # Trade the code for tokens on the Identity Provider. # Google Identity requires to specify again redirect_uri. redirect_uri = request.route_url("openid_token", provider=provider) data = { "code": code, "client_id": client_id, "client_secret": client_secret, "redirect_uri": redirect_uri, "grant_type": "authorization_code", } resp = requests.post(token_endpoint, data=data) # The IdP response is forwarded to the client in the querystring/location hash. # (eg. callback=`http://localhost:3000/#tokens=`) token_info = resp.text.encode("utf-8") encoded_token = base64.b64encode(token_info) redirect = callback + urllib.parse.quote(encoded_token.decode("utf-8")) raise httpexceptions.HTTPTemporaryRedirect(redirect)
def get_token(request): """Trades the specified code and state against access and ID tokens. The client is redirected to the original ``callback`` URI with the result in querystring.""" # Settings. provider = request.matchdict['provider'] settings_prefix = 'multiauth.policy.%s.' % provider issuer = request.registry.settings[settings_prefix + 'issuer'] client_id = request.registry.settings[settings_prefix + 'client_id'] client_secret = request.registry.settings[settings_prefix + 'client_secret'] # Read OpenID configuration (cached by issuer) oid_config = fetch_openid_config(issuer) token_endpoint = oid_config['token_endpoint'] code = request.GET['code'] state = request.GET['state'] # State can be used only once. callback = request.registry.cache.delete('openid:state:' + state) if callback is None: error_details = { 'name': 'state', 'description': 'Invalid state', 'errno': ERRORS.INVALID_AUTH_TOKEN.value, } raise_invalid(request, **error_details) # Trade the code for tokens on the Identity Provider. # Google Identity requires to specify again redirect_uri. redirect_uri = request.route_url('openid_token', provider=provider) + '?' data = { 'code': code, 'client_id': client_id, 'client_secret': client_secret, 'redirect_uri': redirect_uri, 'grant_type': 'authorization_code', } resp = requests.post(token_endpoint, data=data) # The IdP response is forwarded to the client in the querystring/location hash. # (eg. callback=`http://localhost:3000/#tokens=`) redirect = callback + urllib.parse.quote(resp.text) raise httpexceptions.HTTPTemporaryRedirect(redirect)
def redirect_to_version(request): """Redirect to the current version of the API.""" raise httpexceptions.HTTPTemporaryRedirect( '/%s/%s' % (API_VERSION, request.matchdict['path']))
def boot_to_author(request): raise http.HTTPTemporaryRedirect(location='/author/%s/' % api_version)
def widget(context, request): location = request.resource_url(context, 'viewer', query=request.GET) return httpexceptions.HTTPTemporaryRedirect(location=location)