3 from PLC.Faults import *
4 from PLC.Parameter import Parameter
5 from PLC.Debug import profile
6 from PLC.Table import Row, Table
7 from PLC.KeyTypes import KeyType, KeyTypes
11 Representation of a row in the keys table. To use, instantiate with a
12 dict of values. Update as you would a dict. Commit to the database
17 primary_key = 'key_id'
19 'key_id': Parameter(int, "Key identifier"),
20 'key_type': Parameter(str, "Key type"),
21 'key': Parameter(str, "Key value", max = 4096),
24 def __init__(self, api, fields = {}):
25 Row.__init__(self, fields)
28 def validate_key_type(self, key_type):
29 if key_type not in KeyTypes(self.api):
30 raise PLCInvalidArgument, "Invalid key type"
33 def validate_key(self, key):
36 # Key must not be blacklisted
37 rows = self.api.db.selectall("SELECT 1 from keys" \
38 " WHERE key = %(key)s" \
39 " AND is_blacklisted IS True",
42 raise PLCInvalidArgument, "Key is blacklisted and cannot be used"
53 if self['key_type'] == 'ssh':
54 # Accept only SSH version 2 keys without options. From
57 # Each protocol version 2 public key consists of: options,
58 # keytype, base64 encoded key, comment. The options field
59 # is optional...The comment field is not used for anything
60 # (but may be convenient for the user to identify the
61 # key). For protocol version 2 the keytype is ``ssh-dss''
64 good_ssh_key = r'^.*(?:ssh-dss|ssh-rsa)[ ]+[A-Za-z0-9+/=]+(?: .*)?$'
65 if not re.match(good_ssh_key, key, re.IGNORECASE):
66 raise PLCInvalidArgument, "Invalid SSH version 2 public key"
68 def blacklist(self, commit = True):
70 Permanently blacklist key (and all other identical keys),
71 preventing it from ever being added again. Because this could
72 affect multiple keys associated with multiple accounts, it
76 assert 'key_id' in self
79 # Get all matching keys
80 rows = self.api.db.selectall("SELECT key_id FROM keys WHERE key = %(key)s",
82 key_ids = [row['key_id'] for row in rows]
84 assert self['key_id'] in key_ids
86 # Keep the keys in the table
87 self.api.db.do("UPDATE keys SET is_blacklisted = True" \
88 " WHERE key_id IN (%s)" % ", ".join(map(str, key_ids)))
90 # But disassociate them from all join tables
91 for table in ['person_key']:
92 self.api.db.do("DELETE FROM %s WHERE key_id IN (%s)" % \
93 (table, ", ".join(map(str, key_ids))))
98 def delete(self, commit = True):
100 Delete key from the database.
103 assert 'key_id' in self
105 for table in ['person_key', 'keys']:
106 self.api.db.do("DELETE FROM %s WHERE key_id = %d" % \
107 (table, self['key_id']))
114 Representation of row(s) from the keys table in the
118 def __init__(self, api, key_id_list = None, is_blacklisted = False):
121 sql = "SELECT %s FROM keys WHERE True" % \
122 ", ".join(Key.fields)
124 if is_blacklisted is not None:
125 sql += " AND is_blacklisted IS %(is_blacklisted)s"
128 sql += " AND key_id IN (%s)" % ", ".join(map(str, key_id_list))
130 rows = self.api.db.selectall(sql, locals())
133 self[row['key_id']] = Key(api, row)