Fix PostgreSQL specifc issue with credentials encoding

Decode the encrypted credential value to a string value before handing
it over the database, when running under Python 3.x. Otherwise the
underlying database driver (e.g. psycopg2) might treat it as binary
data.

Change-Id: I87425b54f471e66a9ab3974ab46c4b7f3838b962
Closes-Bug: #1833739
This commit is contained in:
Ralf Haferkamp 2019-09-12 14:44:08 +02:00 committed by Ralf Haferkamp
parent 18e0080af3
commit a4be0cb9e8
3 changed files with 39 additions and 1 deletions

View File

@ -13,6 +13,8 @@
# under the License.
from oslo_db import api as oslo_db_api
import six
from sqlalchemy.ext.hybrid import hybrid_property
from keystone.common import driver_hints
from keystone.common import sql
@ -29,11 +31,24 @@ class CredentialModel(sql.ModelBase, sql.ModelDictMixinWithExtras):
user_id = sql.Column(sql.String(64),
nullable=False)
project_id = sql.Column(sql.String(64))
encrypted_blob = sql.Column(sql.Text(), nullable=True)
_encrypted_blob = sql.Column('encrypted_blob', sql.Text(), nullable=True)
type = sql.Column(sql.String(255), nullable=False)
key_hash = sql.Column(sql.String(64), nullable=True)
extra = sql.Column(sql.JsonBlob())
@hybrid_property
def encrypted_blob(self):
return self._encrypted_blob
@encrypted_blob.setter
def encrypted_blob(self, encrypted_blob):
# Make sure to hand over the encrypted credential as a string value
# to the backend driver to avoid the sql drivers (esp. psycopg2)
# treating this as binary data and e.g. hex-escape it.
if six.PY3 and isinstance(encrypted_blob, six.binary_type):
encrypted_blob = encrypted_blob.decode('utf-8')
self._encrypted_blob = encrypted_blob
class Credential(base.CredentialDriverBase):

View File

@ -21,6 +21,8 @@ from keystone.tests.unit import default_fixtures
from keystone.tests.unit import ksfixtures
from keystone.tests.unit.ksfixtures import database
from keystone.credential.backends import sql as credential_sql
PROVIDERS = provider_api.ProviderAPIs
@ -90,3 +92,15 @@ class SqlCredential(SqlTests):
def test_backend_credential_sql_no_hints(self):
credentials = PROVIDERS.credential_api.list_credentials()
self._validate_credential_list(credentials, self.user_credentials)
def test_backend_credential_sql_encrypted_string(self):
cred_dict = {
'id': uuid.uuid4().hex,
'type': uuid.uuid4().hex,
'hash': uuid.uuid4().hex,
'encrypted_blob': b'randomdata'
}
ref = credential_sql.CredentialModel.from_dict(cred_dict)
# Make sure CredentialModel is handing over a text string
# to the database. To avoid encoding issues
self.assertIsInstance(ref.encrypted_blob, str)

View File

@ -0,0 +1,9 @@
---
fixes:
- |
[`bug 1833739 <https://bugs.launchpad.net/keystone/+bug/1833739>`_]
Fix PostgreSQL specifc issue with storing encrypted credentials. In
Python 3 the psycopg2 module treats bytes strings as binary data. This
causes issues when storing encrypted credentials in the Database.
To fix this isseu the credentials sql backend is updated to encode the
credential into a text string before handing it over to the database.