2017-04-21 1 views
2

J'essaye d'écrire un petit script en python pour me connecter à BOX, mais ça continue à me donner cette erreur: l'objet 'NoneType' n'a pas de attribut 'encoder'Boxsdk JWTAuth continue à me donner cette erreur: l'objet 'NoneType' n'a pas d'attribut 'encoder'

Au début, je pensais qu'il était causé lorsque j'ai codé la phrase secrète, mais il semble que ce n'est pas le cas. Le script échoue lorsque j'essaie de m'authentifier avec access_token = auth.authenticate_instance(). Si je cours le script sans cela, cela semble fonctionner. Qu'est-ce qui peut causer cela?

Merci d'avance pour toute aide que vous pouvez fournir.

C'est ce que j'ai:

import keyring 
from boxsdk import JWTAuth 
from boxsdk import Client 

def read_tokens(): 
    """Reads authorisation tokens from keyring""" 
    # Use keyring to read the tokens 
    auth_token = keyring.get_password('Box_Auth', '[email protected]') 
    refresh_token = keyring.get_password('Box_Refresh', '[email protected]') 
    return auth_token, refresh_token 


def store_tokens(access_token, refresh_token): 
    """Callback function when Box SDK refreshes tokens""" 
    # Use keyring to store the tokens 
    keyring.set_password('Box_Auth', '[email protected]', access_token) 
    keyring.set_password('Box_Refresh', '[email protected]', refresh_token) 

Passphrase = 'xxxxxxx'; 
my_str_as_bytes = Passphrase.encode('UTF-8','strict') 

auth = JWTAuth(
    client_id='xxxxxxxxxx', 
    client_secret='xxxxxxxx', 
    enterprise_id='xxxxxxx', 
    jwt_key_id='xxxxxxx', 
    rsa_private_key_file_sys_path='/home/Marketscale/keys/private_key2.pem', 
    rsa_private_key_passphrase=my_str_as_bytes, 
    store_tokens=store_tokens, 
) 

access_token = auth.authenticate_instance() 

Ceci est le texte intégral de l'erreur:

Traceback (most recent call last): 
    File "/home/Marketscale/Tests/JWTTest.py", line 37, in <module> 
    access_token = auth.authenticate_instance() 
    File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/jwt_auth.py", line 186, in authenticate_instance 
    return self._auth_with_jwt(self._enterprise_id, 'enterprise') 
    File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/jwt_auth.py", line 158, in _auth_with_jwt 
    return self.send_token_request(data, access_token=None, expect_refresh_token=False)[0] 
    File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 298, in send_token_request 
    self._store_tokens(access_token, refresh_token) 
    File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 233, in _store_tokens 
    self._store_tokens_callback(access_token, refresh_token) 
    File "/home/Marketscale/Tests/JWTTest.py", line 22, in store_tokens 
    keyring.set_password('Box_Refresh', '[email protected]', refresh_token) 
    File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyring/core.py", line 48, in set_password 
    _keyring_backend.set_password(service_name, username, password) 
    File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyrings/alt/file_base.py", line 128, in set_password 
    password_encrypted = self.encrypt(password.encode('utf-8'), assoc) 
AttributeError: 'NoneType' object has no attribute 'encode' 

Répondre

1

Je ne sais pas l'API que vous utilisez du tout, mais quelques-uns pensées sur la base regardant le code:

de travail à travers la trace de la pile du bas vers le haut, vous avez:

File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyrings/alt/file_base.py", line 128, in set_password 
    password_encrypted = self.encrypt(password.encode('utf-8'), assoc) 
AttributeError: 'NoneType' object has no attribute 'encode' 

Ce code est à https://github.com/jaraco/keyrings.alt/blob/master/keyrings/alt/file_base.py, et le mot de passe (que nous savons être None) est le dernier paramètre passé à la fonction set_password. On appelle cela de:

File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyring/core.py", line 48, in set_password 
    _keyring_backend.set_password(service_name, username, password) 

Ce code est à https://github.com/jaraco/keyring/blob/master/keyring/core.py, et le mot de passe est à nouveau le dernier paramètre à la fonction set_password. Ensuite, nous avons:

File "/home/Marketscale/Tests/JWTTest.py", line 22, in store_tokens 
    keyring.set_password('Box_Refresh', '[email protected]', refresh_token) 

.... qui est votre code, donc refresh_token doit avoir été None. Cela signifie que votre stock_tokens doit avoir été appelé avec un refresh_token de None. Suivant:

File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 233, in _store_tokens 
    self._store_tokens_callback(access_token, refresh_token) 

Ceci est à https://github.com/box/box-python-sdk/blob/master/boxsdk/auth/oauth2.py, et signifie encore une fois que _store_tokens a été appelé avec l'ensemble refresh_token Aucun. ... Onwards

File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 298, in send_token_request 
    self._store_tokens(access_token, refresh_token) 

code sur la même page que le dernier, mais maintenant il est un peu plus intéressant:

 url = '{base_auth_url}/token'.format(base_auth_url=API.OAUTH2_API_URL) 
     headers = {'content-type': 'application/x-www-form-urlencoded'} 
     network_response = self._network_layer.request(
      'POST', 
      url, 
      data=data, 
      headers=headers, 
      access_token=access_token, 
     ) 
     if not network_response.ok: 
      raise BoxOAuthException(network_response.status_code, network_response.content, url, 'POST') 
     try: 
      response = network_response.json() 
      access_token = response['access_token'] 
      refresh_token = response.get('refresh_token', None) 
      if refresh_token is None and expect_refresh_token: 
       raise BoxOAuthException(network_response.status_code, network_response.content, url, 'POST') 
     except (ValueError, KeyError): 
      raise BoxOAuthException(network_response.status_code, network_response.content, url, 'POST') 
     self._store_tokens(access_token, refresh_token) 
     return self._access_token, self._refresh_token 

Nous savons donc que self._store_tokens a été appelé avec refresh_token à None, ce qui signifie que expect_refresh_token doit avoir été False, sinon l'exception BoxOAuthException aurait été déclenchée. Et, en effet, si l'on regarde la ligne suivante dans la trace de la pile, nous pouvons voir que:

File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/jwt_auth.py", line 158, in _auth_with_jwt 
    return self.send_token_request(data, access_token=None, expect_refresh_token=False)[0] 

Cela me porte à croire que lorsque vous utilisez JWT Auth, vous ne devriez pas attendre un jeton de rafraîchissement. Et étant donné que le backend de fichier pour le keyring explose lorsque vous lui passez un None comme mot de passe, il semble que vous ayez besoin de gérer le cas None différemment. Donc, je vous suggère de changer les store_tokens fournir une fonction vous afin que soit il ignore le jeton de rafraîchissement si c'est None, à savoir:

def store_tokens(access_token, refresh_token): 
    """Callback function when Box SDK refreshes tokens""" 
    # Use keyring to store the tokens 
    keyring.set_password('Box_Auth', '[email protected]', access_token) 
    if refresh_token is not None: 
     keyring.set_password('Box_Refresh', '[email protected]', refresh_token) 

...ou pour qu'il se transforme en quelque chose que None le back-end de fichier peut keyring gracieusement gérer - peut-être une chaîne vide ferait l'affaire:

def store_tokens(access_token, refresh_token): 
     """Callback function when Box SDK refreshes tokens""" 
     # Use keyring to store the tokens 
     keyring.set_password('Box_Auth', '[email protected]', access_token) 
     if refresh_token is None: 
      refresh_token = "" 
     keyring.set_password('Box_Refresh', '[email protected]', refresh_token) 

Une mise en garde - comme je l'ai dit, je ne sais pas ces API - - ni la boîte un, ni le porte-clés que vous utilisez. Mais sur la base du code qui est là, faire quelque chose comme ça sonne comme si ça valait le coup d'essayer.