Permalink
Browse files

- many new fixes, updates... and workarounds

- copying info (LGPL)
- SASL and legacy auth is working (at least pyxmpp <-> pyxmpp)
  • Loading branch information...
Jajcus committed Jun 3, 2003
1 parent c757130 commit d5ed22c4d29ff0b81fb91ea7bfcca5687a0c9822
@@ -0,0 +1,2 @@
.memdump
*.pyc
504 COPYING

Large diffs are not rendered by default.

Oops, something went wrong.
22 examples/stest.py 100755 → 100644
@@ -6,19 +6,17 @@
import traceback
import socket

from pyxmpp import ClientStream,JID,Iq,Presence,Message
from pyxmpp import ClientStream,JID,Iq,Presence,Message,StreamError

class Disconnected(Exception):
pass

class Stream(ClientStream):
def post_in_auth(self):
def post_auth(self):
print ":-)"
self.write(Presence())
def idle(self):
if self.peer_authenticated():
target=JID("jajcus",s.jid.domain)
self.write(Message(to=target,body="Test"))
self.set_message_handler("normal",self.message_in)
self.set_message_handler("chat",self.message_in)

def post_disconnect(self):
raise Disconnected

@@ -30,6 +28,12 @@ def get_password(self,username,realm=None,acceptable_formats=("plain",)):
return unicode("zieleñ","iso-8859-2"),"plain"
return None,None

def message_in(self,stanza):
echo=Message(fr=stanza.get_to(),to=stanza.get_from(),
body=stanza.get_body(), subject=stanza.get_subject())
self.send(echo)


libxml2.debugMemory(1)

print "creating socket..."
@@ -39,7 +43,7 @@ def get_password(self,username,realm=None,acceptable_formats=("plain",)):
sock.listen(1)

print "creating stream..."
s=Stream(JID("localhost"))
s=Stream(JID("localhost"),auth_methods=("plain","digest"))

while 1:
print "accepting..."
@@ -55,7 +59,7 @@ def get_password(self,username,realm=None,acceptable_formats=("plain",)):
except KeyboardInterrupt:
traceback.print_exc(file=sys.stderr)
break
except (stream.StreamError,Disconnected),e:
except (StreamError,Disconnected),e:
traceback.print_exc(file=sys.stderr)

libxml2.cleanupParser()
8 examples/test.py 100755 → 100644
@@ -5,7 +5,7 @@
import traceback
import sys

from pyxmpp import ClientStream,JID,Iq,Presence,Message
from pyxmpp import ClientStream,JID,Iq,Presence,Message,StreamError

class Disconnected(Exception):
pass
@@ -15,7 +15,9 @@ def post_auth(self):
print ":-)"
self.send(Presence())
def idle(self):
if self.authenticated():
print "idle"
ClientStream.idle(self)
if self.authenticated:
target=JID("jajcus",s.jid.domain)
self.send(Message(to=target,body=unicode("Te¶cik","iso-8859-2")))
def post_disconnect(self):
@@ -38,7 +40,7 @@ def post_disconnect(self):
s.disconnect()
except KeyboardInterrupt:
traceback.print_exc(file=sys.stderr)
except (stream.StreamError,Disconnected,KeyboardInterrupt),e:
except (StreamError,Disconnected),e:
raise

libxml2.cleanupParser()
@@ -1 +1,2 @@
*.pyc
.memdump
@@ -1,7 +1,24 @@
#
# (C) Copyright 2003 Jacek Konieczny <jajcus@bnet.pl>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License Version
# 2.1 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from stream import Stream
from stream import Stream,StreamError
from client import ClientStream
from iq import Iq
from presence import Presence
from message import Message
from jid import JID
from jid import JID,JIDError
from stanza import StanzaError
@@ -1,6 +1,23 @@
#
# (C) Copyright 2003 Jacek Konieczny <jajcus@bnet.pl>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License Version
# 2.1 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import libxml2
import sha
import time
from types import UnicodeType

import stream
@@ -17,7 +34,7 @@ class AuthenticationError(ClientError):

class ClientStream(stream.Stream):
def __init__(self,jid,password=None,server=None,port=5222,
auth_methods=["sasl:DIGEST-MD5","digest","plain"],
auth_methods=["sasl:DIGEST-MD5","digest"],
enable_tls=0,require_tls=0):
sasl_mechanisms=[]
for m in auth_methods:
@@ -35,11 +52,12 @@ def __init__(self,jid,password=None,server=None,port=5222,
self.server=jid.domain
self.port=port
self.jid=jid
self.peer_jid=None
self.password=password
self.auth_methods=auth_methods
self._authenticated=0
self._peer_authenticated=0
self.auth_methods_left=[]
self.available_auth_methods=None
self.features_timeout=None
self.auth_stanza=None

def connect(self,server=None,port=None):
if not self.jid.node or not self.jid.resource:
@@ -55,15 +73,67 @@ def accept(self,sock):

def post_connect(self):
if self.initiator:
self.peer_jid=JID(self.peer)
#self.auth_stage1()
self.sasl_authorize(self.jid.node,self.jid.as_unicode())
self.auth_methods_left=self.auth_methods
#self.try_auth()
else:
self.set_iq_get_handler("query","jabber:iq:auth",self.auth_in_stage1)
self.set_iq_set_handler("query","jabber:iq:auth",self.auth_in_stage2)
if "plain" in self.auth_methods or "digest" in self.auth_methods:
self.set_iq_get_handler("query","jabber:iq:auth",
self.auth_in_stage1,pre_auth=1)
self.set_iq_set_handler("query","jabber:iq:auth",
self.auth_in_stage2, pre_auth=1)

def post_disconnect(self):
self._authenticated=0
def idle(self):
stream.Stream.idle(self)
if self.features_timeout and self.features_timeout<=time.time():
self.debug("Timout while waiting for <features/>")
self.features_timeout=None
if self.auth_methods_left:
self.auth_methods_left.pop(0)
self.try_auth()

def got_features(self):
self.debug("Got <features/>")
stream.Stream.got_features(self)
self.try_auth()

def try_auth(self):
if self.authenticated:
self.debug("try_auth: already authenticated")
return
self.features_timeout=None
self.debug("trying auth: %r" % (self.auth_methods_left,))
if not self.auth_methods_left:
raise AuthenticationError,"No allowed authentication methods available"
method=self.auth_methods_left[0]
if method.startswith("sasl:"):
if self.features:
self.auth_methods_left.pop(0)
try:
self.sasl_authenticate(self.jid.node,self.jid.as_unicode(),
mechanism=method[5:].upper())
except stream.SASLMechanismNotAvailable:
self.debug("Skipping unavailable auth method: %s" % method)
return self.try_auth()
else:
self.features_timeout=time.time()+60
self.debug("Must wait for <features/>")
return
elif method not in ("plain","digest"):
self.debug("Skipping unknown auth method: %s" % method)
return try_auth()
elif self.available_auth_methods is not None:
if method in self.available_auth_methods:
self.auth_methods_left.pop(0)
if method=="digest":
self.digest_auth_stage2(self.auth_stanza)
else:
self.plain_auth_stage2(self.auth_stanza)
self.auth_stanza=None
return
else:
self.debug("Skipping unavailable auth method: %s" % method)
else:
self.auth_stage1()

def auth_in_stage1(self,stanza):
if "plain" not in self.auth_methods and "digest" not in self.auth_methods:
@@ -121,25 +191,30 @@ def auth_stage1(self):
q.newChild(q.ns(),"username",to_utf8(self.jid.node))
q.newChild(q.ns(),"resource",to_utf8(self.jid.resource))
self.send(iq)
self.set_reply_handlers(iq,self.auth_stage2,self.auth_error)
self.set_reply_handlers(iq,self.auth_stage2,self.auth_error,
self.features_timeout,timeout=60)
iq.free()

def features_timeout(self,*args):
debug("Timeout while waiting for jabber:iq:auth result")
if self.auth_methods_left:
self.auth_methods_left.pop(0)

def auth_error(self,stanza):
err=stanza.get_error()
raise AuthenticationError,("Athentication error class=%r condition=%r"
% (err.get_class(), err.get_condition().serialize()))

def auth_stage2(self,stanza):
print "Procesing auth reply..."

for m in self.auth_methods:
if (m=="digest"
and stanza.xpath_eval("a:query/a:digest",{"a":"jabber:iq:auth"})
and self.stream_id):
return self.digest_auth_stage2(stanza)
if (m=="plain"
and stanza.xpath_eval("a:query/a:password",{"a":"jabber:iq:auth"})):
return self.plain_auth_stage2(stanza)
raise AuthenticationError,"No allowed authentication method supported"

self.available_auth_methods=[]
if (stanza.xpath_eval("a:query/a:digest",{"a":"jabber:iq:auth"}) and self.stream_id):
self.available_auth_methods.append("digest")
if (stanza.xpath_eval("a:query/a:password",{"a":"jabber:iq:auth"})):
self.available_auth_methods.append("plain")
self.auth_stanza=stanza.copy()
self.try_auth()

def plain_auth_stage2(self,stanza):
iq=Iq(type="set")
@@ -164,7 +239,10 @@ def plain_auth_in_stage2(self,username,resource,stanza):
if self.check_password(username,password):
iq=stanza.make_result_reply()
self.send(iq)
self.peer_authenticated=1
self.post_auth()
else:
self.debug("Plain auth failed")
iq=stanza.make_error_reply("access",
('jabber:iq:auth:error',"user-unauthorized",None))
self.send(iq)
@@ -190,8 +268,8 @@ def digest_auth_in_stage2(self,username,resource,stanza):
self.send(iq)
return

password=self.get_password(username)
if not password:
password,pwformat=self.get_password(username)
if not password or pwformat!="plain":
iq=stanza.make_error_reply("access",
('jabber:iq:auth:error',"user-unauthorized",None))
self.send(iq)
@@ -202,14 +280,18 @@ def digest_auth_in_stage2(self,username,resource,stanza):
if mydigest==digest:
iq=stanza.make_result_reply()
self.send(iq)
self.peer_authenticated=1
self.post_auth()
else:
self.debug("Digest auth failed: %r != %r" % (digest,mydigest))
iq=stanza.make_error_reply("access",
('jabber:iq:auth:error',"user-unauthorized",None))
self.send(iq)

def auth_finish(self,stanza):
print "Authenticated"
self._authenticated=1
self.me=self.jid
self.authenticated=1
self.post_auth()

def get_password(self,username,realm=None,acceptable_formats=("plain",)):
@@ -250,12 +332,13 @@ def get_serv_name(self):

def get_serv_host(self):
return self.jid.domain

def post_auth(self):
pass

def authenticated(self):
return self._authenticated
def fix_out_stanza(self,stanza):
if self.initiator:
stanza.set_from(None)
if not stanza.get_to() and self.peer:
stanza.set_to(self.peer)
else:
stream.Stream.fix_out_stanza(self,stanza)

def peer_authenticated(self):
return self._peer_authenticated

@@ -1,3 +1,19 @@
#
# (C) Copyright 2003 Jacek Konieczny <jajcus@bnet.pl>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License Version
# 2.1 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import libxml2

Oops, something went wrong.

0 comments on commit d5ed22c

Please sign in to comment.