In an effort to test an API via an HTTPS connection locally, I followed the approach described here by Evan Grim where I use stunnel4
as a middleman between my requests and my API server.
Here's a minimalist urls.py
that will generate a token provided a valid username and password.
from django.urls import include, path
from django.contrib import admin
from rest_framework_simplejwt import views as jwt_views
urlpatterns = [
path("admin", admin.site.urls),
path('api/token/', jwt_views.TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', jwt_views.TokenRefreshView.as_view(), name='token_refresh'),]
I have also modified the stunnel4
config file as below.
pid=
cert = stunnel/stunnel.pem
sslVersion = all
foreground = yes
output = stunnel.log
options = NO_SSLv2
[https]
accept=8443
connect=8001
TIMEOUTclose=1
And here is my runserver
script. You'll notice that I'm using pdm
for package management.
#!/bin/bash
stunnel4 stunnel/dev_https &
pdm run python3 manage.py runserver &
HTTPS=1 pdm run python3 manage.py runserver 0.0.0.0:8001
When I try any route via postman or curl (at port 8443
), I receive the following errors.
I get a tls_setup_handshake:internal
error from stunnel4
.
2021.12.19 18:51:22 LOG5[16]: Service [https] accepted connection from 127.0.0.1:36502
2021.12.19 18:51:22 LOG3[16]: SSL_accept: ../ssl/statem/statem_lib.c:109: error:141FC044:SSL routines:tls_setup_handshake:internal error
2021.12.19 18:51:22 LOG5[16]: Connection reset: 0 byte(s) sent to TLS, 0 byte(s) sent to socket
Postman gives me the following error in its console when I submit requests through it.
Error: write EPROTO 48081748826312:error:10000438:SSL routines:OPENSSL_internal:TLSV1_ALERT_INTERNAL_ERROR:../../third_party/boringssl/src/ssl/tls_record.cc:594:SSL alert number 80
And when I try curl
(curl -v --location --request POST 'https://localhost:8443/api/token/' --form 'username="username_here"' --form 'password="password_here"')
, I see the following.
* Trying 127.0.0.1:8443...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS alert, unknown CA (560):
* SSL certificate problem: self signed certificate
* Closing connection 0
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
Full stunnel.log
2021.12.20 16:57:48 LOG7[ui]: Clients allowed=500
2021.12.20 16:57:48 LOG5[ui]: stunnel 5.56 on x86_64-pc-linux-gnu platform
2021.12.20 16:57:48 LOG5[ui]: Compiled with OpenSSL 1.1.1c 28 May 2019
2021.12.20 16:57:48 LOG5[ui]: Running with OpenSSL 1.1.1f 31 Mar 2020
2021.12.20 16:57:48 LOG5[ui]: Threading:PTHREAD Sockets:POLL,IPv6,SYSTEMD TLS:ENGINE,FIPS,OCSP,PSK,SNI Auth:LIBWRAP
2021.12.20 16:57:48 LOG7[ui]: errno: (*__errno_location ())
2021.12.20 16:57:48 LOG5[ui]: Reading configuration from file /home/max/Ledgestone/dev/verdova/verdova-web-core/stunnel/dev_https
2021.12.20 16:57:48 LOG5[ui]: UTF-8 byte order mark not detected
2021.12.20 16:57:48 LOG5[ui]: FIPS mode disabled
2021.12.20 16:57:48 LOG7[ui]: Compression disabled
2021.12.20 16:57:48 LOG7[ui]: No PRNG seeding was required
2021.12.20 16:57:48 LOG6[ui]: Initializing service [https]
2021.12.20 16:57:48 LOG7[ui]: Ciphers: HIGH:!aNULL:!SSLv2:!DH:!kDHEPSK
2021.12.20 16:57:48 LOG7[ui]: TLSv1.3 ciphersuites: TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256
2021.12.20 16:57:48 LOG7[ui]: TLS options: 0x02100004 (+0x00000000, -0x00000000)
2021.12.20 16:57:48 LOG6[ui]: Loading certificate from file: stunnel/stunnel.pem
2021.12.20 16:57:48 LOG6[ui]: Certificate loaded from file: stunnel/stunnel.pem
2021.12.20 16:57:48 LOG6[ui]: Loading private key from file: stunnel/stunnel.pem
2021.12.20 16:57:48 LOG4[ui]: Insecure file permissions on stunnel/stunnel.pem
2021.12.20 16:57:48 LOG6[ui]: Private key loaded from file: stunnel/stunnel.pem
2021.12.20 16:57:48 LOG7[ui]: Private key check succeeded
2021.12.20 16:57:48 LOG6[ui]: DH initialization not needed
2021.12.20 16:57:48 LOG7[ui]: ECDH initialization
2021.12.20 16:57:48 LOG7[ui]: ECDH initialized with curves X25519:P-256:X448:P-521:P-384
2021.12.20 16:57:48 LOG5[ui]: Configuration successful
2021.12.20 16:57:48 LOG7[ui]: Binding service [https]
2021.12.20 16:57:48 LOG7[ui]: Listening file descriptor created (FD=9)
2021.12.20 16:57:48 LOG7[ui]: Setting accept socket options (FD=9)
2021.12.20 16:57:48 LOG7[ui]: Option SO_REUSEADDR set on accept socket
2021.12.20 16:57:48 LOG6[ui]: Service [https] (FD=9) bound to 0.0.0.0:8443
2021.12.20 16:57:48 LOG7[ui]: Listening file descriptor created (FD=10)
2021.12.20 16:57:48 LOG7[ui]: Setting accept socket options (FD=10)
2021.12.20 16:57:48 LOG7[ui]: Option SO_REUSEADDR set on accept socket
2021.12.20 16:57:48 LOG5[ui]: Binding service [https] to :::8443: Address already in use (98)
2021.12.20 16:57:48 LOG7[ui]: No pid file being created
2021.12.20 16:57:48 LOG7[cron]: Cron thread initialized
2021.12.20 16:57:48 LOG6[cron]: Executing cron jobs
2021.12.20 16:57:48 LOG6[cron]: Cron jobs completed in 0 seconds
2021.12.20 16:57:48 LOG7[cron]: Waiting 86400 seconds
2021.12.20 16:58:54 LOG7[ui]: Found 1 ready file descriptor(s)
2021.12.20 16:58:54 LOG7[ui]: FD=4 events=0x2001 revents=0x0
2021.12.20 16:58:54 LOG7[ui]: FD=9 events=0x2001 revents=0x1
2021.12.20 16:58:54 LOG7[ui]: Service [https] accepted (FD=3) from 127.0.0.1:48444
2021.12.20 16:58:54 LOG7[0]: Service [https] started
2021.12.20 16:58:54 LOG7[0]: Setting local socket options (FD=3)
2021.12.20 16:58:54 LOG7[0]: Option TCP_NODELAY set on local socket
2021.12.20 16:58:54 LOG5[0]: Service [https] accepted connection from 127.0.0.1:48444
2021.12.20 16:58:54 LOG6[0]: Peer certificate not required
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): before SSL initialization
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): before SSL initialization
2021.12.20 16:58:54 LOG7[0]: SNI: no virtual services defined
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): SSLv3/TLS read client hello
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): SSLv3/TLS write server hello
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): SSLv3/TLS write change cipher spec
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): TLSv1.3 write encrypted extensions
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): SSLv3/TLS write certificate
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): TLSv1.3 write server certificate verify
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): SSLv3/TLS write finished
2021.12.20 16:58:54 LOG7[0]: TLS state (accept): TLSv1.3 early data
2021.12.20 16:58:54 LOG3[0]: SSL_accept: Peer suddenly disconnected
2021.12.20 16:58:54 LOG5[0]: Connection reset: 0 byte(s) sent to TLS, 0 byte(s) sent to socket
2021.12.20 16:58:54 LOG7[0]: Deallocating application specific data for session connect address
2021.12.20 16:58:54 LOG7[0]: Local descriptor (FD=3) closed
2021.12.20 16:58:54 LOG7[0]: Service [https] finished (0 left)
Any guidance on adjusting my approach to facilitate local testing?