Captive portal stuck at login page
-
Hi pfSense community.
I have a problem with a multi captive portal implementation where user get stuck on login page even after a succeed authentication.
The implementation is a pfSense box (virtual machine on top of a VMware ESXi 5.5 host) with 4 interfaces, 1 for WAN connection and 3 for different vlan that are used for WiFi connections (they are not wifi interfaces, they are LAN ones maped to VLAN that are used for WiFi access). Attached is a very simplified diagram of the infrastructure.
For the 3 "wifi" interfaces is set up a captive portal zone, with RADIUS authentication (against Active Directory) and custom login and error page.
Normally every thing works fine, but ultimately (and increasingly frequent) the issue described earlier arise.
In order to troubleshoot this problem I made a package capture of a wifi client conversation between the pfsense box under normal condition and when things go wrong. Test were made only to one captive portal zone, but the issue presents on any one. This are the things I have found.Host IP information
-WiFi client IP: 172.20.0.67
-pfSense box IP: 172.20.0.17
-PORTAL_REDIRURL web server IP: 10.83.14.20 (institutional web page that is shown after sussesful authentication)UNDER NORMAL CONDITION
First Conversation
-WiFi Client do a HTTP GET for a web page (www.google.cl) which is intercepted by the captive portal.
-pfSense box reply with an HTTP 302 Found redirecting to its web login page.TCP Stream conversation (package info atached)
GET /index.php?zone=funcionarios&redirurl=http%3A%2F%2Fwww.google.cl%2F HTTP/1.1 Host: 172.21.0.1:8004 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive HTTP/1.1 302 Found Expires: Thu, 10 Mar 2016 14:39:48 GMT Expires: 0 Cache-Control: max-age=180000 Cache-Control: no-store, no-cache, must-revalidate Cache-Control: post-check=0, pre-check=0 Pragma: no-cache Connection: close Location: captiveportal-func_desktop.html Content-type: text/html Content-Length: 0 Date: Tue, 08 Mar 2016 12:39:48 GMT Server: lighttpd/1.4.38
Second Conversation
-WiFi client do a HTTP POST to the captive portal $PORTAL_ACTION$ page with login information.
-pfSense BOX reply with an HTTP 302 Found redirecting to the PORTAL_REDIRURL which is the institutional web page.TCP Stream conversation (package info atached)
POST /$PORTAL_ACTION$ HTTP/1.1 Host: 172.21.0.1:8004 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 91 auth_user=XXXXXXXauth_pass=XXXXXXXXX&redirurl=%24PORTAL_REDIRURL%24&accept=Login HTTP/1.1 302 Found Expires: Thu, 10 Mar 2016 14:39:53 GMT Expires: 0 Cache-Control: max-age=180000 Cache-Control: no-store, no-cache, must-revalidate Cache-Control: post-check=0, pre-check=0 Pragma: no-cache Connection: close Location: http://www.example.com/~generalidades/utilidades/bridge_v2.php Content-type: text/html Content-Length: 0 Date: Tue, 08 Mar 2016 12:39:53 GMT Server: lighttpd/1.4.38
Third Conversation
-WiFi client do a HTTP GET for the PORTAL_REDIRURL
-Web server reply with a HTTP 200 OK and push the html data.TCP Stream Conversation (package info atached)
GET /~generalidades/utilidades/bridge_v2.php HTTP/1.1 Host: www.example.com User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html Cookie: __utma=148467059.77328146.1374268415.1457032415.1457098656.304; s_fid=60866299936F00AC-39DFACC42EA142BC; oup-cookie=1_14-7-2015; __gads=ID=57bfa7611c77604c:T=1438694894:S=ALNI_MY0d-vsK9nhquXb5vyHXdSLFqHQtA; __utmz=148467059.1456510654.301.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none) Connection: keep-alive HTTP/1.1 200 OK Date: Tue, 08 Mar 2016 12:40:32 GMT Server: Apache Content-Length: 213 Keep-Alive: timeout=10, max=2000 Connection: Keep-Alive Content-Type: text/html; charset=ISO-8859-1 Content-Language: es
After that web page is render on client web browser and everything works fine.
UNDER PROBLEM CONDITION
First conversation
- It wasn't captured, but is the same as under normal condition.
Second conversation
-WiFi client do a HTTP POST to the captive portal $PORTAL_ACTION$ page with login information.
-pfSense BOX reply with an HTTP 302 Found redirecting to the PORTAL_REDIRURL which is the institutional web page.TCP Stream Flow (package info attached)
[1 bytes missing in capture file]POST /$PORTAL_ACTION$ HTTP/1.1 Host: 172.21.0.1:8004 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 91 auth_user=XXXXXXX&auth_pass=XXXXXXXX&redirurl=%24PORTAL_REDIRURL%24&accept=Login HTTP/1.1 302 Found Expires: Thu, 10 Mar 2016 14:34:27 GMT Expires: 0 Cache-Control: max-age=180000 Cache-Control: no-store, no-cache, must-revalidate Cache-Control: post-check=0, pre-check=0 Pragma: no-cache Connection: close Location: http://www.unap.cl/~generalidades/utilidades/bridge_v2.php Content-type: text/html Content-Length: 0 Date: Tue, 08 Mar 2016 12:34:27 GMT Server: lighttpd/1.4.38
Third Conversation
-WiFi client do a HTTP GET for the PORTAL_REDIRURL
-Web server reply with a HTTP 302 Found redirecting to the pfsense box with url for captive portal treatment (PROBLEM!!!!)TCP Stream Flow (package info attached)
GET /~generalidades/utilidades/bridge_v2.php HTTP/1.1 Host: www.example.com User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html Cookie: __utma=148467059.77328146.1374268415.1457032415.1457098656.304; s_fid=60866299936F00AC-39DFACC42EA142BC; oup-cookie=1_14-7-2015; __gads=ID=57bfa7611c77604c:T=1438694894:S=ALNI_MY0d-vsK9nhquXb5vyHXdSLFqHQtA; __utmz=148467059.1456510654.301.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none) Connection: keep-alive HTTP/1.1 302 Found Expires: Thu, 10 Mar 2016 14:34:27 GMT Expires: 0 Cache-Control: max-age=180000 Cache-Control: no-store, no-cache, must-revalidate Cache-Control: post-check=0, pre-check=0 Pragma: no-cache Connection: close Location: http://172.21.0.1:8004/index.php?zone=funcionarios&redirurl=http%3A%2F%2Fwww.example.com%2F%7Egeneralidades%2Futilidades%2Fbridge_v2.php Content-type: text/html Content-Length: 0 Date: Tue, 08 Mar 2016 12:34:27 GMT Server: lighttpd/1.4.38
Fourth conversation
-WiFi Client do a HTTP GET for the web page redirected from the previus step.
-pfSense box reply with an HTTP 302 Found redirecting to its web login page.TCP Stream Flow (package info attached)
GET /index.php?zone=funcionarios&redirurl=http%3A%2F%2Fwww.example.com%2F%7Egeneralidades%2Futilidades%2Fbridge_v2.php HTTP/1.1 Host: 172.21.0.1:8004 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html Connection: keep-alive HTTP/1.1 302 Found Expires: Thu, 10 Mar 2016 14:34:27 GMT Expires: 0 Cache-Control: max-age=180000 Cache-Control: no-store, no-cache, must-revalidate Cache-Control: post-check=0, pre-check=0 Pragma: no-cache Connection: close Location: captiveportal-func_desktop.html Content-type: text/html Content-Length: 0 Date: Tue, 08 Mar 2016 12:34:27 GMT Server: lighttpd/1.4.38
Fifth conversation
-WiFi client do a HTTP GET for the captive portal login page.
-pfSense box reply with a HTTP 200 OK with the login page.
-WiFi client dot a HTTP POST to $PORTAL_ACTION$ captive portal page with login info.
-pfSense box reply with a HTTP 302 Found with institutional web url redirection.TCP Stream Flow (package info attached)
GET /captiveportal-func_desktop.html HTTP/1.1 Host: 172.21.0.1:8004 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html Connection: keep-alive HTTP/1.1 200 OK Expires: Thu, 10 Mar 2016 14:34:27 GMT Cache-Control: max-age=180000 Content-Type: text/html Accept-Ranges: bytes ETag: "1662992581" Last-Modified: Mon, 29 Feb 2016 12:33:18 GMT Content-Length: 4171 Date: Tue, 08 Mar 2016 12:34:27 GMT Server: lighttpd/1.4.38 POST /$PORTAL_ACTION$ HTTP/1.1 Host: 172.21.0.1:8004 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 91 auth_user=XXXXXXXX&auth_pass=XXXXXXX&redirurl=%24PORTAL_REDIRURL%24&accept=Login HTTP/1.1 302 Found Expires: Thu, 10 Mar 2016 14:34:33 GMT Expires: 0 Cache-Control: max-age=180000 Cache-Control: no-store, no-cache, must-revalidate Cache-Control: post-check=0, pre-check=0 Pragma: no-cache Connection: close Location: http://www.example.com/~generalidades/utilidades/bridge_v2.php Content-type: text/html Content-Length: 0 Date: Tue, 08 Mar 2016 12:34:33 GMT Server: lighttpd/1.4.38
After this, everything cycles, that mean that institutional web server reply a HTTP 302 fount (instead of a 200 OK) redirecting again to the captive portal page, entering into an infinite loop and user only see captive portal login page.
When this issue is present, the only solution right now it to restart pfsense box. Must say also that only present under wifi connection, if I connect fiscally (cable) it doesn't happen.
Don't know if this a pfsense problem or a network one.
Please, any advise will be appreciated.
-
An idea? anyone? :-\
-
Last image, last line.
In the URL I see the variable "/$PORTAL_ACTION$". This isn't normal at all, using (PHP) variables like this in an URL, that won't work. Check why it isn't replaced it actual value. -
What version of pfSense are you running ?
Does the logged in user appear in the captive-portal status and in the FreeRADIUS user database ? -
Last image, last line.
In the URL I see the variable "/$PORTAL_ACTIONS$". This isn't normal at all, using (PHP) variables like this in an URL, that won't work. Check why it isn't replaced it actual value.Yeah there's a broken custom portal page on the box. It's PORTAL_ACTION not ACTIONS.
-
What version of pfSense are you running ?
Does the logged in user appear in the captive-portal status and in the FreeRADIUS user database ?pfSense version 2.2.6 (last one), did happen with 2.2.5 and 2.2.4 though.
Users appears as logged at captive portal and RADIUS log file. -
@cmb:
Last image, last line.
In the URL I see the variable "/$PORTAL_ACTIONS$". This isn't normal at all, using (PHP) variables like this in an URL, that won't work. Check why it isn't replaced it actual value.Yeah there's a broken custom portal page on the box. It's PORTAL_ACTION not ACTIONS.
The image show $PORTAL_ACTION$ no $PORTAL_ACTIONS$ (custom portal page have been working fine since 2 years and haven't been changed). Don't know how this is treated by pfSense, but it seems that this is the normal behavior, at least for what is seen when everything works fine, client POST to /$PORTAL_ACTION$ and is redirected to the $PORTAL_REDIRURL$
-
Dude. Look at your TCP Stream captures:
POST /$PORTAL_ACTION$ HTTP/1.1
Host: 172.21.0.1:8004
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 91
auth_user=XXXXXXXauth_pass=XXXXXXXXX&redirurl=%24PORTAL_REDIRURL%24&accept=LoginWhat is the user's browser supposed to do with POST /$PORTAL_ACTION$ HTTP/1.1 That should be referring to the portal IP address and port URL, not the text $PORTAL_ACTION$.
As has been said, your portal html is broken.
This is from view source of one of mine:
<form class="form-signin" method="POST" action="http://172.21.199.4:8004/">
You probably will see something like:
Which will never work because lighttpd has no clue WTF $PORTAL_ACTION$ URL is.
The POST should look like this:
POST / HTTP/1.1
Host: 172.21.0.1:8004</form> -
Dude. Look at your TCP Stream captures:
POST /$PORTAL_ACTION$ HTTP/1.1
Host: 172.21.0.1:8004
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 91
auth_user=XXXXXXXauth_pass=XXXXXXXXX&redirurl=%24PORTAL_REDIRURL%24&accept=LoginWhat is the user's browser supposed to do with POST /$PORTAL_ACTION$ HTTP/1.1 That should be referring to the portal IP address and port URL, not the text $PORTAL_ACTION$.
As has been said, your portal html is broken.
Sorry but I disagree with you. URL and port is mentioned on "Host: 172.21.0.1:8004" and /$PORTAL_ACTION$/ is the web resource that is in the host. As far as I know $PORTAL_ACTION$ is a pfSense internal variable to handle some captive portal function. I really don't know how pfSense handle this kind of request (not a programmer) but I do know that under normal condition IT DOES WORK. You can check it with the screeenshot captive_portal-normal_condition01.PNG where client do a POST request to http://172.20.0.1:8004/$PORTAL_ACTION$ which is processed by pfSense and reply with a HTTP 302 Found status indicating the "Location" where web browser should be redirected.
As I can see, the problem comes after that, when client do a HTTP GET to http://www.example.com/~generalidades/utilidades/bridge_v2.php (of course this is just an example URL, at least the host part) and web server reply with a HTTP 302 Found status (redirecting again to captive portal page) instead of a HTTP 200 Ok.
I really don't think that custom captive portal page is the problem, as it been working ok for 2 years and it still does, and as I can see, pfSense doesn't seems to have problem to handle a POST request to /$PORTAL_ACTION$ web resource.
Pleas, point me out if I'm wrong with this (and where). -
The image show $PORTAL_ACTION$ no $PORTAL_ACTIONS$ (custom portal page have been working fine since 2 years and haven't been changed). Don't know how this is treated by pfSense, but it seems that this is the normal behavior, at least for what is seen when everything works fine, client POST to /$PORTAL_ACTION$ and is redirected to the $PORTAL_REDIRURL$
I could have sworn it was typoed in one of those screenshots, but on second look, apparently not. It is still a problem that it's in there that way though, what are the contents of your portal page?
-
Dude. Look at your TCP Stream captures:
POST /$PORTAL_ACTION$ HTTP/1.1
Host: 172.21.0.1:8004
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 91
auth_user=XXXXXXXauth_pass=XXXXXXXXX&redirurl=%24PORTAL_REDIRURL%24&accept=LoginWhat is the user's browser supposed to do with POST /$PORTAL_ACTION$ HTTP/1.1 That should be referring to the portal IP address and port URL, not the text $PORTAL_ACTION$.
As has been said, your portal html is broken.
Sorry but I disagree with you. URL and port is mentioned on "Host: 172.21.0.1:8004" and /$PORTAL_ACTION$/ is the web resource that is in the host. As far as I know $PORTAL_ACTION$ is a pfSense internal variable to handle some captive portal function. I really don't know how pfSense handle this kind of request (not a programmer) but I do know that under normal condition IT DOES WORK. You can check it with the screeenshot captive_portal-normal_condition01.PNG where client do a POST request to http://172.20.0.1:8004/$PORTAL_ACTION$ which is processed by pfSense and reply with a HTTP 302 Found status indicating the "Location" where web browser should be redirected.
As I can see, the problem comes after that, when client do a HTTP GET to http://www.example.com/~generalidades/utilidades/bridge_v2.php (of course this is just an example URL, at least the host part) and web server reply with a HTTP 302 Found status (redirecting again to captive portal page) instead of a HTTP 200 Ok.
I really don't think that custom captive portal page is the problem, as it been working ok for 2 years and it still does, and as I can see, pfSense doesn't seems to have problem to handle a POST request to /$PORTAL_ACTION$ web resource.
Pleas, point me out if I'm wrong with this (and where).Fine. Disagree. Good luck. At best the $PORTAL_ACTION$ is tossed by lightppd and it serves up / instead. Regardless it doesn't belong there. When index.php is processing your HTML it is supposed to be replaced by the captive portal url:port and THAT sent to the user.
-
Dude. Look at your TCP Stream captures:
POST /$PORTAL_ACTION$ HTTP/1.1
Host: 172.21.0.1:8004
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://172.21.0.1:8004/captiveportal-func_desktop.html
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 91
auth_user=XXXXXXXauth_pass=XXXXXXXXX&redirurl=%24PORTAL_REDIRURL%24&accept=LoginWhat is the user's browser supposed to do with POST /$PORTAL_ACTION$ HTTP/1.1 That should be referring to the portal IP address and port URL, not the text $PORTAL_ACTION$.
As has been said, your portal html is broken.
Sorry but I disagree with you. URL and port is mentioned on "Host: 172.21.0.1:8004" and /$PORTAL_ACTION$/ is the web resource that is in the host. As far as I know $PORTAL_ACTION$ is a pfSense internal variable to handle some captive portal function. I really don't know how pfSense handle this kind of request (not a programmer) but I do know that under normal condition IT DOES WORK. You can check it with the screeenshot captive_portal-normal_condition01.PNG where client do a POST request to http://172.20.0.1:8004/$PORTAL_ACTION$ which is processed by pfSense and reply with a HTTP 302 Found status indicating the "Location" where web browser should be redirected.
As I can see, the problem comes after that, when client do a HTTP GET to http://www.example.com/~generalidades/utilidades/bridge_v2.php (of course this is just an example URL, at least the host part) and web server reply with a HTTP 302 Found status (redirecting again to captive portal page) instead of a HTTP 200 Ok.
I really don't think that custom captive portal page is the problem, as it been working ok for 2 years and it still does, and as I can see, pfSense doesn't seems to have problem to handle a POST request to /$PORTAL_ACTION$ web resource.
Pleas, point me out if I'm wrong with this (and where).Fine. Disagree. Good luck. At best the $PORTAL_ACTION$ is tossed by lightppd and it serves up / instead. Regardless it doesn't belong there. When index.php is processing your HTML it is supposed to be replaced by the captive portal url:port and THAT sent to the user.
I won't argue you as how pfSense handle this request, but how would be wrong if normally does work this way?
By the way, sorry if it bother you that I disagree with you, but isn't it that something that would be expected when discussing a solution for something? I mean, I thank you for your help, but it doesn't mean that I must agree with everything you say just as it is. Please, don't take it the bad way. -
@cmb:
The image show $PORTAL_ACTION$ no $PORTAL_ACTIONS$ (custom portal page have been working fine since 2 years and haven't been changed). Don't know how this is treated by pfSense, but it seems that this is the normal behavior, at least for what is seen when everything works fine, client POST to /$PORTAL_ACTION$ and is redirected to the $PORTAL_REDIRURL$
I could have sworn it was typoed in one of those screenshots, but on second look, apparently not. It is still a problem that it's in there that way though, what are the contents of your portal page?
Ok. The actual login page is a PHP file that detects if browser is a desktop or mobile one and redirect to a HTML file, which is uploaded directly on pfsense box by the file manager tab.
func_desktop.html.txt
func_index.php.txt
func_movil.html.txt