1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 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 652 2006-08-27 19:41:15Z jajcus $" 
 25  __docformat__="restructuredtext en" 
 26   
 27  import sha 
 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   
 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   
 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   
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   
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   
136          """Compute the authentication handshake value. 
137   
138          :return: the computed hash value. 
139          :returntype: `str`""" 
140          return sha.new(to_utf8(self.stream_id)+to_utf8(self.secret)).hexdigest() 
 141   
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   
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   
203