From 1f4f03c995231ce81af83c73d7898acd1b1cea3c Mon Sep 17 00:00:00 2001 From: Josue Kouka Date: Mon, 11 Jan 2016 12:58:42 +0100 Subject: [PATCH] encrypt user credentials (#9534) --- debian/control | 1 + mandayejs/mandaye/models.py | 51 +++++++++++++++++++++++++++++++++++++++++++-- mandayejs/mandaye/utils.py | 8 +++++++ mandayejs/mandaye/views.py | 1 + tests/tests.py | 45 +++++++++++++++++++++++++++++++++++++++ tox.ini | 16 ++++++++++++++ 6 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 tests/tests.py create mode 100644 tox.ini diff --git a/debian/control b/debian/control index d3f9302..0a160f2 100644 --- a/debian/control +++ b/debian/control @@ -13,6 +13,7 @@ Depends: ${misc:Depends}, ${python:Depends}, python-gadjo, python-django-jsonfield, python-ldap, + python-crypto Recommends: python-django-mellon Description: Authentication Reverse Proxy diff --git a/mandayejs/mandaye/models.py b/mandayejs/mandaye/models.py index c7b0154..3e5a56e 100644 --- a/mandayejs/mandaye/models.py +++ b/mandayejs/mandaye/models.py @@ -14,11 +14,17 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import base64 +from Crypto.Cipher import AES from django.db import models -from jsonfield import JSONField +from django.conf import settings from django.utils.translation import ugettext_lazy as _ +from jsonfield import JSONField + +from mandayejs.mandaye.utils import get_password_field + class UserCredentials(models.Model): user = models.ForeignKey('auth.User') @@ -33,6 +39,47 @@ class UserCredentials(models.Model): or self.user.email \ or self.user.username - def to_login_info(self): + def save(self, *args, **kwargs): + self.encrypt() + super(UserCredentials, self).save(*args, **kwargs) + + def _get_secret_key(self): + """Return secret key under 32 characters + """ + return settings.SECRET_KEY[0:-(len(settings.SECRET_KEY)-32)] + + def _get_cipher(self): + """Return cipher object + """ + return AES.new(self._get_secret_key(), AES.MODE_CFB, "0000000000000000") + + def encrypt(self,): + """Encrypt password + """ + password_field_name = get_password_field() + cipher = self._get_cipher() + self.locators[password_field_name] = \ + base64.b64encode(cipher.encrypt( + self.locators.get(password_field_name,'') + )) + + return self.locators + + def decrypt(self,): + """Decrypt password + """ + password_field_name = get_password_field() + cipher = self._get_cipher() + self.locators[password_field_name] = \ + cipher.decrypt( + base64.b64decode( + self.locators.get(password_field_name,'') + )) + + return self.locators + + def to_login_info(self, decrypt=False): + if decrypt: + self.decrypt() return {'#'+k : v for k,v in self.locators.items() } diff --git a/mandayejs/mandaye/utils.py b/mandayejs/mandaye/utils.py index b146cd8..cfc189b 100644 --- a/mandayejs/mandaye/utils.py +++ b/mandayejs/mandaye/utils.py @@ -51,4 +51,12 @@ def get_location(url): url = url._replace(netloc=settings.SITE_DOMAIN) return url.path +def get_password_field(): + """Return name of the password field + """ + try: + field_name = [ field.get('name') for field in settings.SITE_LOCATORS if field.get('kind') == 'password' ] + return field_name[0] + except (IndexError,): + return None diff --git a/mandayejs/mandaye/views.py b/mandayejs/mandaye/views.py index a01ce60..43c70be 100644 --- a/mandayejs/mandaye/views.py +++ b/mandayejs/mandaye/views.py @@ -153,6 +153,7 @@ def post_login_do(request, *args, **kwargs): 'auth_checker': os.path.join(site_static_root, site_auth_checker) } logger.debug(login_info) + login_info['locators'] = [ credentials.to_login_info(decrypt=True)] result = exec_phantom(login_info) logger.debug(result) diff --git a/tests/tests.py b/tests/tests.py new file mode 100644 index 0000000..ede3740 --- /dev/null +++ b/tests/tests.py @@ -0,0 +1,45 @@ +import pytest + +from django.conf import settings +from django.contrib.auth.models import User + +from mandayejs.mandaye.models import UserCredentials + +pytestmark = pytest.mark.django_db + +def create_user(**kwargs): + password = kwargs.pop('password', None) or kwargs.get('username') + user, created = User.objects.get_or_create(**kwargs) + if password: + user.set_password(password) + user.save() + return user + +def create_credentials(user, credentials): + user, created = UserCredentials.objects.get_or_create(user=user, locators=credentials) + return user + + +@pytest.fixture +def user_john(db): + return create_user(username='john') + +@pytest.fixture +def cred_john(db,user_john): + return create_credentials(user_john, { + "username": "john", + "password": "john password" + }) + +@pytest.fixture(params=['cred_john']) +def credentials(request, cred_john): + return locals().get(request.param) + + +def test_encryption(credentials): + decrypted = credentials.decrypt() + assert decrypted.get('password') == 'john password' + + +def test_migrate_users_command(): + pass diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..56a2295 --- /dev/null +++ b/tox.ini @@ -0,0 +1,16 @@ +[tox] +envlist = django17 + +[testenv:django17] +setenv = DJANGO_SETTINGS_MODULE=mandayejs.settings +usedevelop = True +command = pytest -vs tests/tests.py + +deps = django>1.7,<1.8 + pytest + pytest-django + +[testenv:pylint] +usedevelop = True +command = pylint mandayejs +deps = pylint -- 2.6.4