~ubuntu-branches/ubuntu/utopic/maas/utopic-security

« back to all changes in this revision

Viewing changes to src/maasserver/models/sslkey.py

  • Committer: Package Import Robot
  • Author(s): Julian Edwards, Julian Edwards, Andres Rodriguez
  • Date: 2014-08-21 18:38:27 UTC
  • mfrom: (1.2.34)
  • Revision ID: package-import@ubuntu.com-20140821183827-9xyb5u2o4l8g3zxj
Tags: 1.6.1+bzr2550-0ubuntu1
* New upstream bugfix release:
  - Auto-link node MACs to Networks (LP: #1341619)

[ Julian Edwards ]
* debian/maas-region-controller.postinst: Don't restart RabbitMQ on
  upgrades, just ensure it's running.  Should prevent a race with the
  cluster celery restarting.
* debian/rules: Pull upstream branch from the right place.

[ Andres Rodriguez ]
* debian/maas-region-controller.postinst: Ensure cluster celery is
  started if it also runs on the region.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2014 Cloudbase Solutions SRL.
 
2
# Copyright 2012 Canonical Ltd.  This software is licensed under the
 
3
# GNU Affero General Public License version 3 (see the file LICENSE).
 
4
 
 
5
""":class:`SSLKey` and friends."""
 
6
 
 
7
from __future__ import (
 
8
    absolute_import,
 
9
    print_function,
 
10
    unicode_literals,
 
11
    )
 
12
 
 
13
str = None
 
14
 
 
15
__metaclass__ = type
 
16
__all__ = [
 
17
    'SSLKey',
 
18
    ]
 
19
 
 
20
 
 
21
from cgi import escape
 
22
 
 
23
from django.contrib.auth.models import User
 
24
from django.core.exceptions import ValidationError
 
25
from django.db.models import (
 
26
    ForeignKey,
 
27
    Manager,
 
28
    TextField,
 
29
    )
 
30
from django.utils.safestring import mark_safe
 
31
from maasserver import (
 
32
    DefaultMeta,
 
33
    logger,
 
34
    )
 
35
from maasserver.models.cleansave import CleanSave
 
36
from maasserver.models.timestampedmodel import TimestampedModel
 
37
from OpenSSL import crypto
 
38
 
 
39
 
 
40
class SSLKeyManager(Manager):
 
41
    """A utility to manage the colletion of `SSLKey`s."""
 
42
 
 
43
    def get_keys_for_user(self, user):
 
44
        """Return the text of the ssl keys associated with a user."""
 
45
        return SSLKey.objects.filter(user=user).values_list('key', flat=True)
 
46
 
 
47
 
 
48
def validate_ssl_key(value):
 
49
    """Validate that the given value contains a valid SSL key."""
 
50
    try:
 
51
        crypto.load_certificate(crypto.FILETYPE_PEM, value)
 
52
    except Exception:
 
53
        # crypto.load_certificate raises all sorts of exceptions.
 
54
        # Here, we catch them all and return a ValidationError since this
 
55
        # method only aims at validating keys and not return the exact cause of
 
56
        # the failure.
 
57
        logger.exception("Invalid SSL key.")
 
58
        raise ValidationError("Invalid SSL key.")
 
59
 
 
60
 
 
61
def find_ssl_common_name(subject):
 
62
    """Returns the common name for the ssl key."""
 
63
    for component in subject.get_components():
 
64
        if len(component) < 2:
 
65
            continue
 
66
        if component[0] == 'CN':
 
67
            return component[1]
 
68
    return None
 
69
 
 
70
 
 
71
def get_html_display_for_key(key):
 
72
    """Returns the html escaped string for the key."""
 
73
    cert = crypto.load_certificate(crypto.FILETYPE_PEM, key)
 
74
    subject = cert.get_subject()
 
75
    md5 = cert.digest('MD5')
 
76
    cn = find_ssl_common_name(subject)
 
77
    if cn is not None:
 
78
        key = "%s %s" % (cn, md5)
 
79
    else:
 
80
        key = md5
 
81
    return escape(key, quote=True)
 
82
 
 
83
 
 
84
class SSLKey(CleanSave, TimestampedModel):
 
85
    """An `SSLKey` represents a user SSL key.
 
86
 
 
87
    Users will be able to access Windows winrm service with
 
88
    any of the registered keys.
 
89
 
 
90
    :ivar user: The user which owns the key.
 
91
    :ivar key: The SSL key.
 
92
 
 
93
    """
 
94
    objects = SSLKeyManager()
 
95
 
 
96
    user = ForeignKey(User, null=False, editable=False)
 
97
    key = TextField(
 
98
        null=False, blank=False, editable=True, validators=[validate_ssl_key])
 
99
 
 
100
    class Meta(DefaultMeta):
 
101
        verbose_name = "SSL key"
 
102
        unique_together = ('user', 'key')
 
103
 
 
104
    def unique_error_message(self, model_class, unique_check):
 
105
        if unique_check == ('user', 'key'):
 
106
            return "This key has already been added for this user."
 
107
        return super(
 
108
            SSLKey, self).unique_error_message(model_class, unique_check)
 
109
 
 
110
    def __unicode__(self):
 
111
        return self.key
 
112
 
 
113
    def display_html(self):
 
114
        """Return a compact HTML representation of this key.
 
115
 
 
116
        :return: The HTML representation of this key.
 
117
        :rtype: unicode
 
118
        """
 
119
        return mark_safe(get_html_display_for_key(self.key))