-
Notifications
You must be signed in to change notification settings - Fork 430
Deserialization error (Invalid Padding) after django_orm.CredentialsField.to_python #142
Comments
Oh, here is the serialization of my Credentials Django model that stores the oauth2client.django_orm.CredentialsField value:
So pretty hard to deserialize... Shouldn't my credential field be dumped to JSON using
from oauth2client.django_orm.CredentialsField.get_db_prep_value ??? |
Okay I figured out that the CredentialsField field requires a value_to_string method so Django 1.7 knows how to dump it correctly. I ended up with the following code to get it working: def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_prep_value(value) and changed get_db_prep_value to get_prep_value : def get_prep_value(self, value):
if value is None:
return None
return base64.b64encode(pickle.dumps(value)) I have to test this update in a dedicated virtualenv before making a pull request. If this looks wrong to anyone please let me know ;) Cheers, |
Hey, I'm having the same problem but couldn't make it work with the solution you point out. Did you just changed those two functions??? Please, provide some more details |
Hello Alejandro, Here is my field full code for the CredentialsField: class CredentialsField(models.Field):
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
if 'null' not in kwargs:
kwargs['null'] = True
super(CredentialsField, self).__init__(*args, **kwargs)
def get_internal_type(self):
return "TextField"
def to_python(self, value):
if value is None:
return None
if isinstance(value, oauth2client.client.Credentials):
return value
return pickle.loads(base64.b64decode(value))
def get_prep_value(self, value):
if value is None:
return None
return base64.b64encode(pickle.dumps(value))
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_prep_value(value)
#def deconstruct(self):
# name, path, args, kwargs = super(CommaSepField, self).deconstruct()
# return name, path, args, kwargs Hope this helps :) Cheers, |
Hello Quentin, thanks for the quick response! I tried using your code, but still get an incorrect padding error. I'm using Django 1.7.3 with python 3.4.3. Because of this reason, I had to change the metaclass definition from: class CredentialsField(models.Field):
__metaclass__ = models.SubfieldBase to class CredentialsField(models.Field, metaclass=models.SubfieldBase): This because of python 3 change in metaclass definition: https://docs.python.org/3/whatsnew/3.0.html#changed-syntax Do you know what may be happening, or what should I try to do? Many thanks in advance. alejandro. |
Hello Alejandro, I had the same problem. I'm using Django 1.8 with Python 3.4 and the padding errors occured when I used the PostgreSQL backend (for some strange reason the padding errors didn't happen when SQLite backend was used). I ended up with following solution, which seems to work for both PostgresSQL and SQLite backends: class FixedCredentialsField(models.Field, metaclass=models.SubfieldBase):
'''
currently, CredentialsField does not work correctly because:
* __metaclass__ attribute is no longer used in Python 3.
* using get_db_prep_value instead of get_prep_value may cause problems,
see: https://github.com/google/oauth2client/issues/142 for details.
* the data needs to be converted to bytes before processing via base64
(this affects mostly Python 3).
'''
def __init__(self, *args, **kwargs):
if 'null' not in kwargs:
kwargs['null'] = True
super().__init__(*args, **kwargs)
def get_internal_type(self):
return 'TextField'
def to_python(self, value):
if value is None:
return None
if isinstance(value, Credentials):
return value
# Ensure that the string input is converted to bytes
if isinstance(value, str):
value = bytes(value, 'utf-8')
return pickle.loads(base64.b64decode(value))
def get_prep_value(self, value):
if value is None:
return None
# Ensure that the representation is a string
return base64.b64encode(pickle.dumps(value)).decode('utf-8')
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_prep_value(value) Please keep in mind this is Python 3 only and wouldn't work on Python 2. Hope it helps anyone. |
Where does the fix occur? What version of |
|
@szopu Can you provide a diff with the current source or point to a fork that you're currently using? |
@dhermes here is the diff (the autogenerated link above is to outdated commit): master...szopu:django-credentials-field-py3-fix I refactored it to make it also Python 2 compatible, and also used I can create PR if that's OK. |
Please do. Note also that there are |
Issue #142: CredentialField Python 3 fix
I just run into this issue. When is the next release expected? |
It's up to @nathanielmanistaatgoogle Here is our most recent release schedule:
@craigcitro Our last two releases have been automatic via Travis.
|
|
Gotcher. I'll leave it alone for now, but will update if people request other formats. Thanks! |
@nagyv: to the extent that "it is up to [me]", we release when we are told it would be helpful to release, and/or when we feel like it. I take it that it would be helpful to you for a release to be made? I therefore decree: release! |
I'm super busy until about next Friday (October 23). Someone else can do the release / release notes if it's desired before then. |
Hi guys !
I am using google-api-python-client to deal with Google Analytics API. google-api-python-client uses oauth2client to deal with Google's OAuth 2 authentication tokens (which are saved in my Django PostgreSQL DB).
I have created tests which used to pass with Django==1.6.5 and google-api-python-client==1.2 but now fail. I run my test with a fixture containing a model using a oauth2client.django_orm.CredentialsField field. Here is my full stack trace generated when the test is run:
The code line from oauth2client.django_orm.CredentialsField.to_python (line 47):
which should work fine with this code from oauth2client.django_orm.CredentialsField.get_db_prep_value (line 52):
My Django text fixture is created using manage.py dumpdata. I am using oauth2client==1.4.6.
Thanks for your support!!
The text was updated successfully, but these errors were encountered: