Package pyxmpp :: Package jabberd :: Module componentstream
[hide private]

Source Code for Module pyxmpp.jabberd.componentstream

  1  # 
  2  # (C) Copyright 2003-2010 Jacek Konieczny <jajcus@jajcus.net> 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU Lesser General Public License Version 
  6  # 2.1 as published by the Free Software Foundation. 
  7  # 
  8  # This program is distributed in the hope that it will be useful, 
  9  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 11  # GNU Lesser General Public License for more details. 
 12  # 
 13  # You should have received a copy of the GNU Lesser General Public 
 14  # License along with this program; if not, write to the Free Software 
 15  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 16  # 
 17  # pylint: disable-msg=W0221, W0201 
 18  """Component (jabber:component:accept) stream handling. 
 19   
 20  Normative reference: 
 21    - `JEP 114 <http://www.jabber.org/jeps/jep-0114.html>`__ 
 22  """ 
 23   
 24  __revision__="$Id: componentstream.py 703 2010-04-03 17:45:43Z jajcus $" 
 25  __docformat__="restructuredtext en" 
 26   
 27  import hashlib 
 28   
 29  import logging 
 30   
 31  from pyxmpp.stream import Stream 
 32  from pyxmpp.streambase import stanza_factory,HostMismatch 
 33  from pyxmpp.xmlextra import common_doc,common_root 
 34  from pyxmpp.utils import to_utf8 
 35  from pyxmpp.exceptions import StreamError,FatalStreamError,ComponentStreamError,FatalComponentStreamError 
 36   
37 -class ComponentStream(Stream):
38 """Handles jabberd component (jabber:component:accept) connection stream. 39 40 :Ivariables: 41 - `server`: server to use. 42 - `port`: port number to use. 43 - `secret`: authentication secret. 44 :Types: 45 - `server`: `unicode` 46 - `port`: `int` 47 - `secret`: `unicode`""" 48
49 - def __init__(self, jid, secret, server, port, keepalive = 0, owner = None):
50 """Initialize a `ComponentStream` object. 51 52 :Parameters: 53 - `jid`: JID of the component. 54 - `secret`: authentication secret. 55 - `server`: server address. 56 - `port`: TCP port number on the server. 57 - `keepalive`: keepalive interval. 0 to disable. 58 - `owner`: `Client`, `Component` or similar object "owning" this stream. 59 """ 60 Stream.__init__(self, "jabber:component:accept", 61 sasl_mechanisms = [], 62 tls_settings = None, 63 keepalive = keepalive, 64 owner = owner) 65 self.server=server 66 self.port=port 67 self.me=jid 68 self.secret=secret 69 self.process_all_stanzas=1 70 self.__logger=logging.getLogger("pyxmpp.jabberd.ComponentStream")
71
72 - def _reset(self):
73 """Reset `ComponentStream` object state, making the object ready to 74 handle new connections.""" 75 Stream._reset(self)
76
77 - def connect(self,server=None,port=None):
78 """Establish a client connection to a server. 79 80 [component only] 81 82 :Parameters: 83 - `server`: name or address of the server to use. If not given 84 then use the one specified when creating the object. 85 - `port`: port number of the server to use. If not given then use 86 the one specified when creating the object. 87 88 :Types: 89 - `server`: `unicode` 90 - `port`: `int`""" 91 self.lock.acquire() 92 try: 93 self._connect(server,port) 94 finally: 95 self.lock.release()
96
97 - def _connect(self,server=None,port=None):
98 """Same as `ComponentStream.connect` but assume `self.lock` is acquired.""" 99 if self.me.node or self.me.resource: 100 raise Value, "Component JID may have only domain defined" 101 if not server: 102 server=self.server 103 if not port: 104 port=self.port 105 if not server or not port: 106 raise ValueError, "Server or port not given" 107 Stream._connect(self,server,port,None,self.me)
108
109 - def accept(self,sock):
110 """Accept an incoming component connection. 111 112 [server only] 113 114 :Parameters: 115 - `sock`: a listening socket.""" 116 Stream.accept(self,sock,None)
117
118 - def stream_start(self,doc):
119 """Process <stream:stream> (stream start) tag received from peer. 120 121 Call `Stream.stream_start`, but ignore any `HostMismatch` error. 122 123 :Parameters: 124 - `doc`: document created by the parser""" 125 try: 126 Stream.stream_start(self,doc) 127 except HostMismatch: 128 pass
129
130 - def _post_connect(self):
131 """Initialize authentication when the connection is established 132 and we are the initiator.""" 133 if self.initiator: 134 self._auth()
135
136 - def _compute_handshake(self):
137 """Compute the authentication handshake value. 138 139 :return: the computed hash value. 140 :returntype: `str`""" 141 return hashlib.sha1(to_utf8(self.stream_id)+to_utf8(self.secret)).hexdigest()
142
143 - def _auth(self):
144 """Authenticate on the server. 145 146 [component only]""" 147 if self.authenticated: 148 self.__logger.debug("_auth: already authenticated") 149 return 150 self.__logger.debug("doing handshake...") 151 hash_value=self._compute_handshake() 152 n=common_root.newTextChild(None,"handshake",hash_value) 153 self._write_node(n) 154 n.unlinkNode() 155 n.freeNode() 156 self.__logger.debug("handshake hash sent.")
157
158 - def _process_node(self,node):
159 """Process first level element of the stream. 160 161 Handle component handshake (authentication) element, and 162 treat elements in "jabber:component:accept", "jabber:client" 163 and "jabber:server" equally (pass to `self.process_stanza`). 164 All other elements are passed to `Stream._process_node`. 165 166 :Parameters: 167 - `node`: XML node describing the element 168 """ 169 ns=node.ns() 170 if ns: 171 ns_uri=node.ns().getContent() 172 if (not ns or ns_uri=="jabber:component:accept") and node.name=="handshake": 173 if self.initiator and not self.authenticated: 174 self.authenticated=1 175 self.state_change("authenticated",self.me) 176 self._post_auth() 177 return 178 elif not self.authenticated and node.getContent()==self._compute_handshake(): 179 self.peer=self.me 180 n=common_doc.newChild(None,"handshake",None) 181 self._write_node(n) 182 n.unlinkNode() 183 n.freeNode() 184 self.peer_authenticated=1 185 self.state_change("authenticated",self.peer) 186 self._post_auth() 187 return 188 else: 189 self._send_stream_error("not-authorized") 190 raise FatalComponentStreamError,"Hanshake error." 191 192 if ns_uri in ("jabber:component:accept","jabber:client","jabber:server"): 193 stanza=stanza_factory(node) 194 self.lock.release() 195 try: 196 self.process_stanza(stanza) 197 finally: 198 self.lock.acquire() 199 stanza.free() 200 return 201 return Stream._process_node(self,node)
202 203 # vi: sts=4 et sw=4 204