Revision f4a2f532 lib/serializer.py

b/lib/serializer.py
27 27

  
28 28
import simplejson
29 29
import re
30
import hmac
31
import hashlib
32

  
33
from ganeti import errors
30 34

  
31 35

  
32 36
# Check whether the simplejson module supports indentation
......
70 74
  return simplejson.loads(txt)
71 75

  
72 76

  
77
def DumpSignedJson(data, key, salt=None):
78
  """Serialize a given object and authenticate it.
79

  
80
  @param data: the data to serialize
81
  @param key: shared hmac key
82
  @return: the string representation of data signed by the hmac key
83

  
84
  """
85
  txt = DumpJson(data, indent=False)
86
  if salt is None:
87
    salt = ''
88
  signed_dict = {
89
    'msg': txt,
90
    'salt': salt,
91
    'hmac': hmac.new(key, salt + txt, hashlib.sha256).hexdigest(),
92
  }
93
  return DumpJson(signed_dict)
94

  
95

  
96
def LoadSignedJson(txt, key, salt_verifier=None):
97
  """Verify that a given message was signed with the given key, and load it.
98

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

  
106
  """
107
  signed_dict = LoadJson(txt)
108
  if not isinstance(signed_dict, dict):
109
    raise errors.SignatureError('Invalid external message')
110
  try:
111
    msg = signed_dict['msg']
112
    salt = signed_dict['salt']
113
    hmac_sign = signed_dict['hmac']
114
  except KeyError:
115
    raise errors.SignatureError('Invalid external message')
116

  
117
  if salt and not salt_verifier:
118
    raise errors.SignatureError('Salted message is not verified')
119
  elif salt_verifier is not None:
120
    if not salt_verifier(salt):
121
      raise errors.SignatureError('Invalid salt')
122

  
123
  if hmac.new(key, salt + msg, hashlib.sha256).hexdigest() != hmac_sign:
124
    raise errors.SignatureError('Invalid Signature')
125
  return LoadJson(msg)
126

  
127

  
128
def SaltEqualTo(expected):
129
  """Helper salt verifier function that checks for equality.
130

  
131
  @type expected: string
132
  @param expected: expected salt
133
  @rtype: function
134
  @return: salt verifier that returns True if the target salt is "x"
135

  
136
  """
137
  return lambda salt: salt == expected
138

  
139

  
140
def SaltIn(expected):
141
  """Helper salt verifier function that checks for equality.
142

  
143
  @type expected: collection
144
  @param expected: collection of possible valid salts
145
  @rtype: function
146
  @return: salt verifier that returns True if the salt is in the collection
147

  
148
  """
149
  return lambda salt: salt in expected
150

  
151

  
152
def SaltInRange(min, max):
153
  """Helper salt verifier function that checks for equality.
154

  
155
  @type min: integer
156
  @param min: minimum salt value
157
  @type max: integer
158
  @param max: maximum salt value
159
  @rtype: function
160
  @return: salt verifier that returns True if the salt is in the min,max range
161

  
162
  """
163
  def _CheckSaltInRange(salt):
164
    try:
165
      i_salt = int(salt)
166
    except (TypeError, ValueError), err:
167
      return False
168

  
169
    return i_salt > min and i_salt < max
170

  
171
  return _CheckSaltInRange
172

  
173

  
73 174
Dump = DumpJson
74 175
Load = LoadJson
176
DumpSigned = DumpSignedJson
177
LoadSigned = LoadSignedJson

Also available in: Unified diff