8 Wrapper around safexmlrpc.ServerProxy to automagically add an Auth
9 struct as the first argument to every XML-RPC call. Initialize
12 (node_id, key) => BootAuth
14 session => SessionAuth
16 To authenticate using the Boot Manager authentication method, or
17 the new session-based method.
20 def __init__(self, uri, cacert, auth, timeout = 90, **kwds):
21 if isinstance(auth, (tuple, list)):
22 (self.node_id, self.key) = auth
25 self.node_id = self.key = None
28 self.server = safexmlrpc.ServerProxy(uri, cacert, timeout, allow_none = 1, **kwds)
30 def add_auth(self, function):
32 Returns a wrapper which adds an Auth struct as the first
33 argument when the function is called.
36 def canonicalize(args):
38 BootAuth canonicalization method. Parameter values are
39 collected, sorted, converted to strings, then hashed with
46 if isinstance(arg, list) or isinstance(arg, tuple):
47 # The old implementation did not recursively handle
48 # lists of lists. But neither did the old API itself.
49 values += canonicalize(arg)
50 elif isinstance(arg, dict):
51 # Yes, the comments in the old implementation are
52 # misleading. Keys of dicts are not included in the
54 values += canonicalize(arg.values())
56 # We use unicode() instead of str().
57 values.append(unicode(arg))
63 Adds an Auth struct as the first argument when the
67 if self.session is not None:
68 # Use session authentication
69 auth = {'AuthMethod': "session",
70 'session': self.session}
72 # Yes, this is the "canonicalization" method used.
73 args = canonicalize(params)
75 msg = "[" + "".join(args) + "]"
77 # We encode in UTF-8 before calculating the HMAC, which is
79 digest = hmac.new(self.key, msg.encode('utf-8'), sha).hexdigest()
81 auth = {'AuthMethod': "hmac",
82 'node_id': self.node_id,
85 # Automagically add auth struct to every call
86 params = (auth,) + params
88 return function(*params)
92 def __getattr__(self, methodname):
93 function = getattr(self.server, methodname)
94 return self.add_auth(function)