X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/f4a2f532f9c6243444ab52b67fad18e0628e036e..cff5fa7f25e60a9c08fd68306b4c11d81880901e:/lib/serializer.py diff --git a/lib/serializer.py b/lib/serializer.py index 9781187..b568497 100644 --- a/lib/serializer.py +++ b/lib/serializer.py @@ -24,25 +24,51 @@ This module introduces a simple abstraction over the serialization backend (currently json). """ +# pylint: disable-msg=C0103 + +# C0103: Invalid name, since pylint doesn't see that Dump points to a +# function and not a constant import simplejson import re import hmac -import hashlib from ganeti import errors +try: + from hashlib import sha1 +except ImportError: + import sha as sha1 + -# Check whether the simplejson module supports indentation _JSON_INDENT = 2 -try: - simplejson.dumps(1, indent=_JSON_INDENT) -except TypeError: - _JSON_INDENT = None _RE_EOLSP = re.compile('[ \t]+$', re.MULTILINE) +def _GetJsonDumpers(_encoder_class=simplejson.JSONEncoder): + """Returns two JSON functions to serialize data. + + @rtype: (callable, callable) + @return: The function to generate a compact form of JSON and another one to + generate a more readable, indented form of JSON (if supported) + + """ + plain_encoder = _encoder_class(sort_keys=True) + + # Check whether the simplejson module supports indentation + try: + indent_encoder = _encoder_class(indent=_JSON_INDENT, sort_keys=True) + except TypeError: + # Indentation not supported + indent_encoder = plain_encoder + + return (plain_encoder.encode, indent_encoder.encode) + + +(_DumpJson, _DumpJsonIndent) = _GetJsonDumpers() + + def DumpJson(data, indent=True): """Serialize a given object. @@ -52,14 +78,15 @@ def DumpJson(data, indent=True): @return: the string representation of data """ - if not indent or _JSON_INDENT is None: - txt = simplejson.dumps(data) + if indent: + fn = _DumpJsonIndent else: - txt = simplejson.dumps(data, indent=_JSON_INDENT) + fn = _DumpJson - txt = _RE_EOLSP.sub("", txt) + txt = _RE_EOLSP.sub("", fn(data)) if not txt.endswith('\n'): txt += '\n' + return txt @@ -88,19 +115,18 @@ def DumpSignedJson(data, key, salt=None): signed_dict = { 'msg': txt, 'salt': salt, - 'hmac': hmac.new(key, salt + txt, hashlib.sha256).hexdigest(), + 'hmac': hmac.new(key, salt + txt, sha1).hexdigest(), } - return DumpJson(signed_dict) + return DumpJson(signed_dict, indent=False) -def LoadSignedJson(txt, key, salt_verifier=None): +def LoadSignedJson(txt, key): """Verify that a given message was signed with the given key, and load it. @param txt: json-encoded hmac-signed message @param key: shared hmac key - @param salt_verifier: function taking a salt as input and returning boolean @rtype: tuple of original data, string - @return: (original data, salt) + @return: original data, salt @raises errors.SignatureError: if the message signature doesn't verify """ @@ -114,61 +140,10 @@ def LoadSignedJson(txt, key, salt_verifier=None): except KeyError: raise errors.SignatureError('Invalid external message') - if salt and not salt_verifier: - raise errors.SignatureError('Salted message is not verified') - elif salt_verifier is not None: - if not salt_verifier(salt): - raise errors.SignatureError('Invalid salt') - - if hmac.new(key, salt + msg, hashlib.sha256).hexdigest() != hmac_sign: + if hmac.new(key, salt + msg, sha1).hexdigest() != hmac_sign: raise errors.SignatureError('Invalid Signature') - return LoadJson(msg) - - -def SaltEqualTo(expected): - """Helper salt verifier function that checks for equality. - - @type expected: string - @param expected: expected salt - @rtype: function - @return: salt verifier that returns True if the target salt is "x" - - """ - return lambda salt: salt == expected - - -def SaltIn(expected): - """Helper salt verifier function that checks for equality. - - @type expected: collection - @param expected: collection of possible valid salts - @rtype: function - @return: salt verifier that returns True if the salt is in the collection - - """ - return lambda salt: salt in expected - - -def SaltInRange(min, max): - """Helper salt verifier function that checks for equality. - - @type min: integer - @param min: minimum salt value - @type max: integer - @param max: maximum salt value - @rtype: function - @return: salt verifier that returns True if the salt is in the min,max range - - """ - def _CheckSaltInRange(salt): - try: - i_salt = int(salt) - except (TypeError, ValueError), err: - return False - - return i_salt > min and i_salt < max - return _CheckSaltInRange + return LoadJson(msg), salt Dump = DumpJson