Update the django_gpg app to support organizations.

This commit is contained in:
Roberto Rosario
2016-06-24 04:22:49 -04:00
parent 0be3e130c1
commit debec7b4a2
8 changed files with 147 additions and 20 deletions

View File

@@ -10,6 +10,7 @@ import gnupg
from django.db import models
from common.utils import mkdtemp, mkstemp
from organizations.managers import CurrentOrganizationManager
from .classes import KeyStub, SignatureVerification
from .exceptions import (
@@ -193,3 +194,7 @@ class KeyManager(models.Manager):
else:
logger.debug('file not signed')
raise VerificationError('File not signed')
class OrganizationKeyManager(KeyManager, CurrentOrganizationManager):
pass

View File

@@ -14,6 +14,9 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='key',
name='key_data',
field=models.TextField(help_text='ASCII armored version of the key.', verbose_name='Key data'),
field=models.TextField(
help_text='ASCII armored version of the key.',
verbose_name='Key data'
),
),
]

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import organizations.shortcuts
class Migration(migrations.Migration):
dependencies = [
('organizations', '0002_add_data_default_organization'),
('django_gpg', '0006_auto_20160510_0025'),
]
operations = [
migrations.AddField(
model_name='key',
name='organization',
field=models.ForeignKey(default=organizations.shortcuts.get_current_organization, to='organizations.Organization'),
),
]

View File

@@ -14,6 +14,8 @@ from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from common.utils import mkdtemp
from organizations.models import Organization
from organizations.shortcuts import get_current_organization
from .exceptions import NeedPassphrase, PassphraseError
from .literals import (
@@ -21,7 +23,7 @@ from .literals import (
ERROR_MSG_GOOD_PASSPHRASE, KEY_TYPE_CHOICES, KEY_TYPE_SECRET,
OUTPUT_MESSAGE_CONTAINS_PRIVATE_KEY
)
from .managers import KeyManager
from .managers import KeyManager, OrganizationKeyManager
from .settings import setting_gpg_path
logger = logging.getLogger(__name__)
@@ -44,6 +46,9 @@ def gpg_command(function):
@python_2_unicode_compatible
class Key(models.Model):
organization = models.ForeignKey(
Organization, default=get_current_organization
)
key_data = models.TextField(
help_text=_('ASCII armored version of the key.'),
verbose_name=_('Key data')
@@ -72,11 +77,15 @@ class Key(models.Model):
)
objects = KeyManager()
on_organization = OrganizationKeyManager()
class Meta:
verbose_name = _('Key')
verbose_name_plural = _('Keys')
def __str__(self):
return '{} - {}'.format(self.key_id, self.user_id)
def clean(self):
def import_key(gpg):
return gpg.import_keys(key_data=self.key_data)
@@ -86,7 +95,7 @@ class Key(models.Model):
if not import_results.count:
raise ValidationError(_('Invalid key data'))
if Key.objects.filter(fingerprint=import_results.fingerprints[0]).exists():
if Key.on_organization.filter(fingerprint=import_results.fingerprints[0]).exists():
raise ValidationError(_('Key already exists.'))
def get_absolute_url(self):
@@ -123,9 +132,6 @@ class Key(models.Model):
super(Key, self).save(*args, **kwargs)
def __str__(self):
return '{} - {}'.format(self.key_id, self.user_id)
def sign_file(self, file_object, passphrase=None, clearsign=False, detached=False, binary=False, output=None):
# WARNING: using clearsign=True and subsequent decryption corrupts the
# file. Appears to be a problem in python-gnupg or gpg itself.

View File

@@ -5,9 +5,8 @@ import StringIO
import gnupg
import mock
from django.test import TestCase
from common.utils import TemporaryFile
from organizations.tests import OrganizationTestCase
from ..exceptions import (
DecryptionError, KeyDoesNotExist, NeedPassphrase, PassphraseError,
@@ -44,7 +43,7 @@ def mock_recv_keys(self, keyserver, *keyids):
return ImportResult()
class KeyTestCase(TestCase):
class KeyTestCase(OrganizationTestCase):
def test_key_instance_creation(self):
# Creating a Key instance is analogous to importing a key
key = Key.objects.create(key_data=TEST_KEY_DATA)

View File

@@ -0,0 +1,83 @@
from __future__ import unicode_literals
from django.test import override_settings
from django_downloadview.test import assert_download_response
from organizations.tests.test_organization_views import OrganizationViewTestCase
from ..models import Key
from .literals import TEST_KEY_DATA, TEST_KEY_FINGERPRINT
@override_settings(OCR_AUTO_OCR=False)
class OrganizationKeyViewsTestCase(OrganizationViewTestCase):
def create_key(self):
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
self.key = Key.on_organization.create(key_data=TEST_KEY_DATA)
def test_key_delete_view(self):
self.create_key()
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
response = self.post(
'django_gpg:key_delete',
args=(self.key.pk,), follow=True
)
self.assertEqual(response.status_code, 404)
def test_key_download_view(self):
self.create_key()
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
response = self.get(
viewname='django_gpg:key_download', args=(self.key.pk,)
)
self.assertEqual(response.status_code, 404)
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
response = self.get(
viewname='django_gpg:key_download', args=(self.key.pk,)
)
assert_download_response(
self, response=response, content=self.key.key_data,
basename=self.key.key_id,
)
def test_key_upload_view(self):
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
response = self.post(
viewname='django_gpg:key_upload',
data={'key_data': TEST_KEY_DATA}, follow=True
)
self.assertContains(response, 'created', status_code=200)
self.assertEqual(Key.on_organization.count(), 1)
self.assertEqual(
Key.on_organization.first().fingerprint, TEST_KEY_FINGERPRINT
)
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
self.assertEqual(Key.on_organization.count(), 0)
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
self.assertEqual(Key.on_organization.count(), 1)
def test_key_private_list_view(self):
self.create_key()
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
response = self.get(viewname='django_gpg:key_private_list')
self.assertNotContains(
response, text=self.key.key_id, status_code=200
)
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
response = self.get(viewname='django_gpg:key_private_list')
self.assertContains(
response, text=self.key.key_id, status_code=200
)

View File

@@ -3,9 +3,7 @@ from __future__ import absolute_import, unicode_literals
from django_downloadview.test import assert_download_response
from common.tests.test_views import GenericViewTestCase
from user_management.tests import (
TEST_USER_USERNAME, TEST_USER_PASSWORD
)
from user_management.tests import TEST_USER_USERNAME, TEST_USER_PASSWORD
from ..models import Key
from ..permissions import permission_key_download, permission_key_upload

View File

@@ -25,7 +25,6 @@ logger = logging.getLogger(__name__)
class KeyDeleteView(SingleObjectDeleteView):
model = Key
object_permission = permission_key_delete
def get_post_action_redirect(self):
@@ -37,10 +36,12 @@ class KeyDeleteView(SingleObjectDeleteView):
def get_extra_context(self):
return {'title': _('Delete key: %s') % self.get_object()}
def get_queryset(self):
return Key.on_organization.all()
class KeyDetailView(SingleObjectDetailView):
form_class = KeyDetailForm
model = Key
object_permission = permission_key_view
def get_extra_context(self):
@@ -48,9 +49,11 @@ class KeyDetailView(SingleObjectDetailView):
'title': _('Details for key: %s') % self.get_object(),
}
def get_queryset(self):
return Key.on_organization.all()
class KeyDownloadView(SingleObjectDownloadView):
model = Key
object_permission = permission_key_download
def get_file(self):
@@ -58,6 +61,9 @@ class KeyDownloadView(SingleObjectDownloadView):
return ContentFile(key.key_data, name=key.key_id)
def get_queryset(self):
return Key.on_organization.all()
class KeyReceive(ConfirmView):
post_action_redirect = reverse_lazy('django_gpg:key_public_list')
@@ -71,7 +77,7 @@ class KeyReceive(ConfirmView):
def view_action(self):
try:
Key.objects.receive_key(key_id=self.kwargs['key_id'])
Key.on_organization.receive_key(key_id=self.kwargs['key_id'])
except Exception as exception:
messages.error(
self.request,
@@ -122,14 +128,13 @@ class KeyQueryResultView(SingleObjectListView):
def get_queryset(self):
term = self.request.GET.get('term')
if term:
return Key.objects.search(query=term)
return Key.on_organization.search(query=term)
else:
return ()
class KeyUploadView(SingleObjectCreateView):
fields = ('key_data',)
model = Key
post_action_redirect = reverse_lazy('django_gpg:key_public_list')
view_permission = permission_key_upload
@@ -138,10 +143,12 @@ class KeyUploadView(SingleObjectCreateView):
'title': _('Upload new key'),
}
def get_queryset(self):
return Key.on_organization.all()
class PublicKeyListView(SingleObjectListView):
object_permission = permission_key_view
queryset = Key.objects.public_keys()
def get_extra_context(self):
return {
@@ -149,13 +156,18 @@ class PublicKeyListView(SingleObjectListView):
'title': _('Public keys')
}
def get_queryset(self):
return Key.on_organization.public_keys()
class PrivateKeyListView(SingleObjectListView):
object_permission = permission_key_view
queryset = Key.objects.private_keys()
def get_extra_context(self):
return {
'hide_object': True,
'title': _('Private keys')
}
def get_queryset(self):
return Key.on_organization.private_keys()