summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCosimo Cecchi <cosimo.cecchi@collabora.co.uk>2010-09-15 12:59:29 +0200
committerCosimo Cecchi <cosimo.cecchi@collabora.co.uk>2010-09-15 13:00:22 +0200
commit8aac39069ef43f26953eaa93d748597873883ea1 (patch)
tree1eee06d2f1e716b961a45bbaf58c4d324231d75a
parent96a65bfd5d05591276d8c4f228fa7e26becd4496 (diff)
parentf956ba40fdc8a5832c3d99c76a3a49521bc37a6c (diff)
downloadtelepathy-gabble-8aac39069ef43f26953eaa93d748597873883ea1.tar.gz
Merge branch 'tls-tests-2'
Reviewed-by: Will Thompson <will.thompson@collabora.co.uk>
-rw-r--r--src/connection.c2
-rw-r--r--src/server-tls-manager.c6
-rw-r--r--tests/twisted/Makefile.am5
-rw-r--r--tests/twisted/constants.py17
-rw-r--r--tests/twisted/gabbletest.py39
-rw-r--r--tests/twisted/ns.py3
-rw-r--r--tests/twisted/tls-cert.pem24
-rw-r--r--tests/twisted/tls-key.pem27
-rw-r--r--tests/twisted/tls/server-tls-channel.py215
9 files changed, 320 insertions, 18 deletions
diff --git a/src/connection.c b/src/connection.c
index 236743590..8166433a0 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -2004,7 +2004,7 @@ _gabble_connection_connect (TpBaseConnection *base,
tls_handler = WOCKY_TLS_HANDLER (priv->server_tls_manager);
priv->connector = wocky_connector_new (jid, priv->password, priv->resource,
gabble_auth_manager_get_auth_registry (priv->auth_manager),
- g_object_ref (tls_handler));
+ tls_handler);
g_free (jid);
/* system certs */
diff --git a/src/server-tls-manager.c b/src/server-tls-manager.c
index d2d9b0b29..de9e44659 100644
--- a/src/server-tls-manager.c
+++ b/src/server-tls-manager.c
@@ -146,6 +146,8 @@ server_tls_channel_closed_cb (GabbleServerTLSChannel *channel,
self->priv->async_data);
}
+ tp_clear_object (&self->priv->async_result);
+
tp_channel_manager_emit_channel_closed_for_object (self,
TP_EXPORTABLE_CHANNEL (channel));
@@ -282,6 +284,8 @@ gabble_server_tls_manager_dispose (GObject *object)
{
GabbleServerTLSManager *self = GABBLE_SERVER_TLS_MANAGER (object);
+ DEBUG ("%p", self);
+
if (self->priv->dispose_has_run)
return;
@@ -297,6 +301,8 @@ gabble_server_tls_manager_finalize (GObject *object)
{
GabbleServerTLSManager *self = GABBLE_SERVER_TLS_MANAGER (object);
+ DEBUG ("%p", self);
+
if (self->priv->channel != NULL)
tp_base_channel_close (TP_BASE_CHANNEL (self->priv->channel));
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index 10c478d44..9fb53fdb6 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -83,6 +83,7 @@ TWISTED_TESTS = \
text/test-text-delayed.py \
text/test-text-no-body.py \
text/test-text.py \
+ tls/server-tls-channel.py \
tubes/accept-muc-dbus-tube.py \
tubes/accept-muc-stream-tube.py \
tubes/accept-private-dbus-tube.py \
@@ -287,7 +288,9 @@ EXTRA_DIST = \
sasl/saslutil.py \
search/search_helper.py \
file-transfer/file_transfer_helper.py \
- presence/invisible_helper.py
+ presence/invisible_helper.py \
+ tls-cert.pem \
+ tls-key.pem
noinst_PROGRAMS = \
telepathy-gabble-debug
diff --git a/tests/twisted/constants.py b/tests/twisted/constants.py
index aacde9621..3ff865df2 100644
--- a/tests/twisted/constants.py
+++ b/tests/twisted/constants.py
@@ -38,6 +38,8 @@ CHANNEL_TYPE_TEXT = CHANNEL + ".Type.Text"
CHANNEL_TYPE_FILE_TRANSFER = CHANNEL + ".Type.FileTransfer"
CHANNEL_TYPE_SERVER_AUTHENTICATION = \
CHANNEL + ".Type.ServerAuthentication.DRAFT"
+CHANNEL_TYPE_SERVER_TLS_CONNECTION = \
+ CHANNEL + ".Type.ServerTLSConnection"
TP_AWKWARD_PROPERTIES = "org.freedesktop.Telepathy.Properties"
PROPERTY_FLAG_READ = 1
@@ -132,6 +134,7 @@ CONNECTION_REPLACED = ERROR + '.ConnectionReplaced'
ALREADY_CONNECTED = ERROR + '.AlreadyConnected'
NETWORK_ERROR = ERROR + '.NetworkError'
INVALID_HANDLE = ERROR + '.InvalidHandle'
+CERT_UNTRUSTED = ERROR + '.Cert.Untrusted'
UNKNOWN_METHOD = 'org.freedesktop.DBus.Error.UnknownMethod'
@@ -347,6 +350,10 @@ AUTH_METHOD = CHANNEL_TYPE_SERVER_AUTHENTICATION + ".AuthenticationMethod"
AUTH_INFO = CHANNEL_TYPE_SERVER_AUTHENTICATION + ".AuthenticationInformation"
SASL_AVAILABLE_MECHANISMS = CHANNEL_IFACE_SASL_AUTH + ".AvailableMechanisms"
+# Channel_Type_ServerTLSConnection
+TLS_CERT_PATH = CHANNEL_TYPE_SERVER_TLS_CONNECTION + ".ServerCertificate"
+TLS_HOSTNAME = CHANNEL_TYPE_SERVER_TLS_CONNECTION + ".Hostname"
+
# Connection.Interface.Location
LOCATION_FEATURE_CAN_SET = 1
@@ -365,3 +372,13 @@ PARAM_REGISTER = 2
PARAM_HAS_DEFAULT = 4
PARAM_SECRET = 8
PARAM_DBUS_PROPERTY = 16
+
+AUTHENTICATION = 'org.freedesktop.Telepathy.Authentication'
+AUTH_TLS_CERT = AUTHENTICATION + ".TLSCertificate"
+
+TLS_CERT_STATE_PENDING = 0
+TLS_CERT_STATE_ACCEPTED = 1
+TLS_CERT_STATE_REJECTED = 2
+
+TLS_REJECT_REASON_UNKNOWN = 0
+TLS_REJECT_REASON_UNTRUSTED = 1
diff --git a/tests/twisted/gabbletest.py b/tests/twisted/gabbletest.py
index c8be75d5c..181ab4f35 100644
--- a/tests/twisted/gabbletest.py
+++ b/tests/twisted/gabbletest.py
@@ -21,7 +21,7 @@ import twisted
from twisted.words.xish import domish, xpath
from twisted.words.protocols.jabber.client import IQ
from twisted.words.protocols.jabber import xmlstream
-from twisted.internet import reactor
+from twisted.internet import reactor, ssl
import dbus
@@ -156,34 +156,41 @@ class JabberAuthenticator(GabbleAuthenticator):
self.xmlstream.send(result)
self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
-
class XmppAuthenticator(GabbleAuthenticator):
def __init__(self, username, password, resource=None):
GabbleAuthenticator.__init__(self, username, password, resource)
self.authenticated = False
- def streamStarted(self, root=None):
+ def streamInitialize(self, root):
if root:
self.xmlstream.sid = root.getAttribute('id')
self.xmlstream.sendHeader()
- if self.authenticated:
- # Initiator authenticated itself, and has started a new stream.
+ def streamIQ(self):
+ features = domish.Element((xmlstream.NS_STREAMS, 'features'))
+ bind = features.addElement((NS_XMPP_BIND, 'bind'))
+ self.xmlstream.send(features)
- features = domish.Element((xmlstream.NS_STREAMS, 'features'))
- bind = features.addElement((NS_XMPP_BIND, 'bind'))
- self.xmlstream.send(features)
+ self.xmlstream.addOnetimeObserver(
+ "/iq/bind[@xmlns='%s']" % NS_XMPP_BIND, self.bindIq)
- self.xmlstream.addOnetimeObserver(
- "/iq/bind[@xmlns='%s']" % NS_XMPP_BIND, self.bindIq)
- else:
- features = domish.Element((xmlstream.NS_STREAMS, 'features'))
- mechanisms = features.addElement((NS_XMPP_SASL, 'mechanisms'))
- mechanism = mechanisms.addElement('mechanism', content='PLAIN')
- self.xmlstream.send(features)
+ def streamSASL(self):
+ features = domish.Element((xmlstream.NS_STREAMS, 'features'))
+ mechanisms = features.addElement((NS_XMPP_SASL, 'mechanisms'))
+ mechanism = mechanisms.addElement('mechanism', content='PLAIN')
+ self.xmlstream.send(features)
- self.xmlstream.addOnetimeObserver("/auth", self.auth)
+ self.xmlstream.addOnetimeObserver("/auth", self.auth)
+
+ def streamStarted(self, root=None):
+ self.streamInitialize(root)
+
+ if self.authenticated:
+ # Initiator authenticated itself, and has started a new stream.
+ self.streamIQ()
+ else:
+ self.streamSASL()
def auth(self, auth):
assert (base64.b64decode(str(auth)) ==
diff --git a/tests/twisted/ns.py b/tests/twisted/ns.py
index b9510338d..6bbbd81dd 100644
--- a/tests/twisted/ns.py
+++ b/tests/twisted/ns.py
@@ -37,6 +37,9 @@ MUC_BYTESTREAM = 'http://telepathy.freedesktop.org/xmpp/protocol/muc-bytestream'
MUC_OWNER = '%s#owner' % MUC
MUC_USER = '%s#user' % MUC
NICK = "http://jabber.org/protocol/nick"
+NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
+NS_XMPP_BIND = 'urn:ietf:params:xml:ns:xmpp-bind'
+NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls'
OLPC_ACTIVITIES = "http://laptop.org/xmpp/activities"
OLPC_ACTIVITIES_NOTIFY = "%s+notify" % OLPC_ACTIVITIES
OLPC_ACTIVITY = "http://laptop.org/xmpp/activity"
diff --git a/tests/twisted/tls-cert.pem b/tests/twisted/tls-cert.pem
new file mode 100644
index 000000000..0a393c145
--- /dev/null
+++ b/tests/twisted/tls-cert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEHDCCAwagAwIBAgIBAjALBgkqhkiG9w0BAQUwbDELMAkGA1UEBhMCVUsxEjAQ
+BgNVBAoTCUNvbGxhYm9yYTEZMBcGA1UECxMQV29ja3kgVGVzdCBTdWl0ZTERMA8G
+A1UECBMIQ29uZnVzZWQxGzAZBgNVBAMTEldvY2t5IFhNUFAgTGlicmFyeTAeFw0w
+OTA5MTgxMjU0MDdaFw0zNzA5MTExMjU0MDdaMGkxCzAJBgNVBAYTAlVLMRIwEAYD
+VQQKEwlDb2xsYWJvcmExGTAXBgNVBAsTEFdvY2t5IFRlc3QgU3VpdGUxDjAMBgNV
+BAgTBURhemVkMRswGQYDVQQDExJXb2NreSBYTVBQIExpYnJhcnkwggEfMAsGCSqG
+SIb3DQEBAQOCAQ4AMIIBCQKCAQDC30AXWnLcakXrq3rHIfy+0u7zNAmdRYw88MIA
+7wpZZ4LxMHMqu4YnnyysoRNI9wblCPkJ29XyBmhfLc9Gmnnl6phzf04n9x93Z8t9
+JHnnwqqJzdtxfuHsAWa/+2He3uNxWML+dUy/OB5iazPeCwKtqwmh57oLFLHkF+Dh
+hrweUkoQDDnJ/1xT0bHmdslQ9qnMIxhjDUoZ9TkAk+8PpsoHbPclfr6ytnCjGfLO
+oA9vWehPokTDvQPQmXc52vIFNp8A3h05jep3DBYzkG+WJcJRNhyxC0dzFqyrFJW2
+XMtCs0p1cPaHgXVPCe4icXLY48ehVaFvBR02K3jVQ7WketzxAgMBAAGjgdIwgc8w
+DAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwIQYD
+VR0RBBowGIIQd2Vhc2VsLWp1aWNlLm9yZ4cEfwAAATAPBgNVHQ8BAf8EBQMDByAA
+MB0GA1UdDgQWBBRDAfw/7QRZO5a0qmJ75Oeo3hA01zAfBgNVHSMEGDAWgBRJMCYI
+jJrWac2LwMwOXAKOSh+mjDAsBgNVHR8EJTAjMCGgH6AdhhtmaWxlOi8vL3RtcC93
+b2NreS10ZXN0cy9jcmwwCwYJKoZIhvcNAQEFA4IBAQAIcwQ8FN7lnnQPm4al6y5v
+zrGzVSxkUuN+I8457E9ZAoFpItMGqWWKjjbOgjS3d95yJWmEW2eBVC3/LMEAvv4z
+Q6HkTRhafkiLWmXNa8DtbUq1cZ2hNrR1lNTOL4zXwg9JQbtFw0EAM7LfSgqHhTzs
+xO0AbXaO0TlbYkn9/amPCNQcFjg6Dgdm3x0T3g/tLQjtzjro/hdgYZqPng0MYBpG
+AUj99FwahI5D8cAPoUjtpxZOlsexz4r8UVGNRvL0Wqg57w8KKF7GVr15b2ZAeQwo
+pNJkMSXAyPpKW24Q06zwYFnC+Cp32udf2wIB9FEC3zNQugUbtFitHzPjzhum13iR
+-----END CERTIFICATE-----
diff --git a/tests/twisted/tls-key.pem b/tests/twisted/tls-key.pem
new file mode 100644
index 000000000..b1921b04d
--- /dev/null
+++ b/tests/twisted/tls-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAwt9AF1py3GpF66t6xyH8vtLu8zQJnUWMPPDCAO8KWWeC8TBz
+KruGJ58srKETSPcG5Qj5CdvV8gZoXy3PRpp55eqYc39OJ/cfd2fLfSR558Kqic3b
+cX7h7AFmv/th3t7jcVjC/nVMvzgeYmsz3gsCrasJoee6CxSx5Bfg4Ya8HlJKEAw5
+yf9cU9Gx5nbJUPapzCMYYw1KGfU5AJPvD6bKB2z3JX6+srZwoxnyzqAPb1noT6JE
+w70D0Jl3OdryBTafAN4dOY3qdwwWM5BvliXCUTYcsQtHcxasqxSVtlzLQrNKdXD2
+h4F1TwnuInFy2OPHoVWhbwUdNit41UO1pHrc8QIDAQABAoIBAC0rgHipT4yF2bU5
+51i3KRW2YQrgmgXpdAtAJ0f+IKD+nFx5xYg3NW6Dt+A/6e90yxVV0hwV5+6Uy6ac
+QLp13iGMElBbRut+nb2YwpM8XEF7XvpYTDBvn8CLxpxjkZkOgxvn3jMLT4HXaTuY
+68nhNXq59Z6gzv/4iQ989XRxPbOtKWI1m96ZTFstkG8TJjaO9AnDxR2sEGHQ+rhP
+IRMbHLagY1qA0OxMhHCHMTwq/oVBR7xtgraLzeHnSg+Q4Z+hY+TSNmlmJxZINHTK
+c4kxVhAv2iGJaLDC7XviyKs/AMmoVfcSuG+BGDDOxhpOjx/G4ZzKmp2VVwNOEYk1
+E2z7JH0CgYEAy+zMzpdgNIYIcKRAYqQITInsNnfGY+y2tOhUeNA558ZVoqt7Gf1Z
+TWegqyxtP71ZYkLqidNlJasgX2cU6aAkAHfO1EnpZiaX6WKSXGIfukLhH9Jwc6MW
+Xnnv0dZ9i83IL5sLIkAVb0TqqIIBvbxZjEYFSQVwpfG8BCvxNwQJ2U8CgYEA9KKh
+/DkoULrC8SIQ1TroOFcqLZPUFcCPHEfxHC+urWkYpRCrQ43jiZMCegPnKuUEQ9Nu
+7UZqOrP0WYyEqQ3P+jC4I4xBozJigGttMTBnC2rm40PCPZcUz28Ja/Tos4oiEN6q
+qVG5/IlfcjuZZGsFIKbTCxM2uXwykmJDeAC91b8CgYAvbIWAsfF8pYMG9xvGFNGd
+QyH81MP9bwpabgFfC0W8IgK+TtTVCXcgKi5SQIWzogxMbrVukgvew7pGlYlmf4h/
+11zxP7MYv3bqnrLc6zDnty/1n5HpQo8sL31XNmOCBLw+Xfcr4u1ZMBTGVV2kS04j
+8hC+l5ZH8TzBV5rEKZtEvwKBgQCtltmqyEQ7RMsfoDShmfM+R1u+i69q4ACs6L/G
+aG9izbiXKITeoshazt5rBmn6nhewqU+FPvoSPa+d+4AHFa4Gspt3XgcVbqNGzPPm
+e5ojF/BOQ76JRbOWngvpdxfIjrQtlFM1YrC+6hu4S2JFR0uUJ8yJh1DFvcOE7AVE
+GgKasQKBgET77FdaEiiajroe0CE8Ulmge4mpok7QQ81ag6gV6X3R7Ru20pg9iqGo
+U9OS2VgpqhoWz9PSoI/ZZghRYq0oQz9XDNLtZeGswFJgl4A/TrVs6gWcRxbVfAtg
+9EmaJucDIxXNHqoD2yXj7XJPqDkNuD7rV7IOnrsg4La1N7SQpQk2
+-----END RSA PRIVATE KEY-----
diff --git a/tests/twisted/tls/server-tls-channel.py b/tests/twisted/tls/server-tls-channel.py
new file mode 100644
index 000000000..1f59ea0d5
--- /dev/null
+++ b/tests/twisted/tls/server-tls-channel.py
@@ -0,0 +1,215 @@
+# coding=utf-8
+
+"""
+Copyright © 2010 Collabora Ltd.
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+"""
+
+"""
+Test the server TLS channel
+"""
+
+import base64
+import dbus
+
+from OpenSSL import crypto
+
+from twisted.words.protocols.jabber import xmlstream
+from twisted.words.protocols.jabber.client import IQ
+from twisted.words.xish import domish, xpath
+from twisted.internet import ssl
+
+import ns
+from gabbletest import exec_test, XmppAuthenticator
+from servicetest import ProxyWrapper, EventPattern, assertEquals, assertLength
+import constants as cs
+
+JID = "test@example.org"
+
+CA_CERT = 'tls-cert.pem'
+CA_KEY = 'tls-key.pem'
+
+# the certificate is for the domain name 'weasel-juice.org'.
+# the files are copied from wocky/tests/certs/tls-[cert,key].pem
+
+class TlsAuthenticator(XmppAuthenticator):
+ def __init__(self, username, password, resource=None):
+ XmppAuthenticator.__init__(self, username, password, resource)
+ self.tls_encrypted = False
+
+ def streamTLS(self):
+ features = domish.Element((xmlstream.NS_STREAMS, 'features'))
+ starttls = features.addElement((ns.NS_XMPP_TLS, 'starttls'))
+ starttls.addElement('required')
+
+ mechanisms = features.addElement((ns.NS_XMPP_SASL, 'mechanisms'))
+ mechanism = mechanisms.addElement('mechanism', content='PLAIN')
+ self.xmlstream.send(features)
+
+ self.xmlstream.addOnetimeObserver("/starttls", self.tlsAuth)
+
+ def streamStarted(self, root=None):
+ self.streamInitialize(root)
+
+ if self.authenticated and self.tls_encrypted:
+ self.streamIQ()
+ elif self.tls_encrypted:
+ self.streamSASL()
+ else:
+ self.streamTLS()
+
+ def tlsAuth(self, auth):
+ with open(CA_KEY, 'rb') as file:
+ pem_key = file.read()
+ pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, pem_key, "")
+
+ with open(CA_CERT, 'rb') as file:
+ pem_cert = file.read()
+ cert = crypto.load_certificate(crypto.FILETYPE_PEM, pem_cert)
+
+ tls_ctx = ssl.CertificateOptions(privateKey=pkey, certificate=cert)
+
+ self.xmlstream.send(domish.Element((ns.NS_XMPP_TLS, 'proceed')))
+ self.xmlstream.transport.startTLS(tls_ctx)
+ self.xmlstream.reset()
+ self.tls_encrypted = True
+
+class ServerTlsChanWrapper(ProxyWrapper):
+ def __init__(self, object, default=cs.CHANNEL, interfaces={
+ "ServerTLSConnection" : cs.CHANNEL_TYPE_SERVER_TLS_CONNECTION}):
+ ProxyWrapper.__init__(self, object, default, interfaces)
+
+class TlsCertificateWrapper(ProxyWrapper):
+ def __init__(self, object, default=cs.AUTH_TLS_CERT, interfaces={
+ "TLSCertificate" : cs.AUTH_TLS_CERT}):
+ ProxyWrapper.__init__(self, object, default, interfaces)
+
+def is_server_tls_chan_event(event):
+ channels = event.args[0];
+
+ if len(channels) > 1:
+ return False
+
+ path, props = channels[0]
+ return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_SERVER_TLS_CONNECTION
+
+def connect_and_get_tls_objects(q, bus, conn):
+ conn.Connect()
+
+ q.expect('dbus-signal', signal='StatusChanged',
+ args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED])
+
+ ev, = q.expect_many(
+ EventPattern('dbus-signal', signal='NewChannels',
+ predicate=is_server_tls_chan_event))
+
+ channels = ev.args[0]
+ path, props = channels[0]
+
+ chan = ServerTlsChanWrapper(bus.get_object(conn.bus_name, path))
+ hostname = props[cs.TLS_HOSTNAME]
+ certificate_path = props[cs.TLS_CERT_PATH]
+
+ assertEquals(hostname, 'example.org')
+
+ return chan, hostname, certificate_path
+
+def test_connect_early_close_success(q, bus, conn, stream):
+ chan, hostname, certificate_path = connect_and_get_tls_objects(q, bus, conn)
+
+ # close the channel early
+ chan.Close()
+
+ # we expect the fallback verification process to connect successfully,
+ # even if the certificate doesn't match the hostname, as encryption-required is not set
+ q.expect_many(
+ EventPattern('dbus-signal', signal='Closed'),
+ EventPattern('dbus-signal', signal='ChannelClosed'),
+ EventPattern('dbus-signal', signal='StatusChanged',
+ args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
+ )
+
+def test_connect_early_close_fail(q, bus, conn, stream):
+ chan, hostname, certificate_path = connect_and_get_tls_objects(q, bus, conn)
+
+ # close the channel early
+ chan.Close()
+
+ # we expect the fallback verification process to fail, as there's a hostname mismatch,
+ # encryption-required is set and ignore-ssl-errors is not
+ q.expect_many(
+ EventPattern('dbus-signal', signal='Closed'),
+ EventPattern('dbus-signal', signal='ChannelClosed'),
+ EventPattern('dbus-signal', signal='StatusChanged',
+ args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_CERT_HOSTNAME_MISMATCH])
+ )
+
+def rejection_list_match(event):
+ rejections = event.args[0];
+
+ if len(rejections) != 1:
+ return False
+
+ return rejections == [(cs.TLS_REJECT_REASON_UNTRUSTED, cs.CERT_UNTRUSTED, {})]
+
+def test_connect_fail(q, bus, conn, stream):
+ chan, hostname, certificate_path = connect_and_get_tls_objects(q, bus, conn)
+
+ certificate = TlsCertificateWrapper(bus.get_object(conn.bus_name, certificate_path))
+ certificate.TLSCertificate.Reject([(cs.TLS_REJECT_REASON_UNTRUSTED, cs.CERT_UNTRUSTED, {})])
+
+ # we first expect the certificate to be rejected
+ q.expect('dbus-signal', signal='Rejected', predicate=rejection_list_match)
+
+ # this should trigger a ConnectionError
+ q.expect('dbus-signal', signal='ConnectionError', args=[cs.CERT_UNTRUSTED, {}])
+
+ # at this point the channel should be closed
+ q.expect_many(
+ EventPattern('dbus-signal', signal='Closed'),
+ EventPattern('dbus-signal', signal='ChannelClosed')
+ )
+
+ # finally, we should receive a StatusChanged signal on the connection
+ q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_CERT_UNTRUSTED])
+
+def test_connect_success(q, bus, conn, stream):
+ chan, hostname, certificate_path = connect_and_get_tls_objects(q, bus, conn)
+
+ certificate = TlsCertificateWrapper(bus.get_object(conn.bus_name, certificate_path))
+ certificate.TLSCertificate.Accept()
+
+ q.expect('dbus-signal', signal='Accepted')
+
+ cert_props = dbus.Interface(certificate, cs.PROPERTIES_IFACE)
+ state = cert_props.Get(cs.AUTH_TLS_CERT, 'State')
+ rejections = cert_props.Get(cs.AUTH_TLS_CERT, 'Rejections')
+
+ assertLength(0, rejections)
+
+ chan.Close()
+
+ q.expect_many(
+ EventPattern('dbus-signal', signal='Closed'),
+ EventPattern('dbus-signal', signal='ChannelClosed'),
+ EventPattern('dbus-signal', signal='StatusChanged',
+ args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
+ )
+
+if __name__ == '__main__':
+ exec_test(test_connect_success, { 'account' : JID },
+ authenticator=TlsAuthenticator(username='test', password='pass'))
+ exec_test(test_connect_fail, { 'account' : JID },
+ authenticator=TlsAuthenticator(username='test', password='pass'))
+ exec_test(test_connect_early_close_success,
+ { 'account' : JID,
+ 'ignore-ssl-errors' : False,
+ 'require-encryption' : False },
+ authenticator=TlsAuthenticator(username='test', password='pass'))
+ exec_test(test_connect_early_close_fail,
+ { 'account' : JID,
+ 'ignore-ssl-errors' : False,
+ 'require-encryption' : True },
+ authenticator=TlsAuthenticator(username='test', password='pass'))