Skip to content
This repository was archived by the owner on May 6, 2020. It is now read-only.

Commit d3a1ba1

Browse files
committed
fix(key): ssh key name has to be unique now - migration included that appends a number
Fixes #1023
1 parent d63fe7f commit d3a1ba1

4 files changed

Lines changed: 62 additions & 8 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.10 on 2016-09-30 23:51
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations, models
6+
from django.db.models import Count
7+
8+
9+
def fix_duplicate_keys(apps, schema_editor):
10+
Keys = apps.get_model("api", "Key")
11+
12+
# find duplicates
13+
duplicates = Keys.objects.values('id') \
14+
.annotate(Count('id')) \
15+
.order_by() \
16+
.filter(id__count__gt=1)
17+
for dup in duplicates:
18+
# update all duplicates
19+
inc = 1
20+
for key in Keys.objects.filter(id=dup['id']):
21+
key_id = '{}-{}'.format(key.id, inc)
22+
key.id = key_id
23+
key.save()
24+
inc += 1
25+
26+
27+
class Migration(migrations.Migration):
28+
29+
dependencies = [
30+
('api', '0018_auto_20160908_1748'),
31+
]
32+
33+
operations = [
34+
migrations.RunPython(fix_duplicate_keys),
35+
migrations.AlterField(
36+
model_name='key',
37+
name='id',
38+
field=models.CharField(max_length=128, unique=True),
39+
),
40+
]

rootfs/api/models/key.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class Key(UuidAuditedModel):
2020
"""An SSH public key."""
2121

2222
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
23-
id = models.CharField(max_length=128)
23+
id = models.CharField(max_length=128, unique=True)
2424
public = models.TextField(
2525
unique=True, validators=[validate_base64],
2626
error_messages={

rootfs/api/tests/test_hooks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def test_key_hook(self, mock_requests):
6868
public = response.data['public']
6969

7070
# Create another keys
71-
body = {'id': str(self.user), 'public': RSA_PUBKEY2}
71+
body = {'id': str(self.user) + '-2', 'public': RSA_PUBKEY2}
7272
response = self.client.post('/v2/keys', body)
7373
self.assertEqual(response.status_code, 201, response.data)
7474
public2 = response.data['public']

rootfs/api/tests/test_key.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,29 +107,43 @@ def test_bad_key(self):
107107
response = self._check_bad_key(BAD_KEY)
108108
self.assertEqual(response.data, {'public': ['Key contains invalid base64 chars']})
109109

110-
def _check_duplicate_key(self, pubkey, pubkey2):
110+
def _check_duplicate_fingerprint(self, pubkey, pubkey2):
111111
"""
112112
Test that a user cannot add a duplicate key
113113
"""
114114
url = '/v2/keys'
115+
# initial key
115116
body = {'id': 'mykey@box.local', 'public': pubkey}
116117
response = self.client.post(url, body)
117118
self.assertEqual(response.status_code, 201, response.data)
118-
response = self.client.post(url, body)
119-
self.assertEqual(response.status_code, 400, response.data)
119+
120120
# test that adding a key with the same fingerprint fails
121121
body = {'id': 'mykey2@box.local', 'public': pubkey}
122122
response = self.client.post(url, body)
123123
self.assertEqual(response.status_code, 400, response.data)
124-
body = {'id': 'mykey2@box.local', 'public': pubkey2}
124+
self.assertEqual(response.data, {'public': ['Public Key is already in use']}, response.data) # noqa
125+
126+
body = {'id': 'mykey3@box.local', 'public': pubkey2}
125127
response = self.client.post(url, body)
126128
self.assertEqual(response.status_code, 201, response.data)
127129

128130
def test_rsa_duplicate_key(self):
129-
self._check_duplicate_key(RSA_PUBKEY, RSA_PUBKEY2)
131+
self._check_duplicate_fingerprint(RSA_PUBKEY, RSA_PUBKEY2)
130132

131133
def test_ecdsa_duplicate_key(self):
132-
self._check_duplicate_key(ECDSA_PUBKEY, ECDSA_PUBKEY2)
134+
self._check_duplicate_fingerprint(ECDSA_PUBKEY, ECDSA_PUBKEY2)
135+
136+
def test_duplicate_id(self):
137+
url = '/v2/keys'
138+
body = {'id': 'duplicae@box.local', 'public': RSA_PUBKEY}
139+
response = self.client.post(url, body)
140+
self.assertEqual(response.status_code, 201, response.data)
141+
142+
# same name, diff key
143+
body = {'id': 'duplicae@box.local', 'public': RSA_PUBKEY2}
144+
response = self.client.post(url, body)
145+
self.assertEqual(response.status_code, 400, response.data)
146+
self.assertEqual(response.data, {'id': ['SSH Key with this id already exists.']}, response.data) # noqa
133147

134148
def test_rsa_key_str(self):
135149
"""Test the text representation of a key"""

0 commit comments

Comments
 (0)