Example #1
0
def access_token():

    oauth_server, oauth_request = initialize_server_request(request)

    if oauth_server is None:
        return oauth_error_response(OAuthError('Invalid request parameters.'))

    try:
        # Create our access token
        token = oauth_server.fetch_access_token(oauth_request)
        if not token:
            return oauth_error_response(OAuthError("Cannot find corresponding access token."))

        # Grab the mapping of access tokens to our identity providers
        oauth_map = OAuthMap.get_from_request_token(oauth_request.get_parameter("oauth_token"))
        if not oauth_map:
            return oauth_error_response(OAuthError("Cannot find oauth mapping for request token."))

        oauth_map.access_token = token.key_
        oauth_map.access_token_secret = token.secret

        oauth_map.put()
        # Flush the "apply phase" of the above put() to ensure that subsequent
        # retrievals of this OAuthmap returns fresh data. GAE's HRD can
        # otherwise take a second or two to propagate the data, and the
        # client may use the access token quicker than that.
        oauth_map = OAuthMap.get(oauth_map.key())

    except OAuthError, e:
        return oauth_error_response(e)
Example #2
0
def access_token():

    oauth_server, oauth_request = initialize_server_request(request)

    if oauth_server is None:
        return oauth_error_response(OAuthError('Invalid request parameters.'))

    try:
        # Create our access token
        token = oauth_server.fetch_access_token(oauth_request)
        if not token:
            return oauth_error_response(
                OAuthError("Cannot find corresponding "
                           "access token."))

        # Grab the mapping of access tokens to our identity providers
        oauth_map = OAuthMap.get_from_request_token(
            oauth_request.get_parameter("oauth_token"))
        if not oauth_map:
            return oauth_error_response(
                OAuthError("Cannot find oauth mapping "
                           "for request token."))

        oauth_map.access_token = token.key_
        oauth_map.access_token_secret = token.secret

        oauth_map.put()

    except OAuthError, e:
        return oauth_error_response(e)
Example #3
0
        def wrapper(*args, **kwargs):
            if is_valid_request(request):
                try:
                    consumer, token, parameters = validate_token(request)
                    if (not consumer) or (not token):
                        return oauth_error_response(OAuthError(
                                "Not valid consumer or token"))
                    # If this API method requires an anointed consumer,
                    # restrict any that haven't been manually approved.
                    if require_anointed_consumer and not consumer.anointed:
                        return oauth_error_response(OAuthError(
                                "Consumer access denied."))

                    # Store the OAuthMap containing all auth info in the request
                    # global for easy access during the rest of this request.
                    flask.g.oauth_map = OAuthMap.get_from_access_token(token.key_)

                    if not util.get_current_user_id():
                        # 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.
                        return oauth_error_response(OAuthError(
                            "Unable to get current user from oauth token"))

                except OAuthError, e:
                    return oauth_error_response(e)
Example #4
0
        def wrapper(*args, **kwargs):
            if is_valid_request(request):
                try:
                    consumer, token, parameters = validate_token(request)
                    if consumer and token:

                        # Store the OAuthMap containing all auth info in the request global
                        # for easy access during the rest of this request.
                        flask.g.oauth_map = OAuthMap.get_from_access_token(
                            token.key_)

                        # If this API method requires an anointed consumer,
                        # restrict any that haven't been manually approved.
                        if require_anointed_consumer and not consumer.anointed:
                            flask.g.oauth_map = None

                        if not util.get_current_user_id():
                            # 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.
                            flask.g.oauth_map = None

                except OAuthError, e:
                    # OAuthErrors are ignored, treated as user that's just not logged in
                    pass
Example #5
0
def current_oauth_map_from_session_unsafe():

    # We have to use plain 'ole cookie handling before we switch over to a Flask-only
    # app, at which point we can strictly rely on Flask sessions.
    session_cookie_name = "session"
    session_cookie_value = cookie_util.get_cookie_value(session_cookie_name)
    if session_cookie_value and App.flask_secret_key:

        # Strip double quotes
        if session_cookie_value.startswith("\""):
            session_cookie_value = session_cookie_value[1:-1]

        # Fake little Flask request object to load up the Flask session cookie.
        fake_request = RequestMock(cookies={session_cookie_name: unicode(session_cookie_value)})

        # Flask's sessions are secured by the secret key.
        session_cookie = Session.load_cookie(fake_request, session_cookie_name, secret_key=App.flask_secret_key)
        if session_cookie and session_cookie.has_key("oam"):

            oauth_map_id = session_cookie["oam"]
            oauth_map = OAuthMap.get_by_id_safe(oauth_map_id)
            if oauth_map:
                return oauth_map

    return None
Example #6
0
def current_oauth_map_from_session_unsafe():

    # We have to use plain 'ole cookie handling before we switch over to a Flask-only
    # app, at which point we can strictly rely on Flask sessions.
    session_cookie_name = "session"
    session_cookie_value = cookie_util.get_cookie_value(session_cookie_name)
    if session_cookie_value and App.flask_secret_key:

        # Strip double quotes
        if session_cookie_value.startswith("\""):
            session_cookie_value = session_cookie_value[1:-1]

        # Fake little Flask request object to load up the Flask session cookie.
        fake_request = RequestMock(
            cookies={session_cookie_name: unicode(session_cookie_value)})

        # Flask's sessions are secured by the secret key.
        session_cookie = Session.load_cookie(fake_request,
                                             session_cookie_name,
                                             secret_key=App.flask_secret_key)
        if session_cookie and session_cookie.has_key("oam"):

            oauth_map_id = session_cookie["oam"]
            oauth_map = OAuthMap.get_by_id_safe(oauth_map_id)
            if oauth_map:
                return oauth_map

    return None
Example #7
0
def access_token():

    oauth_server, oauth_request = initialize_server_request(request)

    if oauth_server is None:
        return oauth_error_response(OAuthError('Invalid request parameters.'))

    try:
        # Create our access token
        token = oauth_server.fetch_access_token(oauth_request)
        if not token:
            return oauth_error_response(OAuthError("Cannot find corresponding "
                                                   "access token."))

        # Grab the mapping of access tokens to our identity providers
        oauth_map = OAuthMap.get_from_request_token(
            oauth_request.get_parameter("oauth_token"))
        if not oauth_map:
            return oauth_error_response(OAuthError("Cannot find oauth mapping "
                                                   "for request token."))

        oauth_map.access_token = token.key_
        oauth_map.access_token_secret = token.secret

        oauth_map.put()

    except OAuthError, e:
        return oauth_error_response(e)
Example #8
0
def authorize_token():

    try:
        oauth_server, oauth_request = initialize_server_request(request)

        if oauth_server is None:
            raise OAuthError('Invalid request parameters.')

        # get the request token
        token = oauth_server.fetch_request_token(oauth_request)

        oauth_map = OAuthMap.get_from_request_token(token.key_)
        if not oauth_map:
            raise OAuthError("Unable to find oauth_map from request token "
                             "during authorization.")

        # Get user from oauth map using either FB or Google access token
        user_data = oauth_map.get_user_data()
        if not user_data:
            raise OAuthError("User not logged in during authorize_token "
                             "process.")
        # For now we don't require user intervention to authorize our tokens,
        # since the user already authorized FB/Google. If we need to do this
        # for security reasons later, there's no reason we can't.
        token = oauth_server.authorize_token(token, user_data.user)
        oauth_map.verifier = token.verifier
        oauth_map.put()

        return custom_scheme_redirect(
            oauth_map.callback_url_with_request_token_params(
                include_verifier=True))

    except OAuthError, e:
        return oauth_error_response(e)
Example #9
0
def authorize_token():

    try:
        oauth_server, oauth_request = initialize_server_request(request)

        if oauth_server is None:
            raise OAuthError('Invalid request parameters.')

        # get the request token
        token = oauth_server.fetch_request_token(oauth_request)

        oauth_map = OAuthMap.get_from_request_token(token.key_)
        if not oauth_map:
            raise OAuthError("Unable to find oauth_map from request token "
                             "during authorization.")

        # Get user from oauth map using either FB or Google access token
        user_data = oauth_map.get_user_data()
        if not user_data:
            raise OAuthError("User not logged in during authorize_token "
                             "process.")
        # For now we don't require user intervention to authorize our tokens,
        # since the user already authorized FB/Google. If we need to do this
        # for security reasons later, there's no reason we can't.
        token = oauth_server.authorize_token(token, user_data.user)
        oauth_map.verifier = token.verifier
        oauth_map.put()

        return custom_scheme_redirect(
            oauth_map.callback_url_with_request_token_params(
                include_verifier=True))

    except OAuthError, e:
        return oauth_error_response(e)
Example #10
0
def request_token_callback(provider, oauth_map_id):

    oauth_map = OAuthMap.get_by_id_safe(oauth_map_id)
    if not oauth_map:
        return oauth_error_response(OAuthError("Unable to find OAuthMap by id during request token callback."))

    if provider == "google":
        return google_request_token_handler(oauth_map)
    elif provider == "facebook":
        return facebook_request_token_handler(oauth_map)
Example #11
0
def request_token_callback(provider, oauth_map_id):

    oauth_map = OAuthMap.get_by_id_safe(oauth_map_id)
    if not oauth_map:
        return oauth_error_response(OAuthError("Unable to find OAuthMap by id during request token callback."))

    if provider == "google":
        return google_request_token_handler(oauth_map)
    elif provider == "facebook":
        return facebook_request_token_handler(oauth_map)
Example #12
0
    def post(self):
        """POST submissions are for username/password based logins to
        acquire an OAuth access token.
        """

        identifier = self.request_string('identifier')
        password = self.request_string('password')
        if not identifier or not password:
            self.render_login_page("Please enter your username and password.")
            return

        user_data = UserData.get_from_username_or_email(identifier.strip())
        if not user_data or not user_data.validate_password(password):
            # TODO(benkomalo): IP-based throttling of failed logins?
            self.render_login_page("Your login or password is incorrect.")
            return

        # Successful login - convert to an OAuth access_token
        oauth_map_id = self.request_string("oauth_map_id", default="")
        oauth_map = OAuthMap.get_by_id_safe(oauth_map_id)
        if not oauth_map:
            self.render_login_page("Unable to find OAuthMap by id.")
            return

        # Mint the token and persist to the oauth_map
        oauth_map.khan_auth_token = AuthToken.for_user(user_data).value
        oauth_map.put()

        # Flush the "apply phase" of the above put() to ensure that subsequent
        # retrievals of this OAuthmap returns fresh data. GAE's HRD can
        # otherwise take a second or two to propagate the data, and the
        # following authorize endpoint redirect below could happen quicker
        # than that in some cases.
        oauth_map = OAuthMap.get(oauth_map.key())

        # Need to redirect back to the http authorize endpoint
        return auth_util.authorize_token_redirect(oauth_map, force_http=True)
Example #13
0
    def post(self):
        """POST submissions are for username/password based logins to
        acquire an OAuth access token.
        """

        identifier = self.request_string('identifier')
        password = self.request_string('password')
        if not identifier or not password:
            self.render_login_page("Please enter your username and password.")
            return

        user_data = UserData.get_from_username_or_email(identifier.strip())
        if not user_data or not user_data.validate_password(password):
            # TODO(benkomalo): IP-based throttling of failed logins?
            self.render_login_page("Your login or password is incorrect.")
            return

        # Successful login - convert to an OAuth access_token
        oauth_map_id = self.request_string("oauth_map_id", default="")
        oauth_map = OAuthMap.get_by_id_safe(oauth_map_id)
        if not oauth_map:
            self.render_login_page("Unable to find OAuthMap by id.")
            return

        # Mint the token and persist to the oauth_map
        oauth_map.khan_auth_token = AuthToken.for_user(user_data).value
        oauth_map.put()

        # Flush the "apply phase" of the above put() to ensure that subsequent
        # retrievals of this OAuthmap returns fresh data. GAE's HRD can
        # otherwise take a second or two to propagate the data, and the
        # following authorize endpoint redirect below could happen quicker
        # than that in some cases.
        oauth_map = OAuthMap.get(oauth_map.key())

        # Need to redirect back to the http authorize endpoint
        return auth_util.authorize_token_redirect(oauth_map, force_http=True)
Example #14
0
def google_token_callback():
    oauth_map = OAuthMap.get_by_id_safe(request.values.get("oauth_map_id"))

    if not oauth_map:
        return oauth_error_response(OAuthError("Unable to find OAuthMap by id."))

    if oauth_map.google_verification_code:
        return oauth_error_response(OAuthError("Request token already has google verification code."))

    oauth_map.google_verification_code = request.values.get("oauth_verifier")

    try:
        oauth_map = retrieve_google_access_token(oauth_map)
    except OAuthError, e:
        return oauth_error_response(e)
Example #15
0
def facebook_token_callback():
    oauth_map = OAuthMap.get_by_id_safe(request.values.get("oauth_map_id"))

    if not oauth_map:
        return oauth_error_response(OAuthError("Unable to find OAuthMap by id."))

    if oauth_map.facebook_authorization_code:
        return oauth_error_response(OAuthError("Request token already has facebook authorization code."))

    oauth_map.facebook_authorization_code = request.values.get("code")

    try:
        oauth_map = retrieve_facebook_access_token(oauth_map)
    except OAuthError, e:
        return oauth_error_response(e)
def facebook_token_callback():
    oauth_map = OAuthMap.get_by_id_safe(request.values.get("oauth_map_id"))

    if not oauth_map:
        return oauth_error_response(OAuthError(
                "Unable to find OAuthMap by id."))

    if oauth_map.facebook_authorization_code:
        return oauth_error_response(OAuthError(
                "Request token already has facebook authorization code."))

    oauth_map.facebook_authorization_code = request.values.get("code")

    try:
        oauth_map = retrieve_facebook_access_token(oauth_map)
    except OAuthBadRequestError, e:
        return pretty_error_response('Unable to log in with Facebook.')
Example #17
0
        def wrapper(*args, **kwargs):
            if is_valid_request(request):
                try:
                    consumer, token, parameters = validate_token(request)
                    if consumer and token:

                        # Store the OAuthMap containing all auth info in the request global
                        # for easy access during the rest of this request.
                        flask.g.oauth_map = OAuthMap.get_from_access_token(token.key_)

                        if not util.get_current_user_id():
                            # 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.
                            flask.g.oauth_map = None

                except OAuthError, e:
                    # OAuthErrors are ignored, treated as user that's just not logged in
                    pass
Example #18
0
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")
Example #19
0
@route("/api/auth/request_token", methods=["GET", "POST"])
@decorators.manual_access_checking
def request_token():

    oauth_server, oauth_request = initialize_server_request(request)

    if oauth_server is None:
        return oauth_error_response(OAuthError('Invalid request parameters.'))

    try:
        # Create our request token
        token = oauth_server.fetch_request_token(oauth_request)
    except OAuthError, e:
        return oauth_error_response(e)

    if OAuthMap.get_from_request_token(token.key_):
        logging.error("OAuth key %s already used" % token.key_)
        params = dict([(key, request.get(key)) for key in request.arguments()])
        logging.info("params: %r" % params)
        logging.info("Authorization: %s", request.headers.get('Authorization'))
        return oauth_error_response(OAuthError("OAuth parameters already used."))

    # Start a new OAuth mapping
    oauth_map = OAuthMap()
    oauth_map.request_token_secret = token.secret
    oauth_map.request_token = token.key_
    oauth_map.callback_url = requested_oauth_callback()

    if request.values.get("view") == "mobile":
        oauth_map.view = "mobile"
Example #20
0
# hands off to Google/Facebook to gather the appropriate request tokens.
@route("/api/auth/request_token", methods=["GET", "POST"])
def request_token():

    oauth_server, oauth_request = initialize_server_request(request)

    if oauth_server is None:
        return oauth_error_response(OAuthError('Invalid request parameters.'))

    try:
        # Create our request token
        token = oauth_server.fetch_request_token(oauth_request)
    except OAuthError, e:
        return oauth_error_response(e)

    if OAuthMap.get_from_request_token(token.key_):
        return oauth_error_response(OAuthError("OAuth parameters already used."))

    # Start a new OAuth mapping
    oauth_map = OAuthMap()
    oauth_map.request_token_secret = token.secret
    oauth_map.request_token = token.key_
    oauth_map.callback_url = requested_oauth_callback()
    
    if request.values.get("view") == "mobile":
        oauth_map.view = "mobile"

    oauth_map.put()

    chooser_url = "/login/mobileoauth?oauth_map_id=%s&view=%s" % (oauth_map.key().id(), oauth_map.view)
Example #21
0
@route("/api/auth/request_token", methods=["GET", "POST"])
@decorators.manual_access_checking
def request_token():

    oauth_server, oauth_request = initialize_server_request(request)

    if oauth_server is None:
        return oauth_error_response(OAuthError('Invalid request parameters.'))

    try:
        # Create our request token
        token = oauth_server.fetch_request_token(oauth_request)
    except OAuthError, e:
        return oauth_error_response(e)

    if OAuthMap.get_from_request_token(token.key_):
        logging.error("OAuth key %s already used" % token.key_)
        params = dict([(key, request.get(key)) for key in request.arguments()])
        logging.info("params: %r" % params)
        logging.info("Authorization: %s", request.headers.get('Authorization'))
        return oauth_error_response(OAuthError("OAuth parameters already "
                                               "used."))

    # Start a new OAuth mapping
    oauth_map = OAuthMap()
    oauth_map.request_token_secret = token.secret
    oauth_map.request_token = token.key_
    oauth_map.callback_url = requested_oauth_callback()

    if request.values.get("view") == "mobile":
        oauth_map.view = "mobile"
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")
Example #23
0
@route("/api/auth/request_token", methods=["GET", "POST"])
@decorators.manual_access_checking
def request_token():

    oauth_server, oauth_request = initialize_server_request(request)

    if oauth_server is None:
        return oauth_error_response(OAuthError('Invalid request parameters.'))

    try:
        # Create our request token
        token = oauth_server.fetch_request_token(oauth_request)
    except OAuthError, e:
        return oauth_error_response(e)

    if OAuthMap.get_from_request_token(token.key_):
        logging.error("OAuth key %s already used" % token.key_)
        params = dict([(key, request.get(key)) for key in request.arguments()])
        logging.info("params: %r" % params)
        logging.info("Authorization: %s", request.headers.get('Authorization'))
        return oauth_error_response(
            OAuthError("OAuth parameters already "
                       "used."))

    # Start a new OAuth mapping
    oauth_map = OAuthMap()
    oauth_map.request_token_secret = token.secret
    oauth_map.request_token = token.key_
    oauth_map.callback_url = requested_oauth_callback()

    if request.values.get("view") == "mobile":