Coding standards and documentation improvements in auth_nb.py
This commit is contained in:
parent
7427399a2a
commit
de73b76771
|
@ -14,10 +14,13 @@
|
||||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
## GNU General Public License for more details.
|
## GNU General Public License for more details.
|
||||||
'''
|
'''
|
||||||
Provides library with all Non-SASL and SASL authentication mechanisms.
|
Provides plugs for SASL and NON-SASL authentication mechanisms.
|
||||||
Can be used both for client and transport authentication.
|
Can be used both for client and transport authentication.
|
||||||
|
|
||||||
|
See client_nb.py
|
||||||
'''
|
'''
|
||||||
from protocol import *
|
from protocol import NS_SASL, NS_SESSION, NS_STREAMS, NS_BIND, NS_AUTH
|
||||||
|
from protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID
|
||||||
from client import PlugIn
|
from client import PlugIn
|
||||||
import sha
|
import sha
|
||||||
import base64
|
import base64
|
||||||
|
@ -41,14 +44,20 @@ except ImportError:
|
||||||
|
|
||||||
GSS_STATE_STEP = 0
|
GSS_STATE_STEP = 0
|
||||||
GSS_STATE_WRAP = 1
|
GSS_STATE_WRAP = 1
|
||||||
|
SASL_FAILURE = 'failure'
|
||||||
|
SASL_SUCCESS = 'success'
|
||||||
|
SASL_UNSUPPORTED = 'not-supported'
|
||||||
|
SASL_IN_PROCESS = 'in-process'
|
||||||
|
|
||||||
def challenge_splitter(data):
|
def challenge_splitter(data):
|
||||||
''' Helper function that creates a dict from challenge string.
|
''' Helper function that creates a dict from challenge string.
|
||||||
Sample chalenge string:
|
|
||||||
|
Sample challenge string:
|
||||||
username="example.org",realm="somerealm",\
|
username="example.org",realm="somerealm",\
|
||||||
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\
|
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\
|
||||||
nc=00000001,qop="auth,auth-int,auth-conf",charset=utf-8
|
nc=00000001,qop="auth,auth-int,auth-conf",charset=utf-8
|
||||||
in the above example:
|
|
||||||
|
Expected result for challan:
|
||||||
dict['qop'] = ('auth','auth-int','auth-conf')
|
dict['qop'] = ('auth','auth-int','auth-conf')
|
||||||
dict['realm'] = 'somerealm'
|
dict['realm'] = 'somerealm'
|
||||||
'''
|
'''
|
||||||
|
@ -102,43 +111,64 @@ def challenge_splitter(data):
|
||||||
quotes_open = False
|
quotes_open = False
|
||||||
return dict_
|
return dict_
|
||||||
|
|
||||||
|
|
||||||
class SASL(PlugIn):
|
class SASL(PlugIn):
|
||||||
''' Implements SASL authentication. '''
|
'''
|
||||||
def __init__(self,username,password, on_sasl):
|
Implements SASL authentication. Can be plugged into NonBlockingClient
|
||||||
|
to start authentication.
|
||||||
|
'''
|
||||||
|
def __init__(self, username, password, on_sasl):
|
||||||
|
'''
|
||||||
|
:param user: XMPP username
|
||||||
|
:param password: XMPP password
|
||||||
|
:param on_sasl: Callback, will be called after each SASL auth-step.
|
||||||
|
'''
|
||||||
PlugIn.__init__(self)
|
PlugIn.__init__(self)
|
||||||
self.username=username
|
self.username = username
|
||||||
self.password=password
|
self.password = password
|
||||||
self.on_sasl = on_sasl
|
self.on_sasl = on_sasl
|
||||||
self.realm = None
|
self.realm = None
|
||||||
def plugin(self,owner):
|
|
||||||
|
def plugin(self, owner):
|
||||||
if 'version' not in self._owner.Dispatcher.Stream._document_attrs:
|
if 'version' not in self._owner.Dispatcher.Stream._document_attrs:
|
||||||
self.startsasl='not-supported'
|
self.startsasl = SASL_UNSUPPORTED
|
||||||
elif self._owner.Dispatcher.Stream.features:
|
elif self._owner.Dispatcher.Stream.features:
|
||||||
try:
|
try:
|
||||||
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
|
self.FeaturesHandler(self._owner.Dispatcher,
|
||||||
|
self._owner.Dispatcher.Stream.features)
|
||||||
except NodeProcessed:
|
except NodeProcessed:
|
||||||
pass
|
pass
|
||||||
else: self.startsasl=None
|
else:
|
||||||
|
self.startsasl = None
|
||||||
|
|
||||||
|
def plugout(self):
|
||||||
|
''' Remove SASL handlers from owner's dispatcher. Used internally. '''
|
||||||
|
self._owner.UnregisterHandler('features', self.FeaturesHandler,
|
||||||
|
xmlns=NS_STREAMS)
|
||||||
|
self._owner.UnregisterHandler('challenge', self.SASLHandler,
|
||||||
|
xmlns=NS_SASL)
|
||||||
|
self._owner.UnregisterHandler('failure', self.SASLHandler, xmlns=NS_SASL)
|
||||||
|
self._owner.UnregisterHandler('success', self.SASLHandler, xmlns=NS_SASL)
|
||||||
|
|
||||||
def auth(self):
|
def auth(self):
|
||||||
''' Start authentication. Result can be obtained via "SASL.startsasl" attribute and will be
|
'''
|
||||||
either "success" or "failure". Note that successfull auth will take at least
|
Start authentication. Result can be obtained via "SASL.startsasl"
|
||||||
two Dispatcher.Process() calls. '''
|
attribute and will be either SASL_SUCCESS or SASL_FAILURE.
|
||||||
|
|
||||||
|
Note that successfull auth will take at least two Dispatcher.Process()
|
||||||
|
calls.
|
||||||
|
'''
|
||||||
if self.startsasl:
|
if self.startsasl:
|
||||||
pass
|
pass
|
||||||
elif self._owner.Dispatcher.Stream.features:
|
elif self._owner.Dispatcher.Stream.features:
|
||||||
try:
|
try:
|
||||||
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
|
self.FeaturesHandler(self._owner.Dispatcher,
|
||||||
|
self._owner.Dispatcher.Stream.features)
|
||||||
except NodeProcessed:
|
except NodeProcessed:
|
||||||
pass
|
pass
|
||||||
else: self._owner.RegisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
|
else:
|
||||||
|
self._owner.RegisterHandler('features',
|
||||||
def plugout(self):
|
self.FeaturesHandler, xmlns=NS_STREAMS)
|
||||||
''' Remove SASL handlers from owner's dispatcher. Used internally. '''
|
|
||||||
self._owner.UnregisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
|
|
||||||
self._owner.UnregisterHandler('challenge', self.SASLHandler, xmlns=NS_SASL)
|
|
||||||
self._owner.UnregisterHandler('failure', self.SASLHandler, xmlns=NS_SASL)
|
|
||||||
self._owner.UnregisterHandler('success', self.SASLHandler, xmlns=NS_SASL)
|
|
||||||
|
|
||||||
def FeaturesHandler(self, conn, feats):
|
def FeaturesHandler(self, conn, feats):
|
||||||
''' Used to determine if server supports SASL auth. Used internally. '''
|
''' Used to determine if server supports SASL auth. Used internally. '''
|
||||||
|
@ -146,9 +176,11 @@ class SASL(PlugIn):
|
||||||
self.startsasl='not-supported'
|
self.startsasl='not-supported'
|
||||||
log.error('SASL not supported by server')
|
log.error('SASL not supported by server')
|
||||||
return
|
return
|
||||||
self.mecs=[]
|
self.mecs = []
|
||||||
for mec in feats.getTag('mechanisms', namespace=NS_SASL).getTags('mechanism'):
|
for mec in feats.getTag('mechanisms', namespace=NS_SASL).getTags(
|
||||||
|
'mechanism'):
|
||||||
self.mecs.append(mec.getData())
|
self.mecs.append(mec.getData())
|
||||||
|
|
||||||
self._owner.RegisterHandler('challenge', self.SASLHandler, xmlns=NS_SASL)
|
self._owner.RegisterHandler('challenge', self.SASLHandler, xmlns=NS_SASL)
|
||||||
self._owner.RegisterHandler('failure', self.SASLHandler, xmlns=NS_SASL)
|
self._owner.RegisterHandler('failure', self.SASLHandler, xmlns=NS_SASL)
|
||||||
self._owner.RegisterHandler('success', self.SASLHandler, xmlns=NS_SASL)
|
self._owner.RegisterHandler('success', self.SASLHandler, xmlns=NS_SASL)
|
||||||
|
@ -167,29 +199,30 @@ class SASL(PlugIn):
|
||||||
self.gss_step = GSS_STATE_STEP
|
self.gss_step = GSS_STATE_STEP
|
||||||
elif 'DIGEST-MD5' in self.mecs:
|
elif 'DIGEST-MD5' in self.mecs:
|
||||||
self.mecs.remove('DIGEST-MD5')
|
self.mecs.remove('DIGEST-MD5')
|
||||||
node=Node('auth',attrs={'xmlns': NS_SASL, 'mechanism': 'DIGEST-MD5'})
|
node = Node('auth',attrs={'xmlns': NS_SASL, 'mechanism': 'DIGEST-MD5'})
|
||||||
self.mechanism = 'DIGEST-MD5'
|
self.mechanism = 'DIGEST-MD5'
|
||||||
elif 'PLAIN' in self.mecs:
|
elif 'PLAIN' in self.mecs:
|
||||||
self.mecs.remove('PLAIN')
|
self.mecs.remove('PLAIN')
|
||||||
sasl_data='%s\x00%s\x00%s' % (self.username+'@' + self._owner.Server,
|
sasl_data='%s\x00%s\x00%s' % (self.username+'@' + self._owner.Server,
|
||||||
self.username, self.password)
|
self.username, self.password)
|
||||||
node=Node('auth', attrs={'xmlns':NS_SASL,'mechanism':'PLAIN'},
|
node = Node('auth', attrs={'xmlns':NS_SASL,'mechanism':'PLAIN'},
|
||||||
payload=[base64.encodestring(sasl_data).replace('\n','')])
|
payload=[base64.encodestring(sasl_data).replace('\n','')])
|
||||||
self.mechanism = 'PLAIN'
|
self.mechanism = 'PLAIN'
|
||||||
else:
|
else:
|
||||||
self.startsasl='failure'
|
self.startsasl = SASL_FAILURE
|
||||||
log.error('I can only use DIGEST-MD5, GSSAPI and PLAIN mecanisms.')
|
log.error('I can only use DIGEST-MD5, GSSAPI and PLAIN mecanisms.')
|
||||||
return
|
return
|
||||||
self.startsasl='in-process'
|
self.startsasl = SASL_IN_PROCESS
|
||||||
self._owner.send(node.__str__())
|
self._owner.send(str(node))
|
||||||
raise NodeProcessed
|
raise NodeProcessed
|
||||||
|
|
||||||
def SASLHandler(self, conn, challenge):
|
def SASLHandler(self, conn, challenge):
|
||||||
''' Perform next SASL auth step. Used internally. '''
|
''' Perform next SASL auth step. Used internally. '''
|
||||||
if challenge.getNamespace() != NS_SASL:
|
if challenge.getNamespace() != NS_SASL:
|
||||||
return
|
return
|
||||||
|
### Handle Auth result
|
||||||
if challenge.getName() == 'failure':
|
if challenge.getName() == 'failure':
|
||||||
self.startsasl = 'failure'
|
self.startsasl = SASL_FAILURE
|
||||||
try:
|
try:
|
||||||
reason = challenge.getChildren()[0]
|
reason = challenge.getChildren()[0]
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -199,30 +232,34 @@ class SASL(PlugIn):
|
||||||
# There are other mechanisms to test
|
# There are other mechanisms to test
|
||||||
self.MechanismHandler()
|
self.MechanismHandler()
|
||||||
raise NodeProcessed
|
raise NodeProcessed
|
||||||
if self.on_sasl :
|
if self.on_sasl:
|
||||||
self.on_sasl ()
|
self.on_sasl()
|
||||||
raise NodeProcessed
|
raise NodeProcessed
|
||||||
elif challenge.getName() == 'success':
|
elif challenge.getName() == 'success':
|
||||||
self.startsasl='success'
|
self.startsasl = SASL_SUCCESS
|
||||||
log.info('Successfully authenticated with remote server.')
|
log.info('Successfully authenticated with remote server.')
|
||||||
handlers=self._owner.Dispatcher.dumpHandlers()
|
handlers = self._owner.Dispatcher.dumpHandlers()
|
||||||
|
|
||||||
|
# Bosh specific dispatcher replugging
|
||||||
# save old features. They will be used in case we won't get response on
|
# save old features. They will be used in case we won't get response on
|
||||||
# stream restart after SASL auth (happens with XMPP over BOSH with Openfire)
|
# stream restart after SASL auth (happens with XMPP over BOSH with
|
||||||
|
# Openfire)
|
||||||
old_features = self._owner.Dispatcher.Stream.features
|
old_features = self._owner.Dispatcher.Stream.features
|
||||||
|
|
||||||
self._owner.Dispatcher.PlugOut()
|
self._owner.Dispatcher.PlugOut()
|
||||||
dispatcher_nb.Dispatcher().PlugIn(self._owner, after_SASL=True,
|
dispatcher_nb.Dispatcher().PlugIn(self._owner, after_SASL=True,
|
||||||
old_features=old_features)
|
old_features=old_features)
|
||||||
self._owner.Dispatcher.restoreHandlers(handlers)
|
self._owner.Dispatcher.restoreHandlers(handlers)
|
||||||
self._owner.User = self.username
|
self._owner.User = self.username
|
||||||
if self.on_sasl :
|
|
||||||
|
if self.on_sasl:
|
||||||
self.on_sasl()
|
self.on_sasl()
|
||||||
raise NodeProcessed
|
raise NodeProcessed
|
||||||
########################################3333
|
|
||||||
|
### Perform auth step
|
||||||
incoming_data = challenge.getData()
|
incoming_data = challenge.getData()
|
||||||
data=base64.decodestring(incoming_data)
|
data=base64.decodestring(incoming_data)
|
||||||
log.info('Got challenge:' + data)
|
log.info('Got challenge:' + data)
|
||||||
|
|
||||||
if self.mechanism == 'GSSAPI':
|
if self.mechanism == 'GSSAPI':
|
||||||
if self.gss_step == GSS_STATE_STEP:
|
if self.gss_step == GSS_STATE_STEP:
|
||||||
rc = kerberos.authGSSClientStep(self.gss_vc, incoming_data)
|
rc = kerberos.authGSSClientStep(self.gss_vc, incoming_data)
|
||||||
|
@ -237,55 +274,60 @@ class SASL(PlugIn):
|
||||||
if not response:
|
if not response:
|
||||||
response = ''
|
response = ''
|
||||||
self._owner.send(Node('response', attrs={'xmlns':NS_SASL},
|
self._owner.send(Node('response', attrs={'xmlns':NS_SASL},
|
||||||
payload=response).__str__())
|
payload=response).__str__())
|
||||||
raise NodeProcessed
|
raise NodeProcessed
|
||||||
|
|
||||||
|
# magic foo...
|
||||||
chal = challenge_splitter(data)
|
chal = challenge_splitter(data)
|
||||||
if not self.realm and 'realm' in chal:
|
if not self.realm and 'realm' in chal:
|
||||||
self.realm = chal['realm']
|
self.realm = chal['realm']
|
||||||
if 'qop' in chal and ((isinstance(chal['qop'], str) and \
|
if 'qop' in chal and ((isinstance(chal['qop'], str) and \
|
||||||
chal['qop'] =='auth') or (isinstance(chal['qop'], list) and 'auth' in \
|
chal['qop'] =='auth') or (isinstance(chal['qop'], list) and 'auth' in \
|
||||||
chal['qop'])):
|
chal['qop'])):
|
||||||
resp={}
|
resp = {}
|
||||||
resp['username'] = self.username
|
resp['username'] = self.username
|
||||||
if self.realm:
|
if self.realm:
|
||||||
resp['realm'] = self.realm
|
resp['realm'] = self.realm
|
||||||
else:
|
else:
|
||||||
resp['realm'] = self._owner.Server
|
resp['realm'] = self._owner.Server
|
||||||
resp['nonce']=chal['nonce']
|
resp['nonce'] = chal['nonce']
|
||||||
resp['cnonce'] = ''.join("%x" % randint(0, 2**28) for randint in
|
resp['cnonce'] = ''.join("%x" % randint(0, 2**28) for randint in
|
||||||
itertools.repeat(random.randint, 7))
|
itertools.repeat(random.randint, 7))
|
||||||
resp['nc'] = ('00000001')
|
resp['nc'] = ('00000001')
|
||||||
resp['qop'] = 'auth'
|
resp['qop'] = 'auth'
|
||||||
resp['digest-uri'] = 'xmpp/'+self._owner.Server
|
resp['digest-uri'] = 'xmpp/' + self._owner.Server
|
||||||
A1=C([H(C([resp['username'], resp['realm'], self.password])),
|
A1=C([H(C([resp['username'], resp['realm'], self.password])),
|
||||||
resp['nonce'], resp['cnonce']])
|
resp['nonce'], resp['cnonce']])
|
||||||
A2=C(['AUTHENTICATE',resp['digest-uri']])
|
A2=C(['AUTHENTICATE',resp['digest-uri']])
|
||||||
response= HH(C([HH(A1), resp['nonce'], resp['nc'], resp['cnonce'],
|
response= HH(C([HH(A1), resp['nonce'], resp['nc'], resp['cnonce'],
|
||||||
resp['qop'], HH(A2)]))
|
resp['qop'], HH(A2)]))
|
||||||
resp['response'] = response
|
resp['response'] = response
|
||||||
resp['charset'] = 'utf-8'
|
resp['charset'] = 'utf-8'
|
||||||
sasl_data=''
|
sasl_data = ''
|
||||||
for key in ('charset', 'username', 'realm', 'nonce', 'nc', 'cnonce', 'digest-uri', 'response', 'qop'):
|
for key in ('charset', 'username', 'realm', 'nonce', 'nc', 'cnonce',
|
||||||
if key in ['nc','qop','response','charset']:
|
'digest-uri', 'response', 'qop'):
|
||||||
sasl_data += "%s=%s," % (key,resp[key])
|
if key in ('nc','qop','response','charset'):
|
||||||
|
sasl_data += "%s=%s," % (key, resp[key])
|
||||||
else:
|
else:
|
||||||
sasl_data += '%s="%s",' % (key,resp[key])
|
sasl_data += '%s="%s",' % (key, resp[key])
|
||||||
########################################3333
|
node = Node('response', attrs={'xmlns':NS_SASL},
|
||||||
node=Node('response', attrs={'xmlns':NS_SASL},
|
payload=[base64.encodestring(sasl_data[:-1]).replace('\r','').
|
||||||
payload=[base64.encodestring(sasl_data[:-1]).replace('\r','').replace('\n','')])
|
replace('\n','')])
|
||||||
self._owner.send(node.__str__())
|
self._owner.send(str(node))
|
||||||
elif 'rspauth' in chal:
|
elif 'rspauth' in chal:
|
||||||
self._owner.send(Node('response', attrs={'xmlns':NS_SASL}).__str__())
|
self._owner.send(str(Node('response', attrs={'xmlns':NS_SASL})))
|
||||||
else:
|
else:
|
||||||
self.startsasl='failure'
|
self.startsasl = SASL_FAILURE
|
||||||
log.error('Failed SASL authentification: unknown challenge')
|
log.error('Failed SASL authentification: unknown challenge')
|
||||||
if self.on_sasl :
|
if self.on_sasl:
|
||||||
self.on_sasl ()
|
self.on_sasl()
|
||||||
raise NodeProcessed
|
raise NodeProcessed
|
||||||
|
|
||||||
|
|
||||||
class NonBlockingNonSASL(PlugIn):
|
class NonBlockingNonSASL(PlugIn):
|
||||||
''' Implements old Non-SASL (JEP-0078) authentication used
|
'''
|
||||||
in jabberd1.4 and transport authentication.
|
Implements old Non-SASL (JEP-0078) authentication used in jabberd1.4 and
|
||||||
|
transport authentication.
|
||||||
'''
|
'''
|
||||||
def __init__(self, user, password, resource, on_auth):
|
def __init__(self, user, password, resource, on_auth):
|
||||||
''' Caches username, password and resource for auth. '''
|
''' Caches username, password and resource for auth. '''
|
||||||
|
@ -296,34 +338,38 @@ class NonBlockingNonSASL(PlugIn):
|
||||||
self.on_auth = on_auth
|
self.on_auth = on_auth
|
||||||
|
|
||||||
def plugin(self, owner):
|
def plugin(self, owner):
|
||||||
''' Determine the best auth method (digest/0k/plain) and use it for auth.
|
'''
|
||||||
Returns used method name on success. Used internally. '''
|
Determine the best auth method (digest/0k/plain) and use it for auth.
|
||||||
|
Returns used method name on success. Used internally.
|
||||||
|
'''
|
||||||
log.info('Querying server about possible auth methods')
|
log.info('Querying server about possible auth methods')
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
|
|
||||||
owner.Dispatcher.SendAndWaitForResponse(
|
owner.Dispatcher.SendAndWaitForResponse(
|
||||||
Iq('get', NS_AUTH, payload=[Node('username', payload=[self.user])]), func=self._on_username
|
Iq('get', NS_AUTH, payload=[Node('username', payload=[self.user])]),
|
||||||
)
|
func=self._on_username)
|
||||||
|
|
||||||
def _on_username(self, resp):
|
def _on_username(self, resp):
|
||||||
if not isResultNode(resp):
|
if not isResultNode(resp):
|
||||||
log.error('No result node arrived! Aborting...')
|
log.error('No result node arrived! Aborting...')
|
||||||
return self.on_auth(None)
|
return self.on_auth(None)
|
||||||
|
|
||||||
iq=Iq(typ='set',node=resp)
|
iq=Iq(typ='set',node=resp)
|
||||||
query=iq.getTag('query')
|
query = iq.getTag('query')
|
||||||
query.setTagData('username',self.user)
|
query.setTagData('username',self.user)
|
||||||
query.setTagData('resource',self.resource)
|
query.setTagData('resource',self.resource)
|
||||||
|
|
||||||
if query.getTag('digest'):
|
if query.getTag('digest'):
|
||||||
log.info("Performing digest authentication")
|
log.info("Performing digest authentication")
|
||||||
query.setTagData('digest',
|
query.setTagData('digest',
|
||||||
sha.new(self.owner.Dispatcher.Stream._document_attrs['id']+self.password).hexdigest())
|
sha.new(self.owner.Dispatcher.Stream._document_attrs['id'] +
|
||||||
|
self.password).hexdigest())
|
||||||
if query.getTag('password'):
|
if query.getTag('password'):
|
||||||
query.delChild('password')
|
query.delChild('password')
|
||||||
self._method='digest'
|
self._method = 'digest'
|
||||||
elif query.getTag('token'):
|
elif query.getTag('token'):
|
||||||
token=query.getTagData('token')
|
token = query.getTagData('token')
|
||||||
seq=query.getTagData('sequence')
|
seq = query.getTagData('sequence')
|
||||||
log.info("Performing zero-k authentication")
|
log.info("Performing zero-k authentication")
|
||||||
|
|
||||||
def hasher(s):
|
def hasher(s):
|
||||||
|
@ -336,58 +382,71 @@ class NonBlockingNonSASL(PlugIn):
|
||||||
query.setTagData('hash', hash_)
|
query.setTagData('hash', hash_)
|
||||||
self._method='0k'
|
self._method='0k'
|
||||||
else:
|
else:
|
||||||
log.warn("Sequre methods unsupported, performing plain text authentication")
|
log.warn("Sequre methods unsupported, performing plain text \
|
||||||
query.setTagData('password',self.password)
|
authentication")
|
||||||
self._method='plain'
|
query.setTagData('password', self.password)
|
||||||
resp=self.owner.Dispatcher.SendAndWaitForResponse(iq, func=self._on_auth)
|
self._method = 'plain'
|
||||||
|
resp = self.owner.Dispatcher.SendAndWaitForResponse(iq,func=self._on_auth)
|
||||||
|
|
||||||
def _on_auth(self, resp):
|
def _on_auth(self, resp):
|
||||||
if isResultNode(resp):
|
if isResultNode(resp):
|
||||||
log.info('Sucessfully authenticated with remove host.')
|
log.info('Sucessfully authenticated with remote host.')
|
||||||
self.owner.User=self.user
|
self.owner.User = self.user
|
||||||
self.owner.Resource=self.resource
|
self.owner.Resource = self.resource
|
||||||
self.owner._registered_name=self.owner.User+'@'+self.owner.Server+'/'+self.owner.Resource
|
self.owner._registered_name = self.owner.User+'@'+self.owner.Server+\
|
||||||
|
'/'+self.owner.Resource
|
||||||
return self.on_auth(self._method)
|
return self.on_auth(self._method)
|
||||||
log.error('Authentication failed!')
|
log.error('Authentication failed!')
|
||||||
return self.on_auth(None)
|
return self.on_auth(None)
|
||||||
|
|
||||||
|
|
||||||
class NonBlockingBind(PlugIn):
|
class NonBlockingBind(PlugIn):
|
||||||
''' Bind some JID to the current connection to allow router know of our location.'''
|
'''
|
||||||
|
Bind some JID to the current connection to allow router know of our
|
||||||
|
location. Must be plugged after successful SASL auth.
|
||||||
|
'''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
PlugIn.__init__(self)
|
PlugIn.__init__(self)
|
||||||
self.bound=None
|
self.bound = None
|
||||||
|
|
||||||
def plugin(self, owner):
|
def plugin(self, owner):
|
||||||
''' Start resource binding, if allowed at this time. Used internally. '''
|
''' Start resource binding, if allowed at this time. Used internally. '''
|
||||||
if self._owner.Dispatcher.Stream.features:
|
if self._owner.Dispatcher.Stream.features:
|
||||||
try:
|
try:
|
||||||
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
|
self.FeaturesHandler(self._owner.Dispatcher,
|
||||||
|
self._owner.Dispatcher.Stream.features)
|
||||||
except NodeProcessed:
|
except NodeProcessed:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
self._owner.RegisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
|
self._owner.RegisterHandler('features', self.FeaturesHandler,
|
||||||
|
xmlns=NS_STREAMS)
|
||||||
|
|
||||||
def FeaturesHandler(self,conn,feats):
|
def FeaturesHandler(self, conn, feats):
|
||||||
''' Determine if server supports resource binding and set some internal attributes accordingly. '''
|
'''
|
||||||
if not feats.getTag('bind',namespace=NS_BIND):
|
Determine if server supports resource binding and set some internal
|
||||||
|
attributes accordingly.
|
||||||
|
'''
|
||||||
|
if not feats.getTag('bind', namespace=NS_BIND):
|
||||||
log.error('Server does not requested binding.')
|
log.error('Server does not requested binding.')
|
||||||
# we try to bind resource anyway
|
# we try to bind resource anyway
|
||||||
#self.bound='failure'
|
#self.bound='failure'
|
||||||
self.bound=[]
|
self.bound = []
|
||||||
return
|
return
|
||||||
if feats.getTag('session',namespace=NS_SESSION):
|
if feats.getTag('session', namespace=NS_SESSION):
|
||||||
self.session=1
|
self.session = 1
|
||||||
else:
|
else:
|
||||||
self.session=-1
|
self.session = -1
|
||||||
self.bound=[]
|
self.bound = []
|
||||||
|
|
||||||
def plugout(self):
|
def plugout(self):
|
||||||
''' Remove Bind handler from owner's dispatcher. Used internally. '''
|
''' Remove Bind handler from owner's dispatcher. Used internally. '''
|
||||||
self._owner.UnregisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
|
self._owner.UnregisterHandler('features', self.FeaturesHandler,
|
||||||
|
xmlns=NS_STREAMS)
|
||||||
|
|
||||||
def NonBlockingBind(self, resource=None, on_bound=None):
|
def NonBlockingBind(self, resource=None, on_bound=None):
|
||||||
''' Perform binding. Use provided resource name or random (if not provided). '''
|
''' Perform binding.
|
||||||
|
Use provided resource name or random (if not provided).
|
||||||
|
'''
|
||||||
self.on_bound = on_bound
|
self.on_bound = on_bound
|
||||||
self._resource = resource
|
self._resource = resource
|
||||||
if self._resource:
|
if self._resource:
|
||||||
|
@ -397,18 +456,19 @@ class NonBlockingBind(PlugIn):
|
||||||
|
|
||||||
self._owner.onreceive(None)
|
self._owner.onreceive(None)
|
||||||
self._owner.Dispatcher.SendAndWaitForResponse(
|
self._owner.Dispatcher.SendAndWaitForResponse(
|
||||||
Protocol('iq',typ='set',
|
Protocol('iq',typ='set', payload=[Node('bind', attrs={'xmlns':NS_BIND},
|
||||||
payload=[Node('bind', attrs={'xmlns':NS_BIND}, payload=self._resource)]),
|
payload=self._resource)]), func=self._on_bound)
|
||||||
func=self._on_bound)
|
|
||||||
def _on_bound(self, resp):
|
def _on_bound(self, resp):
|
||||||
if isResultNode(resp):
|
if isResultNode(resp):
|
||||||
self.bound.append(resp.getTag('bind').getTagData('jid'))
|
self.bound.append(resp.getTag('bind').getTagData('jid'))
|
||||||
log.info('Successfully bound %s.'%self.bound[-1])
|
log.info('Successfully bound %s.' % self.bound[-1])
|
||||||
jid=JID(resp.getTag('bind').getTagData('jid'))
|
jid = JID(resp.getTag('bind').getTagData('jid'))
|
||||||
self._owner.User=jid.getNode()
|
self._owner.User = jid.getNode()
|
||||||
self._owner.Resource=jid.getResource()
|
self._owner.Resource = jid.getResource()
|
||||||
self._owner.SendAndWaitForResponse(Protocol('iq', typ='set',
|
self._owner.SendAndWaitForResponse(Protocol('iq', typ='set',
|
||||||
payload=[Node('session', attrs={'xmlns':NS_SESSION})]), func=self._on_session)
|
payload=[Node('session', attrs={'xmlns':NS_SESSION})]),
|
||||||
|
func=self._on_session)
|
||||||
elif resp:
|
elif resp:
|
||||||
log.error('Binding failed: %s.' % resp.getTag('error'))
|
log.error('Binding failed: %s.' % resp.getTag('error'))
|
||||||
self.on_bound(None)
|
self.on_bound(None)
|
||||||
|
|
Loading…
Reference in New Issue