https://bugs.kde.org/show_bug.cgi?id=527387

            Bug ID: 527387
           Summary: Captive portal "Log in" opens the connectivity check
                    URL over HTTPS instead of the portal login page
    Classification: Plasma
           Product: plasmashell
      Version First master
       Reported In:
          Platform: Fedora RPMs
                OS: Linux
            Status: REPORTED
          Severity: normal
          Priority: NOR
         Component: Networking in general
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: 1.0

SUMMARY

When NetworkManager detects a captive portal, the "Log in" button in the
notification and the applet opens a connectivity check URI. On Fedora that URI
is http://fedoraproject.org/static/hotspot.txt, and fedoraproject.org is on the
HSTS preload list (https://hstspreload.org/?domain=fedoraproject.org). Browsers
often upgrade that request to HTTPS, because of HSTS on the check domain or
HTTPS-First/HTTPS-Only mode. A captive portal cannot intercept an HTTPS
request, so instead of the login page the user gets a "Secure Connection
Failed" and the login page is never shown.

This affects all three entry points:
- the "Log in" button on the "You need to log into this network" notification
(kded/connectivitymonitor.cpp)
- the "Log in" button on the "You need to log in to this network" banner in the
network applet (applet/ConnectionListPage.qml)
- "Open Network Login Page…" in the network tray icon's context menu
(applet/main.qml)

STEPS TO REPRODUCE

I explain two cases: A & B. A describes how I encountered it, which is hard to
reproduce. B describes how to reproduce it locally, without access to some
captive portal.

A. On a real captive portal (Fedora defaults)
1. Connect to a Wi-Fi network with a captive portal (hotel, restaurant, train
Wi-Fi, etc.)
2. When the "You need to log into this network" notification appears, click
"Log in".

B. Simulated locally (any distribution, no captive portal needed)
Make a fake portal for fedoraproject.org on your own machine. NetworkManager
then reports "portal", and the browser upgrades the request exactly as it does
on a real portal.

1. Paste this as one command and leave it running:
python3 - <<'EOF'
import socket
from http.server import BaseHTTPRequestHandler, HTTPServer
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("1.1.1.1", 80))  # sends nothing, only picks the LAN IP
IP = s.getsockname()[0]
s.close()
class H(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == "/login":
            self.send_response(200)
            self.send_header("Content-Type", "text/html")
            self.end_headers()
            self.wfile.write(b"<h1>Fake portal login page</h1>")
        else:
            self.send_response(302)
            self.send_header("Location", f"http://{IP}:8080/login";)
            self.end_headers()
print(f"Fake portal running on http://{IP}:8080";, flush=True)
HTTPServer(("0.0.0.0", 8080), H).serve_forever()
EOF

2. Open a second terminal. Point fedoraproject.org at the fake portal and use a
check URI on port 8080. The IP must be the Wi-Fi/Ethernet address, not
127.0.0.1, because NetworkManager runs the check through the network interface:
IP=$(ip -4 route get 1.1.1.1 | grep -oP 'src \K\S+')
echo "$IP fedoraproject.org" | sudo tee -a /etc/hosts
printf
'[connectivity]\nenabled=true\nuri=http://fedoraproject.org:8080/static/hotspot.txt\nresponse=OK\ninterval=30\n'
| sudo tee /etc/NetworkManager/conf.d/99-fake-portal.conf
sudo systemctl restart NetworkManager

3. Check that NetworkManager sees a portal:
nmcli networking connectivity check
It should print "portal".

4. Click "Log in" on the "You need to log into this network" notification, or
use one of the applet actions.

5. Clean up:
sudo sed -i '/ fedoraproject\.org$/d' /etc/hosts
sudo rm /etc/NetworkManager/conf.d/99-fake-portal.conf
sudo systemctl restart NetworkManager
Then stop the fake portal with Ctrl+C in its terminal.

OBSERVED RESULT
A. The browser shows "Secure Connection Failed" (url
https://fedoraproject.org/static/hotspot.txt), seen on the NS (Dutch Railways)
train Wi-Fi, whose portal is portal.nstrein.ns.nl. Firefox's own captive portal
detection, which uses a dedicated HTTP-only domain, correctly showed the portal
login page on the same network.

B. Firefox opens https://fedoraproject.org:8080/static/hotspot.txt, the check
URI upgraded to HTTPS, and shows "Secure Connection Failed":
"An error occurred during a connection to fedoraproject.org:8080. SSL received
a record that exceeded the maximum permissible length."
That's the TLS handshake hitting the fake portal, which only speaks plain HTTP,
just like a real portal. "Fake portal login page" is never shown.

EXPECTED RESULT
"Log in" opens the captive portal's login page. In the simulation that's
http://<your IP>:8080/login, "Fake portal login page".

SOFTWARE/OS VERSIONS
Linux/KDE Plasma: Fedora 44 KDE Plasma (Wayland), kernel 7.2.8
KDE Plasma Version: 6.7.5 (plasma-nm 6.7.5)
KDE Frameworks Version: 6.31.0
Qt Version: 6.11.2
NetworkManager: 1.56.1
Browser: Firefox 158.0

ADDITIONAL INFORMATION
A captive portal works by intercepting plain-HTTP requests and answering them
with a redirect to its login page. Opening the check URI in a browser therefore
only works if the browser actually sends it over plain HTTP. For an
HSTS-preloaded domain like fedoraproject.org, no browser does.

I'm working on a merge request that resolves the portal's redirect target in
plasma-nm before opening the browser.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to