From 5b349773b029e0ca20f711f25fe6eaca3562515d Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Mon, 10 Dec 2018 19:26:02 +0100 Subject: [PATCH] mail: Fix new breakage on python 2.7 (backport) (#49222) * mail: Fix new breakage on python 2.7 * Add changelog fragment * Add basic SMTP testing * Add SMTP integration tests using starttls and TLS --- .../47019-mail-fix-py27-regression.yaml | 2 + lib/ansible/modules/notification/mail.py | 11 ++- test/integration/targets/mail/aliases | 1 + .../targets/mail/files/smtpserver.crt | 22 +++++ .../targets/mail/files/smtpserver.key | 28 ++++++ .../targets/mail/files/smtpserver.py | 68 +++++++++++++++ test/integration/targets/mail/tasks/main.yml | 85 +++++++++++++++++++ 7 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/47019-mail-fix-py27-regression.yaml create mode 100644 test/integration/targets/mail/aliases create mode 100644 test/integration/targets/mail/files/smtpserver.crt create mode 100644 test/integration/targets/mail/files/smtpserver.key create mode 100755 test/integration/targets/mail/files/smtpserver.py create mode 100644 test/integration/targets/mail/tasks/main.yml diff --git a/changelogs/fragments/47019-mail-fix-py27-regression.yaml b/changelogs/fragments/47019-mail-fix-py27-regression.yaml new file mode 100644 index 00000000000..0bbaff4d511 --- /dev/null +++ b/changelogs/fragments/47019-mail-fix-py27-regression.yaml @@ -0,0 +1,2 @@ +bugfixes: +- mail - fix python 2.7 regression diff --git a/lib/ansible/modules/notification/mail.py b/lib/ansible/modules/notification/mail.py index 7e4ff356346..0aa5d0e2f55 100644 --- a/lib/ansible/modules/notification/mail.py +++ b/lib/ansible/modules/notification/mail.py @@ -194,6 +194,7 @@ from email.mime.text import MIMEText from email.header import Header from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import PY3 from ansible.module_utils._text import to_native @@ -248,7 +249,10 @@ def main(): try: if secure != 'never': try: - smtp = smtplib.SMTP_SSL(host=host, port=port, timeout=timeout) + if PY3: + smtp = smtplib.SMTP_SSL(host=host, port=port, timeout=timeout) + else: + smtp = smtplib.SMTP_SSL(timeout=timeout) code, smtpmessage = smtp.connect(host, port) secure_state = True except ssl.SSLError as e: @@ -259,7 +263,10 @@ def main(): pass if not secure_state: - smtp = smtplib.SMTP(host=host, port=port, timeout=timeout) + if PY3: + smtp = smtplib.SMTP(host=host, port=port, timeout=timeout) + else: + smtp = smtplib.SMTP(timeout=timeout) code, smtpmessage = smtp.connect(host, port) except smtplib.SMTPException as e: diff --git a/test/integration/targets/mail/aliases b/test/integration/targets/mail/aliases new file mode 100644 index 00000000000..a6dafcf8cd8 --- /dev/null +++ b/test/integration/targets/mail/aliases @@ -0,0 +1 @@ +shippable/posix/group1 diff --git a/test/integration/targets/mail/files/smtpserver.crt b/test/integration/targets/mail/files/smtpserver.crt new file mode 100644 index 00000000000..44c18a243ef --- /dev/null +++ b/test/integration/targets/mail/files/smtpserver.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIJAJyHQUcqSOQpMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNV +BAYTAkJFMRMwEQYDVQQIDApWbGFhbmRlcmVuMQ0wCwYDVQQHDARHZW50MQ4wDAYD +VQQKDAVEYWdpdDELMAkGA1UECwwCSVQxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2Nh +bGRvbWFpbjAeFw0xODExMjgxMjQ3MzlaFw0yODExMjUxMjQ3MzlaMG4xCzAJBgNV +BAYTAkJFMRMwEQYDVQQIDApWbGFhbmRlcmVuMQ0wCwYDVQQHDARHZW50MQ4wDAYD +VQQKDAVEYWdpdDELMAkGA1UECwwCSVQxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2Nh +bGRvbWFpbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANLqBGgIF44U +zRhNupGwSKAeTIXT4nXPIJKlIi1kTSQwtywQmBw6leBlvj1qwU73+nhqwSclIrYx +3ltvrpKHAWG1jqqsExuLRaKRdWgx1YC2WPgZwYC0C+LkE8vs/Kl1v0HgPuPMkzeK +hDctQfWOaykFOy0mB/BfP2vSVoEckffMlDjG/bHwNt7cG8BnqKd8e9VR+ZcBazFK +bnKhht0ldR84Wbp+5wpuCr1R1R0ltdO2O+LACrXzvH9Kf0CGhKXGccwGpi43eXyK +CDbubkGcLjg9Fo7kZ6uW5nU2vHJ1iDGnvUl8X96qKoOFU0EvBveCisc1bY433uG1 +NjEZ1xLPGK8CAwEAAaNQME4wHQYDVR0OBBYEFO6nDFzJBZBLJt4yza+VrUEOy3Zl +MB8GA1UdIwQYMBaAFO6nDFzJBZBLJt4yza+VrUEOy3ZlMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADggEBALTq0ycKhEr/3KOsfKBup4bs5Oqv0x7ePaUNxyef +JSyKTjD0gPY8YNAeNA7gU5XGjMr4h9cNpRmJ0TyfwWJxH4uK4d2p5k1ZpQWKv8jG +4U9sZTQzkh8nqRBaEl94qsiCIRCllb6VveWbIGE6eqt4rT0V9l9fvbw+hSXdiYXT +KkkX5VZxctV2OMkbP1mbOYIA22jqZKQiIvAVcMA6vSnlDAJKTi9/kw99/zjUQ9Jb +8bF2gcnzAijJAWsCqf8hZVq9+pogptBd/bkKUCuTA4MACX5ppgQltkgX2mLrj6Ep +Po2euqzUZREzKl2cUaP85m+8tClYk0Wjfm0RjxPRa8fgUfM= +-----END CERTIFICATE----- diff --git a/test/integration/targets/mail/files/smtpserver.key b/test/integration/targets/mail/files/smtpserver.key new file mode 100644 index 00000000000..48ddf644c97 --- /dev/null +++ b/test/integration/targets/mail/files/smtpserver.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDS6gRoCBeOFM0Y +TbqRsEigHkyF0+J1zyCSpSItZE0kMLcsEJgcOpXgZb49asFO9/p4asEnJSK2Md5b +b66ShwFhtY6qrBMbi0WikXVoMdWAtlj4GcGAtAvi5BPL7Pypdb9B4D7jzJM3ioQ3 +LUH1jmspBTstJgfwXz9r0laBHJH3zJQ4xv2x8Dbe3BvAZ6infHvVUfmXAWsxSm5y +oYbdJXUfOFm6fucKbgq9UdUdJbXTtjviwAq187x/Sn9AhoSlxnHMBqYuN3l8igg2 +7m5BnC44PRaO5GerluZ1NrxydYgxp71JfF/eqiqDhVNBLwb3gorHNW2ON97htTYx +GdcSzxivAgMBAAECggEALDCRucYwQTmEexoWA94+aSXP/J4XLX23ImJs1bvVGccH +KblUVV3E9x36DN4oIEZ+eOpNC8mRC0FJiDjPB643kOQ8PvAMlNHKRjRZt/nw9KW/ +4ENtMm0GrIQCzdAaY9ritoeoRYwgMBvadcEKt8seEpsg+eWk9izOmeWY8DYvMw6N +hNu5zQLkMGTTqfDxkl7KnyKPhjW/++eUdgsTIA31/wHsJSiNR5Pkoy2fOVtNO7JN +EghcKE3lYKKzOW6vg0LBY8xVQ4KMbCVgnYNI3MU9qpG2bYxy1hlWIrsjrt9PyRp8 +jDSKnLD4Zvv4L6gj2fhelES/YQ/055YyzG801Q+gUQKBgQDohqr5fwQj8Awrc0K/ +DodaIkVwXHkQAhSWidrqxZXmtn4ZsgDA3V82ZTIjWe2v7ES5U4jeYKGoUweCUodr +PPT0IKEFmS2Fq1AZZx7Ry+ihA7gw6PV5DbG5DwyNYlhn6F6Bghl8pKAcXPGuwtgd +BKXj7utEp57Q9ue3P00cGNokKQKBgQDoNNFMPnfv5UQp+K0A89cKW8q6sf93/ul4 +kjh72q/KbK57ouhWPNib3tJLvkl7P8S45nrUGQZtd6zLhU/6SzAnGGnNZ7gNAs3l +SWidcmZDqIiIXh6BF4/4WxXMXJdhfrux9/O8Xk89v+EDAbLbN8jSrvy87+6mOmRM +r/MAXToxFwKBgHpGbtxalbPMRKoIp33OxxB32yoWBreLUIZFIfC5THWRW8hpWYoS +H0J8fpwmax5K0WzfZ6cBC6F3YAiBG6Mh3/IMwoAuJ8kV6D4jgwpx/vfE+/QEXSl2 +MRIOvtwObkzd3eyenIZ2D5g6rADphznjOtUcy21D8/kRDZLIX+U5kGTZAoGBAIYg +/ETuUJlh9V3JJyXFtBFntFLjPo4x0Oq0i6v/RkvHO4JvN4WY4AYpT5Aw+oEW9KtZ +dtnNGslgt49YEjqh886ha3wazVW2qPgozyUjT68FSth6hWRMF/19n7nMQiUu73x9 +nWzRjTQ+Aduav5WhQ39vVM5OSav7TrR9bgBn2ZVBAoGBAN4Hle/PIFzApQYQRIT0 +wPpOvEVx56+c70ZMvLv5UgmY2jLKZKFUV6oGGUZlJXfh1ZMnXShWY1pjvi/FnIIi +AKDB9N17DE5AmpzuXFjU3YwXde98MjuUY03P3yaFQ4cXYryqgZxuMPgyGFM9vtMd +WXFdvCtm0c3WMpPJSr9kgy6Q +-----END PRIVATE KEY----- diff --git a/test/integration/targets/mail/files/smtpserver.py b/test/integration/targets/mail/files/smtpserver.py new file mode 100755 index 00000000000..01b257e1898 --- /dev/null +++ b/test/integration/targets/mail/files/smtpserver.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2018, Dag Wieers (@dagwieers) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import asyncore +import os.path +import ssl +import sys + +# Handle TLS and non-TLS support +try: + import smtpd_tls + HAS_TLS = True +except ImportError: + import smtpd + HAS_TLS = False + print('Library smtpd-tls is missing or not supported, hence starttls is NOT supported.') + +# Handle custom ports +port = '25:465' +if len(sys.argv) > 1: + port = sys.argv[1] +ports = port.split(':') +if len(ports) > 1: + port1, port2 = int(ports[0]), int(ports[1]) +else: + port1, port2 = int(port), None + +# Handle custom certificate +basename = os.path.splitext(sys.argv[0])[0] +certfile = basename + '.crt' +if len(sys.argv) > 2: + certfile = sys.argv[2] + +# Handle custom key +keyfile = basename + '.key' +if len(sys.argv) > 3: + keyfile = sys.argv[3] + +try: + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) +except AttributeError: + ssl_ctx = None + if HAS_TLS: + print('Python ssl library does not support SSLContext, hence starttls and TLS are not supported.') + import smtpd + +if HAS_TLS and ssl_ctx is not None: + print('Using %s and %s' % (certfile, keyfile)) + ssl_ctx.load_cert_chain(certfile=certfile, keyfile=keyfile) + + print('Start SMTP server on port', port1) + smtp_server1 = smtpd_tls.DebuggingServer(('127.0.0.1', port1), None, ssl_ctx=ssl_ctx, starttls=True) + if port2: + print('Start TLS SMTP server on port', port2) + smtp_server2 = smtpd_tls.DebuggingServer(('127.0.0.1', port2), None, ssl_ctx=ssl_ctx, starttls=False) +else: + print('Start SMTP server on port', port1) + smtp_server1 = smtpd.DebuggingServer(('127.0.0.1', port1), None) + if port2: + print('WARNING: TLS is NOT supported on this system, not listening on port %s.' % port2) + +asyncore.loop() diff --git a/test/integration/targets/mail/tasks/main.yml b/test/integration/targets/mail/tasks/main.yml new file mode 100644 index 00000000000..8a3280d77db --- /dev/null +++ b/test/integration/targets/mail/tasks/main.yml @@ -0,0 +1,85 @@ +# TODO: Our current implementation does not handle SMTP authentication + +# NOTE: If the system does not support smtpd-tls (python 2.6 and older) we do basic tests +- name: Attempt to install smtpd-tls + pip: + name: smtpd-tls + state: present + ignore_errors: yes + register: smtpd_tls + +- name: Install test smtpserver + copy: + src: '{{ item }}' + dest: '{{ output_dir }}/{{ item }}' + loop: + - smtpserver.py + - smtpserver.crt + - smtpserver.key + +# FIXME: Verify the mail after it was send would be nice +# This would require either dumping the content, or registering async task output +- name: Start test smtpserver + shell: '{{ ansible_python.executable }} {{ output_dir }}/smtpserver.py 10025:10465' + async: 30 + poll: 0 + register: smtpserver + +- name: Send a basic test-mail + mail: + port: 10025 + subject: Test mail 1 (smtp) + secure: never + +- name: Send a test-mail with body and specific recipient + mail: + port: 10025 + from: ansible@localhost + to: root@localhost + subject: Test mail 2 (smtp + body) + body: Test body 2 + secure: never + +- name: Send a test-mail with attachment + mail: + port: 10025 + from: ansible@localhost + to: root@localhost + subject: Test mail 3 (smtp + body + attachment) + body: Test body 3 + attach: /etc/group + secure: never + +# NOTE: This might fail if smtpd-tls is missing or python 2.7.8 or older is used +- name: Send a test-mail using starttls + mail: + port: 10025 + from: ansible@localhost + to: root@localhost + subject: Test mail 4 (smtp + starttls + body + attachment) + body: Test body 4 + attach: /etc/group + secure: starttls + ignore_errors: yes + register: starttls_support + +# NOTE: This might fail if smtpd-tls is missing or python 2.7.8 or older is used +- name: Send a test-mail using TLS + mail: + port: 10465 + from: ansible@localhost + to: root@localhost + subject: Test mail 5 (smtp + tls + body + attachment) + body: Test body 5 + attach: /etc/group + secure: always + ignore_errors: yes + register: tls_support + +- fail: + msg: Sending mail using starttls failed. + when: smtpd_tls is succeeded and starttls_support is failed and tls_support is succeeded + +- fail: + msg: Send mail using TLS failed. + when: smtpd_tls is succeeded and tls_support is failed and starttls_support is succeeded