web2ldap  1.7.7
About: web2ldap is a full-featured web-based LDAPv3 client.
  Fossies Dox: web2ldap-1.7.7.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

opensshlpk.py
Go to the documentation of this file.
1# -*- coding: ascii -*-
2"""
3web2ldap plugin classes for OpenSSH-LPK
4(see https://code.google.com/p/openssh-lpk/)
5"""
6
7import re
8import hashlib
9import binascii
10
11import paramiko
12
13from ...log import logger
14from ..schema.syntaxes import DirectoryString, syntax_registry
15
16PARAMIKO_KEYCLASS = {
17 'ssh-rsa': paramiko.RSAKey,
18 'ssh-dss': paramiko.DSSKey,
19}
20#PARAMIKO_KEYCLASS.update({
21# 'ecdsa-sha2-nistp256': ,
22# 'ssh-ed25519': ,
23#})
24
25
27 oid: str = 'SshPublicKey-oid'
28 desc: str = 'SSH public key of a user'
29 input_pattern: str = (
30 '(^|.* )'
31 '(ssh-rsa|ssh-dss|ecdsa-sha2-nistp256|ecdsa-sha2-nistp384|ecdsa-sha2-nistp521|ssh-ed25519)'
32 ' (?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?(| .+)$'
33 )
34 pattern = re.compile(input_pattern)
35 # names of hash algorithms to be used when displaying fingerprint(s)
36 hash_algorithms = ('md5', 'sha1', 'sha256', 'sha512')
37 fileExt = 'pub'
38 # minimum secure key size per algorithm
39 min_key_size = {
40 'ssh-rsa': 2048,
41 'ssh-dss': 2048,
42 }
43
44 def sanitize(self, attr_value: bytes) -> bytes:
45 if attr_value:
46 return DirectoryString.sanitize(
47 self, attr_value
48 ).strip().replace(b'\r', b'').replace(b'\n', b'')
49 return attr_value
50
51 def _extract_pk_params(self, attr_value):
52 attr_value = attr_value.decode(self._app.ls.charset)
53 try:
54 pk_type, pk_base64, pk_comment = attr_value.split(' ', 2)
55 except ValueError:
56 pk_comment = None
57 pk_type, pk_base64 = attr_value.split(' ', 1)
58 try:
59 pk_bin = binascii.a2b_base64(pk_base64)
60 pk_fingerprints = {
61 hash_algo: hashlib.new(hash_algo, pk_bin).digest()
62 for hash_algo in self.hash_algorithms
63 }
64 except Exception as err:
65 logger.warning('Error decoding SSH public key: %s', err)
66 pk_bin, pk_fingerprints = None, None
67 return pk_type, pk_comment, pk_bin, pk_fingerprints
68
69 @staticmethod
70 def _strip_padding(b64_val):
71 i = len(b64_val)
72 while b64_val[i-1] == '=':
73 i = i - 1
74 return b64_val[:i]
75
76 @staticmethod
77 def _get_key_size(pk_type, pk_bin):
78 try:
79 pkey = PARAMIKO_KEYCLASS[pk_type](data=pk_bin)
80 except (KeyError, paramiko.SSHException):
81 return None
82 return pkey.get_bits()
83
84 def _validate(self, attr_value: bytes) -> bool:
85 valid = DirectoryString._validate(self, attr_value)
86 if not valid:
87 return False
88 try:
89 pk_type, _, pk_bin, _ = self._extract_pk_params(attr_value)
90 except ValueError:
91 return False
92 if pk_type not in self.min_key_size:
93 # no min-size defined for key type
94 return True
95 pk_size = self._get_key_size(pk_type, pk_bin)
96 return (pk_size is None) or (pk_size >= self.min_key_size[pk_type])
97
99 self,
100 vidx,
101 links,
102 pk_type,
103 pk_comment,
104 pk_bin,
105 pk_fingerprints,
106 ):
107 result = []
108 result.append('<dt>SSH Key:</dt><dd><input readonly size="70" value="{}"></dd>'.format(
109 DirectoryString.display(self, vidx, links)
110 ))
111 if pk_comment:
112 result.append(
113 '<dt>Key comment:</dt><dd>{}</dd>'.format(self._app.form.s2d(pk_comment))
114 )
115 if pk_fingerprints:
116 result.append('<dt>Fingerprints:</dt><dd><dl>')
117 for hash_algo, pk_fingerprint in sorted(pk_fingerprints.items()):
118 result.append(
119 '<dt>{0}:</dt><dd>{1}</dd>'.format(
120 hash_algo.upper(),
121 ':'.join([hex(b)[2:] for b in pk_fingerprint]),
122 )
123 )
124 for hash_algo in ('sha1', 'sha256', 'sha512'):
125 result.append(
126 '<dt>ssh-keygen -l -E {0}</dt><dd>{1}</dd>'.format(
127 hash_algo,
128 self._app.form.s2d(
129 self._strip_padding(
130 binascii.b2a_base64(pk_fingerprints[hash_algo]).strip()
131 ).decode('ascii')
132 ),
133 )
134 )
135 result.append('</dl></dd>')
136 if pk_bin:
137 pk_size = self._get_key_size(pk_type, pk_bin)
138 if pk_size is None:
139 result.append('<dt>Key size:</dt><dd>unknown</dd>')
140 else:
141 result.append('<dt>Key size:</dt><dd>%d</dd>' % (pk_size))
142 return result
143
144 def display(self, vidx, links) -> str:
145 pk_type, pk_comment, pk_bin, pk_fingerprints = self._extract_pk_params(self._av)
146 result = ['<dl>']
147 result.extend(
148 self._display_lines(
149 vidx,
150 links,
151 pk_type,
152 pk_comment,
153 pk_bin,
154 pk_fingerprints,
155 )
156 )
157 result.append('</dl>')
158 return '\n'.join(result)
159
160
161syntax_registry.reg_at(
162 SshPublicKey.oid, [
163 '1.3.6.1.4.1.24552.500.1.1.1.13', # sshPublicKey
164 ]
165)
166
167
168# Register all syntax classes in this module
169syntax_registry.reg_syntaxes(__name__)
def _display_lines(self, vidx, links, pk_type, pk_comment, pk_bin, pk_fingerprints)
Definition: opensshlpk.py:106
bool _validate(self, bytes attr_value)
Definition: opensshlpk.py:84
bytes sanitize(self, bytes attr_value)
Definition: opensshlpk.py:44