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-msg=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 simplejson 
 33  import re 
 34   
 35  from ganeti import errors 
 36  from ganeti import utils 
 37   
 38   
 39  _JSON_INDENT = 2 
 40   
 41  _RE_EOLSP = re.compile('[ \t]+$', re.MULTILINE) 
 42   
 43   
44 -def _GetJsonDumpers(_encoder_class=simplejson.JSONEncoder):
45 """Returns two JSON functions to serialize data. 46 47 @rtype: (callable, callable) 48 @return: The function to generate a compact form of JSON and another one to 49 generate a more readable, indented form of JSON (if supported) 50 51 """ 52 plain_encoder = _encoder_class(sort_keys=True) 53 54 # Check whether the simplejson module supports indentation 55 try: 56 indent_encoder = _encoder_class(indent=_JSON_INDENT, sort_keys=True) 57 except TypeError: 58 # Indentation not supported 59 indent_encoder = plain_encoder 60 61 return (plain_encoder.encode, indent_encoder.encode)
62 63 64 (_DumpJson, _DumpJsonIndent) = _GetJsonDumpers() 65 66
67 -def DumpJson(data, indent=True):
68 """Serialize a given object. 69 70 @param data: the data to serialize 71 @param indent: whether to indent output (depends on simplejson version) 72 73 @return: the string representation of data 74 75 """ 76 if indent: 77 fn = _DumpJsonIndent 78 else: 79 fn = _DumpJson 80 81 txt = _RE_EOLSP.sub("", fn(data)) 82 if not txt.endswith('\n'): 83 txt += '\n' 84 85 return txt
86 87
88 -def LoadJson(txt):
89 """Unserialize data from a string. 90 91 @param txt: the json-encoded form 92 93 @return: the original data 94 95 """ 96 return simplejson.loads(txt)
97 98
99 -def DumpSignedJson(data, key, salt=None, key_selector=None):
100 """Serialize a given object and authenticate it. 101 102 @param data: the data to serialize 103 @param key: shared hmac key 104 @param key_selector: name/id that identifies the key (in case there are 105 multiple keys in use, e.g. in a multi-cluster environment) 106 @return: the string representation of data signed by the hmac key 107 108 """ 109 txt = DumpJson(data, indent=False) 110 if salt is None: 111 salt = '' 112 signed_dict = { 113 'msg': txt, 114 'salt': salt, 115 } 116 117 if key_selector: 118 signed_dict["key_selector"] = key_selector 119 else: 120 key_selector = "" 121 122 signed_dict["hmac"] = utils.Sha1Hmac(key, txt, salt=salt + key_selector) 123 124 return DumpJson(signed_dict, indent=False)
125 126
127 -def LoadSignedJson(txt, key):
128 """Verify that a given message was signed with the given key, and load it. 129 130 @param txt: json-encoded hmac-signed message 131 @param key: the shared hmac key or a callable taking one argument (the key 132 selector), which returns the hmac key belonging to the key selector. 133 Typical usage is to pass a reference to the get method of a dict. 134 @rtype: tuple of original data, string 135 @return: original data, salt 136 @raises errors.SignatureError: if the message signature doesn't verify 137 138 """ 139 signed_dict = LoadJson(txt) 140 if not isinstance(signed_dict, dict): 141 raise errors.SignatureError('Invalid external message') 142 try: 143 msg = signed_dict['msg'] 144 salt = signed_dict['salt'] 145 hmac_sign = signed_dict['hmac'] 146 except KeyError: 147 raise errors.SignatureError('Invalid external message') 148 149 if callable(key): 150 # pylint: disable-msg=E1103 151 key_selector = signed_dict.get("key_selector", None) 152 hmac_key = key(key_selector) 153 if not hmac_key: 154 raise errors.SignatureError("No key with key selector '%s' found" % 155 key_selector) 156 else: 157 key_selector = "" 158 hmac_key = key 159 160 if not utils.VerifySha1Hmac(hmac_key, msg, hmac_sign, 161 salt=salt + key_selector): 162 raise errors.SignatureError('Invalid Signature') 163 164 return LoadJson(msg), salt
165 166 167 Dump = DumpJson 168 Load = LoadJson 169 DumpSigned = DumpSignedJson 170 LoadSigned = LoadSignedJson 171