forked from tildaslash/RatticWeb
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding first class support for ssh keys in creds
- Loading branch information
Showing
16 changed files
with
289 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
cred/migrations/0034_auto__add_field_cred_ssh_key__add_field_cred_ssh_key_name.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
# -*- coding: utf-8 -*- | ||
from south.utils import datetime_utils as datetime | ||
from south.db import db | ||
from south.v2 import SchemaMigration | ||
from django.db import models | ||
|
||
|
||
class Migration(SchemaMigration): | ||
|
||
def forwards(self, orm): | ||
# Adding field 'Cred.ssh_key' | ||
db.add_column(u'cred_cred', 'ssh_key', | ||
self.gf('cred.fields.SizedFileField')(max_length=100, null=True, blank=True), | ||
keep_default=False) | ||
|
||
# Adding field 'Cred.ssh_key_name' | ||
db.add_column(u'cred_cred', 'ssh_key_name', | ||
self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True), | ||
keep_default=False) | ||
|
||
|
||
def backwards(self, orm): | ||
# Deleting field 'Cred.ssh_key' | ||
db.delete_column(u'cred_cred', 'ssh_key') | ||
|
||
# Deleting field 'Cred.ssh_key_name' | ||
db.delete_column(u'cred_cred', 'ssh_key_name') | ||
|
||
|
||
models = { | ||
u'auth.group': { | ||
'Meta': {'object_name': 'Group'}, | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
}, | ||
u'auth.permission': { | ||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
}, | ||
u'auth.user': { | ||
'Meta': {'object_name': 'User'}, | ||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), | ||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) | ||
}, | ||
u'contenttypes.contenttype': { | ||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
}, | ||
u'cred.cred': { | ||
'Meta': {'object_name': 'Cred'}, | ||
'attachment': ('cred.fields.SizedFileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), | ||
'attachment_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), | ||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), | ||
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), | ||
'descriptionmarkdown': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.Group']"}), | ||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'child_creds'", 'default': 'None', 'to': u"orm['auth.Group']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True'}), | ||
'iconname': ('django.db.models.fields.CharField', [], {'default': "'Key.png'", 'max_length': '64'}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'is_deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), | ||
'latest': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'history'", 'null': 'True', 'to': u"orm['cred.Cred']"}), | ||
'modified': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), | ||
'password': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}), | ||
'ssh_key': ('cred.fields.SizedFileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), | ||
'ssh_key_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), | ||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'child_creds'", 'default': 'None', 'to': u"orm['cred.Tag']", 'blank': 'True', 'symmetrical': 'False', 'null': 'True'}), | ||
'title': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}), | ||
'url': ('django.db.models.fields.URLField', [], {'db_index': 'True', 'max_length': '200', 'null': 'True', 'blank': 'True'}), | ||
'username': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '250', 'null': 'True', 'blank': 'True'}) | ||
}, | ||
u'cred.credaudit': { | ||
'Meta': {'ordering': "('-time',)", 'object_name': 'CredAudit'}, | ||
'audittype': ('django.db.models.fields.CharField', [], {'max_length': '1'}), | ||
'cred': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'logs'", 'to': u"orm['cred.Cred']"}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), | ||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'credlogs'", 'to': u"orm['auth.User']"}) | ||
}, | ||
u'cred.credchangeq': { | ||
'Meta': {'object_name': 'CredChangeQ'}, | ||
'cred': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['cred.Cred']", 'unique': 'True'}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) | ||
}, | ||
u'cred.tag': { | ||
'Meta': {'object_name': 'Tag'}, | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}) | ||
} | ||
} | ||
|
||
complete_apps = ['cred'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from six import StringIO | ||
import paramiko | ||
import binascii | ||
|
||
|
||
def insert_char_every_n_chars(string, char='\n', every=64): | ||
return char.join(string[i:i + every] for i in xrange(0, len(string), every)) | ||
|
||
|
||
class SSHKey(object): | ||
def __init__(self, key, password): | ||
self.key = key | ||
self.password = password | ||
|
||
@property | ||
def key_obj(self): | ||
return paramiko.RSAKey.from_private_key(StringIO(self.key), password=self.password) | ||
|
||
def fingerprint(self): | ||
fingerprint = binascii.hexlify(self.key_obj.get_fingerprint()) | ||
return insert_char_every_n_chars(fingerprint, ':', 2) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
a9:d3:18:c7:01:62:36:a0:92:40:9f:19:ee:79:27:fd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
-----BEGIN RSA PRIVATE KEY----- | ||
MIIEpAIBAAKCAQEA4KRV/MqnIpLYG90j6lA6Ng83wMq8LkLl+Fu5GAXhvRYwfyn/ | ||
q05b+2qa7XDE7jh9JCWaWppx74susG5wNFYx/d8/Vs3Gz6x22+AISisIInKIm8NQ | ||
q9gcAfdncciAm1AsGXPhxBR9Gf8pTciarkd2vkJ8/pTidXXyVQNdla39Yoz+yI9V | ||
HPhHT+7SBFKFJQvvxPQdnJMy+RUIVbv2XHcfV7zDOuaaCKs+CjodV4afdgiGIR2D | ||
WlEgh5ulQxTG6ijCF3GDK1LUb1w6nHoOBc9wX3+SNv1SA6Zaw8/U4bkviUc3dEX4 | ||
sa+F4VrqlicVv8J04oLQPKWD2VNSK+0+SAchiQIDAQABAoIBAQCVLIvtUqWqT9ky | ||
p6cx8hS10WU0oWxVTBdq1X4UddNxvUp3J2ygVWi/jAtVoY0kpF51ooLdp7IBYGug | ||
vbXFC3gnHhjxi7R6NAy59guLNQgx19zfktP/SYNPyvrmlD7S5GpkfI9vpittGARV | ||
ouEU2l//+CcI59V6KtjBm3qJ6wBYcAo7P761TZ+qC+cHI6AYOfWStARhT0Ya3LLE | ||
QyoBloN5si5GKCRyJ1SGdYpdCtWNJKsG1TcUrWVeTWmNg0hrYMXG/4YyVGQXSk/2 | ||
/w4X3Rd3nlK1LRpALMFcZAxxXMZsOxBsfQsoWBmLLpNDyCnvOAa469PE0UPbEhc7 | ||
mK2Xm6ABAoGBAPLwC0/CeO35BJN257C5rPKwZJlsR29LUzOeIxHBPWdPJ2aLlHjZ | ||
lmQfismGo6D/tqsWRK51TSK1Ia3T7SzPpQ93rnMc+/ETgFQTFMXBxL4UKHa7KuR1 | ||
3OrHFSr205/JaFANPVT/gEteKnw8d/fHdFbpSHesyW4NLNy70U8XzUbtAoGBAOy4 | ||
dP9k91Hb7eia6FcUQMouqz1JZ2QvDu1ezzWFArlxrflXeKfOQl1pfwpLfc1hRXpo | ||
9pXHD1IVMIIxhrhSviNU0Clc3YhfWcmKb8skimsFABT4DvLvQGSjqXt8WS+yTxyg | ||
7lXsVHzwscIBzhhfooFzSJPCFsN3ULQ6XlPMaDWNAoGAY4WzHJmusM6y8TZk9CEc | ||
mM9qZu/U0+Mn0p2WAFAJt6jVm0zTJi79TUcetDBUGECptK0Kte2YC//oLC4Fm7X1 | ||
CMEe1kmpbLlweQDYIaufzb60VO+YQr+GISgto8w6Jdt8wE6sMYX6KOYKwZqECx3K | ||
q1AmP+CpJEyBdGv880ns7oECgYEA19X7v13k7vtzebG8hKFPzcktkyzZm4wYtS/M | ||
CIVljYZsVTt/JKm48wkcr1tTsi6ttcX8h2Y/vtzZJOxZZLj06qwLPJuS1iPybwPN | ||
mNCRcLDXeUcQAktJUDm1b4VaoFWZMoY9qZRZGK4xta4Fp02Tkyp1E1xVexXQPPQ3 | ||
S3rFzYUCgYA8SQ7fWldMXkrAnodnsmUMd1lpsEdOZx/PHw7fpYBT7SXGqtrUrHnZ | ||
b3hqI/Ttz17NTttJHdOxKGJKINobYlBoe51yRBexDyL1tU2wQiqBtz2RH4HwBYgP | ||
NngrYcXv1SBblT9cSUZQRAwY+/wXA1zVydd5nDorXHKJdzoucZ+Jsw== | ||
-----END RSA PRIVATE KEY----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
e5:28:9b:1e:61:f3:0f:0b:60:70:e7:d2:8a:a1:6a:16 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
whatever |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
-----BEGIN RSA PRIVATE KEY----- | ||
Proc-Type: 4,ENCRYPTED | ||
DEK-Info: AES-128-CBC,29D8F37407735B42163CC0533DD61F51 | ||
|
||
Krs4tAjhX+KghiMOMx3R50Qu8lto0TdHaHUZKfguU7yRmhovaPAjNMrROAw8xRJh | ||
Qo4XsQfET9pHAVW4/n6LN6mugD3anVYUFb0HrJNUebVspACXoil5462LqLMyTm/J | ||
8rFUZpSOQhw7u8qRuS5EAdoqAuIOYgoqpNNv1iycol08OvdSvQZYjndVw54gxQZ8 | ||
I6ki22xGsziGVl6xkfJYfqOw1biVNjnMjvWHsDfpiGUGOchFpnobbX1X9hZHEHuC | ||
lk41rvOVJp1sm1t/TwQkKUfjQJEfqGbs0BTt3gc9aP7Yu1NMvA1gFNIt0hL+qvjs | ||
yKh9gH1WQnkWKmxYR8zmqrdJrE1G1bVEq3rS9VGEuX25wiyPzdDM9pSMdUVZ8cam | ||
ngLf/Ybq9bCD0qNXoNdp5aJbGmIbSNem714pCnuR6RgZiCP4kT5J+pgUjAwUicrQ | ||
lYWu9pv1r1UYeyBA0PLNWpOLOMS9ix6vCJUQv5fVTQcpt9sL4m8o2Y8hQjpxvbpw | ||
zNoAHQzZ6Iu+IA+Jnwj+wTHtmtkk5KNL8hj/tOOEbNOJMAJFN+3k9W3XoWbufxI5 | ||
Acu5E8NxmE+LBEh30bBgyRzFkem4HM4ovfRzSK8LOS0XkWtqQAHws7CWWnXtFNXX | ||
xod+4XMkItatTz4ooJz+NDgOtFANlvIZZXzteINfBQ0I70QGKF4zhWNfzxjtN+Xg | ||
OkbFoadnUrPxPgg/kRnTeLt+Xjt/uU4hJqUY+dMa/XioI+hLHfERn+88dh/MGpUY | ||
i93NjG0eWjwo3HaumoYkXOXJyOsWNr0PCWKZ0pjxHZ4F7+O9OkBGHLk+j+0SlL1B | ||
nO7Jrmol6l4M2JFQm/MPHkT2TOdBmLU8Oenp9+uRa8zt+P6vea0KTqMbTgNQuGTU | ||
oQYO0ozMp80GTMAcAa6Sav8SMx+9BpGc5A+keGIaEzkn7Ofx9Nmidj+6SYdTU9Ty | ||
t4DyiQDbqiXuid9c+aRm1C+v5gOmCb/kKDUInm7U44G+hj494MSY1Yr7kkx4vHMu | ||
IangLs6CVfgxe9A4oIZR8Rnr3gI0NPNVfSyWtcEVmbe8G0HuKE1VxIMfpWohMxgu | ||
ycLzSzZlchEgRdoHr8qjr2CdoFD8JOr2+RGEz3GXcryWXMhzAg1fTc7ZC/oflzqF | ||
njdglLFCCs1DTm96ixaWYXs1Ce9PkYpt7WJOTER67KmHIAq1wcTL2P62M8v2wDHY | ||
y1J2aQJvMRhFHXJomBQ2ar7NXKTVQEJXw+4NefVtlmZ/SZ1sz9ZW8ghK7ZEhpN5J | ||
Oz0JGgnQ7z2H4n11VUJplgd+XqOkie+8MKw3RwWDZ0wLdx0Oxge4QhVrs8uCn3wQ | ||
DeoYWkA2AvbX8u1pWgZixG6QHQDiwSyGAPgl/PnCJ3WWqSD2h7eAk+B4TI3byHM8 | ||
rM1oBcRMbDlshUuxiWhjEp8vVc0NQEeXvEK5cWfacUsml+Dl0fukT+zcEgV9Zek3 | ||
PdkgHrYgkmx7QsYBm++KdwOSMEWWA2WLDEjC7bVOiz3njJd1/0g0WmJodO1bc2gZ | ||
qBJEqonRVgHL3iOnj7qlYc8oHVZkFCELo3hKbeBcdTX0LDbLBp4n45p4n89F6SC3 | ||
-----END RSA PRIVATE KEY----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from django.test import TestCase | ||
from django.core.files import File | ||
from django.core.urlresolvers import reverse | ||
from django.test.utils import override_settings | ||
|
||
from ratticweb.tests.helper import TestData | ||
from cred.models import Cred, Group | ||
import os | ||
|
||
|
||
here = os.path.abspath(os.path.dirname(__file__)) | ||
ssh_keys = os.path.join(here, "ssh_keys") | ||
|
||
|
||
class CredSSHKeyTest(TestCase): | ||
def setUp(self): | ||
self.data = TestData() | ||
|
||
def test_upload_cred(self): | ||
# Load the edit form | ||
resp = self.data.norm.get( | ||
reverse('cred.views.edit', args=(self.data.cred.id, )) | ||
) | ||
self.assertEqual(resp.status_code, 200) | ||
|
||
# Get the data from the form to submit | ||
form = resp.context['form'] | ||
post = form.initial | ||
del post['url'] | ||
del post['attachment'] | ||
|
||
# Open a test file and upload it | ||
with open(os.path.join(ssh_keys, "1.pem"), 'r') as fp: | ||
post['ssh_key'] = fp | ||
|
||
resp = self.data.norm.post( | ||
reverse('cred.views.edit', args=(self.data.cred.id, )), | ||
post | ||
) | ||
self.assertEqual(resp.status_code, 302) | ||
|
||
# Get a new copy of the cred from the DB | ||
cred = Cred.objects.get(pk=self.data.cred.id) | ||
|
||
# Check it matches the test file | ||
with open(os.path.join(ssh_keys, "1.pem"), 'r') as fp: | ||
self.assertEqual(fp.read(), cred.ssh_key.read()) | ||
|
||
def test_cred_fingerprint(self): | ||
group = Group.objects.create(name="group") | ||
with open(os.path.join(ssh_keys, "1.pem")) as fle: | ||
cred = Cred.objects.create(ssh_key=File(fle), group=group) | ||
cred.save() | ||
self.assertEqual(cred.ssh_key_fingerprint(), open(os.path.join(ssh_keys, "1.fingerprint")).read().strip()) | ||
|
||
def test_cred_with_password_fingerprint(self): | ||
group = Group.objects.create(name="group") | ||
with open(os.path.join(ssh_keys, "2.pem")) as fle: | ||
with open(os.path.join(ssh_keys, "2.password")) as pfle: | ||
cred = Cred.objects.create(ssh_key=File(fle), group=group, password=pfle.read().strip()) | ||
cred.save() | ||
self.assertEqual(cred.ssh_key_fingerprint(), open(os.path.join(ssh_keys, "2.fingerprint")).read().strip()) | ||
|
||
|
||
CredSSHKeyTest = override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.MD5PasswordHasher',))(CredSSHKeyTest) |
Oops, something went wrong.