{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# SSL Connection Examples"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Connecting to a Valkey instance via SSL"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import valkey\n",
    "\n",
    "r = valkey.Valkey(\n",
    "    host='localhost', \n",
    "    port=6666, \n",
    "    ssl=True, \n",
    "    ssl_cert_reqs=\"none\",\n",
    ")\n",
    "r.ping()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Connecting to a Valkey instance via a URL string"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import valkey\n",
    "\n",
    "r = valkey.from_url(\"valkeys://localhost:6666?ssl_cert_reqs=none&decode_responses=True&health_check_interval=2\")\n",
    "r.ping()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Connecting to a Valkey instance using a ConnectionPool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import valkey\n",
    "\n",
    "valkey_pool = valkey.ConnectionPool(\n",
    "    host=\"localhost\", \n",
    "    port=6666, \n",
    "    connection_class=valkey.SSLConnection, \n",
    "    ssl_cert_reqs=\"none\",\n",
    ")\n",
    "\n",
    "r = valkey.StrictValkey(connection_pool=valkey_pool) \n",
    "r.ping()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Connecting to a Valkey instance via SSL, while specifying a minimum TLS version"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import valkey\n",
    "import ssl\n",
    "\n",
    "r = valkey.Valkey(\n",
    "    host=\"localhost\",\n",
    "    port=6666,\n",
    "    ssl=True,\n",
    "    ssl_min_version=ssl.TLSVersion.TLSv1_3,\n",
    "    ssl_cert_reqs=\"none\",\n",
    ")\n",
    "r.ping()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Connecting to a Valkey instance via SSL, while specifying a self-signed SSL CA certificate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import os\n",
    "import valkey\n",
    "\n",
    "pki_dir = os.path.join(\"..\", \"..\", \"dockers\", \"stunnel\", \"keys\")\n",
    "\n",
    "r = valkey.Valkey(\n",
    "    host=\"localhost\",\n",
    "    port=6666,\n",
    "    ssl=True,\n",
    "    ssl_certfile=os.path.join(pki_dir, \"client-cert.pem\"),\n",
    "    ssl_keyfile=os.path.join(pki_dir, \"client-key.pem\"),\n",
    "    ssl_cert_reqs=\"required\",\n",
    "    ssl_ca_certs=os.path.join(pki_dir, \"ca-cert.pem\"),\n",
    ")\n",
    "r.ping()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Connecting to a Valkey instance via SSL, and validate the OCSP status of the certificate\n",
    "\n",
    "The valkey package is designed to be small, meaning extra libraries must be installed, in order to support OCSP stapling. As a result, first install valkey via:\n",
    "\n",
    "`pip install valkey[ocsp]`\n",
    "\n",
    "This will install cryptography, requests, and PyOpenSSL, none of which are generally required to use Valkey.\n",
    "\n",
    "In the next example, we will connect to a Valkey instance via SSL, and validate the OCSP status of the certificate. However, the certificate we are using does not have an AIA extension, which means that the OCSP validation cannot be performed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OCSP validation failed as expected.\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import valkey\n",
    "\n",
    "pki_dir = os.path.join(\"..\", \"..\", \"dockers\", \"stunnel\", \"keys\")\n",
    "\n",
    "r = valkey.Valkey(\n",
    "    host=\"localhost\",\n",
    "    port=6666,\n",
    "    ssl=True,\n",
    "    ssl_certfile=os.path.join(pki_dir, \"client-cert.pem\"),\n",
    "    ssl_keyfile=os.path.join(pki_dir, \"client-key.pem\"),\n",
    "    ssl_cert_reqs=\"required\",\n",
    "    ssl_ca_certs=os.path.join(pki_dir, \"ca-cert.pem\"),\n",
    "    ssl_validate_ocsp=True,\n",
    ")\n",
    "\n",
    "try:\n",
    "    r.ping()\n",
    "except valkey.ConnectionError as e:\n",
    "    assert e.args[0] == \"No AIA information present in ssl certificate\"\n",
    "    print(\"OCSP validation failed as expected.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Connect to a Valkey instance via SSL, and validate OCSP-stapled certificates\n",
    "\n",
    "It is also possible to validate an OCSP stapled response. Again, for this example the server does not send an OCSP stapled response, so the validation will fail."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OCSP validation failed as expected.\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import valkey\n",
    "\n",
    "pki_dir = os.path.join(\"..\", \"..\", \"dockers\", \"stunnel\", \"keys\")\n",
    "ca_cert = os.path.join(pki_dir, \"ca-cert.pem\")\n",
    "\n",
    "# It is possible to specify an expected certificate, or leave it out.\n",
    "expected_certificate = open(ca_cert, 'rb').read()\n",
    "\n",
    "# If needed, a custom SSL context for OCSP can be specified via ssl_ocsp_context\n",
    "\n",
    "r = valkey.Valkey(\n",
    "    host=\"localhost\",\n",
    "    port=6666,\n",
    "    ssl=True,\n",
    "    ssl_certfile=os.path.join(pki_dir, \"client-cert.pem\"),\n",
    "    ssl_keyfile=os.path.join(pki_dir, \"client-key.pem\"),\n",
    "    ssl_cert_reqs=\"required\",\n",
    "    ssl_ca_certs=ca_cert,\n",
    "    ssl_validate_ocsp_stapled=True,\n",
    "    ssl_ocsp_expected_cert=expected_certificate,\n",
    ")\n",
    "\n",
    "try:\n",
    "    r.ping()\n",
    "except valkey.ConnectionError as e:\n",
    "    assert e.args[0] == \"no ocsp response present\"\n",
    "    print(\"OCSP validation failed as expected.\")"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "d45c99ba0feda92868abafa8257cbb4709c97f1a0b5dc62bbeebdf89d4fad7fe"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
