def verify_and_cache_oauth_or_cookie(request): """ For a given request, try to oauth-verify or cookie-verify it. If the request has a valid oauth token, we store all the auth info in a per-request global (for easy access) and return. If the request does not have a valid oauth token, but has a valid http cookie *and* a valid xsrf token, return. Otherwise -- including the cases where there is an oauth token or cookie but they're not valid, raise an OAuthError of one form or another. This function is designed to be idempotent: it's safe (and fast) to call multiple times on the same request. It caches enough per-request information to avoid repeating expensive work. Arguments: request: A 'global' flask var holding the current active request. Raises: OAuthError: are not able to authenticate the current user. (Note we give OAuthError even when we're failing the cookie-based request, which is a bit of abuse of terminology since there's no oauth involved in that step.) """ if hasattr(flask.g, "oauth_map"): # Already called this routine and succeeded, so no need to call again. return # is_valid_request() verifies this request has something in it # that looks like an oauth token. if is_valid_request(request): consumer, token, parameters = validate_token(request) if (not consumer) or (not token): raise OAuthError("Not valid consumer or token") # Store the OAuthMap containing all auth info in the request # global for easy access during the rest of this request. # We do this now because current_req_has_auth_credentials() # accesses oauth_map. flask.g.oauth_map = OAuthMap.get_from_access_token(token.key_) if not util.current_req_has_auth_credentials(): # If our OAuth provider thinks you're logged in but the # identity providers we consume (Google/Facebook) # disagree, we act as if our token is no longer valid. del flask.g.oauth_map raise NotLoggedInError("verifying oauth token") # (We can do all the other global-setting after # current_req_has_auth_credentials.) # Store enough information from the consumer token that we can # do anointed checks. # TODO(csilvers): is it better to just store all of # 'consumer'? Seems too big given we just need to cache this # one piece of information right now. flask.g.is_anointed = consumer.anointed elif util.allow_cookie_based_auth(): # TODO(csilvers): simplify; this duplicates a lot of calls # (current_req_has_auth_credentials calls allow_cookie_based_auth too). # Would suffice to call util._get_current_user_id_from_cookies_unsafe() # and maybe auth_util.current_oauth_map_from_session_unsafe() as well. if not util.current_req_has_auth_credentials(): raise NotLoggedInError("verifying cookie values") else: raise NotLoggedInError("looking at oauth headers and cookies")
def verify_and_cache_oauth_or_cookie(request): """ For a given request, try to oauth-verify or cookie-verify it. If the request has a valid oauth token, we store all the auth info in a per-request global (for easy access) and return. If the request does not have a valid oauth token, but has a valid http cookie *and* a valid xsrf token, return. Otherwise -- including the cases where there is an oauth token or cookie but they're not valid, raise an OAuthError of one form or another. This function is designed to be idempotent: it's safe (and fast) to call multiple times on the same request. It caches enough per-request information to avoid repeating expensive work. Arguments: request: A 'global' flask var holding the current active request. Raises: OAuthError: are not able to authenticate the current user. (Note we give OAuthError even when we're failing the cookie-based request, which is a bit of abuse of terminology since there's no oauth involved in that step.) """ if hasattr(flask.g, "oauth_map"): # Already called this routine and succeeded, so no need to call again. return # is_valid_request() verifies this request has something in it # that looks like an oauth token. if is_valid_request(request): consumer, token, parameters = validate_token(request) if (not consumer) or (not token): raise OAuthError("Not valid consumer or token") # Store the OAuthMap containing all auth info in the request # global for easy access during the rest of this request. # We do this now because current_req_has_auth_credentials() # accesses oauth_map. flask.g.oauth_map = OAuthMap.get_from_access_token(token.key_) if not util.current_req_has_auth_credentials(): # If our OAuth provider thinks you're logged in but the # identity providers we consume (Google/Facebook) # disagree, we act as if our token is no longer valid. del flask.g.oauth_map raise NotLoggedInError("verifying oauth token") # Child users cannot authenticate against our API via oauth unless the # oauth consumer is anointed by us. This stops children from approving # third party app data access. if not consumer.anointed and user_util.is_current_user_child(): del flask.g.oauth_map raise NotLoggedInError("under-13 accounts are denied API access") # (We can do all the other global-setting after # current_req_has_auth_credentials.) # Store enough information from the consumer token that we can # do anointed checks. # TODO(csilvers): is it better to just store all of # 'consumer'? Seems too big given we just need to cache this # one piece of information right now. flask.g.is_anointed = consumer.anointed elif util.allow_cookie_based_auth(): # TODO(csilvers): simplify; this duplicates a lot of calls # (current_req_has_auth_credentials calls allow_cookie_based_auth too). # Would suffice to call util._get_current_user_id_from_cookies_unsafe() # and maybe auth_util.current_oauth_map_from_session_unsafe() as well. if not util.current_req_has_auth_credentials(): raise NotLoggedInError("verifying cookie values") else: raise NotLoggedInError("looking at oauth headers and cookies")