Form Based Authentication with external SOAP web services
Problem this snippet solves:
1- You need to authenticate users against an external authentication system relying on SOAP calls.
2- The session identifier must be provided by an external third party system.
How to use this snippet:
Installation
Files
You need to upload an html login page using ifiles.
You need to upload the SOAP body of the external web service using ifiles.
irule
You need to install the irule on your Virtual Server you need to protect.
Variables
set static::holdtime 3600 # session timeout set static::login_url "/login" # login url set static::sideband_vs "VS_EXTERNAL_AUTH_PROVIDER" # Virtual Server that publish the web service
Features
Version 1.0
- Form based login (provided by a custom ifile)
- Authentication against an external SOAP web service
- Manage Session timeout
Backlog
- Improve logging
- Allow 2-factor authentication (Challenge)
- Encrypt Session cookie
- Provide internal mecanism to generate a session cookie
- accept Basic Authentication
External links
Github : https://github.com/e-XpertSolutions/f5
Code :
when RULE_INIT { set static::holdtime 3600 set static::login_url "/login" set static::sideband_vs "VS_EXTERNAL_AUTH_PROVIDER" } when HTTP_REQUEST { if { [HTTP::cookie exists SessionCook] and [table lookup -subtable "active_sessions" [HTTP::cookie SessionCook]] != "" } { return } else { if { [HTTP::path] eq $static::login_url } { if { [HTTP::method] eq "POST" } { if {[HTTP::header "Content-Length"] ne "" && [HTTP::header "Content-Length"] <= 1048576}{ set content_length [HTTP::header "Content-Length"] } else { set content_length 1048576 } if { $content_length > 0} { HTTP::collect $content_length } } else { HTTP::respond 200 content [ifile get login.html] "Cache-Control" "no-cache, must-revalidate" "Content-Type" "text/html" } } else { HTTP::respond 302 noserver "Location" $static::login_url "Cache-Control" "no-cache, must-revalidate" Set-Cookie "SessionCook=$result;domain=[HTTP::host];path=/" } } } when HTTP_REQUEST_DATA { set payload [HTTP::payload] set username "" set password "" regexp {Login1\%3AtxtUserName\=(.*)\&Login1\%3AtxtPassword\=(.*)\&Login1\%3AbtnSubmit\=(.*)} $payload -> username password garbage if {[catch {connect -timeout 1000 -idle 30 -status conn_status $static::sideband_vs} conn_id] == 0 && $conn_id ne ""}{ log local0. "Connect returns: $conn_id and conn status: $conn_status" } else { log local0. "Connection could not be established to sideband_virtual_server" } set content [subst -nocommands -nobackslashes [ifile get soap_body]] set length [string length $content] set data "POST /apppath/webservicename.asmx HTTP/1.1\r\nHost: www.hostname.com\r\nContent-Type: text/xml; charset=utf-8\r\nContent-Length: $length\r\nSOAPAction: http://schemas.microsoft.com/sqlserver/2004/SOAP\r\n\r\n$content" set send_bytes [send -timeout 1000 -status send_status $conn_id $data] set recv_data [recv -timeout 1000 $conn_id] # parse response to retrieve the authentication result, it gives 0 if authentication failed or a session_id if it succeed regexp {(.*) (.*)} $recv_data -> result garbage unset content unset length unset data unset recv_data close $conn_id # add a custom alert notification to the login page if { $result == 0 } { set alert "Invalid credentials." HTTP::respond 200 content [subst -nocommands -nobackslashes [ifile get login.html]] "Cache-Control" "no-cache, must-revalidate" "Content-Type" "text/html" Set-Cookie "SessionCook=deleted;expires=Thu, 01-Jan-1970 00:00:10 GMT;domain=[HTTP::host];path=/" } else { HTTP::respond 302 noserver "Location" "/" "Cache-Control" "no-cache, must-revalidate" Set-Cookie "SessionCook=$result;domain=[HTTP::host];path=/" # save the cookie value in a cache for fast checking table add -subtable "active_sessions" $result $username indef $static::holdtime } }
Tested this on version:
11.5Updated Jun 06, 2023
Version 2.0Yann_Desmarest
Cirrus
Joined September 11, 2012
- Danielle_Alper1Nimbostratus
Thank you!