Ejemplo n.º 1
0
    class CustomHTTPSConnection(httplib.HTTPSConnection):
        def __init__(self, *args, **kwargs):
            httplib.HTTPSConnection.__init__(self, *args, **kwargs)
            self.context = None
            if HAS_SSLCONTEXT:
                self.context = create_default_context()
            elif HAS_URLLIB3_PYOPENSSLCONTEXT:
                self.context = PyOpenSSLContext(PROTOCOL)
            if self.context and self.cert_file:
                self.context.load_cert_chain(self.cert_file, self.key_file)

        def connect(self):
            "Connect to a host on a given (SSL) port."

            if hasattr(self, 'source_address'):
                sock = socket.create_connection((self.host, self.port), self.timeout, self.source_address)
            else:
                sock = socket.create_connection((self.host, self.port), self.timeout)

            server_hostname = self.host
            # Note: self._tunnel_host is not available on py < 2.6 but this code
            # isn't used on py < 2.6 (lack of create_connection)
            if self._tunnel_host:
                self.sock = sock
                self._tunnel()
                server_hostname = self._tunnel_host

            if HAS_SSLCONTEXT or HAS_URLLIB3_PYOPENSSLCONTEXT:
                self.sock = self.context.wrap_socket(sock, server_hostname=server_hostname)
            elif HAS_URLLIB3_SSL_WRAP_SOCKET:
                self.sock = ssl_wrap_socket(sock, keyfile=self.key_file, cert_reqs=ssl.CERT_NONE, certfile=self.cert_file, ssl_version=PROTOCOL,
                                            server_hostname=server_hostname)
            else:
                self.sock = ssl.wrap_socket(sock, keyfile=self.key_file, certfile=self.cert_file, ssl_version=PROTOCOL)
Ejemplo n.º 2
0
    class CustomHTTPSConnection(httplib.HTTPSConnection):
        def __init__(self, *args, **kwargs):
            httplib.HTTPSConnection.__init__(self, *args, **kwargs)
            self.context = None
            if HAS_SSLCONTEXT:
                self.context = create_default_context()
            elif HAS_URLLIB3_PYOPENSSLCONTEXT:
                self.context = PyOpenSSLContext(PROTOCOL)
            if self.context and self.cert_file:
                self.context.load_cert_chain(self.cert_file, self.key_file)

        def connect(self):
            "Connect to a host on a given (SSL) port."

            if hasattr(self, 'source_address'):
                sock = socket.create_connection((self.host, self.port), self.timeout, self.source_address)
            else:
                sock = socket.create_connection((self.host, self.port), self.timeout)

            server_hostname = self.host
            # Note: self._tunnel_host is not available on py < 2.6 but this code
            # isn't used on py < 2.6 (lack of create_connection)
            if self._tunnel_host:
                self.sock = sock
                self._tunnel()
                server_hostname = self._tunnel_host

            if HAS_SSLCONTEXT or HAS_URLLIB3_PYOPENSSLCONTEXT:
                self.sock = self.context.wrap_socket(sock, server_hostname=server_hostname)
            elif HAS_URLLIB3_SSL_WRAP_SOCKET:
                self.sock = ssl_wrap_socket(sock, keyfile=self.key_file, cert_reqs=ssl.CERT_NONE, certfile=self.cert_file, ssl_version=PROTOCOL,
                                            server_hostname=server_hostname)
            else:
                self.sock = ssl.wrap_socket(sock, keyfile=self.key_file, certfile=self.cert_file, ssl_version=PROTOCOL)
Ejemplo n.º 3
0
 def _make_context(self, to_add_ca_cert_path):
     if HAS_URLLIB3_PYOPENSSLCONTEXT:
         context = PyOpenSSLContext(PROTOCOL)
     else:
         context = create_default_context()
     if to_add_ca_cert_path:
         context.load_verify_locations(to_add_ca_cert_path)
     return context
Ejemplo n.º 4
0
 def _make_context(self, to_add_ca_cert_path):
     if HAS_URLLIB3_PYOPENSSLCONTEXT:
         context = PyOpenSSLContext(PROTOCOL)
     else:
         context = create_default_context()
     if to_add_ca_cert_path:
         context.load_verify_locations(to_add_ca_cert_path)
     return context
Ejemplo n.º 5
0
 def __init__(self, *args, **kwargs):
     httplib.HTTPSConnection.__init__(self, *args, **kwargs)
     self.context = None
     if HAS_SSLCONTEXT:
         self.context = create_default_context()
     elif HAS_URLLIB3_PYOPENSSLCONTEXT:
         self.context = PyOpenSSLContext(PROTOCOL)
     if self.context and self.cert_file:
         self.context.load_cert_chain(self.cert_file, self.key_file)
Ejemplo n.º 6
0
    def _make_context(self, to_add_ca_cert_path):
        if HAS_SSLCONTEXT:
            context = create_default_context()
        elif HAS_URLLIB3_PYOPENSSLCONTEXT:
            context = PyOpenSSLContext(PROTOCOL)
        else:
            raise NotImplementedError('Host libraries are too old to support creating an sslcontext')

        if to_add_ca_cert_path:
            context.load_verify_locations(to_add_ca_cert_path)
        return context
Ejemplo n.º 7
0
    def _make_context(self, to_add_ca_cert_path):
        if HAS_SSLCONTEXT:
            context = create_default_context()
        elif HAS_URLLIB3_PYOPENSSLCONTEXT:
            context = PyOpenSSLContext(PROTOCOL)
        else:
            raise NotImplementedError('Host libraries are too old to support creating an sslcontext')

        if to_add_ca_cert_path:
            context.load_verify_locations(to_add_ca_cert_path)
        return context
Ejemplo n.º 8
0
 def __init__(self, *args, **kwargs):
     httplib.HTTPSConnection.__init__(self, *args, **kwargs)
     self.context = None
     if HAS_SSLCONTEXT:
         self.context = create_default_context()
     elif HAS_URLLIB3_PYOPENSSLCONTEXT:
         self.context = PyOpenSSLContext(PROTOCOL)
     if self.context and self.cert_file:
         self.context.load_cert_chain(self.cert_file, self.key_file)
Ejemplo n.º 9
0
def create_pyopenssl_sslcontext(pkcs12_data, pkcs12_password_bytes, ssl_protocol=default_ssl_protocol):
    p12 = load_pkcs12(pkcs12_data, pkcs12_password_bytes)
    cert = p12.get_certificate()
    check_cert_not_after(cert)
    ssl_context = PyOpenSSLContext(ssl_protocol)
    ssl_context._ctx.use_certificate(cert)
    ca_certs = p12.get_ca_certificates()
    if ca_certs:
        for ca_cert in ca_certs:
            check_cert_not_after(ca_cert)
            ssl_context._ctx.add_extra_chain_cert(ca_cert)
    ssl_context._ctx.use_privatekey(p12.get_privatekey())
    return ssl_context
Ejemplo n.º 10
0
def create_pyopenssl_sslcontext(data: bytes, password: bytes):
    private_key, certificate, additional = pkcs12.load_key_and_certificates(
        data, password)
    assert certificate is not None
    check_cert_not_after(certificate)
    ssl_context = PyOpenSSLContext(ssl_protocol)
    ssl_context._ctx.use_certificate(
        crypto.X509.from_cryptography(certificate))
    logging.info(f"Certificate found with subject {certificate.subject}, "
                 f"expire on {certificate.not_valid_after}")
    if additional:
        for ca_cert in additional:
            check_cert_not_after(ca_cert)
            ssl_context._ctx.add_extra_chain_cert(
                crypto.X509.from_cryptography(ca_cert))
    ssl_context._ctx.use_privatekey(
        crypto.PKey.from_cryptography_key(private_key))
    return ssl_context
Ejemplo n.º 11
0
    def create_ssl_context(pkcs12_cert):
        """
        :param pkcs12_cert: OpenSSL.crypto.PKCS12
        :return: context
        :rtype: urllib3.contrib.pyopenssl.PyOpenSSLContext
        """

        cert = pkcs12_cert.get_certificate()
        CertificateReader._check_cert_not_expired(cert)

        context = PyOpenSSLContext(ssl_protocol)
        context._ctx.use_certificate(cert)

        ca_certs = pkcs12_cert.get_ca_certificates()
        if ca_certs:
            for ca_cert in ca_certs:
                CertificateReader._check_cert_not_expired(ca_cert)
                context._ctx.add_extra_chain_cert(ca_cert)

        context._ctx.use_privatekey(pkcs12_cert.get_privatekey())

        return context
Ejemplo n.º 12
0
    def connect(self,
                host=None,
                port=None,
                user=None,
                password=None,
                encryption=None,
                smtp_from=None,
                ssl_certificate=None,
                ssl_private_key=None,
                smtp_debug=False,
                mail_server_id=None):
        """Returns a new SMTP connection to the given SMTP server.
           When running in test mode, this method does nothing and returns `None`.

           :param host: host or IP of SMTP server to connect to, if mail_server_id not passed
           :param int port: SMTP port to connect to
           :param user: optional username to authenticate with
           :param password: optional password to authenticate with
           :param string encryption: optional, ``'ssl'`` | ``'starttls'``
           :param smtp_from: FROM SMTP envelop, used to find the best mail server
           :param ssl_certificate: filename of the SSL certificate used for authentication
               Used when no mail server is given and overwrite  the odoo-bin argument "smtp_ssl_certificate"
           :param ssl_private_key: filename of the SSL private key used for authentication
               Used when no mail server is given and overwrite  the odoo-bin argument "smtp_ssl_private_key"
           :param bool smtp_debug: toggle debugging of SMTP sessions (all i/o
                              will be output in logs)
           :param mail_server_id: ID of specific mail server to use (overrides other parameters)
        """
        # Do not actually connect while running in test mode
        if self._is_test_mode():
            return

        mail_server = smtp_encryption = None
        if mail_server_id:
            mail_server = self.sudo().browse(mail_server_id)
        elif not host:
            mail_server, smtp_from = self.sudo()._find_mail_server(smtp_from)

        ssl_context = None
        if mail_server:
            smtp_server = mail_server.smtp_host
            smtp_port = mail_server.smtp_port
            if mail_server.smtp_authentication == "login":
                smtp_user = mail_server.smtp_user
                smtp_password = mail_server.smtp_pass
            else:
                smtp_user = None
                smtp_password = None
            smtp_encryption = mail_server.smtp_encryption
            smtp_debug = smtp_debug or mail_server.smtp_debug
            from_filter = mail_server.from_filter
            if (mail_server.smtp_authentication == "certificate"
                    and mail_server.smtp_ssl_certificate
                    and mail_server.smtp_ssl_private_key):
                try:
                    ssl_context = PyOpenSSLContext(ssl.PROTOCOL_TLS)
                    smtp_ssl_certificate = base64.b64decode(
                        mail_server.smtp_ssl_certificate)
                    certificate = SSLCrypto.load_certificate(
                        FILETYPE_PEM, smtp_ssl_certificate)
                    smtp_ssl_private_key = base64.b64decode(
                        mail_server.smtp_ssl_private_key)
                    private_key = SSLCrypto.load_privatekey(
                        FILETYPE_PEM, smtp_ssl_private_key)
                    ssl_context._ctx.use_certificate(certificate)
                    ssl_context._ctx.use_privatekey(private_key)
                    # Check that the private key match the certificate
                    ssl_context._ctx.check_privatekey()
                except SSLCryptoError as e:
                    raise UserError(
                        _(
                            'The private key or the certificate is not a valid file. \n%s',
                            str(e)))
                except SSLError as e:
                    raise UserError(
                        _(
                            'Could not load your certificate / private key. \n%s',
                            str(e)))

        else:
            # we were passed individual smtp parameters or nothing and there is no default server
            smtp_server = host or tools.config.get('smtp_server')
            smtp_port = tools.config.get('smtp_port',
                                         25) if port is None else port
            smtp_user = user or tools.config.get('smtp_user')
            smtp_password = password or tools.config.get('smtp_password')
            from_filter = self.env['ir.config_parameter'].sudo().get_param(
                'mail.default.from_filter', tools.config.get('from_filter'))
            smtp_encryption = encryption
            if smtp_encryption is None and tools.config.get('smtp_ssl'):
                smtp_encryption = 'starttls'  # smtp_ssl => STARTTLS as of v7
            smtp_ssl_certificate_filename = ssl_certificate or tools.config.get(
                'smtp_ssl_certificate_filename')
            smtp_ssl_private_key_filename = ssl_private_key or tools.config.get(
                'smtp_ssl_private_key_filename')

            if smtp_ssl_certificate_filename and smtp_ssl_private_key_filename:
                try:
                    ssl_context = PyOpenSSLContext(ssl.PROTOCOL_TLS)
                    ssl_context.load_cert_chain(
                        smtp_ssl_certificate_filename,
                        keyfile=smtp_ssl_private_key_filename)
                    # Check that the private key match the certificate
                    ssl_context._ctx.check_privatekey()
                except SSLCryptoError as e:
                    raise UserError(
                        _(
                            'The private key or the certificate is not a valid file. \n%s',
                            str(e)))
                except SSLError as e:
                    raise UserError(
                        _(
                            'Could not load your certificate / private key. \n%s',
                            str(e)))

        if not smtp_server:
            raise UserError((_("Missing SMTP Server") + "\n" +
                             _("Please define at least one SMTP server, "
                               "or provide the SMTP parameters explicitly.")))

        if smtp_encryption == 'ssl':
            if 'SMTP_SSL' not in smtplib.__all__:
                raise UserError(
                    _("Your Odoo Server does not support SMTP-over-SSL. "
                      "You could use STARTTLS instead. "
                      "If SSL is needed, an upgrade to Python 2.6 on the server-side "
                      "should do the trick."))
            connection = smtplib.SMTP_SSL(smtp_server,
                                          smtp_port,
                                          timeout=SMTP_TIMEOUT)
        else:
            connection = smtplib.SMTP(smtp_server,
                                      smtp_port,
                                      timeout=SMTP_TIMEOUT)

        connection.set_debuglevel(smtp_debug)
        if smtp_encryption == 'starttls':
            # starttls() will perform ehlo() if needed first
            # and will discard the previous list of services
            # after successfully performing STARTTLS command,
            # (as per RFC 3207) so for example any AUTH
            # capability that appears only on encrypted channels
            # will be correctly detected for next step
            connection.starttls(context=ssl_context)

        if smtp_user:
            # Attempt authentication - will raise if AUTH service not supported
            local, at, domain = smtp_user.rpartition('@')
            if at:
                smtp_user = local + at + idna.encode(domain).decode('ascii')
            connection.login(smtp_user, smtp_password or '')

        # Some methods of SMTP don't check whether EHLO/HELO was sent.
        # Anyway, as it may have been sent by login(), all subsequent usages should consider this command as sent.
        connection.ehlo_or_helo_if_needed()

        # Store the "from_filter" of the mail server / odoo-bin argument to  know if we
        # need to change the FROM headers or not when we will prepare the mail message
        connection.from_filter = from_filter
        connection.smtp_from = smtp_from

        return connection