Parse username from HTTP requests

Problem this snippet solves:

This example was used to log the user name from web login attempts to a web application. It could be extended to perform some action based on the user name. Though depending on which action you want to take, you may need to replace the stream functionality with payload collection using HTTP::collect.

Code :

# parse_username_from_http_requests_rule
#
# Description: Capture username from web login attempts to a web application
# Look for the basic authorization header in any request and look in POST requests
# Need to tailor the POST request searches to just specific URIs if possible
# Requires a blank stream profile on the virtual server in order to use the STREAM:: commands
#
when RULE_INIT {

# Log debug messages to /var/log/ltm? 1=yes, 0=only syslog event
set ::username_debug 2

# User name parameter name which is searched for in the POST data
set ::user_name "UserIdentifier"

# Regular expression which matches the user name and value in POST requests
set ::user_name_regex [subst -nocommands {${::user_name}=[^&]+}]
if {$::username_debug}{log local0. " \$:

}
when HTTP_REQUEST {

if {$::username_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: New HTTP [HTTP::method] request to [HTTP::host][HTTP::uri]"}

# Check if there is an Authorization header value
# This could come at any time in the application flow so check for it in every request
if {[HTTP::header value Authorization] ne ""}{

# Format should be: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
#   where the token is a base64 encoding of user:pass
if {$::username_debug}{log local0. "[IP::client_addr]:[TCP::client_port]:\
Base64 decoded user
user: [getfield [b64decode [lindex [HTTP::header Authorization] 1]] ":" 1]"}

# Preferred order with the Cookies last (but Secerno current expeects the cookies and then the username)
log local0. "CLIENT=[IP::client_addr]:[TCP::client_port],USERNAME=[getfield [b64decode [lindex [HTTP::header Authorization] 1]] ":" 1]"
}

# Check if request is a POST with a "login" parameter in the URI
if {[HTTP::method] eq "POST" && ([URI::query [HTTP::uri] "login"] ne "")} {
 
if {$::username_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Matched method and parameter check"}

# Use a stream profile to look for the username parameter value in the payload
STREAM::expression "@$::user_name_regex@ @"
STREAM::enable
if {$::username_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Enabling stream"}
} else {
STREAM::disable
if {$::username_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Disabling stream"}
}
}
when STREAM_MATCHED {

if {$::username_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Found match: [STREAM::match]"}

# Prevent the username from being replaced by calling STREAM::replace with no replacement string
STREAM::replace

# Parse the user name from the stream, with the stream expression regex matching username=value.
#   Use getfield to get the value

# Preferred order with the Cookies last (but Secerno current expeects the cookies and then the username)
log local0. "CLIENT=[IP::client_addr]:[TCP::client_port],USERNAME=[getfield [STREAM::match] "=" 2]"

# Disable further matches on this request as there will only be one username to find per request
STREAM::disable
}
Published Mar 18, 2015
Version 1.0
  • Hi Hoolio, many thanks for this example, I was looking for something like this for several days. If I find username in the HTTP header, is it possible to limit Maximum rate for each single client after the user has logged in to the Active Directory? Using for example the HTTP::username command with BWC:: command? Best Rgds