Ana içeriğe atla

Authenticating Through a FortiGate Captive Portal with curl

While setting up a headless Fedora Server, I encountered a common problem on institutional networks: Internet access required authentication through a web-based firewall portal.

The server had a valid network connection and DNS resolution, but HTTPS requests failed because the firewall intercepted unauthenticated traffic. Since the machine had no graphical browser, I needed to authenticate entirely from the command line.

Finding the Captive Portal

A useful trick is to request a deliberately HTTP-only website:

curl -v http://neverssl.com/

Instead of the expected page, the network returned JavaScript redirecting the browser to a FortiGate authentication URL:

window.location="http://192.168.31.4:1000/fgtauth?<TOKEN>";

The token is important because it identifies the current authentication session.

Opening that URL with curl revealed an HTML login form containing fields similar to:

<form action="/" method="post">
    <input type="hidden" name="4Tredir" value="http://neverssl.com/">
    <input type="hidden" name="magic" value="<TOKEN>">
    <input name="username" type="text">
    <input name="password" type="password">
</form>

This tells us exactly what a browser normally submits.

Authenticating with curl

Rather than putting credentials directly into shell history, they can be entered interactively:

read -p "Username: " USERNAME
read -s -p "Password: " PASSWORD
echo

Then submit the form:

curl -v \
  --data-urlencode "username=$USERNAME" \
  --data-urlencode "password=$PASSWORD" \
  --data-urlencode "magic=<TOKEN>" \
  --data-urlencode "4Tredir=http://neverssl.com/" \
  "http://192.168.31.4:1000/"

In my case, successful authentication produced:

HTTP/1.1 303 See Other
Location: https://...

The 303 redirect was the important part: the firewall had accepted the credentials.

There is no need to follow the redirect with curl -L just to determine whether authentication succeeded. In fact, avoiding it makes troubleshooting cleaner because any TLS problem at the redirected website cannot be confused with a firewall authentication failure.

Verify Internet Access Separately

Finally, test a normal HTTPS connection:

curl -I https://google.com/

After authentication, the connection should proceed normally with a valid TLS handshake.

The overall process is therefore quite simple:

curl HTTP site
      ↓
Discover captive-portal redirect
      ↓
Extract session/magic token
      ↓
POST username + password + token with curl
      ↓
Receive HTTP 303
      ↓
Verify normal HTTPS access

This approach is particularly useful for headless Linux servers, Raspberry Pis, remote compute nodes, and other systems connected to networks that assume every device has a graphical web browser.

One important caveat: the magic token is session-specific and should not be hard-coded into a permanent script. A robust login script should first request an HTTP page, extract the current FortiGate token, and then perform the authentication POST. Credentials should likewise not be stored as plaintext in the script.

You can use the following bash script on my github page here.

 As you may guess, AI helped me inspecting the login page and writing correct curl code to follow the page. But it was my idea to make curl follow the login page with my credentials (he was pointing me other directions interestingly, and I was not sure he would find this solution, hence it's still worth publishing on my page).

Yorumlar

Bu blogdaki popüler yayınlar

An Awk feature

I was trying to use sub (or gsub) function in awk to delete an \r from the end of line. For that purpose I used dum=sub(/\r/,"",$0) and thought that the variable "dum" will be filled with the changed value of $0. But I realised that sub function only make the change and returns 0,1 accordingly. So I wrote like this sub(/r/,"") ; x=$0;

Centos 6 Postgresql 9.1 Install

Today I have changed my mind and decided to begin learning and using Postgresql. On a Centos 6 host there are some ways of installing Postgresql. I have chosen the easy one: use repos. Here http://yum.pgrpms.org/repopackages.php is the official Postgresql repos for Red Hat related distros. I have chosen the x86_64 rpm for Centos 6 and installed it. Later using yum install postgresql91-server I have installed three packages postgresql91,postgresql91-server and postgresql91-libs which is enough for now to start Postgresql 9.1. Using the instructions at /usr/share/doc/postgresql91-9.1.1/README.rpm-dist , I first did service postgresql-9.1 initdb and then service postgresql-9.1 start.Voila! Now let the journey begin! Edit:  Here is another place to look instructions http://www.postgresonline.com/journal/archives/203-postgresql90-yum.html

OpenBSD Nfsen install

I was  trying to find a solution for network monitoring as a friend's request. OpenBSD is the firewall. I saw the Nfsen packages and installed to a 5.2 server. After some effort trying to understand what is going on behind, I realised that Netflow is a protocol by Cisco designed to export router traffic to outside. And OpenBSD has a support of it with pflow interface. First I made a new pflow0 interface like ifconfig pflow0 flowdst 127.0.0.1:9998 flowsrc 127.0.0.1 up Then made some configuration changesto /etc/nfsen.conf and /var/www/htdocs/nfsen/conf.php. Because Apache in OpenBSD runs in chrooted by default, if you dont make the necessary changes in these pages you got an error stating  ERROR: nfsend connect() error: Permission denied!  ERROR: nfsend - connection failed!!  ERROR: Can not initialize globals! which is because apache cant reach the communication socket which is initially  located at $PIDDIR/nfsen.comm namely /var/db/nfsen/run direc...