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  __docformat__="restructuredtext en" 
 25   
 26  import hashlib 
 27   
 28  import logging 
 29   
 30  from pyxmpp.stream import Stream 
 31  from pyxmpp.streambase import stanza_factory,HostMismatch 
 32  from pyxmpp.xmlextra import common_doc,common_root 
 33  from pyxmpp.utils import to_utf8 
 34  from pyxmpp.exceptions import StreamError,FatalStreamError,ComponentStreamError,FatalComponentStreamError 
 35   
36 -class ComponentStream(Stream):
37 """Handles jabberd component (jabber:component:accept) connection stream. 38 39 :Ivariables: 40 - `server`: server to use. 41 - `port`: port number to use. 42 - `secret`: authentication secret. 43 :Types: 44 - `server`: `unicode` 45 - `port`: `int` 46 - `secret`: `unicode`""" 47
48 - def __init__(self, jid, secret, server, port, keepalive = 0, owner = None):
49 """Initialize a `ComponentStream` object. 50 51 :Parameters: 52 - `jid`: JID of the component. 53 - `secret`: authentication secret. 54 - `server`: server address. 55 - `port`: TCP port number on the server. 56 - `keepalive`: keepalive interval. 0 to disable. 57 - `owner`: `Client`, `Component` or similar object "owning" this stream. 58 """ 59 Stream.__init__(self, "jabber:component:accept", 60 sasl_mechanisms = [], 61 tls_settings = None, 62 keepalive = keepalive, 63 owner = owner) 64 self.server=server 65 self.port=port 66 self.me=jid 67 self.secret=secret 68 self.process_all_stanzas=1 69 self.__logger=logging.getLogger("pyxmpp.jabberd.ComponentStream")
70
71 - def _reset(self):
72 """Reset `ComponentStream` object state, making the object ready to 73 handle new connections.""" 74 Stream._reset(self)
75
76 - def connect(self,server=None,port=None):
77 """Establish a client connection to a server. 78 79 [component only] 80 81 :Parameters: 82 - `server`: name or address of the server to use. If not given 83 then use the one specified when creating the object. 84 - `port`: port number of the server to use. If not given then use 85 the one specified when creating the object. 86 87 :Types: 88 - `server`: `unicode` 89 - `port`: `int`""" 90 self.lock.acquire() 91 try: 92 self._connect(server,port) 93 finally: 94 self.lock.release()
95
96 - def _connect(self,server=None,port=None):
97 """Same as `ComponentStream.connect` but assume `self.lock` is acquired.""" 98 if self.me.node or self.me.resource: 99 raise Value, "Component JID may have only domain defined" 100 if not server: 101 server=self.server 102 if not port: 103 port=self.port 104 if not server or not port: 105 raise ValueError, "Server or port not given" 106 Stream._connect(self,server,port,None,self.me)
107
108 - def accept(self,sock):
109 """Accept an incoming component connection. 110 111 [server only] 112 113 :Parameters: 114 - `sock`: a listening socket.""" 115 Stream.accept(self,sock,None)
116
117 - def stream_start(self,doc):
118 """Process <stream:stream> (stream start) tag received from peer. 119 120 Call `Stream.stream_start`, but ignore any `HostMismatch` error. 121 122 :Parameters: 123 - `doc`: document created by the parser""" 124 try: 125 Stream.stream_start(self,doc) 126 except HostMismatch: 127 pass
128
129 - def _post_connect(self):
130 """Initialize authentication when the connection is established 131 and we are the initiator.""" 132 if self.initiator: 133 self._auth()
134
135 - def _compute_handshake(self):
136 """Compute the authentication handshake value. 137 138 :return: the computed hash value. 139 :returntype: `str`""" 140 return hashlib.sha1(to_utf8(self.stream_id)+to_utf8(self.secret)).hexdigest()
141
142 - def _auth(self):
143 """Authenticate on the server. 144 145 [component only]""" 146 if self.authenticated: 147 self.__logger.debug("_auth: already authenticated") 148 return 149 self.__logger.debug("doing handshake...") 150 hash_value=self._compute_handshake() 151 n=common_root.newTextChild(None,"handshake",hash_value) 152 self._write_node(n) 153 n.unlinkNode() 154 n.freeNode() 155 self.__logger.debug("handshake hash sent.")
156
157 - def _process_node(self,node):
158 """Process first level element of the stream. 159 160 Handle component handshake (authentication) element, and 161 treat elements in "jabber:component:accept", "jabber:client" 162 and "jabber:server" equally (pass to `self.process_stanza`). 163 All other elements are passed to `Stream._process_node`. 164 165 :Parameters: 166 - `node`: XML node describing the element 167 """ 168 ns=node.ns() 169 if ns: 170 ns_uri=node.ns().getContent() 171 if (not ns or ns_uri=="jabber:component:accept") and node.name=="handshake": 172 if self.initiator and not self.authenticated: 173 self.authenticated=1 174 self.state_change("authenticated",self.me) 175 self._post_auth() 176 return 177 elif not self.authenticated and node.getContent()==self._compute_handshake(): 178 self.peer=self.me 179 n=common_doc.newChild(None,"handshake",None) 180 self._write_node(n) 181 n.unlinkNode() 182 n.freeNode() 183 self.peer_authenticated=1 184 self.state_change("authenticated",self.peer) 185 self._post_auth() 186 return 187 else: 188 self._send_stream_error("not-authorized") 189 raise FatalComponentStreamError,"Hanshake error." 190 191 if ns_uri in ("jabber:component:accept","jabber:client","jabber:server"): 192 stanza=stanza_factory(node) 193 self.lock.release() 194 try: 195 self.process_stanza(stanza) 196 finally: 197 self.lock.acquire() 198 stanza.free() 199 return 200 return Stream._process_node(self,node)
201 202 # vi: sts=4 et sw=4 203