john pfeiffer
  • Home
  • Categories
  • Tags
  • Archives

oauth signature library digital signature hmac

# 2013-03-06 johnpfeiffer
# http://oauth.net/code/ (python oauth v1 library as a reference)
# base_string http://googlecodesamples.com/oauth_playground/
# signature http://oauth.googlecode.com/svn/code/javascript/example/signature.html


class OAuth_Signature():

    method = 'GET'     # must be uppercase
    base_url = 'https://www.google.com/accounts/OAuthGetRequestToken'
    signature_method  = 'HMAC-SHA1'
    oauth_version = '1.0'

#    SCOPE = 'https://www.google.com/calendar/feeds/'
    consumer_secret = 'anonymous'

    oauth_nonce = ''
    oauth_timestamp = ''

    base_string = ''
    signature = ''


# TODO: xoauth_displayname parameter to improve google login prompt

    def __init__( self , parameters ):
        """generalized method for signing an oauth request"""

        self.oauth_nonce = self.generate_nonce( 16 )
        self.oauth_timestamp = self.generate_timestamp()
        self.parameters = parameters


        unencoded_parameters = list()
        unencoded_parameters.append( 'oauth_consumer_key=' + self.consumer_secret )
        unencoded_parameters.append( 'oauth_nonce=' + self.oauth_nonce )
        unencoded_parameters.append( 'oauth_signature_method=' + self.signature_method )
        unencoded_parameters.append( 'oauth_timestamp=' + self.oauth_timestamp )
        unencoded_parameters.append( 'oauth_version=' + self.oauth_version )

        for key, value in parameters.iteritems():
            unencoded_parameters.append( key + '=' + self.encoded( value ) )        # double encoding required?


        unencoded_parameters_sorted = sorted( unencoded_parameters )

        unencoded_parameters_sorted_string = '&'.join( unencoded_parameters_sorted )

        encoded_parameters_string = self.encoded( unencoded_parameters_sorted_string )

        self.base_string = self.method.upper() + '&' + self.encoded( self.base_url ) + '&' + encoded_parameters_string

        self.signature = self.generate_signature()



    def display_status( self ):
        print 'consumer key: %s' % self.consumer_secret
        print 'nonce: %s' % self.oauth_nonce
        print 'signature_method: %s' % self.signature_method
        print 'timestamp: %s' % self.oauth_timestamp
        print 'base_string: %s' % self.base_string
        print 'signature: %s' % self.signature



    def generate_signature( self ):
        import hmac
        import hashlib
        import base64

        key = self.consumer_secret + '&'
        hashed = hmac.new( key, self.base_string , hashlib.sha1 )
        return str( base64.b64encode( hashed.digest() ) )


    @staticmethod
    def generate_nonce( nonce_length ):
        import random
        oauth_nonce = ''.join( [str( random.randint( 0, nonce_length ) ) for i in range( nonce_length )] )
        return oauth_nonce

    @staticmethod
    def generate_timestamp():
        import time
        return str( int( time.time() ) )


    @staticmethod
    def encode_parameter( parameter_key , parameter_value ):
        return OAuth_Signature.encoded( parameter_key + '=' + parameter_value + '&' )


    @staticmethod
    def encoded( s ):
        import urllib
        return urllib.quote( s, safe = '~' )            # Escape a URL including any /








        """
    # The added ampersand is also encoded!
    encoded_oauth_consumer_key_value_pair = encoded( 'oauth_consumer_key' + '=' + self.CONSUMER_SECRET + '&' )
    encoded_oauth_nonce_key_value_pair = encoded( 'oauth_nonce' + '=' + self.oauth_nonce + '&'  )
    encoded_oauth_signature_method_key_value_pair = encoded( 'oauth_signature_method' + '=' + SIGNATURE_METHOD + '&' )
    encoded_oauth_timestamp_key_value_pair = encoded( 'oauth_timestamp' + '=' + str( self.oauth_timestamp ) + '&' )
    encoded_oauth_version_key_value_pair = encoded( 'oauth_version' + '=' + OAUTH_VERSION + '&' )
    encoded_scope_key_value_pair = encoded( 'scope' + '=' +  encoded( SCOPE ) )

        # manually sorted alphabetically by key, this is essentially concatenating 3 parts: METHOD, URL, ENCODED_PARAMETERS
    base_string = METHOD.upper() + '&' + encoded( BASE_URL ) + '&'

    base_string = base_string + encoded_oauth_consumer_key_value_pair
    base_string = base_string + encoded_oauth_nonce_key_value_pair
    base_string = base_string + encoded_oauth_signature_method_key_value_pair
    base_string = base_string + encoded_oauth_timestamp_key_value_pair
    base_string = base_string + encoded_oauth_version_key_value_pair
    base_string = base_string + encoded_scope_key_value_pair

    print 'GOOD base_string:  %s' % base_string


    key = '%s&' % CONSUMER_SECRET


    import hmac
    import hashlib
    import base64

    hashed = hmac.new( key, base_string , hashlib.sha1 )
    signature = base64.b64encode( hashed.digest() )

    print 'GOOD SIGNATURE: %s' % signature



    TARGET = BASE_URL + "?scope=" + encoded(  SCOPE )

    parameters_as_headers = dict()

    authorization = dict()
    authorization[ 'Authorization'] = 'OAuth realm="", oauth_nonce="%s", oauth_timestamp="%s", ' \
        'oauth_consumer_key="%s", oauth_signature_method="%s", oauth_version="%s", oauth_signature="%s"' \
        % ( oauth_nonce , oauth_timestamp , CONSUMER_SECRET , SIGNATURE_METHOD , OAUTH_VERSION , signature )

    print 'AUTHORIZATION HEADERS: %s' % authorization


    # http://docs.python-requests.org/en/latest/
    import requests
    http = requests.Session()

    response = http.get( TARGET , headers = authorization )
    # print response.headers


    token_parameter = ''
    token_secret_parameter = ''
    if response.status_code != 200:
        print '%s' % response.content
    else:
        token_and_secret = response.content
        token_and_secret_list = token_and_secret.split( '&' )
        token_parameter = token_and_secret_list[0]
        token_secret_parameter = token_and_secret_list[-1]

    print 'TOKEN PARAMETER = %s' % token_parameter
    print 'SECRET PARAMETER = %s' % token_secret_parameter


    # Authorization of the Token

    # GET https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=ab3cd9j4ks73hf7g&hd=mycollege.edu&hl=en&btmpl=mobile
    AUTHORIZATION_URL = 'https://www.google.com/accounts/OAuthAuthorizeToken'

    #response = http.get( AUTHORIZATION_URL + '?' + token_parameter )
    #print '%s' % response.content

    import webbrowser
    webbrowser.open( AUTHORIZATION_URL + '?' + token_parameter )


    ACCESS_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetAccessToken'

    authorization_access = dict()
    authorization_access[ 'Authorization'] = 'OAuth realm="", oauth_nonce="%s", oauth_timestamp="%s", '\
                                      'oauth_consumer_key="%s", oauth_signature_method="%s", oauth_version="%s", oauth_signature="%s"'\
                                      % ( oauth_nonce , oauth_timestamp , CONSUMER_SECRET , SIGNATURE_METHOD , OAUTH_VERSION , signature )

    print 'AUTHORIZATION HEADERS: %s' % authorization


    payload = { 'oauth_consumer_key': CONSUMER_SECRET , 'oauth_token' : }
    http.get( ACCESS_TOKEN_URL , )

            """


def main():

    SCOPE = 'https://www.google.com/calendar/feeds/'

    parameters = { 'scope': SCOPE }

    signature = OAuth_Signature(  parameters )

    signature.display_status()


if __name__ == '__main__':
    main()





# 2013-05-17 alternate but similar to oauth digital signature system
import time
import hmac
import base64
import hashlib

def create_signature( method , path , timestamp, appSecret, queryParams=None ):
    queryString = ''                    # Prepare Base String for Signature
    if queryParams:
        for key in sorted( queryParams.keys() ):
            queryString += key.strip( )
            queryString += ' '
            queryString += queryParams[ key ]
            queryString += ' '
    base_string = method
    base_string += ' '
    base_string += path
    base_string += ' '
    base_string += queryString.strip()
    base_string += ' '
    base_string += str( timestamp )

    hashed = hmac.new( appSecret , base_string , hashlib.sha1 )
    expectedSignature = base64.b64encode( hashed.digest( ) )
    return expectedSignature

def create_headers( method, path, timestamp, appKey, appSecret, queryParams=None ):
    signature = create_signature( method, path, timestamp, appSecret, queryParams )
    headers = { 'X-Signature': signature , 'X-Timestamp': str( timestamp ) , 'X-App-Key': appKey }
    return headers


if __name__ == '__main__':
    queryParams = { 'email': 'john@example.com', 'password': 'MyPassword' } # TODO: password in the header, not a param
    method = 'POST'
    timestamp = 1368825184      # int( time.time() )
    appKey = 'yourKey'
    appSecret = 'secret'

    result = create_signature( method, '/rest/account/login', timestamp, appSecret )    # no params
    print result
    result = create_headers(  method, '/rest/account/login', timestamp, appKey, appSecret, queryParams )
    print result
    result = create_signature( method, '/rest/account/login', timestamp, appSecret, queryParams )
    print result

  • « sort sorted list of dictionaries itemgetter
  • jinja2 template jquery tablesorter appengine example »

Published

May 17, 2013

Category

python

~582 words

Tags

  • digital 1
  • hmac 2
  • library 5
  • oauth 2
  • python 180
  • signature 2