Package ganeti :: Module serializer
[hide private]
[frames] | no frames]

Source Code for Module ganeti.serializer

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2007, 2008 Google Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, but 
 12  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 14  # General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 19  # 02110-1301, USA. 
 20   
 21  """Serializer abstraction module 
 22   
 23  This module introduces a simple abstraction over the serialization 
 24  backend (currently json). 
 25   
 26  """ 
 27  # pylint: disable=C0103 
 28   
 29  # C0103: Invalid name, since pylint doesn't see that Dump points to a 
 30  # function and not a constant 
 31   
 32  import re 
 33   
 34  # Python 2.6 and above contain a JSON module based on simplejson. Unfortunately 
 35  # the standard library version is significantly slower than the external 
 36  # module. While it should be better from at least Python 3.2 on (see Python 
 37  # issue 7451), for now Ganeti needs to work well with older Python versions 
 38  # too. 
 39  import simplejson 
 40   
 41  from ganeti import errors 
 42  from ganeti import utils 
 43   
 44   
 45  _RE_EOLSP = re.compile("[ \t]+$", re.MULTILINE) 
 46   
 47   
48 -def DumpJson(data):
49 """Serialize a given object. 50 51 @param data: the data to serialize 52 @return: the string representation of data 53 54 """ 55 encoded = simplejson.dumps(data) 56 57 txt = _RE_EOLSP.sub("", encoded) 58 if not txt.endswith("\n"): 59 txt += "\n" 60 61 return txt
62 63
64 -def LoadJson(txt):
65 """Unserialize data from a string. 66 67 @param txt: the json-encoded form 68 69 @return: the original data 70 71 """ 72 return simplejson.loads(txt)
73 74
75 -def DumpSignedJson(data, key, salt=None, key_selector=None):
76 """Serialize a given object and authenticate it. 77 78 @param data: the data to serialize 79 @param key: shared hmac key 80 @param key_selector: name/id that identifies the key (in case there are 81 multiple keys in use, e.g. in a multi-cluster environment) 82 @return: the string representation of data signed by the hmac key 83 84 """ 85 txt = DumpJson(data) 86 if salt is None: 87 salt = "" 88 signed_dict = { 89 "msg": txt, 90 "salt": salt, 91 } 92 93 if key_selector: 94 signed_dict["key_selector"] = key_selector 95 else: 96 key_selector = "" 97 98 signed_dict["hmac"] = utils.Sha1Hmac(key, txt, salt=salt + key_selector) 99 100 return DumpJson(signed_dict)
101 102
103 -def LoadSignedJson(txt, key):
104 """Verify that a given message was signed with the given key, and load it. 105 106 @param txt: json-encoded hmac-signed message 107 @param key: the shared hmac key or a callable taking one argument (the key 108 selector), which returns the hmac key belonging to the key selector. 109 Typical usage is to pass a reference to the get method of a dict. 110 @rtype: tuple of original data, string 111 @return: original data, salt 112 @raises errors.SignatureError: if the message signature doesn't verify 113 114 """ 115 signed_dict = LoadJson(txt) 116 if not isinstance(signed_dict, dict): 117 raise errors.SignatureError("Invalid external message") 118 try: 119 msg = signed_dict["msg"] 120 salt = signed_dict["salt"] 121 hmac_sign = signed_dict["hmac"] 122 except KeyError: 123 raise errors.SignatureError("Invalid external message") 124 125 if callable(key): 126 # pylint: disable=E1103 127 key_selector = signed_dict.get("key_selector", None) 128 hmac_key = key(key_selector) 129 if not hmac_key: 130 raise errors.SignatureError("No key with key selector '%s' found" % 131 key_selector) 132 else: 133 key_selector = "" 134 hmac_key = key 135 136 if not utils.VerifySha1Hmac(hmac_key, msg, hmac_sign, 137 salt=salt + key_selector): 138 raise errors.SignatureError("Invalid Signature") 139 140 return LoadJson(msg), salt
141 142
143 -def LoadAndVerifyJson(raw, verify_fn):
144 """Parses and verifies JSON data. 145 146 @type raw: string 147 @param raw: Input data in JSON format 148 @type verify_fn: callable 149 @param verify_fn: Verification function, usually from L{ht} 150 @return: De-serialized data 151 152 """ 153 try: 154 data = LoadJson(raw) 155 except Exception, err: 156 raise errors.ParseError("Can't parse input data: %s" % err) 157 158 if not verify_fn(data): 159 raise errors.ParseError("Data does not match expected format: %s" % 160 verify_fn) 161 162 return data
163 164 165 Dump = DumpJson 166 Load = LoadJson 167 DumpSigned = DumpSignedJson 168 LoadSigned = LoadSignedJson 169