merging
This commit is contained in:
commit
e53f95c87e
1 changed files with 60 additions and 51 deletions
|
@ -21,9 +21,11 @@ Can be used both for client and transport authentication
|
||||||
See client_nb.py
|
See client_nb.py
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from protocol import NS_SASL, NS_SESSION, NS_STREAMS, NS_BIND, NS_AUTH, NS_STREAM_MGMT
|
from protocol import NS_SASL, NS_SESSION, NS_STREAMS, NS_BIND, NS_AUTH
|
||||||
|
from protocol import NS_STREAM_MGMT
|
||||||
from protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID
|
from protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID
|
||||||
from plugin import PlugIn
|
from plugin import PlugIn
|
||||||
|
from smacks import Smacks
|
||||||
import base64
|
import base64
|
||||||
import random
|
import random
|
||||||
import itertools
|
import itertools
|
||||||
|
@ -31,7 +33,7 @@ import dispatcher_nb
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import hashlib
|
import hashlib
|
||||||
from smacks import Smacks
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger('gajim.c.x.auth_nb')
|
log = logging.getLogger('gajim.c.x.auth_nb')
|
||||||
|
|
||||||
|
@ -142,7 +144,7 @@ class SASL(PlugIn):
|
||||||
elif self._owner.Dispatcher.Stream.features:
|
elif self._owner.Dispatcher.Stream.features:
|
||||||
try:
|
try:
|
||||||
self.FeaturesHandler(self._owner.Dispatcher,
|
self.FeaturesHandler(self._owner.Dispatcher,
|
||||||
self._owner.Dispatcher.Stream.features)
|
self._owner.Dispatcher.Stream.features)
|
||||||
except NodeProcessed:
|
except NodeProcessed:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
@ -154,16 +156,16 @@ class SASL(PlugIn):
|
||||||
"""
|
"""
|
||||||
if 'features' in self._owner.__dict__:
|
if 'features' in self._owner.__dict__:
|
||||||
self._owner.UnregisterHandler('features', self.FeaturesHandler,
|
self._owner.UnregisterHandler('features', self.FeaturesHandler,
|
||||||
xmlns=NS_STREAMS)
|
xmlns=NS_STREAMS)
|
||||||
if 'challenge' in self._owner.__dict__:
|
if 'challenge' in self._owner.__dict__:
|
||||||
self._owner.UnregisterHandler('challenge', self.SASLHandler,
|
self._owner.UnregisterHandler('challenge', self.SASLHandler,
|
||||||
xmlns=NS_SASL)
|
xmlns=NS_SASL)
|
||||||
if 'failure' in self._owner.__dict__:
|
if 'failure' in self._owner.__dict__:
|
||||||
self._owner.UnregisterHandler('failure', self.SASLHandler,
|
self._owner.UnregisterHandler('failure', self.SASLHandler,
|
||||||
xmlns=NS_SASL)
|
xmlns=NS_SASL)
|
||||||
if 'success' in self._owner.__dict__:
|
if 'success' in self._owner.__dict__:
|
||||||
self._owner.UnregisterHandler('success', self.SASLHandler,
|
self._owner.UnregisterHandler('success', self.SASLHandler,
|
||||||
xmlns=NS_SASL)
|
xmlns=NS_SASL)
|
||||||
|
|
||||||
def auth(self):
|
def auth(self):
|
||||||
"""
|
"""
|
||||||
|
@ -178,12 +180,12 @@ class SASL(PlugIn):
|
||||||
elif self._owner.Dispatcher.Stream.features:
|
elif self._owner.Dispatcher.Stream.features:
|
||||||
try:
|
try:
|
||||||
self.FeaturesHandler(self._owner.Dispatcher,
|
self.FeaturesHandler(self._owner.Dispatcher,
|
||||||
self._owner.Dispatcher.Stream.features)
|
self._owner.Dispatcher.Stream.features)
|
||||||
except NodeProcessed:
|
except NodeProcessed:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
self._owner.RegisterHandler('features',
|
self._owner.RegisterHandler('features',
|
||||||
self.FeaturesHandler, xmlns=NS_STREAMS)
|
self.FeaturesHandler, xmlns=NS_STREAMS)
|
||||||
|
|
||||||
def FeaturesHandler(self, conn, feats):
|
def FeaturesHandler(self, conn, feats):
|
||||||
"""
|
"""
|
||||||
|
@ -198,7 +200,8 @@ class SASL(PlugIn):
|
||||||
'mechanism'):
|
'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)
|
||||||
self.MechanismHandler()
|
self.MechanismHandler()
|
||||||
|
@ -206,7 +209,8 @@ class SASL(PlugIn):
|
||||||
def MechanismHandler(self):
|
def MechanismHandler(self):
|
||||||
if 'ANONYMOUS' in self.mecs and self.username is None:
|
if 'ANONYMOUS' in self.mecs and self.username is None:
|
||||||
self.mecs.remove('ANONYMOUS')
|
self.mecs.remove('ANONYMOUS')
|
||||||
node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'ANONYMOUS'})
|
node = Node('auth', attrs={'xmlns': NS_SASL,
|
||||||
|
'mechanism': 'ANONYMOUS'})
|
||||||
self.mechanism = 'ANONYMOUS'
|
self.mechanism = 'ANONYMOUS'
|
||||||
self.startsasl = SASL_IN_PROCESS
|
self.startsasl = SASL_IN_PROCESS
|
||||||
self._owner.send(str(node))
|
self._owner.send(str(node))
|
||||||
|
@ -226,11 +230,11 @@ class SASL(PlugIn):
|
||||||
self.mecs.remove('GSSAPI')
|
self.mecs.remove('GSSAPI')
|
||||||
try:
|
try:
|
||||||
self.gss_vc = kerberos.authGSSClientInit('xmpp@' + \
|
self.gss_vc = kerberos.authGSSClientInit('xmpp@' + \
|
||||||
self._owner.xmpp_hostname)[1]
|
self._owner.xmpp_hostname)[1]
|
||||||
kerberos.authGSSClientStep(self.gss_vc, '')
|
kerberos.authGSSClientStep(self.gss_vc, '')
|
||||||
response = kerberos.authGSSClientResponse(self.gss_vc)
|
response = kerberos.authGSSClientResponse(self.gss_vc)
|
||||||
node=Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'GSSAPI'},
|
node=Node('auth', attrs={'xmlns': NS_SASL,
|
||||||
payload=(response or ''))
|
'mechanism': 'GSSAPI'}, payload=(response or ''))
|
||||||
self.mechanism = 'GSSAPI'
|
self.mechanism = 'GSSAPI'
|
||||||
self.gss_step = GSS_STATE_STEP
|
self.gss_step = GSS_STATE_STEP
|
||||||
self.startsasl = SASL_IN_PROCESS
|
self.startsasl = SASL_IN_PROCESS
|
||||||
|
@ -247,7 +251,8 @@ class SASL(PlugIn):
|
||||||
raise NodeProcessed
|
raise NodeProcessed
|
||||||
if 'DIGEST-MD5' in self.mecs:
|
if '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'
|
||||||
self.startsasl = SASL_IN_PROCESS
|
self.startsasl = SASL_IN_PROCESS
|
||||||
self._owner.send(str(node))
|
self._owner.send(str(node))
|
||||||
|
@ -294,13 +299,13 @@ class SASL(PlugIn):
|
||||||
handlers = self._owner.Dispatcher.dumpHandlers()
|
handlers = self._owner.Dispatcher.dumpHandlers()
|
||||||
|
|
||||||
# Bosh specific dispatcher replugging
|
# 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
|
||||||
# stream restart after SASL auth (happens with XMPP over BOSH with
|
# on stream restart after SASL auth (happens with XMPP over BOSH
|
||||||
# Openfire)
|
# 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.get_instance().PlugIn(self._owner,
|
dispatcher_nb.Dispatcher.get_instance().PlugIn(self._owner,
|
||||||
after_SASL=True, old_features=old_features)
|
after_SASL=True, old_features=old_features)
|
||||||
self._owner.Dispatcher.restoreHandlers(handlers)
|
self._owner.Dispatcher.restoreHandlers(handlers)
|
||||||
self._owner.User = self.username
|
self._owner.User = self.username
|
||||||
|
|
||||||
|
@ -322,12 +327,12 @@ class SASL(PlugIn):
|
||||||
rc = kerberos.authGSSClientUnwrap(self.gss_vc, incoming_data)
|
rc = kerberos.authGSSClientUnwrap(self.gss_vc, incoming_data)
|
||||||
response = kerberos.authGSSClientResponse(self.gss_vc)
|
response = kerberos.authGSSClientResponse(self.gss_vc)
|
||||||
rc = kerberos.authGSSClientWrap(self.gss_vc, response,
|
rc = kerberos.authGSSClientWrap(self.gss_vc, response,
|
||||||
kerberos.authGSSClientUserName(self.gss_vc))
|
kerberos.authGSSClientUserName(self.gss_vc))
|
||||||
response = kerberos.authGSSClientResponse(self.gss_vc)
|
response = kerberos.authGSSClientResponse(self.gss_vc)
|
||||||
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
|
||||||
if self.mechanism == 'SCRAM-SHA-1':
|
if self.mechanism == 'SCRAM-SHA-1':
|
||||||
hashfn = hashlib.sha1
|
hashfn = hashlib.sha1
|
||||||
|
@ -408,8 +413,8 @@ class SASL(PlugIn):
|
||||||
else:
|
else:
|
||||||
self.resp['realm'] = self._owner.Server
|
self.resp['realm'] = self._owner.Server
|
||||||
self.resp['nonce'] = chal['nonce']
|
self.resp['nonce'] = chal['nonce']
|
||||||
self.resp['cnonce'] = ''.join("%x" % randint(0, 2**28) for randint in
|
self.resp['cnonce'] = ''.join("%x" % randint(0, 2**28) for randint \
|
||||||
itertools.repeat(random.randint, 7))
|
in itertools.repeat(random.randint, 7))
|
||||||
self.resp['nc'] = ('00000001')
|
self.resp['nc'] = ('00000001')
|
||||||
self.resp['qop'] = 'auth'
|
self.resp['qop'] = 'auth'
|
||||||
self.resp['digest-uri'] = 'xmpp/' + self._owner.Server
|
self.resp['digest-uri'] = 'xmpp/' + self._owner.Server
|
||||||
|
@ -449,10 +454,10 @@ class SASL(PlugIn):
|
||||||
hash_realm = self._convert_to_iso88591(self.resp['realm'])
|
hash_realm = self._convert_to_iso88591(self.resp['realm'])
|
||||||
hash_password = self._convert_to_iso88591(self.password)
|
hash_password = self._convert_to_iso88591(self.password)
|
||||||
A1 = C([H(C([hash_username, hash_realm, hash_password])),
|
A1 = C([H(C([hash_username, hash_realm, hash_password])),
|
||||||
self.resp['nonce'], self.resp['cnonce']])
|
self.resp['nonce'], self.resp['cnonce']])
|
||||||
A2 = C(['AUTHENTICATE', self.resp['digest-uri']])
|
A2 = C(['AUTHENTICATE', self.resp['digest-uri']])
|
||||||
response= HH(C([HH(A1), self.resp['nonce'], self.resp['nc'],
|
response= HH(C([HH(A1), self.resp['nonce'], self.resp['nc'],
|
||||||
self.resp['cnonce'], self.resp['qop'], HH(A2)]))
|
self.resp['cnonce'], self.resp['qop'], HH(A2)]))
|
||||||
self.resp['response'] = response
|
self.resp['response'] = response
|
||||||
sasl_data = u''
|
sasl_data = u''
|
||||||
for key in ('charset', 'username', 'realm', 'nonce', 'nc', 'cnonce',
|
for key in ('charset', 'username', 'realm', 'nonce', 'nc', 'cnonce',
|
||||||
|
@ -462,14 +467,15 @@ class SASL(PlugIn):
|
||||||
else:
|
else:
|
||||||
sasl_data += u'%s="%s",' % (key, self.resp[key])
|
sasl_data += u'%s="%s",' % (key, self.resp[key])
|
||||||
sasl_data = sasl_data[:-1].encode('utf-8').encode('base64').replace(
|
sasl_data = sasl_data[:-1].encode('utf-8').encode('base64').replace(
|
||||||
'\r', '').replace('\n', '')
|
'\r', '').replace('\n', '')
|
||||||
node = Node('response', attrs={'xmlns':NS_SASL}, payload=[sasl_data])
|
node = Node('response', attrs={'xmlns': NS_SASL},
|
||||||
|
payload=[sasl_data])
|
||||||
elif self.mechanism == 'PLAIN':
|
elif self.mechanism == 'PLAIN':
|
||||||
sasl_data = u'\x00%s\x00%s' % (self.username, self.password)
|
sasl_data = u'\x00%s\x00%s' % (self.username, self.password)
|
||||||
sasl_data = sasl_data.encode('utf-8').encode('base64').replace(
|
sasl_data = sasl_data.encode('utf-8').encode('base64').replace(
|
||||||
'\n', '')
|
'\n', '')
|
||||||
node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'PLAIN'},
|
node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'PLAIN'},
|
||||||
payload=[sasl_data])
|
payload=[sasl_data])
|
||||||
self._owner.send(str(node))
|
self._owner.send(str(node))
|
||||||
|
|
||||||
|
|
||||||
|
@ -502,8 +508,8 @@ class NonBlockingNonSASL(PlugIn):
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
|
|
||||||
owner.Dispatcher.SendAndWaitForResponse(
|
owner.Dispatcher.SendAndWaitForResponse(
|
||||||
Iq('get', NS_AUTH, payload=[Node('username', payload=[self.user])]),
|
Iq('get', NS_AUTH, payload=[Node('username', payload=[self.user])]),
|
||||||
func=self._on_username)
|
func=self._on_username)
|
||||||
|
|
||||||
def _on_username(self, resp):
|
def _on_username(self, resp):
|
||||||
if not isResultNode(resp):
|
if not isResultNode(resp):
|
||||||
|
@ -518,8 +524,8 @@ class NonBlockingNonSASL(PlugIn):
|
||||||
if query.getTag('digest'):
|
if query.getTag('digest'):
|
||||||
log.info("Performing digest authentication")
|
log.info("Performing digest authentication")
|
||||||
query.setTagData('digest',
|
query.setTagData('digest',
|
||||||
hashlib.sha1(self.owner.Dispatcher.Stream._document_attrs['id']
|
hashlib.sha1(self.owner.Dispatcher.Stream._document_attrs['id']
|
||||||
+ self.password).hexdigest())
|
+ self.password).hexdigest())
|
||||||
if query.getTag('password'):
|
if query.getTag('password'):
|
||||||
query.delChild('password')
|
query.delChild('password')
|
||||||
self._method = 'digest'
|
self._method = 'digest'
|
||||||
|
@ -534,23 +540,25 @@ class NonBlockingNonSASL(PlugIn):
|
||||||
def hash_n_times(s, count):
|
def hash_n_times(s, count):
|
||||||
return count and hasher(hash_n_times(s, count-1)) or s
|
return count and hasher(hash_n_times(s, count-1)) or s
|
||||||
|
|
||||||
hash_ = hash_n_times(hasher(hasher(self.password) + token), int(seq))
|
hash_ = hash_n_times(hasher(hasher(self.password) + token),
|
||||||
|
int(seq))
|
||||||
query.setTagData('hash', hash_)
|
query.setTagData('hash', hash_)
|
||||||
self._method='0k'
|
self._method='0k'
|
||||||
else:
|
else:
|
||||||
log.warn("Secure methods unsupported, performing plain text \
|
log.warn("Secure methods unsupported, performing plain text \
|
||||||
authentication")
|
authentication")
|
||||||
query.setTagData('password', self.password)
|
query.setTagData('password', self.password)
|
||||||
self._method = 'plain'
|
self._method = 'plain'
|
||||||
resp = self.owner.Dispatcher.SendAndWaitForResponse(iq, func=self._on_auth)
|
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 remote 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._registered_name = self.owner.User + '@' + \
|
||||||
'/'+self.owner.Resource
|
self.owner.Server+ '/' + self.owner.Resource
|
||||||
return self.on_auth(self._method)
|
return self.on_auth(self._method)
|
||||||
log.info('Authentication failed!')
|
log.info('Authentication failed!')
|
||||||
return self.on_auth(None)
|
return self.on_auth(None)
|
||||||
|
@ -572,12 +580,12 @@ class NonBlockingBind(PlugIn):
|
||||||
if self._owner.Dispatcher.Stream.features:
|
if self._owner.Dispatcher.Stream.features:
|
||||||
try:
|
try:
|
||||||
self.FeaturesHandler(self._owner.Dispatcher,
|
self.FeaturesHandler(self._owner.Dispatcher,
|
||||||
self._owner.Dispatcher.Stream.features)
|
self._owner.Dispatcher.Stream.features)
|
||||||
except NodeProcessed:
|
except NodeProcessed:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
self._owner.RegisterHandler('features', self.FeaturesHandler,
|
self._owner.RegisterHandler('features', self.FeaturesHandler,
|
||||||
xmlns=NS_STREAMS)
|
xmlns=NS_STREAMS)
|
||||||
|
|
||||||
def FeaturesHandler(self, conn, feats):
|
def FeaturesHandler(self, conn, feats):
|
||||||
"""
|
"""
|
||||||
|
@ -607,7 +615,7 @@ class NonBlockingBind(PlugIn):
|
||||||
Remove Bind handler from owner's dispatcher. Used internally
|
Remove Bind handler from owner's dispatcher. Used internally
|
||||||
"""
|
"""
|
||||||
self._owner.UnregisterHandler('features', self.FeaturesHandler,
|
self._owner.UnregisterHandler('features', self.FeaturesHandler,
|
||||||
xmlns=NS_STREAMS)
|
xmlns=NS_STREAMS)
|
||||||
|
|
||||||
def NonBlockingBind(self, resource=None, on_bound=None):
|
def NonBlockingBind(self, resource=None, on_bound=None):
|
||||||
"""
|
"""
|
||||||
|
@ -622,8 +630,9 @@ class NonBlockingBind(PlugIn):
|
||||||
|
|
||||||
self._owner.onreceive(None)
|
self._owner.onreceive(None)
|
||||||
self._owner.Dispatcher.SendAndWaitForResponse(
|
self._owner.Dispatcher.SendAndWaitForResponse(
|
||||||
Protocol('iq', typ='set', payload=[Node('bind', attrs={'xmlns':NS_BIND},
|
Protocol('iq', typ='set', payload=[Node('bind',
|
||||||
payload=self._resource)]), func=self._on_bound)
|
attrs={'xmlns': NS_BIND}, payload=self._resource)]),
|
||||||
|
func=self._on_bound)
|
||||||
|
|
||||||
def _on_bound(self, resp):
|
def _on_bound(self, resp):
|
||||||
if isResultNode(resp):
|
if isResultNode(resp):
|
||||||
|
@ -647,8 +656,8 @@ class NonBlockingBind(PlugIn):
|
||||||
self.on_bound('ok')
|
self.on_bound('ok')
|
||||||
else:
|
else:
|
||||||
self._owner.SendAndWaitForResponse(Protocol('iq', typ='set',
|
self._owner.SendAndWaitForResponse(Protocol('iq', typ='set',
|
||||||
payload=[Node('session', attrs={'xmlns':NS_SESSION})]),
|
payload=[Node('session', attrs={'xmlns':NS_SESSION})]),
|
||||||
func=self._on_session)
|
func=self._on_session)
|
||||||
return
|
return
|
||||||
if resp:
|
if resp:
|
||||||
log.info('Binding failed: %s.' % resp.getTag('error'))
|
log.info('Binding failed: %s.' % resp.getTag('error'))
|
||||||
|
|
Loading…
Add table
Reference in a new issue