request connection password only when neede. No need to request it for GSSAPI or ANONYMOUS login. see #2465

This commit is contained in:
Yann Leboulanger 2009-02-13 20:24:23 +00:00
parent 95d7e157da
commit 849108b11f
4 changed files with 85 additions and 69 deletions

View File

@ -167,6 +167,7 @@ class Connection(ConnectionHandlers):
# request vcard or os info... to a real JID but act as if it comes from
# the fake jid
self.groupchat_jids = {} # {ID : groupchat_jid}
self.pasword_callback = None
self.on_connect_success = None
self.on_connect_failure = None
@ -1815,6 +1816,19 @@ class Connection(ConnectionHandlers):
q.setTagData('password',password)
self.connection.send(iq)
def get_password(self, callback):
if self.password:
callback(self.password)
return
self.pasword_callback = callback
self.dispatch('PASSWORD_REQUIRED', None)
def set_password(self, password):
self.password = password
if self.pasword_callback:
self.pasword_callback(password)
self.pasword_callback = None
def unregister_account(self, on_remove_success):
# no need to write this as a class method and keep the value of
# on_remove_success as a class property as pass it as an argument

View File

@ -212,13 +212,8 @@ class SASL(PlugIn):
self.mechanism = 'DIGEST-MD5'
elif 'PLAIN' in self.mecs:
self.mecs.remove('PLAIN')
sasl_data = u'%s\x00%s\x00%s' % (self.username + '@' + \
self._owner.Server, self.username, self.password)
sasl_data = sasl_data.encode('utf-8').encode('base64').replace(
'\n','')
node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'PLAIN'},
payload=[sasl_data])
self.mechanism = 'PLAIN'
self._owner._caller.get_password(self.set_password)
else:
self.startsasl = SASL_FAILURE
log.error('I can only use DIGEST-MD5, GSSAPI and PLAIN mecanisms.')
@ -297,36 +292,21 @@ class SASL(PlugIn):
if 'qop' in chal and ((isinstance(chal['qop'], str) and \
chal['qop'] =='auth') or (isinstance(chal['qop'], list) and 'auth' in \
chal['qop'])):
resp = {}
resp['username'] = self.username
self.resp = {}
self.resp['username'] = self.username
if self.realm:
resp['realm'] = self.realm
self.resp['realm'] = self.realm
else:
resp['realm'] = self._owner.Server
resp['nonce'] = chal['nonce']
resp['cnonce'] = ''.join("%x" % randint(0, 2**28) for randint in
self.resp['realm'] = self._owner.Server
self.resp['nonce'] = chal['nonce']
self.resp['cnonce'] = ''.join("%x" % randint(0, 2**28) for randint in
itertools.repeat(random.randint, 7))
resp['nc'] = ('00000001')
resp['qop'] = 'auth'
resp['digest-uri'] = 'xmpp/' + self._owner.Server
A1=C([H(C([resp['username'], resp['realm'], self.password])),
resp['nonce'], resp['cnonce']])
A2=C(['AUTHENTICATE',resp['digest-uri']])
response= HH(C([HH(A1), resp['nonce'], resp['nc'], resp['cnonce'],
resp['qop'], HH(A2)]))
resp['response'] = response
resp['charset'] = 'utf-8'
sasl_data = u''
for key in ('charset', 'username', 'realm', 'nonce', 'nc', 'cnonce',
'digest-uri', 'response', 'qop'):
if key in ('nc','qop','response','charset'):
sasl_data += u"%s=%s," % (key, resp[key])
else:
sasl_data += u'%s="%s",' % (key, resp[key])
sasl_data = sasl_data[:-1].encode('utf-8').encode('base64').replace(
'\r','').replace('\n','')
node = Node('response', attrs={'xmlns':NS_SASL}, payload=[sasl_data])
self._owner.send(str(node))
self.resp['nc'] = ('00000001')
self.resp['qop'] = 'auth'
self.resp['digest-uri'] = 'xmpp/' + self._owner.Server
self.resp['charset'] = 'utf-8'
# Password is now required
self._owner._caller.get_password(self.set_password)
elif 'rspauth' in chal:
self._owner.send(str(Node('response', attrs={'xmlns':NS_SASL})))
else:
@ -335,6 +315,34 @@ class SASL(PlugIn):
if self.on_sasl:
self.on_sasl()
raise NodeProcessed
def set_password(self, password):
self.password = password
if self.mechanism == 'DIGEST-MD5':
A1 = C([H(C([self.resp['username'], self.resp['realm'],
self.password])), self.resp['nonce'], self.resp['cnonce']])
A2 = C(['AUTHENTICATE', self.resp['digest-uri']])
response= HH(C([HH(A1), self.resp['nonce'], self.resp['nc'],
self.resp['cnonce'], self.resp['qop'], HH(A2)]))
self.resp['response'] = response
sasl_data = u''
for key in ('charset', 'username', 'realm', 'nonce', 'nc', 'cnonce',
'digest-uri', 'response', 'qop'):
if key in ('nc','qop','response','charset'):
sasl_data += u"%s=%s," % (key, self.resp[key])
else:
sasl_data += u'%s="%s",' % (key, self.resp[key])
sasl_data = sasl_data[:-1].encode('utf-8').encode('base64').replace(
'\r', '').replace('\n', '')
node = Node('response', attrs={'xmlns':NS_SASL}, payload=[sasl_data])
elif self.mechanism == 'PLAIN':
sasl_data = u'%s\x00%s\x00%s' % (self.username + '@' + \
self._owner.Server, self.username, self.password)
sasl_data = sasl_data.encode('utf-8').encode('base64').replace(
'\n', '')
node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'PLAIN'},
payload=[sasl_data])
self._owner.send(str(node))
class NonBlockingNonSASL(PlugIn):

View File

@ -265,6 +265,7 @@ from common import socks5
from common import helpers
from common import optparser
from common import dataforms
from common import passwords
if verbose: gajim.verbose = True
del verbose
@ -1522,6 +1523,28 @@ class Interface:
self.gpg_passphrase[keyid] = request
request.add_callback(account, callback)
def handle_event_password_required(self, account, array):
#('PASSWORD_REQUIRED', account, None)
text = _('Enter your password for account %s') % account
if passwords.USER_HAS_GNOMEKEYRING and \
not passwords.USER_USES_GNOMEKEYRING:
text += '\n' + _('Gnome Keyring is installed but not \
correctly started (environment variable probably not \
correctly set)')
def on_ok(passphrase, save):
if save:
gajim.config.set_per('accounts', account, 'savepass', True)
passwords.save_password(account, passphrase)
gajim.connections[account].set_password(passphrase)
def on_cancel():
self.roster.set_state(account, 'offline')
self.roster.update_status_combobox()
dialogs.PassphraseDialog(_('Password Required'), text, _('Save password'),
ok_handler=on_ok, cancel_handler=on_cancel)
def handle_event_roster_info(self, account, array):
#('ROSTER_INFO', account, (jid, name, sub, ask, groups))
jid = array[0]
@ -2262,6 +2285,7 @@ class Interface:
self.handle_event_unique_room_id_unsupported,
'UNIQUE_ROOM_ID_SUPPORTED': self.handle_event_unique_room_id_supported,
'GPG_PASSWORD_REQUIRED': self.handle_event_gpg_password_required,
'PASSWORD_REQUIRED': self.handle_event_password_required,
'SSL_ERROR': self.handle_event_ssl_error,
'FINGERPRINT_ERROR': self.handle_event_fingerprint_error,
'PLAIN_CONNECTION': self.handle_event_plain_connection,

View File

@ -54,7 +54,6 @@ import features_window
from common import gajim
from common import helpers
from common import passwords
from common.exceptions import GajimGeneralException
from common import i18n
from common import pep
@ -1909,13 +1908,16 @@ class RosterWindow:
dialogs.InformationDialog(_('Authorization has been removed'),
_('Now "%s" will always see you as offline.') %jid)
def set_connecting_state(self, account):
def set_state(self, account, state):
child_iterA = self._get_account_iter(account, self.model)
if child_iterA:
self.model[child_iterA][0] = \
gajim.interface.jabber_state_images['16']['connecting']
gajim.interface.jabber_state_images['16'][state]
if gajim.interface.systray_enabled:
gajim.interface.systray.change_status('connecting')
gajim.interface.systray.change_status(state)
def set_connecting_state(self, account):
self.set_state(account, 'connecting')
def send_status(self, account, status, txt, auto=False, to=None):
child_iterA = self._get_account_iter(account, self.model)
@ -1927,38 +1929,6 @@ class RosterWindow:
if gajim.connections[account].connected < 2:
self.set_connecting_state(account)
if not gajim.connections[account].password:
text = _('Enter your password for account %s') % account
if passwords.USER_HAS_GNOMEKEYRING and \
not passwords.USER_USES_GNOMEKEYRING:
text += '\n' + _('Gnome Keyring is installed but not \
correctly started (environment variable probably not \
correctly set)')
def on_ok(passphrase, save):
gajim.connections[account].password = passphrase
if save:
gajim.config.set_per('accounts', account, 'savepass', True)
passwords.save_password(account, passphrase)
keyid = gajim.config.get_per('accounts', account, 'keyid')
if keyid and not gajim.connections[account].gpg:
dialogs.WarningDialog(_('GPG is not usable'),
_('You will be connected to %s without OpenPGP.') % \
account)
self.send_status_continue(account, status, txt, auto, to)
def on_cancel():
if child_iterA:
self.model[child_iterA][0] = \
gajim.interface.jabber_state_images['16']['offline']
if gajim.interface.systray_enabled:
gajim.interface.systray.change_status('offline')
self.update_status_combobox()
dialogs.PassphraseDialog(_('Password Required'), text,
_('Save password'), ok_handler=on_ok,
cancel_handler=on_cancel)
return
keyid = gajim.config.get_per('accounts', account, 'keyid')
if keyid and not gajim.connections[account].gpg:
dialogs.WarningDialog(_('GPG is not usable'),