Package src :: Module dispatcher_client
[hide private]
[frames] | no frames]

Source Code for Module src.dispatcher_client

  1  # 
  2  # Copyright (c) 2008--2016 Red Hat, Inc. 
  3  # 
  4  # This software is licensed to you under the GNU General Public License, 
  5  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
  6  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
  8  # along with this software; if not, see 
  9  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
 10  # 
 11  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 12  # granted to use or replicate Red Hat trademarks that are incorporated 
 13  # in this software or its documentation. 
 14  # 
 15   
 16  import time 
 17  import sys 
 18  from spacewalk.common.rhnLog import log_debug 
 19  from spacewalk.server import rhnSQL 
 20   
 21  try: # python 2 
 22      import jabber_lib 
 23  except ImportError: # python 3 
 24      from osad import jabber_lib 
 25   
26 -class Client(jabber_lib.JabberClient):
27 - def __init__(self, *args, **kwargs):
28 jabber_lib.JabberClient.__init__(self, *args, **kwargs) 29 self.username = None 30 self.resource = None
31 #self.DEBUG = jabber_lib.my_debug 32
33 - def start(self, username, password, resource):
34 # XXX find a better name for this function 35 log_debug(2) 36 self.auth(username, password, resource) 37 log_debug(3, "Authenticated") 38 self.username = username 39 self.resource = resource 40 self.jid = "%s@%s/%s" % (self.username, self._host, self.resource) 41 42 self.username = username 43 self.resource = resource
44
45 - def _add_jid_resource(self, jid, resource):
46 if not isinstance(jid, jabber_lib.jabber.JID) or jid.resource: 47 return jid 48 return jabber_lib.jabber.JID(str(jid) + '/' + resource)
49
50 - def _fix_jid(self, jid):
51 return self._add_jid_resource(jid, 'osad')
52
53 - def _check_signature(self, stanza, actions=None):
54 # Do we have this client in the table? 55 jid = stanza.getFrom() 56 if jid is None: 57 log_debug(3, 'no from') 58 return None 59 jid = str(self._fix_jid(jid)) 60 # Look for a <x> child that has our namespace 61 xes = stanza.getTags('x') 62 for x in xes: 63 if x.getNamespace() != jabber_lib.NS_RHN_SIGNED: 64 continue 65 break 66 else: #for 67 log_debug(1, "No signature node found in stanza") 68 return None 69 # We now have our signature node 70 x_client_id = x.getAttr('client-id') 71 72 row = lookup_client_by_name(x_client_id) 73 if not row: 74 log_debug(3, 'no client found', x_client_id) 75 if self.debug_level > 5: 76 raise Exception(1) 77 return None 78 shared_key = row['shared_key'] 79 timestamp = x.getAttr('timestap') 80 serial = x.getAttr('serial') 81 action = x.getAttr('action') 82 83 if actions and action not in actions: 84 log_debug(1, "action %s not allowed" % action) 85 return None 86 87 attrs = { 88 'client-id' : x_client_id, 89 'timestamp' : x.getAttr('timestamp'), 90 'serial' : x.getAttr('serial'), 91 'action' : x.getAttr('action'), 92 'jid' : jid, 93 } 94 signing_comps = ['client-id', 'timestamp', 'serial', 'action', 'jid'] 95 args = [shared_key, self.jid] 96 for sc in signing_comps: 97 args.append(attrs[sc]) 98 99 log_debug(4, "Signature args", args) 100 signature = jabber_lib.sign(*args) 101 x_signature = x.getAttr('signature') 102 if signature != x_signature: 103 log_debug(1, "Signatures do not match", signature, x_signature) 104 if self.debug_level > 5: 105 raise Exception(1) 106 return None 107 # Happy joy 108 return x
109
110 - def _create_signature(self, jid, action):
111 row = lookup_client_by_jid(jid) 112 if not row: 113 log_debug(3, 'no client found for jid', jid) 114 if self.debug_level > 5: 115 raise Exception(1) 116 return None 117 full_jid = row['jabber_id'] 118 shared_key = row['shared_key'] 119 attrs = { 120 'timestamp' : int(time.time()), 121 'serial' : self.get_unique_id(), 122 'action' : action, 123 'jid' : self.jid, 124 } 125 signing_comps = ['timestamp', 'serial', 'action', 'jid'] 126 args = [shared_key, full_jid] 127 for sc in signing_comps: 128 args.append(attrs[sc]) 129 130 log_debug(4, "Signature args", args) 131 attrs['signature'] = jabber_lib.sign(*args) 132 133 x = jabber_lib.jabber.xmlstream.Node('x') 134 x.setNamespace(jabber_lib.NS_RHN_SIGNED) 135 for k, v in attrs.items(): 136 x.putAttr(k, v) 137 return x
138
139 - def _message_callback(self, client, stanza):
140 log_debug(4) 141 assert stanza.getName() == 'message' 142 143 # Actions we know how to react to 144 actions = [ 145 jabber_lib.NS_RHN_MESSAGE_RESPONSE_CHECKIN, 146 jabber_lib.NS_RHN_MESSAGE_RESPONSE_PING, 147 ] 148 sig = self._check_signature_from_message(stanza, actions) 149 if not sig: 150 return 151 152 self.update_client_message_received(stanza.getFrom()) 153 154 action = sig.getAttr('action') 155 if action == jabber_lib.NS_RHN_MESSAGE_RESPONSE_PING: 156 log_debug(1, 'Ping response') 157 # XXX 158 return
159
160 - def ping_clients(self, clients):
161 for client in clients: 162 jid = client['jabber_id'] 163 if jid is None: 164 continue 165 self.send_message(jid, jabber_lib.NS_RHN_MESSAGE_REQUEST_PING)
166
167 - def set_jid_available(self, jid):
168 jabber_lib.JabberClient.set_jid_available(self, jid) 169 self._set_state(jid, self._get_push_state_id('online'))
170
171 - def set_jid_unavailable(self, jid):
172 jabber_lib.JabberClient.set_jid_unavailable(self, jid) 173 self._set_state(jid, self._get_push_state_id('offline'))
174 175 _query_set_state = rhnSQL.Statement(""" 176 update rhnPushClient 177 set state_id = :state_id, 178 last_ping_time = NULL, 179 next_action_time = NULL 180 where jabber_id = :jid 181 """)
182 - def _set_state(self, jid, state_id):
183 h = rhnSQL.prepare(self._query_set_state) 184 h.execute(state_id=state_id, jid=str(jid)) 185 rhnSQL.commit()
186
187 - def _get_push_state_id(self, state):
188 t = rhnSQL.Table('rhnPushClientState', 'label') 189 row = t[state] 190 assert row is not None 191 return row['id']
192 193 _query_update_client_message_received = rhnSQL.Statement(""" 194 update rhnPushClient 195 set state_id = :state_id, 196 last_message_time = current_timestamp, 197 last_ping_time = NULL, 198 next_action_time = NULL 199 where jabber_id = :jid 200 """)
201 - def update_client_message_received(self, jid):
202 jid = str(jid) 203 state_id = self._get_push_state_id('online') 204 h = rhnSQL.prepare(self._query_update_client_message_received) 205 ret = h.execute(jid=jid, state_id=state_id) 206 rhnSQL.commit()
207
208 -class InvalidClientError(Exception):
209 pass
210
211 -def lookup_client_by_name(client_name):
212 client_name = str(client_name) 213 t = rhnSQL.Table('rhnPushClient', 'name') 214 row = t[client_name] 215 if row is None: 216 raise InvalidClientError(client_name) 217 return row
218
219 -def lookup_client_by_jid(jid):
220 if not isinstance(jid, jabber_lib.jabber.JID): 221 jid = jabber_lib.jabber.JID(jid) 222 223 if not jid.getResource(): 224 # add the resource so we can find the guy in our table 225 jid.setResource('osad') 226 227 jid = str(jid) 228 t = rhnSQL.Table('rhnPushClient', 'jabber_id') 229 row = t[jid] 230 if row is None: 231 raise InvalidClientError(jid) 232 return row
233