Statistics
| Branch: | Tag: | Revision:

root / lib / serializer.py @ 936f3c59

History | View | Annotate | Download (3.7 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 d357f531 Michael Hanselmann
40 8d14b30d Iustin Pop
_JSON_INDENT = 2
41 8d14b30d Iustin Pop
42 e91ffe49 Michael Hanselmann
_RE_EOLSP = re.compile('[ \t]+$', re.MULTILINE)
43 8d14b30d Iustin Pop
44 8d14b30d Iustin Pop
45 d357f531 Michael Hanselmann
def _GetJsonDumpers():
46 d357f531 Michael Hanselmann
  """Returns two JSON functions to serialize data.
47 d357f531 Michael Hanselmann

48 d357f531 Michael Hanselmann
  @rtype: (callable, callable)
49 d357f531 Michael Hanselmann
  @return: The function to generate a compact form of JSON and another one to
50 d357f531 Michael Hanselmann
           generate a more readable, indented form of JSON (if supported)
51 d357f531 Michael Hanselmann

52 d357f531 Michael Hanselmann
  """
53 d357f531 Michael Hanselmann
  plain_dump = simplejson.dumps
54 d357f531 Michael Hanselmann
55 d357f531 Michael Hanselmann
  # Check whether the simplejson module supports indentation
56 d357f531 Michael Hanselmann
  try:
57 d357f531 Michael Hanselmann
    simplejson.dumps(1, indent=_JSON_INDENT)
58 d357f531 Michael Hanselmann
  except TypeError:
59 d357f531 Michael Hanselmann
    # Indentation not supported
60 d357f531 Michael Hanselmann
    indent_dump = plain_dump
61 d357f531 Michael Hanselmann
  else:
62 d357f531 Michael Hanselmann
    # Indentation supported
63 d357f531 Michael Hanselmann
    indent_dump = lambda data: simplejson.dumps(data, indent=_JSON_INDENT)
64 d357f531 Michael Hanselmann
65 d357f531 Michael Hanselmann
  assert callable(plain_dump)
66 d357f531 Michael Hanselmann
  assert callable(indent_dump)
67 d357f531 Michael Hanselmann
68 d357f531 Michael Hanselmann
  return (plain_dump, indent_dump)
69 d357f531 Michael Hanselmann
70 d357f531 Michael Hanselmann
71 d357f531 Michael Hanselmann
(_DumpJson, _DumpJsonIndent) = _GetJsonDumpers()
72 d357f531 Michael Hanselmann
73 d357f531 Michael Hanselmann
74 071448fb Michael Hanselmann
def DumpJson(data, indent=True):
75 8d14b30d Iustin Pop
  """Serialize a given object.
76 8d14b30d Iustin Pop

77 c41eea6e Iustin Pop
  @param data: the data to serialize
78 c41eea6e Iustin Pop
  @param indent: whether to indent output (depends on simplejson version)
79 c41eea6e Iustin Pop

80 c41eea6e Iustin Pop
  @return: the string representation of data
81 071448fb Michael Hanselmann

82 8d14b30d Iustin Pop
  """
83 d357f531 Michael Hanselmann
  if indent:
84 d357f531 Michael Hanselmann
    fn = _DumpJsonIndent
85 8d14b30d Iustin Pop
  else:
86 d357f531 Michael Hanselmann
    fn = _DumpJson
87 071448fb Michael Hanselmann
88 d357f531 Michael Hanselmann
  txt = _RE_EOLSP.sub("", fn(data))
89 8d14b30d Iustin Pop
  if not txt.endswith('\n'):
90 8d14b30d Iustin Pop
    txt += '\n'
91 d357f531 Michael Hanselmann
92 8d14b30d Iustin Pop
  return txt
93 8d14b30d Iustin Pop
94 8d14b30d Iustin Pop
95 228538cf Michael Hanselmann
def LoadJson(txt):
96 8d14b30d Iustin Pop
  """Unserialize data from a string.
97 8d14b30d Iustin Pop

98 c41eea6e Iustin Pop
  @param txt: the json-encoded form
99 c41eea6e Iustin Pop

100 c41eea6e Iustin Pop
  @return: the original data
101 c41eea6e Iustin Pop

102 8d14b30d Iustin Pop
  """
103 8d14b30d Iustin Pop
  return simplejson.loads(txt)
104 228538cf Michael Hanselmann
105 228538cf Michael Hanselmann
106 f4a2f532 Guido Trotter
def DumpSignedJson(data, key, salt=None):
107 f4a2f532 Guido Trotter
  """Serialize a given object and authenticate it.
108 f4a2f532 Guido Trotter

109 f4a2f532 Guido Trotter
  @param data: the data to serialize
110 f4a2f532 Guido Trotter
  @param key: shared hmac key
111 f4a2f532 Guido Trotter
  @return: the string representation of data signed by the hmac key
112 f4a2f532 Guido Trotter

113 f4a2f532 Guido Trotter
  """
114 f4a2f532 Guido Trotter
  txt = DumpJson(data, indent=False)
115 f4a2f532 Guido Trotter
  if salt is None:
116 f4a2f532 Guido Trotter
    salt = ''
117 f4a2f532 Guido Trotter
  signed_dict = {
118 f4a2f532 Guido Trotter
    'msg': txt,
119 f4a2f532 Guido Trotter
    'salt': salt,
120 541822e0 Guido Trotter
    'hmac': hmac.new(key, salt + txt, sha1).hexdigest(),
121 f4a2f532 Guido Trotter
  }
122 40765aa0 Guido Trotter
  return DumpJson(signed_dict, indent=False)
123 f4a2f532 Guido Trotter
124 f4a2f532 Guido Trotter
125 4e9dac14 Guido Trotter
def LoadSignedJson(txt, key):
126 f4a2f532 Guido Trotter
  """Verify that a given message was signed with the given key, and load it.
127 f4a2f532 Guido Trotter

128 f4a2f532 Guido Trotter
  @param txt: json-encoded hmac-signed message
129 f4a2f532 Guido Trotter
  @param key: shared hmac key
130 f4a2f532 Guido Trotter
  @rtype: tuple of original data, string
131 4e9dac14 Guido Trotter
  @return: original data, salt
132 f4a2f532 Guido Trotter
  @raises errors.SignatureError: if the message signature doesn't verify
133 f4a2f532 Guido Trotter

134 f4a2f532 Guido Trotter
  """
135 f4a2f532 Guido Trotter
  signed_dict = LoadJson(txt)
136 f4a2f532 Guido Trotter
  if not isinstance(signed_dict, dict):
137 f4a2f532 Guido Trotter
    raise errors.SignatureError('Invalid external message')
138 f4a2f532 Guido Trotter
  try:
139 f4a2f532 Guido Trotter
    msg = signed_dict['msg']
140 f4a2f532 Guido Trotter
    salt = signed_dict['salt']
141 f4a2f532 Guido Trotter
    hmac_sign = signed_dict['hmac']
142 f4a2f532 Guido Trotter
  except KeyError:
143 f4a2f532 Guido Trotter
    raise errors.SignatureError('Invalid external message')
144 f4a2f532 Guido Trotter
145 541822e0 Guido Trotter
  if hmac.new(key, salt + msg, sha1).hexdigest() != hmac_sign:
146 f4a2f532 Guido Trotter
    raise errors.SignatureError('Invalid Signature')
147 f4a2f532 Guido Trotter
148 4e9dac14 Guido Trotter
  return LoadJson(msg), salt
149 f4a2f532 Guido Trotter
150 f4a2f532 Guido Trotter
151 228538cf Michael Hanselmann
Dump = DumpJson
152 228538cf Michael Hanselmann
Load = LoadJson
153 f4a2f532 Guido Trotter
DumpSigned = DumpSignedJson
154 f4a2f532 Guido Trotter
LoadSigned = LoadSignedJson