def test_close_straight_after_accept(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) call_async(q, chan.SASLAuthentication, 'StartMechanismWithData', 'X-TELEPATHY-PASSWORD', PASSWORD) # In_Progress appears before StartMechanismWithData returns q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]) q.expect('dbus-return', method='StartMechanismWithData') q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}]) # fd.o#32278: # When this was breaking, gabble received AcceptSASL and told the # success_async GAsyncResult to complete in an idle. But, before # the result got its callback called, Close was also received and # the auth manager cleared its channel. When the idle function was # finally reached it saw it no longer had a channel (it had been # cleared in the closed callback) and thought it should be # chaining up to the wocky auth registry but of course it should # be calling the channel finish function. call_async(q, chan.SASLAuthentication, 'AcceptSASL') call_async(q, chan, 'Close') q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SUCCEEDED, '', {}]) e = q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
def test_plain_success(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) assertEquals(JID, props.get(cs.SASL_AUTHORIZATION_IDENTITY)) # On some servers we can't do DIGEST auth without this information. assertEquals('example.org', props.get(cs.SASL_DEFAULT_REALM)) # We can't necessarily do PLAIN auth without this information. assertEquals('test', props.get(cs.SASL_DEFAULT_USERNAME)) chan.SASLAuthentication.StartMechanismWithData('PLAIN', INITIAL_RESPONSE) e, _ = q.expect_many( EventPattern('sasl-auth', initial_response=INITIAL_RESPONSE), EventPattern('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]), ) authenticator = e.authenticator authenticator.success(None) q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}]) chan.SASLAuthentication.AcceptSASL() q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SUCCEEDED, '', {}]) e = q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
def test_plain_no_account(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) assertEquals('example.com', props.get(cs.SASL_DEFAULT_REALM)) assertEquals('', props.get(cs.SASL_DEFAULT_USERNAME)) chan.SASLAuthentication.StartMechanismWithData('PLAIN', INITIAL_RESPONSE) e, _ = q.expect_many( EventPattern('sasl-auth', initial_response=INITIAL_RESPONSE), EventPattern('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]), ) authenticator = e.authenticator authenticator.success(None) q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}]) chan.SASLAuthentication.AcceptSASL() q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SUCCEEDED, '', {}]) e = q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
def test_plain_fail_helper(q, bus, conn, stream, element, error, csr): chan, props = connect_and_get_sasl_channel(q, bus, conn) chan.SASLAuthentication.StartMechanismWithData('PLAIN', INITIAL_RESPONSE) e, _ = q.expect_many( EventPattern('sasl-auth', initial_response=INITIAL_RESPONSE), EventPattern('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]), ) authenticator = e.authenticator authenticator.failure(element) e = q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH) assertEquals([cs.SASL_STATUS_SERVER_FAILED, error], e.args[:2]) assertContains('debug-message', e.args[2]) e = q.expect('dbus-signal', signal='ConnectionError') assertEquals(error, e.args[0]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_DISCONNECTED, csr])
def test_bad_usage(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) call_async(q, chan.SASLAuthentication, 'Respond', 'This is uncalled for') q.expect('dbus-error', method='Respond', name=cs.NOT_AVAILABLE) chan.SASLAuthentication.StartMechanismWithData('PLAIN', INITIAL_RESPONSE) e, _ = q.expect_many( EventPattern('sasl-auth', initial_response=INITIAL_RESPONSE), EventPattern('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]), ) authenticator = e.authenticator call_async(q, chan.SASLAuthentication, 'StartMechanismWithData', 'PLAIN', 'foo') q.expect('dbus-error', method='StartMechanismWithData', name=cs.NOT_AVAILABLE) authenticator.success(None) q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}]) call_async(q, chan.SASLAuthentication, 'Respond', 'Responding after success') q.expect('dbus-error', method='Respond', name=cs.NOT_AVAILABLE)
def start_mechanism(q, bus, conn, mechanism="ABORT-TEST", initial_response=EXCHANGE[0][1]): chan, props = connect_and_get_sasl_channel(q, bus, conn) chan.SASLAuthentication.StartMechanismWithData(mechanism, initial_response) q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]) e = q.expect('sasl-auth', initial_response=initial_response) return chan, e.authenticator
def test_no_password(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) chan.Close() q.expect_many( EventPattern('dbus-signal', path=chan.object_path, signal='Closed'), EventPattern('dbus-signal', path=conn.object_path, signal='ChannelClosed', args=[chan.object_path]), EventPattern('dbus-signal', path=conn.object_path, signal='ConnectionError', predicate=lambda e: e.args[0] == cs.AUTHENTICATION_FAILED), EventPattern('dbus-signal', path=conn.object_path, signal='StatusChanged', args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_AUTHENTICATION_FAILED]), )
def test_plain_abort(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) chan.SASLAuthentication.StartMechanismWithData('PLAIN', INITIAL_RESPONSE) e, _ = q.expect_many( EventPattern('sasl-auth', initial_response=INITIAL_RESPONSE), EventPattern('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]), ) authenticator = e.authenticator authenticator.success(None) q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}]) abort_auth(q, chan, cs.SASL_ABORT_REASON_INVALID_CHALLENGE, "Something is fishy")
def test_abort_mid(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) chan.SASLAuthentication.StartMechanismWithData("ABORT-TEST", EXCHANGE[0][1]) q.expect( "dbus-signal", signal="SASLStatusChanged", interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, "", {}], ) e = q.expect("sasl-auth", initial_response=EXCHANGE[0][1]) authenticator = e.authenticator authenticator.challenge(EXCHANGE[1][0]) q.expect("dbus-signal", signal="NewChallenge", interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[EXCHANGE[1][0]]) abort_auth(q, chan, cs.SASL_ABORT_REASON_INVALID_CHALLENGE, "wrong data from server")
def test_close_straight_after_accept(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) call_async(q, chan.SASLAuthentication, 'StartMechanismWithData', 'X-TELEPATHY-PASSWORD', PASSWORD) # In_Progress appears before StartMechanismWithData returns q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]) # Different order to Gabble q.expect_many( EventPattern('dbus-return', method='StartMechanismWithData'), EventPattern('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}]), ) # fd.o#32278: # When this was breaking, gabble received AcceptSASL and told the # success_async GAsyncResult to complete in an idle. But, before # the result got its callback called, Close was also received and # the auth manager cleared its channel. When the idle function was # finally reached it saw it no longer had a channel (it had been # cleared in the closed callback) and thought it should be # chaining up to the wocky auth registry but of course it should # be calling the channel finish function. call_async(q, chan.SASLAuthentication, 'AcceptSASL') call_async(q, chan, 'Close') q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SUCCEEDED, '', {}]) e = q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
def test_no_password(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) chan.Close() _, _, status_changed = q.expect_many( EventPattern('dbus-signal', path=chan.object_path, signal='Closed'), EventPattern('dbus-signal', path=conn.object_path, signal='ChannelClosed', args=[chan.object_path]), # Unhelpfully prpl-jabber just sets the account to disabled so we # don't get an error. # EventPattern('dbus-signal', path=conn.object_path, # signal='ConnectionError', # predicate=lambda e: e.args[0] == cs.AUTHENTICATION_FAILED), EventPattern('dbus-signal', path=conn.object_path, signal='StatusChanged'), ) status, reason = status_changed.args assertEquals(cs.CONN_STATUS_DISCONNECTED, status)
def test_no_password(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) chan.Close() q.expect_many( EventPattern('dbus-signal', path=chan.object_path, signal='Closed'), EventPattern('dbus-signal', path=conn.object_path, signal='ChannelClosed', args=[chan.object_path]), EventPattern( 'dbus-signal', path=conn.object_path, signal='ConnectionError', predicate=lambda e: e.args[0] == cs.AUTHENTICATION_FAILED), EventPattern( 'dbus-signal', path=conn.object_path, signal='StatusChanged', args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_AUTHENTICATION_FAILED]), )
def test_disconnect_mid(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) chan.SASLAuthentication.StartMechanismWithData("ABORT-TEST", EXCHANGE[0][1]) q.expect( "dbus-signal", signal="SASLStatusChanged", interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, "", {}], ) e = q.expect("sasl-auth", initial_response=EXCHANGE[0][1]) authenticator = e.authenticator authenticator.challenge(EXCHANGE[1][0]) q.expect("dbus-signal", signal="NewChallenge", interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[EXCHANGE[1][0]]) call_async(q, conn, "Disconnect") q.expect_many( EventPattern("dbus-signal", signal="StatusChanged", args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_REQUESTED]), EventPattern("dbus-return", method="Disconnect"), )
def test_abort_connected(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) chan.SASLAuthentication.StartMechanismWithData("PLAIN", "\0" + JID.split("@")[0] + "\0" + PASSWORD) e, _ = q.expect_many( EventPattern("sasl-auth"), EventPattern( "dbus-signal", signal="SASLStatusChanged", interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, "", {}], ), ) authenticator = e.authenticator authenticator.success(None) q.expect( "dbus-signal", signal="SASLStatusChanged", interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SERVER_SUCCEEDED, "", {}], ) chan.SASLAuthentication.AcceptSASL() q.expect( "dbus-signal", signal="SASLStatusChanged", interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SUCCEEDED, "", {}], ) e = q.expect("dbus-signal", signal="StatusChanged", args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) call_async(q, chan.SASLAuthentication, "AbortSASL", cs.SASL_ABORT_REASON_USER_ABORT, "aborting too late") q.expect("dbus-error", method="AbortSASL", name=cs.NOT_AVAILABLE) chan.Close()
def test_complex_success(q, bus, conn, stream, with_extra_data=True, accept_early=False): chan, props = connect_and_get_sasl_channel(q, bus, conn) assertSameSets(MECHANISMS + ['X-TELEPATHY-PASSWORD'], props.get(cs.SASL_AVAILABLE_MECHANISMS)) call_async(q, chan.SASLAuthentication, 'StartMechanismWithData', "FOO", "") q.expect('dbus-error', method='StartMechanismWithData', name=cs.NOT_IMPLEMENTED) if with_extra_data: chan.SASLAuthentication.StartMechanismWithData("SCOTTISH-PLAY", INITIAL_RESPONSE) e = q.expect('sasl-auth', initial_response=INITIAL_RESPONSE) else: chan.SASLAuthentication.StartMechanism("SCOTTISH-PLAY") e = q.expect('sasl-auth', has_initial_response=False) authenticator = e.authenticator q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]) if not with_extra_data: # send the stage directions in-band instead authenticator.challenge('') e = q.expect('dbus-signal', signal='NewChallenge', interface=cs.CHANNEL_IFACE_SASL_AUTH) # this ought to be '' but dbus-python has fd.o #28131 assert e.args in ([''], ['None']) chan.SASLAuthentication.Respond(INITIAL_RESPONSE) q.expect('sasl-response', response=INITIAL_RESPONSE) for challenge, response in CR_PAIRS: authenticator.challenge(challenge) q.expect('dbus-signal', signal='NewChallenge', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[challenge]) chan.SASLAuthentication.Respond(response) q.expect('sasl-response', response=response) if with_extra_data: authenticator.success(SUCCESS_DATA) else: # The success data is sent in-band as a challenge authenticator.challenge(SUCCESS_DATA) q.expect('dbus-signal', signal='NewChallenge', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[SUCCESS_DATA]) if accept_early: # the UI can tell that this challenge isn't actually a challenge, # it's a success in disguise chan.SASLAuthentication.AcceptSASL() q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_CLIENT_ACCEPTED, '', {}]) else: chan.SASLAuthentication.Respond(dbus.ByteArray('')) if with_extra_data: # Wocky removes the distinction between a challenge containing # success data followed by a plain success, and a success # containing initial data, so we won't get to Server_Succeeded # til we "respond" to the "challenge". However, at the XMPP level, # we shouldn't get a response to a success. q.forbid_events([EventPattern('sasl-response')]) else: q.expect('sasl-response', response='') authenticator.success(None) if not accept_early: # *now* we accept q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}]) # We're willing to accept this SASL transaction chan.SASLAuthentication.AcceptSASL() q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SUCCEEDED, '', {}]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) chan.Close() # ... and check that the Connection is still OK conn.Properties.Get(cs.CONN, "SelfHandle")
def test_abort_early(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) abort_auth(q, chan, 31337, "maybe if I use an undefined code you'll crash")