Forum Discussion
mahnsc
Nimbostratus
Apr 06, 2012Multi-Conditional iRule using Basic Auth and 9.4.3
I received a request recently regarding a customer of my customer who
has multiple authentication and authorization requirements for web
service requests. The requirements were broken down as follows:
1. Requests only matching URI named "/uri/" should be validated.
2. Requests with a Content-Type of "text/xml" should be validated.
3. Requests must only be allowed from IP address w.x.y.z
4. Requests must be protected with basic auth userid/password
My OS version is 9.4.3
I have written the following rule, which intends to follow these
guidelines but I have doubts that line 7 will do what I'm hoping it will
do. Building off of the rule from the HTTP Basic Access Authentication
iRule Style article, this is what I currently have:
when HTTP_REQUEST {
if {[HTTP::uri] contains "/uri/"} {
if { [HTTP::header "Content-Type"] contains "text/xml" } {
if { ! ( [IP::addr [IP::client_addr] equals w.x.y.z/m.a.s.k] ) } {
if { [HTTP::header exists Authorization] } {
binary scan [md5 [HTTP::password]] H* password
if { [matchclass [HTTP::username] equals $users] equals $password } {
log local0. "User [HTTP::username] authorized to access /uri/"
} elseif { [string length [HTTP::password]] != 0} {
log local0. "User [HTTP::username] not authorized to access /uri/"
HTTP::respond 401
} else {
HTTP::respond 401
}
}
HTTP::respond 403
log local0. "[IP::client_addr]:[TCP::client_port]: Sending 403 Response"
}
}
}
}
Surprisingly, this saves with no parsing errors but since this is 9.4.3,
class lookup does not work so I needed to convert this to using match
class and now I'm afraid that this won't actually do what I want it to
do, which is check to see if the userid is using a valid
password.I'm also not really certain whether the HTTP::respond 401 after the 'else' is needed but I have it in there now simply to include the 'else'. Can someone take a few moments to look this over and let me know where I need to make some changes?
8 Replies
- nitass
Employee
mine is 10.2.3. for 9.4.3, can you try findclass [HTTP::username] users " " instead of class lookup?
findclass wiki
https://devcentral.f5.com/wiki/iRules.findclass.ashx[root@ve1023:Active] config b virtual bar list virtual bar { snat automap pool foo destination 172.28.19.79:80 ip protocol 6 rules myrule profiles { http {} tcp {} } } [root@ve1023:Active] config b class users list class users { "foo" { "acbd18db4cc2f85cedef654fccc4a4d8" } } [root@ve1023:Active] config b rule myrule list rule myrule { when HTTP_REQUEST { if { [HTTP::uri] contains "/uri/" } { if { [HTTP::header "Content-Type"] contains "text/xml" } { if { ! ( [IP::addr [IP::client_addr] equals 1.1.1.0/24] ) } { binary scan [md5 [HTTP::password]] H* password if { [class lookup [HTTP::username] users] equals $password } { log local0. "User [HTTP::username] authorized to access /uri/" } else { if { [string length [HTTP::password]] != 0 } { log local0. "User [HTTP::username] not authorized to access /uri/" } HTTP::respond 401 log local0. "[IP::client_addr]:[TCP::client_port]: Sending 401 Response" } } } } } } 1 [root@ve1023:Active] config curl -i http://172.28.19.79/uri/ -H "Content-Type: text/xml" -d "test=abc" HTTP/1.0 401 Unauthorized WWW-Authenticate: Basic realm="" Server: BigIP Connection: Keep-Alive Content-Length: 0 [root@ve1023:Active] config tail -f /var/log/ltm Apr 5 21:23:16 local/tmm info tmm[4797]: Rule myrule : 172.28.19.80:43504: Sending 401 Response 2 [root@ve1023:Active] config curl -i -u foo:foo http://172.28.19.79/uri/ -H "Content-Type: text/xml" -d "test=abc" HTTP/1.1 404 Not Found Date: Fri, 06 Apr 2012 04:24:54 GMT Server: Apache/2.2.3 (CentOS) Content-Length: 279 Content-Type: text/html; charset=iso-8859-1 ...snipped... [root@ve1023:Active] config tail -f /var/log/ltm Apr 5 21:24:25 local/tmm info tmm[4797]: Rule myrule : User foo authorized to access /uri/ 3 [root@ve1023:Active] config curl -i -u foo:wrong http://172.28.19.79/uri/ -H "Content-Type: text/xml" -d "test=abc" HTTP/1.0 401 Unauthorized WWW-Authenticate: Basic realm="" Server: BigIP Connection: Keep-Alive Content-Length: 0 [root@ve1023:Active] config tail -f /var/log/ltm Apr 5 21:24:59 local/tmm info tmm[4797]: Rule myrule : User foo not authorized to access /uri/ Apr 5 21:24:59 local/tmm info tmm[4797]: Rule myrule : 172.28.19.80:43591: Sending 401 Response - mahnsc
Nimbostratus
Thanks a lot! I'll give that a try. - mahnsc
Nimbostratus
I'm going to have an opportunity to test this a little later on today but I was curious about the format of your class. I created a class in the Data Group List editor of the web console as a string that follows a format of " userid:md5sum_of_password " but yours looks like it has a format of: "userid" {"md5sum_of_password" }. Is your entry literally a string on a single line of: "foo" { "acbd18db4cc2f85cedef654fccc4a4d8" }
Using your ID as an example, my class's entry is a single line string like: foo:acbd18db4cc2f85cedef654fccc4a4d8 - nitass
Employee
if you use colon (:) as separator in findclass (findclass [HTTP::username] $::users ":"), data group should look like this.[root@B3600-R67-S43:Active] config b class users list class users { "foo:acbd18db4cc2f85cedef654fccc4a4d8" } - nitass
Employee
in 9.4.3, $:: is required to reference data group.
CMP Compatibility (Class / Data Group List References section)
https://devcentral.f5.com/wiki/iRules.cmpcompatibility.ashx - mahnsc
Nimbostratus
Great. I had already made the edit to the separator so this is good news. Thanks again for your time! - mahnsc
Nimbostratus
So, things ended up not working too well for me. There were a couple issues. The first was that the client was sending a base64 encoded value for userid and password in the Authorization header, which my rule above doesn't seem to account to for. Do I need to decode this value first prior to doing the binary scan or am I just better off with storing the base64 value in the data group?
The second problem is probably due to me missing an else somewhere but both unauthenticated AND authenticated requests were working fine when I tested this tonight. Requests lacking an Authorization header should have been rejected with a 401 status code.
If anyone has some time to spare, can you give me some pointers to help me figure this out? With the poor testing results with authentication, we didn't even get around to testing the other conditions. - mahnsc
Nimbostratus
Disregard the first question about decoding userid and password now that I've taken the time to re-read the wiki entries on HTTP::username and HTTP::password.
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects
