Repository: opsdroid/opsdroid

Issue:
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed in Slack Connector
<!-- Before you post an issue or if you are unsure about something join our matrix channel https://riot.im/app/#/room/#opsdroid-general:matrix.org and ask away! We are more than happy to help you. -->
# Description
I am trying to build a Slack bot using Opsdroid (master branch). When running `opsdroid start`, I get an error where the Opsdroid bot fails to connect with the Slack Workspace.

## Steps to Reproduce
1. Install opsdroid
```
pip install git+https://github.com/opsdroid/opsdroid.git
```

2. Create `configuration.yaml` with following content
```
welcome-message: true

connectors:
  - name: slack
    api-token: "<Bot OAuth Token>"

skills:
  - name: hello
```

3. Start opsdroid

```
opsdroid start
```

## Expected Functionality
The expected functionality is for the Opsdroid Bot to get connected with Slack Workspace and interact with the Slack user as per the configured skill.


## Experienced Functionality
The Opsdroid Bot failed to connect with the Slack Workspace with the following error:

```
INFO opsdroid.connector.slack: Connecting to Slack
Traceback (most recent call last):
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/aiohttp/connector.py", line 936, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore  # noqa
  File "/usr/lib/python3.6/asyncio/base_events.py", line 820, in create_connection
    sock, protocol_factory, ssl, server_hostname)
  File "/usr/lib/python3.6/asyncio/base_events.py", line 846, in _create_connection_transport
    yield from waiter
  File "/usr/lib/python3.6/asyncio/sslproto.py", line 505, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "/usr/lib/python3.6/asyncio/sslproto.py", line 201, in feed_ssldata
    self._sslobj.do_handshake()
  File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/opsdroid/connector/slack/__init__.py", line 55, in connect
    self.auth_info = (await self.slack.api_call("auth.test")).data
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/slack/web/base_client.py", line 229, in _send
    http_verb=http_verb, api_url=api_url, req_args=req_args
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/slack/web/base_client.py", line 259, in _request
    async with session.request(http_verb, api_url, **req_args) as res:
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/aiohttp/client.py", line 1012, in __aenter__
    self._resp = await self._coro
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/aiohttp/client.py", line 483, in _request
    timeout=real_timeout
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/aiohttp/connector.py", line 523, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/aiohttp/connector.py", line 859, in _create_connection
    req, traces, timeout)
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/aiohttp/connector.py", line 1004, in _create_direct_connection
    raise last_exc
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/aiohttp/connector.py", line 986, in _create_direct_connection
    req=req, client_error=client_error)
  File "/home/daniccan/c8/OpsDroid/c8-alertbot/env/lib/python3.6/site-packages/aiohttp/connector.py", line 941, in _wrap_create_connection
    raise ClientConnectorSSLError(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorSSLError: Cannot connect to host www.slack.com:443 ssl:default [[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)]
```

## Versions
- **Opsdroid version:** master branch in git
- **Python version:** 3.6.8
- **OS/Docker version:** Ubuntu 18.04 LTS

## Configuration File
Please include your version of the configuration file below.

```yaml
welcome-message: true

connectors:
  - name: slack
    api-token: "<Bot OAuth Token>"

skills:
  - name: hello
```

## Additional Details
Any other details you wish to include such as screenshots, console messages, etc.


<!-- Love opsdroid? Please consider supporting our collective:
 +👉  https://opencollective.com/opsdroid/donate -->



Discussion:
It looks like the SSL certificate for Slack is being rejected. Do you have the certificate bundle installed ([instructions](https://www.techrepublic.com/article/how-to-install-ca-certificates-in-ubuntu-server/))?
How do I get the certificate bundle of Slack?
This looks like an issue with the `websocket-client` library version 0.48.0 and above. FYI, https://github.com/websocket-client/websocket-client/issues/451#issuecomment-417918570. I am unable to lock on to version 0.47.0 of the library due to another dependency. 

```
pkg_resources.DistributionNotFound: The 'websocket-client==0.48.0' distribution was not found and is required by ibm-watson
```

Resolving patch:
diff --git a/opsdroid/connector/slack/__init__.py b/opsdroid/connector/slack/__init__.py
--- a/opsdroid/connector/slack/__init__.py
+++ b/opsdroid/connector/slack/__init__.py
@@ -1,6 +1,8 @@
 """A connector for Slack."""
 import logging
 import re
+import ssl
+import certifi
 
 import slack
 from emoji import demojize
@@ -25,8 +27,13 @@ def __init__(self, config, opsdroid=None):
         self.icon_emoji = config.get("icon-emoji", ":robot_face:")
         self.token = config["api-token"]
         self.timeout = config.get("connect-timeout", 10)
-        self.slack = slack.WebClient(token=self.token, run_async=True)
-        self.slack_rtm = slack.RTMClient(token=self.token, run_async=True)
+        self.ssl_context = ssl.create_default_context(cafile=certifi.where())
+        self.slack = slack.WebClient(
+            token=self.token, run_async=True, ssl=self.ssl_context
+        )
+        self.slack_rtm = slack.RTMClient(
+            token=self.token, run_async=True, ssl=self.ssl_context
+        )
         self.websocket = None
         self.bot_name = config.get("bot-name", "opsdroid")
         self.auth_info = None


Test patch: