request connection password only when neede. No need to request it for GSSAPI or ANONYMOUS login. see #2465
This commit is contained in:
parent
95d7e157da
commit
849108b11f
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
24
src/gajim.py
24
src/gajim.py
|
@ -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,
|
||||
|
|
|
@ -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'),
|
||||
|
|
Loading…
Reference in New Issue