# F5 BIG-IP example iRule
# Description: 
#	Capture username and cookies from user login to web application and send to Oracle DBFW
#	Define the Oracle DBFW syslog IP:port in an LTM pool and set that pool name in $static::dbfw_syslog_pool in RULE_INIT 
#
# Global variable definitions and other initialization logic goes here
when RULE_INIT {

	### Customize this to suit your application

	# Define the Oracle DBFW IP:port for TCP syslog in an LTM pool
	# Configure syslog server pool name here as well
	set static::dbfw_syslog_pool "oracle_syslog_pool"
	
	# The page that user logins from
	set static::login_page "/hr_app/controller.jsp"

	# The name of the field holding the user name
	set static::login_parameter_name "username"

	# The method of authentication which will be sent to Oracle Database Firewall
	set static::auth_method "webforms"

	# HTTP protocol methods that is used by the login form
	set static::login_method "POST"

	### Don't change these
	# Limit the length of the HTTP request to prevent TMM memory exhaustion
	# We'll search the first X bytes of the HTTP request payload for the username
	set static::max_header_content_length 1024000

	# Log iRule trace messages to /var/log/ltm? 1=yes, 0=no
	# Set to 0 for production systems to avoid CPU and disk I/O issues
	set static::dbfw_debug 0
}
# HTTP request received, check if it's a login request and start collecting the data
when HTTP_REQUEST {

	# Log the debug message if trace is enabled
	if {$static::dbfw_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: HTTP [HTTP::method] request to [HTTP::host][HTTP::uri]"}

	# If the request is to the login page populate cookie_all variable with all the cookies received
	if {[HTTP::path] starts_with $static::login_page and [HTTP::method] eq $static::login_method} {

		# Log the debug message if trace is enabled
		if {$static::dbfw_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Matched path and method check"}

		# Validate the Content-Length value and set the content_length variable
		if {[HTTP::header value Content-Length] > $static::max_header_content_length } {
			set content_length $static::max_header_content_length
		} else {
		  set content_length [HTTP::header value Content-Length]
		}

		# Get the payload data
		if {$content_length > 0}{

			# Collect the payload
			HTTP::collect $content_length

			# Log the debug message if trace is enabled
			if {$static::dbfw_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Collecting $content_length bytes"}
		}
	}
}
# Got the data, parse them and generate the Oracle Database Firewall syslog message
# Note that this event is only triggered if HTTP::collect was called
when HTTP_REQUEST_DATA {

	# Log the debug message if trace is enabled
	if {$static::dbfw_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Collected request data: [HTTP::payload]"}

	# Parse the username parameter value from the payload
	set username [URI::query "?[HTTP::payload]" $static::login_parameter_name]
	if {$username eq ""}{
		log local0. "ERROR: Oracle Database Firewall iRule failed to extract user name from page $login_page with parameter $login_parameter_name"
	} else {
		# Retrieve the cookie header(s) and log them in name=value comma-separated pairs
		# Example: cookie1=value1,cookie2=value2
		set cookies [string map {"; " , ; ,} [join [HTTP::header values Cookie] ","]]
		if {$static::dbfw_debug}{log -noname local0. "<158>[clock format [clock seconds] -format "%h %m %H:%M:%S"] tmm tmm\[1\]: Rule rule <HTTP_REQUEST_DATA>: DBFIREWALL:CLIENT=[IP::client_addr]:[TCP::client_port],$cookies,USERNAME=$username,AUTHMETHOD=$static::auth_method\n"}

		# Send the syslog message using High Speed Logging to syslog facility local3.info
		# See https://devcentral.f5.com/wiki/iRules.HSL__send.ashx for details.
		# Oracle parses the TCP syslog message expecting a very specific format. Do not modify the format below!
		HSL::send [HSL::open -proto TCP -pool $static::dbfw_syslog_pool] "<158>[clock format [clock seconds] -format "%h %m %H:%M:%S"] tmm tmm\[1\]: Rule rule <HTTP_REQUEST_DATA>: DBFIREWALL:CLIENT=[IP::client_addr]:[TCP::client_port],$cookies,USERNAME=$username,AUTHMETHOD=$static::auth_method\n"
	}
}