Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create session token for API rest using python #19

Closed
AnnBenavides opened this issue Nov 4, 2019 · 3 comments
Closed

Create session token for API rest using python #19

AnnBenavides opened this issue Nov 4, 2019 · 3 comments

Comments

@AnnBenavides
Copy link

AnnBenavides commented Nov 4, 2019

Hello, first of all sorry for posting here this issue, i didn't found an API rest repository to ask there. So if it's a problem placing this here just tell me an i'll delete this post.

Then, my issue is to make an API rest with Tornado (Python) and i have problems with the signature (i guess?) in the first step of creating a session token.

Let me show you my code on python 3.6:

  • Here is the POST asynchronous method
    async def post_create_session(self): #TODO test
        url = "{}/{}".format(self.API_HOST, 'session')
        gen = self.generate_signature(None, None)
        parameters = {
            'application_id': '{}'.format(self.app_id),
            'auth_key': self.auth_key,
            'timestamp': gen[0],
            'nonce': gen[1],
            'signature': gen[2]
        }
        headers = {
            'Content-Type': 'application/json',
            'CB-Token': '<TOKEN>'
        }
        request = HTTPRequest(
            url,
            method='POST',
            headers=headers,
            body=json.dumps(parameters)
        )
        response = await self.application.http_client.fetch(request)
        if response.code == 200:
            json_response = json.loads(response.body.decode('utf-8'))
            self.set_status(200)
            self.finish({
                'results': json_response
            })
        else:
            self.set_status(response.code)
            self.finish({'error': json.loads(response.body.decode('utf-8'))})
  • This is the signature generator:
    def generate_signature(self, user_login, user_pwd):
        nonce = self.generate_nonce()
        timestamp = self.generate_timestamp()
        signature_params = 'application_id={}&auth_key={}&nonce={}&timestamp={}'.format(
            self.app_id, self.auth_key, nonce, timestamp
        )
        if user_login is None or user_pwd is None:
            signature_string = '{}'.format(signature_params)
        else:
            signature_user = 'user[login]={}&user[password]={}'.format(user_login, user_pwd)
            signature_string = '{}&{}'.format(signature_params, signature_user)

        signature = self.hash_hmac_sha1(signature_string, self.auth_secret)
        return timestamp, nonce, signature
  • The HMAC-SHA1 function:
       def hash_hmac_sha1(self, str_input, secure_secret):
        my_secure = bytearray(secure_secret, 'utf-8')
        my_input = bytearray(str_input, 'utf-8')
        my_hmac = hmac.new(my_secure, my_input, hashlib.sha1)
        the_digest = my_hmac.digest()
        return base64.b64encode(the_digest).decode('utf-8')
  • And the nonce and timestamp pickers:
    def generate_nonce(self, length=10):
        """Generate pseudo-random number."""
        return ''.join([str(random.randint(0, 9)) for i in range(length)])

    def generate_timestamp(self):
        """Get seconds since epoch (UTC)."""
        return str(int(time.time()))

Given that, this is my current error, after calling the POST method:

File "<path>\endpoints\session.py", line 102, in post_create_session
    response = await self.application.http_client.fetch(request)
tornado.httpclient.HTTPClientError: HTTP 422: Unprocessable Entity
ERROR:tornado.access:500 POST /session (::1) 71713.50ms

With the follow parameters:

  parameters = {
            'application_id': #string X,
            'auth_key': #string Y,
            'timestamp': '1572908532',
            'nonce': '4102983623',
            'signature': 'GzBqTXHpNcHXJJTVQib0fLkywmE='
        }

So i think there is a problem with the signature generator, but i don't know what to fix. Can you help me?

@DaveLomber
Copy link
Collaborator

Here is a working Python example

import time, random, hmac, urllib, httplib
from hashlib import sha1

nonce = str(random.randint(1, 10000))
timestamp = str(int(time.time()))

signature_raw_body = ("application_id=" + application_id + "&auth_key=" + auth_key + 
            "&nonce=" + nonce + "&timestamp=" + timestamp)

signature = hmac.new(auth_secret, signature_raw_body, sha1).hexdigest()

params = urllib.urlencode({'application_id': application_id, 
                           'auth_key': auth_key, 
                           'timestamp': timestamp, 'nonce' : nonce,
                           'signature' : signature})

conn = httplib.HTTPSConnection("api.connectycube.com")
conn.request("POST", "/session", params, {})
response = conn.getresponse()

Regarding your solution - what I can say so far is the signature looks a bit shorter, could you try the one from our example and check

@AnnBenavides
Copy link
Author

@DaveLomber thank you, it was a great guide. If someone has the same issue, here is my working code for tornado:

    def hash_hmac_sha1(self, str_input, secure_secret):
        byte_secure = bytearray(secure_secret, 'utf-8')
        byte_input = bytearray(str_input, 'utf-8')
        signature = hmac.new(byte_secure, byte_input, sha1).hexdigest()
        return signature

    def generate_signature(self, user_login, user_pwd):
        nonce = str(random.randint(1, 10000))
        timestamp = str(int(time.time()))
        signature_params = 'application_id={}&auth_key={}&nonce={}&timestamp={}'.format(
            self.app_id, self.auth_key, nonce, timestamp
        )
        if user_login is None or user_pwd is None:
            signature_string = '{}'.format(signature_params)
        else:
            signature_user = 'user[login]={}&user[password]={}'.format(user_login, user_pwd)
            signature_string = '{}&{}'.format(signature_params, signature_user)

        signature = self.hash_hmac_sha1(signature_string, self.auth_secret)
        return timestamp, nonce, signature

    async def post_create_session(self): #TODO test
        url = "{}/{}".format(self.API_HOST, 'session')
        gen = self.generate_signature(None, None)
        parameters = {
            'application_id': '{}'.format(self.app_id),
            'auth_key': self.auth_key,
            'nonce': gen[1],
            'timestamp': gen[0],
            'signature': gen[2]
        }
        h = httplib2.Http()
        resp, content = h.request(url, "POST", body=urlencode(parameters))
        if resp.get('status') == '200':
            self.set_status(200)
            self.finish({
                'results': json.loads(content.decode('utf-8'))
            })
        if resp.get('status') == '201':
            self.set_status(201)
            self.finish({
                'results': json.loads(content.decode('utf-8'))
            })
        else:
            self.set_status(resp.status)
            self.finish({'error': json.loads(content.decode('utf-8'))})

@sarpedon333
Copy link

@DaveLomber i believe the api has changed since this issue has been closed. i have tried the proposed approach in here and creating a session for a specific user results in error!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants