def _exchange_oauth_code_for_access_token(code, redirect_uri=None):
    """Try to exchange an OAuth `code` for a proper access_token.
    
    Following code is based on the PHP API:
    https://github.com/facebook/php-sdk/blob/master/src/base_facebook.php
    """
    if not code:
        return None

    ## Create a default for the redirect_uri:
    ## - when using the JavaScript SDK the default should be ''
    ## - for other pages it should be the URL of the current page.
    if not redirect_uri:
        redirect_uri = ''

    ## We need to remove ``signed_request``, ``code`` and ``state``
    ## GET parameters from the current URL.
    redirect_uri = cleanup_oauth_url(redirect_uri)

    try:
        logger.info('Trying to exchange the code for an access_token. redirect_uri=%r', redirect_uri)
        token_response = FacebookAuthorization.convert_code(code, redirect_uri=redirect_uri)
        expires = token_response.get('expires')
        access_token = token_response['access_token']
    except open_facebook_exceptions.OAuthException, e:
        ## This sometimes fails, but it shouldn't raise exceptions
        ## because this happens when an user deauthorizes your
        ## application and then tries to re-authenticate.
        logger.warn('Exchange of code %r failed.', unicode(e))
Exemple #2
0
def get_facebook_graph(request=None, access_token=None, redirect_uri=None, raise_=False):
    '''
    given a request from one of these
    - js authentication flow (signed cookie)
    - facebook app authentication flow (signed cookie)
    - facebook oauth redirect (code param in url)
    - mobile authentication flow (direct access_token)
    - offline access token stored in user profile

    returns a graph object

    redirect path is the path from which you requested the token
    for some reason facebook needs exactly this uri when converting the code
    to a token
    falls back to the current page without code in the request params
    specify redirect_uri if you are not posting and recieving the code
    on the same page
    '''
    # this is not a production flow, but very handy for testing
    if not access_token and request.REQUEST.get('access_token'):
        access_token = request.REQUEST['access_token']
    # should drop query params be included in the open facebook api,
    # maybe, weird this...
    from open_facebook import OpenFacebook, FacebookAuthorization
    from django.core.cache import cache
    expires = None
    if hasattr(request, 'facebook') and request.facebook:
        graph = request.facebook
        _add_current_user_id(graph, request.user)
        return graph

    # parse the signed request if we have it
    signed_data = None
    if request:
        signed_request_string = request.REQUEST.get('signed_data')
        if signed_request_string:
            logger.info('Got signed data from facebook')
            signed_data = parse_signed_request(signed_request_string)
        if signed_data:
            logger.info('We were able to parse the signed data')

    # the easy case, we have an access token in the signed data
    if signed_data and 'oauth_token' in signed_data:
        access_token = signed_data['oauth_token']

    if not access_token:
        # easy case, code is in the get
        code = request.REQUEST.get('code')
        if code:
            logger.info('Got code from the request data')

        if not code:
            # signed request or cookie leading, base 64 decoding needed
            cookie_name = 'fbsr_%s' % facebook_settings.FACEBOOK_APP_ID
            cookie_data = request.COOKIES.get(cookie_name)

            if cookie_data:
                signed_request_string = cookie_data
                if signed_request_string:
                    logger.info('Got signed data from cookie')
                signed_data = parse_signed_request(signed_request_string)
                if signed_data:
                    logger.info('Parsed the cookie data')
                # the javascript api assumes a redirect uri of ''
                redirect_uri = ''

            if signed_data:
                # parsed data can fail because of signing issues
                if 'oauth_token' in signed_data:
                    logger.info('Got access_token from parsed data')
                    # we already have an active access token in the data
                    access_token = signed_data['oauth_token']
                else:
                    logger.info('Got code from parsed data')
                    # no access token, need to use this code to get one
                    code = signed_data.get('code', None)

        if not access_token:
            if code:
                cache_key = hash_key('convert_code_%s' % code)
                access_token = cache.get(cache_key)
                if not access_token:
                    # exchange the code for an access token
                    # based on the php api
                    # https://github.com/facebook/php-sdk/blob/master/src/base_facebook.php
                    # create a default for the redirect_uri
                    # when using the javascript sdk the default
                    # should be '' an empty string
                    # for other pages it should be the url
                    if not redirect_uri:
                        redirect_uri = ''

                    # we need to drop signed_data, code and state
                    redirect_uri = cleanup_oauth_url(redirect_uri)

                    try:
                        logger.info(
                            'trying to convert the code with redirect uri: %s',
                            redirect_uri)
                        # This is realy slow, that's why it's cached
                        token_response = FacebookAuthorization.convert_code(
                            code, redirect_uri=redirect_uri)
                        expires = token_response.get('expires')
                        access_token = token_response['access_token']
                        # would use cookies instead, but django's cookie setting
                        # is a bit of a mess
                        cache.set(cache_key, access_token, 60 * 60 * 2)
                    except (open_facebook_exceptions.OAuthException, open_facebook_exceptions.ParameterException) as e:
                        # this sometimes fails, but it shouldnt raise because
                        # it happens when users remove your
                        # permissions and then try to reauthenticate
                        logger.warn('Error when trying to convert code %s',
                                    unicode(e))
                        if raise_:
                            raise
                        else:
                            return None
            elif request.user.is_authenticated():
                # support for offline access tokens stored in the users profile
                profile = try_get_profile(request.user)
                access_token = get_user_attribute(
                    request.user, profile, 'access_token')
                if not access_token:
                    if raise_:
                        message = 'Couldnt find an access token in the request or the users profile'
                        raise open_facebook_exceptions.OAuthException(message)
                    else:
                        return None
            else:
                if raise_:
                    message = 'Couldnt find an access token in the request or cookies'
                    raise open_facebook_exceptions.OAuthException(message)
                else:
                    return None

    graph = OpenFacebook(access_token, signed_data, expires=expires)
    # add user specific identifiers
    if request:
        _add_current_user_id(graph, request.user)

    return graph
Exemple #3
0
 def _test_equal(self, url, output):
     converted = cleanup_oauth_url(url)
     self.assertEqual(converted, output)
Exemple #4
0
 def _test_equal(self, url, output):
     converted = cleanup_oauth_url(url)
     self.assertEqual(converted, output)
Exemple #5
0
def get_facebook_graph(request=None, access_token=None, redirect_uri=None, raise_=False):
    """
    given a request from one of these
    - js authentication flow (signed cookie)
    - facebook app authentication flow (signed cookie)
    - facebook oauth redirect (code param in url)
    - mobile authentication flow (direct access_token)
    - offline access token stored in user profile

    returns a graph object

    redirect path is the path from which you requested the token
    for some reason facebook needs exactly this uri when converting the code
    to a token
    falls back to the current page without code in the request params
    specify redirect_uri if you are not posting and recieving the code
    on the same page
    """
    # this is not a production flow, but very handy for testing
    if not access_token and request.REQUEST.get("access_token"):
        access_token = request.REQUEST["access_token"]
    # should drop query params be included in the open facebook api,
    # maybe, weird this...
    from open_facebook import OpenFacebook, FacebookAuthorization
    from django.core.cache import cache

    parsed_data = None
    expires = None
    if hasattr(request, "facebook"):
        graph = request.facebook
        _add_current_user_id(graph, request.user)
        return graph

    if not access_token:
        # easy case, code is in the get
        code = request.REQUEST.get("code")
        if code:
            logger.info("Got code from the request data")
        if not code:
            # signed request or cookie leading, base 64 decoding needed
            signed_data = request.REQUEST.get("signed_request")
            cookie_name = "fbsr_%s" % facebook_settings.FACEBOOK_APP_ID
            cookie_data = request.COOKIES.get(cookie_name)

            if cookie_data:
                signed_data = cookie_data
                # the javascript api assumes a redirect uri of ''
                redirect_uri = ""
            if signed_data:
                logger.info("Got signed data from facebook")
                parsed_data = FacebookAuthorization.parse_signed_data(signed_data)
                if parsed_data:
                    logger.info("Got parsed data from facebook")
                    # parsed data can fail because of signing issues
                    if "oauth_token" in parsed_data:
                        logger.info("Got access_token from parsed data")
                        # we already have an active access token in the data
                        access_token = parsed_data["oauth_token"]
                    else:
                        logger.info("Got code from parsed data")
                        # no access token, need to use this code to get one
                        code = parsed_data.get("code", None)

        if not access_token:
            if code:
                cache_key = "convert_code_%s" % code
                access_token = cache.get(cache_key)
                if not access_token:
                    # exchange the code for an access token
                    # based on the php api
                    # https://github.com/facebook/php-sdk/blob/master/src/base_facebook.php
                    # create a default for the redirect_uri
                    # when using the javascript sdk the default
                    # should be '' an empty string
                    # for other pages it should be the url
                    if not redirect_uri:
                        redirect_uri = ""

                    # we need to drop signed_request, code and state
                    redirect_uri = cleanup_oauth_url(redirect_uri)

                    try:
                        logger.info("trying to convert the code with redirect uri: %s", redirect_uri)
                        # This is realy slow, that's why it's cached
                        token_response = FacebookAuthorization.convert_code(code, redirect_uri=redirect_uri)
                        expires = token_response.get("expires")
                        access_token = token_response["access_token"]
                        # would use cookies instead, but django's cookie setting
                        # is a bit of a mess
                        cache.set(cache_key, access_token, 60 * 60 * 2)
                    except open_facebook_exceptions.OAuthException, e:
                        # this sometimes fails, but it shouldnt raise because
                        # it happens when users remove your
                        # permissions and then try to reauthenticate
                        logger.warn("Error when trying to convert code %s", unicode(e))
                        if raise_:
                            raise
                        else:
                            return None
            elif request.user.is_authenticated():
                # support for offline access tokens stored in the users profile
                profile = request.user.get_profile()
                access_token = getattr(profile, "access_token", None)
                if not access_token:
                    if raise_:
                        message = "Couldnt find an access token in the request or the users profile"
                        raise open_facebook_exceptions.OAuthException(message)
                    else:
                        return None
            else:
                if raise_:
                    message = "Couldnt find an access token in the request or cookies"
                    raise open_facebook_exceptions.OAuthException(message)
                else:
                    return None
Exemple #6
0
def get_facebook_graph(request=None,
                       access_token=None,
                       redirect_uri=None,
                       raise_=False):
    '''
    given a request from one of these
    - js authentication flow (signed cookie)
    - facebook app authentication flow (signed cookie)
    - facebook oauth redirect (code param in url)
    - mobile authentication flow (direct access_token)
    - offline access token stored in user profile

    returns a graph object

    redirect path is the path from which you requested the token
    for some reason facebook needs exactly this uri when converting the code
    to a token
    falls back to the current page without code in the request params
    specify redirect_uri if you are not posting and recieving the code
    on the same page
    '''
    #this is not a production flow, but very handy for testing
    if not access_token and request.REQUEST.get('access_token'):
        access_token = request.REQUEST['access_token']
    # should drop query params be included in the open facebook api,
    # maybe, weird this...
    from open_facebook import OpenFacebook, FacebookAuthorization
    from django.core.cache import cache
    parsed_data = None
    expires = None
    if hasattr(request, 'facebook'):
        graph = request.facebook
        _add_current_user_id(graph, request.user)
        return graph

    if not access_token:
        #easy case, code is in the get
        code = request.REQUEST.get('code')
        if code:
            logger.info('Got code from the request data')
        if not code:
            #signed request or cookie leading, base 64 decoding needed
            signed_data = request.REQUEST.get('signed_request')
            cookie_name = 'fbsr_%s' % facebook_settings.FACEBOOK_APP_ID
            cookie_data = request.COOKIES.get(cookie_name)

            if cookie_data:
                signed_data = cookie_data
                #the javascript api assumes a redirect uri of ''
                redirect_uri = ''
            if signed_data:
                logger.info('Got signed data from facebook')
                parsed_data = FacebookAuthorization.parse_signed_data(
                    signed_data)
                if parsed_data:
                    logger.info('Got parsed data from facebook')
                    #parsed data can fail because of signing issues
                    if 'oauth_token' in parsed_data:
                        logger.info('Got access_token from parsed data')
                        # we already have an active access token in the data
                        access_token = parsed_data['oauth_token']
                    else:
                        logger.info('Got code from parsed data')
                        # no access token, need to use this code to get one
                        code = parsed_data.get('code', None)

        if not access_token:
            if code:
                cache_key = 'convert_code_%s' % code
                access_token = cache.get(cache_key)
                if not access_token:
                    # exchange the code for an access token
                    # based on the php api
                    # https://github.com/facebook/php-sdk/blob/master/src/base_facebook.php
                    # create a default for the redirect_uri
                    # when using the javascript sdk the default
                    # should be '' an empty string
                    # for other pages it should be the url
                    if not redirect_uri:
                        redirect_uri = ''

                    # we need to drop signed_request, code and state
                    redirect_uri = cleanup_oauth_url(redirect_uri)

                    try:
                        logger.info(
                            'trying to convert the code with redirect uri: %s',
                            redirect_uri)
                        #This is realy slow, that's why it's cached
                        token_response = FacebookAuthorization.convert_code(
                            code, redirect_uri=redirect_uri)
                        expires = token_response.get('expires')
                        access_token = token_response['access_token']
                        #would use cookies instead, but django's cookie setting
                        #is a bit of a mess
                        cache.set(cache_key, access_token, 60 * 60 * 2)
                    except open_facebook_exceptions.OAuthException, e:
                        # this sometimes fails, but it shouldnt raise because
                        # it happens when users remove your
                        # permissions and then try to reauthenticate
                        logger.warn('Error when trying to convert code %s',
                                    unicode(e))
                        if raise_:
                            raise
                        else:
                            return None
            elif request.user.is_authenticated():
                #support for offline access tokens stored in the users profile
                profile = request.user.get_profile()
                access_token = getattr(profile, 'access_token', None)
                if not access_token:
                    if raise_:
                        message = 'Couldnt find an access token in the request or the users profile'
                        raise open_facebook_exceptions.OAuthException(message)
                    else:
                        return None
            else:
                if raise_:
                    message = 'Couldnt find an access token in the request or cookies'
                    raise open_facebook_exceptions.OAuthException(message)
                else:
                    return None
Exemple #7
0
def get_facebook_graph(request=None, access_token=None, redirect_uri=None):
    '''
    given a request from one of these
    - js authentication flow (signed cookie)
    - facebook app authentication flow (signed cookie)
    - facebook oauth redirect (code param in url)
    - mobile authentication flow (direct access_token)
    - offline access token stored in user profile
    
    returns a graph object
    
    redirect path is the path from which you requested the token
    for some reason facebook needs exactly this uri when converting the code
    to a token
    falls back to the current page without code in the request params
    specify redirect_uri if you are not posting and recieving the code on the same page
    '''
    #should drop query params be included in the open facebook api, maybe, weird this...
    from open_facebook import OpenFacebook, FacebookAuthorization
    parsed_data = None
    expires = None
    
    if hasattr(request, 'facebook'):
        graph = request.facebook
        _add_current_user_id(graph, request.user)
        return graph
    
    if not access_token:
        #easy case, code is in the get
        code = request.REQUEST.get('code')
        if not code:
            #signed request or cookie leading, base 64 decoding needed
            signed_data = request.REQUEST.get('signed_request')
            cookie_name = 'fbsr_%s' % facebook_settings.FACEBOOK_APP_ID
            cookie_data = request.COOKIES.get(cookie_name)

            if cookie_data:
                signed_data = cookie_data
                #the javascript api assumes a redirect uri of ''
                redirect_uri = ''
            if signed_data:
                parsed_data = FacebookAuthorization.parse_signed_data(signed_data)
                if 'oauth_token' in parsed_data:
                    # we already have an active access token in the data
                    access_token = parsed_data['oauth_token']
                else:
                    # no access token, need to use this code to get one
                    code = parsed_data.get('code', None)

        if not access_token:
            if code:
                #exchange the code for an access token
                #based on the php api 
                #https://github.com/facebook/php-sdk/blob/master/src/base_facebook.php
                
                #create a default for the redirect_uri
                #when using the javascript sdk the default should be '' an empty string
                if not redirect_uri:
                    redirect_uri = ''
                
                #we need to drop signed_request, code and state
                redirect_uri = cleanup_oauth_url(redirect_uri)
                    
                try:
                    logger.info('trying to convert the code with redirect uri: %s', redirect_uri)
                    token_response = FacebookAuthorization.convert_code(code, redirect_uri=redirect_uri)
                    expires = token_response.get('expires')
                    access_token = token_response['access_token']
                except open_facebook_exceptions.OAuthException, e:
                    #this sometimes fails, but it shouldnt raise because it happens when users remove your
                    #permissions and then try to reauthenticate
                    logger.warn('Error when trying to convert code %s', unicode(e))
                    return None
            elif request.user.is_authenticated():
                #support for offline access tokens stored in the users profile
                profile = request.user.get_profile()
                access_token = getattr(profile, 'access_token', None)
                if not access_token:
                    return None 
            else:
                return None