implement SshPublicKey model, manager and tests
- implement osusers.models.SshPublicKey and osusers.models.SshPublicKeyManager - fix broken osusers.models.tests.test_models - add new test classes SshPublicKeyManagerTest and SshPublicKeyTest - add migration for SshPublicKey model
This commit is contained in:
parent
9fa351f801
commit
20359681db
3 changed files with 393 additions and 140 deletions
|
@ -4,9 +4,11 @@ This module defines the database models of operating system users.
|
|||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import base64
|
||||
from datetime import date
|
||||
import logging
|
||||
import os
|
||||
import six
|
||||
|
||||
from django.db import models, transaction
|
||||
from django.conf import settings
|
||||
|
@ -477,3 +479,103 @@ class AdditionalGroup(TimeStampedModel, models.Model):
|
|||
'remove_ldap_user_from_group'
|
||||
)
|
||||
super(AdditionalGroup, self).delete(*args, **kwargs)
|
||||
|
||||
|
||||
class SshPublicKeyManager(models.Manager):
|
||||
"""
|
||||
Default manager for :py:class:`SSH public key
|
||||
<osusers.models.SshPublicKey>` instances.
|
||||
|
||||
"""
|
||||
|
||||
def parse_keytext(self, keytext):
|
||||
"""
|
||||
Parse a SSH public key in OpenSSH or :rfc:`4716` format into its
|
||||
components algorithm, key data and comment.
|
||||
|
||||
:param str keytext: key text
|
||||
:return: triple of algorithm name, key data and comment
|
||||
:rtype: triple of str
|
||||
|
||||
"""
|
||||
if keytext.startswith('---- BEGIN SSH2 PUBLIC KEY ----'):
|
||||
comment = ''
|
||||
data = ''
|
||||
continued = ''
|
||||
headers = {}
|
||||
for line in keytext.splitlines():
|
||||
if line == '---- BEGIN SSH2 PUBLIC KEY ----':
|
||||
continue
|
||||
elif ':' in line: # a header line
|
||||
header_tag, header_value = [
|
||||
item.strip() for item in line.split(':', 1)]
|
||||
if header_value.endswith('\\'):
|
||||
continued = header_value[:-1]
|
||||
else:
|
||||
headers[header_tag.lower()] = header_value
|
||||
elif continued:
|
||||
if line.endswith('\\'):
|
||||
continued += line[:-1]
|
||||
continue
|
||||
header_value = continued + line
|
||||
headers[header_tag.lower()] = header_value
|
||||
continued = ''
|
||||
elif line == '---- END SSH2 PUBLIC KEY ----':
|
||||
break
|
||||
elif line: # ignore empty lines
|
||||
data += line
|
||||
if 'comment' in headers:
|
||||
comment = headers['comment']
|
||||
else:
|
||||
parts = keytext.split()
|
||||
if len(parts) > 3:
|
||||
raise ValueError("unsupported key format")
|
||||
data = parts[1]
|
||||
comment = len(parts) == 3 and parts[2] or ""
|
||||
keybytes = base64.b64decode(data)
|
||||
parts = keybytes.split(b'\x00' * 3)
|
||||
alglength = six.byte2int(parts[1])
|
||||
algname = parts[1][1:1+alglength]
|
||||
return algname, data, comment
|
||||
|
||||
def create_ssh_public_key(self, user, keytext):
|
||||
"""
|
||||
Create a new :py:class:`SSH public key <osusers.models.SshPublicKey>`
|
||||
for a user from the given key text representation. The text can be
|
||||
either in openssh format or :rfc:`4716` format.
|
||||
|
||||
:param user: :py:class:`operating system user <osusers.models.User>`
|
||||
:param str keytext: key text
|
||||
:return: public key
|
||||
:retype: :py:class:`osusers.models.SshPublicKey`
|
||||
|
||||
"""
|
||||
algorithm, data, comment = self.parse_keytext(keytext)
|
||||
return self.create(
|
||||
user=user, algorithm=algorithm, data=data, comment=comment)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class SshPublicKey(TimeStampedModel):
|
||||
"""
|
||||
This entity class represents single SSH keys for an :py:class:`operating
|
||||
system user <osusers.models.User>`.
|
||||
|
||||
"""
|
||||
user = models.ForeignKey(User, verbose_name=_('User'))
|
||||
algorithm = models.CharField(_('Algorithm'), max_length=20)
|
||||
data = models.TextField(_('Key bytes'),
|
||||
help_text=_('Base64 encoded key bytes'))
|
||||
comment = models.TextField(_('Comment'), blank=True)
|
||||
|
||||
objects = SshPublicKeyManager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('SSH public key')
|
||||
verbose_name_plural = _('SSH public keys')
|
||||
unique_together = [('user', 'algorithm', 'data')]
|
||||
|
||||
def __str__(self):
|
||||
return "{algorithm} {data} {comment}".format(
|
||||
algorithm=self.algorithm, data=self.data, comment=self.comment
|
||||
).strip()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue