Statistics
| Branch: | Tag: | Revision:

root / lib / serializer.py @ e5a45a16

History | View | Annotate | Download (4.5 kB)

1 8d14b30d Iustin Pop
#
2 8d14b30d Iustin Pop
#
3 8d14b30d Iustin Pop
4 8d14b30d Iustin Pop
# Copyright (C) 2007, 2008 Google Inc.
5 8d14b30d Iustin Pop
#
6 8d14b30d Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 8d14b30d Iustin Pop
# it under the terms of the GNU General Public License as published by
8 8d14b30d Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 8d14b30d Iustin Pop
# (at your option) any later version.
10 8d14b30d Iustin Pop
#
11 8d14b30d Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 8d14b30d Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 8d14b30d Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 8d14b30d Iustin Pop
# General Public License for more details.
15 8d14b30d Iustin Pop
#
16 8d14b30d Iustin Pop
# You should have received a copy of the GNU General Public License
17 8d14b30d Iustin Pop
# along with this program; if not, write to the Free Software
18 8d14b30d Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 8d14b30d Iustin Pop
# 02110-1301, USA.
20 8d14b30d Iustin Pop
21 8d14b30d Iustin Pop
"""Serializer abstraction module
22 8d14b30d Iustin Pop

23 8d14b30d Iustin Pop
This module introduces a simple abstraction over the serialization
24 8d14b30d Iustin Pop
backend (currently json).
25 8d14b30d Iustin Pop

26 8d14b30d Iustin Pop
"""
27 8d14b30d Iustin Pop
28 8d14b30d Iustin Pop
import simplejson
29 8d14b30d Iustin Pop
import re
30 f4a2f532 Guido Trotter
import hmac
31 f4a2f532 Guido Trotter
32 f4a2f532 Guido Trotter
from ganeti import errors
33 8d14b30d Iustin Pop
34 541822e0 Guido Trotter
try:
35 541822e0 Guido Trotter
  from hashlib import sha1
36 541822e0 Guido Trotter
except ImportError:
37 541822e0 Guido Trotter
  import sha as sha1
38 071448fb Michael Hanselmann
39 8d14b30d Iustin Pop
# Check whether the simplejson module supports indentation
40 8d14b30d Iustin Pop
_JSON_INDENT = 2
41 8d14b30d Iustin Pop
try:
42 8d14b30d Iustin Pop
  simplejson.dumps(1, indent=_JSON_INDENT)
43 8d14b30d Iustin Pop
except TypeError:
44 8d14b30d Iustin Pop
  _JSON_INDENT = None
45 8d14b30d Iustin Pop
46 e91ffe49 Michael Hanselmann
_RE_EOLSP = re.compile('[ \t]+$', re.MULTILINE)
47 8d14b30d Iustin Pop
48 8d14b30d Iustin Pop
49 071448fb Michael Hanselmann
def DumpJson(data, indent=True):
50 8d14b30d Iustin Pop
  """Serialize a given object.
51 8d14b30d Iustin Pop

52 c41eea6e Iustin Pop
  @param data: the data to serialize
53 c41eea6e Iustin Pop
  @param indent: whether to indent output (depends on simplejson version)
54 c41eea6e Iustin Pop

55 c41eea6e Iustin Pop
  @return: the string representation of data
56 071448fb Michael Hanselmann

57 8d14b30d Iustin Pop
  """
58 071448fb Michael Hanselmann
  if not indent or _JSON_INDENT is None:
59 8d14b30d Iustin Pop
    txt = simplejson.dumps(data)
60 8d14b30d Iustin Pop
  else:
61 8d14b30d Iustin Pop
    txt = simplejson.dumps(data, indent=_JSON_INDENT)
62 071448fb Michael Hanselmann
63 e91ffe49 Michael Hanselmann
  txt = _RE_EOLSP.sub("", txt)
64 8d14b30d Iustin Pop
  if not txt.endswith('\n'):
65 8d14b30d Iustin Pop
    txt += '\n'
66 8d14b30d Iustin Pop
  return txt
67 8d14b30d Iustin Pop
68 8d14b30d Iustin Pop
69 228538cf Michael Hanselmann
def LoadJson(txt):
70 8d14b30d Iustin Pop
  """Unserialize data from a string.
71 8d14b30d Iustin Pop

72 c41eea6e Iustin Pop
  @param txt: the json-encoded form
73 c41eea6e Iustin Pop

74 c41eea6e Iustin Pop
  @return: the original data
75 c41eea6e Iustin Pop

76 8d14b30d Iustin Pop
  """
77 8d14b30d Iustin Pop
  return simplejson.loads(txt)
78 228538cf Michael Hanselmann
79 228538cf Michael Hanselmann
80 f4a2f532 Guido Trotter
def DumpSignedJson(data, key, salt=None):
81 f4a2f532 Guido Trotter
  """Serialize a given object and authenticate it.
82 f4a2f532 Guido Trotter

83 f4a2f532 Guido Trotter
  @param data: the data to serialize
84 f4a2f532 Guido Trotter
  @param key: shared hmac key
85 f4a2f532 Guido Trotter
  @return: the string representation of data signed by the hmac key
86 f4a2f532 Guido Trotter

87 f4a2f532 Guido Trotter
  """
88 f4a2f532 Guido Trotter
  txt = DumpJson(data, indent=False)
89 f4a2f532 Guido Trotter
  if salt is None:
90 f4a2f532 Guido Trotter
    salt = ''
91 f4a2f532 Guido Trotter
  signed_dict = {
92 f4a2f532 Guido Trotter
    'msg': txt,
93 f4a2f532 Guido Trotter
    'salt': salt,
94 541822e0 Guido Trotter
    'hmac': hmac.new(key, salt + txt, sha1).hexdigest(),
95 f4a2f532 Guido Trotter
  }
96 f4a2f532 Guido Trotter
  return DumpJson(signed_dict)
97 f4a2f532 Guido Trotter
98 f4a2f532 Guido Trotter
99 f4a2f532 Guido Trotter
def LoadSignedJson(txt, key, salt_verifier=None):
100 f4a2f532 Guido Trotter
  """Verify that a given message was signed with the given key, and load it.
101 f4a2f532 Guido Trotter

102 f4a2f532 Guido Trotter
  @param txt: json-encoded hmac-signed message
103 f4a2f532 Guido Trotter
  @param key: shared hmac key
104 f4a2f532 Guido Trotter
  @param salt_verifier: function taking a salt as input and returning boolean
105 f4a2f532 Guido Trotter
  @rtype: tuple of original data, string
106 f4a2f532 Guido Trotter
  @return: (original data, salt)
107 f4a2f532 Guido Trotter
  @raises errors.SignatureError: if the message signature doesn't verify
108 f4a2f532 Guido Trotter

109 f4a2f532 Guido Trotter
  """
110 f4a2f532 Guido Trotter
  signed_dict = LoadJson(txt)
111 f4a2f532 Guido Trotter
  if not isinstance(signed_dict, dict):
112 f4a2f532 Guido Trotter
    raise errors.SignatureError('Invalid external message')
113 f4a2f532 Guido Trotter
  try:
114 f4a2f532 Guido Trotter
    msg = signed_dict['msg']
115 f4a2f532 Guido Trotter
    salt = signed_dict['salt']
116 f4a2f532 Guido Trotter
    hmac_sign = signed_dict['hmac']
117 f4a2f532 Guido Trotter
  except KeyError:
118 f4a2f532 Guido Trotter
    raise errors.SignatureError('Invalid external message')
119 f4a2f532 Guido Trotter
120 f4a2f532 Guido Trotter
  if salt and not salt_verifier:
121 f4a2f532 Guido Trotter
    raise errors.SignatureError('Salted message is not verified')
122 f4a2f532 Guido Trotter
  elif salt_verifier is not None:
123 f4a2f532 Guido Trotter
    if not salt_verifier(salt):
124 f4a2f532 Guido Trotter
      raise errors.SignatureError('Invalid salt')
125 f4a2f532 Guido Trotter
126 541822e0 Guido Trotter
  if hmac.new(key, salt + msg, sha1).hexdigest() != hmac_sign:
127 f4a2f532 Guido Trotter
    raise errors.SignatureError('Invalid Signature')
128 f4a2f532 Guido Trotter
  return LoadJson(msg)
129 f4a2f532 Guido Trotter
130 f4a2f532 Guido Trotter
131 f4a2f532 Guido Trotter
def SaltEqualTo(expected):
132 f4a2f532 Guido Trotter
  """Helper salt verifier function that checks for equality.
133 f4a2f532 Guido Trotter

134 f4a2f532 Guido Trotter
  @type expected: string
135 f4a2f532 Guido Trotter
  @param expected: expected salt
136 f4a2f532 Guido Trotter
  @rtype: function
137 f4a2f532 Guido Trotter
  @return: salt verifier that returns True if the target salt is "x"
138 f4a2f532 Guido Trotter

139 f4a2f532 Guido Trotter
  """
140 f4a2f532 Guido Trotter
  return lambda salt: salt == expected
141 f4a2f532 Guido Trotter
142 f4a2f532 Guido Trotter
143 f4a2f532 Guido Trotter
def SaltIn(expected):
144 f4a2f532 Guido Trotter
  """Helper salt verifier function that checks for equality.
145 f4a2f532 Guido Trotter

146 f4a2f532 Guido Trotter
  @type expected: collection
147 f4a2f532 Guido Trotter
  @param expected: collection of possible valid salts
148 f4a2f532 Guido Trotter
  @rtype: function
149 f4a2f532 Guido Trotter
  @return: salt verifier that returns True if the salt is in the collection
150 f4a2f532 Guido Trotter

151 f4a2f532 Guido Trotter
  """
152 f4a2f532 Guido Trotter
  return lambda salt: salt in expected
153 f4a2f532 Guido Trotter
154 f4a2f532 Guido Trotter
155 f4a2f532 Guido Trotter
def SaltInRange(min, max):
156 f4a2f532 Guido Trotter
  """Helper salt verifier function that checks for equality.
157 f4a2f532 Guido Trotter

158 f4a2f532 Guido Trotter
  @type min: integer
159 f4a2f532 Guido Trotter
  @param min: minimum salt value
160 f4a2f532 Guido Trotter
  @type max: integer
161 f4a2f532 Guido Trotter
  @param max: maximum salt value
162 f4a2f532 Guido Trotter
  @rtype: function
163 f4a2f532 Guido Trotter
  @return: salt verifier that returns True if the salt is in the min,max range
164 f4a2f532 Guido Trotter

165 f4a2f532 Guido Trotter
  """
166 f4a2f532 Guido Trotter
  def _CheckSaltInRange(salt):
167 f4a2f532 Guido Trotter
    try:
168 f4a2f532 Guido Trotter
      i_salt = int(salt)
169 f4a2f532 Guido Trotter
    except (TypeError, ValueError), err:
170 f4a2f532 Guido Trotter
      return False
171 f4a2f532 Guido Trotter
172 f4a2f532 Guido Trotter
    return i_salt > min and i_salt < max
173 f4a2f532 Guido Trotter
174 f4a2f532 Guido Trotter
  return _CheckSaltInRange
175 f4a2f532 Guido Trotter
176 f4a2f532 Guido Trotter
177 228538cf Michael Hanselmann
Dump = DumpJson
178 228538cf Michael Hanselmann
Load = LoadJson
179 f4a2f532 Guido Trotter
DumpSigned = DumpSignedJson
180 f4a2f532 Guido Trotter
LoadSigned = LoadSignedJson