Issue #171 new

TypeError: character mapping must return integer, None or unicode -- On token request

Anonymous created an issue

Getting the following exception when trying to request a token.

{{{

!nvironment:

Request Method: GET Request URL: http://localhost:8000/api/oauth/request_token/?oauth_nonce=32921052&oauth_timestamp=1291331173&oauth_consumer_key=ghof7av2vu8hal2hek&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature= Python Version:

Traceback: File "/Users/derek/.virtualenvs/optimal-rest/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 100. response = callback(request, callback_args, *callback_kwargs) File "/Users/derek/.virtualenvs/optimal-rest/lib/python2.7/site-packages/piston/authentication.py" in oauth_request_token 130. token = oauth_server.fetch_request_token(oauth_request) File "/Users/derek/.virtualenvs/optimal-rest/lib/python2.7/site-packages/piston/oauth.py" in fetch_request_token 302. self._check_signature(oauth_request, consumer, None) File "/Users/derek/.virtualenvs/optimal-rest/lib/python2.7/site-packages/piston/oauth.py" in _check_signature 393. valid_sig = signature_method.check_signature(oauth_request, consumer, token, signature) File "/Users/derek/.virtualenvs/optimal-rest/lib/python2.7/site-packages/piston/oauth.py" in check_signature 482. built = self.build_signature(oauth_request, consumer, token) File "/Users/derek/.virtualenvs/optimal-rest/lib/python2.7/site-packages/piston/oauth.py" in build_signature 513. hashed = hmac.new(key, raw, sha) File "/usr/local/Cellar/python/2.7/lib/python2.7/hmac.py" in new 133. return HMAC(key, msg, digestmod) File "/usr/local/Cellar/python/2.7/lib/python2.7/hmac.py" in init 72. self.outer.update(key.translate(trans_5C))

Exception Type: TypeError at /api/oauth/request_token/?oauth_nonce=32921052&oauth_timestamp=1291331173&oauth_consumer_key=ghof7av2vu8hal2hek&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature= Exception Value: character mapping must return integer, None or unicode

}}}

Using the oauth2 library -- wondering if that may have something to do with it. {{{

!import os

import cgi import oauth2 as oauth

settings for the local test consumer

CONSUMER_SERVER = os.environ.get("CONSUMER_SERVER") or 'localhost' CONSUMER_PORT = os.environ.get("CONSUMER_PORT") or '8000' print CONSUMER_SERVER , CONSUMER_PORT

fake urls for the test server (matches ones in server.py)

REQUEST_TOKEN_URL = 'http://%s:%s/api/oauth/request_token/' % (CONSUMER_SERVER, CONSUMER_PORT) ACCESS_TOKEN_URL = 'http://%s:%s/api/oauth/access_token/' % (CONSUMER_SERVER, CONSUMER_PORT) AUTHORIZE_URL = 'http://%s:%s/api/oauth/authorize/' % (CONSUMER_SERVER, CONSUMER_PORT)

key and secret granted by the service provider for this consumer application - same as the MockOAuthDataStore

CONSUMER_KEY = 'ghof7av2vu8hal2hek' CONSUMER_SECRET = 'ohhey'

consumer = oauth.Consumer(CONSUMER_KEY, CONSUMER_SECRET) client = oauth.Client(consumer)

Step 1: Get a request token. This is a temporary token that is used for

having the user authorize an access token and to sign the request to obtain

said access token.

resp, content = client.request(REQUEST_TOKEN_URL, "GET") if resp['status'] != '200': raise Exception("Invalid response %s." % resp['status'])

}}}

Comments (4)

  1. Anonymous

    I got the same issue, it comes from an encoding problem of the key/secret of the consumer. The solution is to force the encoding of the key/secret returned from the database to ASCII.

    In the store.py file of Piston, modify the lookup_consumer so it look like this:

    def lookup_consumer(self, key):
        try:
            self.consumer = Consumer.objects.get(key=key)
            self.consumer.key = self.consumer.key.encode('ascii')
            self.consumer.secret = self.consumer.secret.encode('ascii')
            return self.consumer
        except Consumer.DoesNotExist:
            return None
    

    A cleaner way would be to change the storage of the key and the secret from a varchar to a binary storage format. But it requires heavier django patching.

    nbarraille

  2. Ernest Semerda

    You may also need to hack the lookup_token method to encode the 3 CharField values in store.py when signing the request.

        def lookup_token(self, token_type, token):
            if token_type == 'request':
                token_type = Token.REQUEST
            elif token_type == 'access':
                token_type = Token.ACCESS
            try:
                self.request_token = Token.objects.get(key=token,
                                                       token_type=token_type)
    
                # Fix for error "character mapping must return integer, None or unicode"
                # when signing the request. Next 3 lines modded by Ernest Semerda.
                self.request_token.key = self.request_token.key.encode('ascii')
                self.request_token.secret = self.request_token.secret.encode('ascii')
                self.request_token.verifier = self.request_token.verifier.encode('ascii')
    
                return self.request_token
            except Token.DoesNotExist:
                return None
    
  3. Log in to comment