As of right now I’m using Haproxy to route requests to a 3rd party proxy provider.
Short explanation:
Haproxy listens on port 8887 and accepts requests from connections that provide a valid proxy-authorization via Header that match my haproxy userlist.
Requests are forwarded to my backend which deletes the proxy-header and sets the actual header needed to be authorized to access the 3rd party provider and sends out the request to them.
What I would like to achieve is being able to replace a certrain string of the username and replace it with a fixed value, while letting the rest of the string that was not matched stay as it is.
As an example.
User sends a request to us at 85.55.55.55:8887 with username admin_2 and password password
We receive a Authorization header corresponding to the base64 encoded value of admin_2:password
which is
Authorization Basic ‘YWRtaW5fMjpwYXNzd29yZA==’
What I would like to do is only replace the username admin with for example customerABC and keep the _2. So I end up with customerABC_2:password
What I tried in backend is using http-request replace-value like so:
So not only you want to replace the username, you want to replace only part of the username?
It does not suffice to replace admin_2 with customerabc_2 statically? Then what is it, exactly, that you want to replace? Everything before an underscore?
Yes exactly. The issue is the 3rd party provider uses suffixes like
username_country-Germany
or
username_session-ABC
so that the users are able to choose target location or sticky ip sessions.
I know this is kind of a very special request to have but since haproxy offers such huge possiblities I was wondering if its somehow possible to get this working without the need of a custom module.
Regexp 1 should remove the Basic and whitespace and only return the b64 encoded bit of the authorization header value
Regexp 2 should match and replace username and password while letting the -country-DE and -session-abc bit as it is.
What I need to do now is work to find out how I set up those regular expressions. While I do know the basic stuff these seem a bit advanced and I’m failing at properly setting this up, I guess this not really a HAProxy related issue however.
Wow. What an amazingly indepth answer. I really appreciate it. I was actually on step 3 (acl underscore_found) after 4 hours of working around with the options.
Simply amazing how quick you’ve managed to achieve this, I’m realizing I still have lots of work to do until I am truly familiar with HAProxy.
Thanks a thousand times for your input, if there is any way I can contribute to you, please let me know
Is the scenario above, I would have to add the different options in my userlist so the request does not get denied, as user admin is authed user admin_country-de or admin_session-123 is not.
Is there a way to set up my authentification in a similar way so only the base username is being matched against my ACL?
Example of my current setup:
In my global section I have setup a userlist:
userlist L1
group AuthedUsers users admin
user admin insecure-password password
In my frontend section I have set up a ACL and a http-request auth rule to only allow users from my userlist:
Now when a user tries to access the server with credentials: admin_country-de:password
It will get denied since the http_auth_group looks for the match of those credentials in my list and is unable to find it.
I was thinking of setting it similiarly to the solution to my main question, in which I strip the part after _ before matching the credentials with my list. Is there such a possibility?
Still trying to figure out how exactly I can setup authentification so it works with this.
What I was thinking was doing a similiar approach by declaring variables and check them against http_auth_group, however it doesn’t seem to work that way. Here is my try:
# reverse base64 current auth
http-request set-var(req.username_with_addition_and_pass) req.fhdr(proxy-authorization),regsub(^Basic\s+,,i),b64dec
#extract username without additions
http-request set-var(req.username_no_additions) var(req.username_with_addition_and_pass),regsub(-.+,)
#extract password
http-request set-var(req.password_only) var(req.username_with_addition_and_pass),regsub(.+:,)
#add user password to username without additions and compile as base64 encoded string
http-request set-var(req.username_no_addition_with_password) var(req.username_no_additions),concat(':',req.password_only),base64
#acl match with http_auth_group
acl auth_group_match var(req.username_no_addition_with_password) -m found http_auth_group(L1)
Then I declare my auth realm as
http-request auth realm myrealm unless auth_ok or auth_group_match
Sadly this does not work as intended as it just lets through any combinations of user and password that contain underscores.
Would appreciate some more help to see what exactly I’m doing wrong
Are you saying your are authenticating both on haproxy and then again on your backend application, and now you need to rewrite for haproxy itself also?
Hello lukas, yes, since the backend is a 3rd party I have to authenticate on both. I did however figure out how to do it, if anyone has the same problem here is the solution
On top of lukastribus edit I had to do my own which removes extra strings, checks them against auth group:
# reverse base64 current auth
http-request set-var(req.username_with_addition_and_pass_b64) req.fhdr(proxy-authorization),regsub(^Basic\s+,,i)
http-request set-var(req.username_with_addition_and_pass) req.fhdr(proxy-authorization),regsub(^Basic\s+,,i),b64dec
#extract username without additions
http-request set-var(req.username_no_additions) var(req.username_with_addition_and_pass),regsub(-.+,)
#extract password
http-request set-var(req.password_only) var(req.username_with_addition_and_pass),regsub(.+:,)
#add user password to username without additions and compile as base64 encoded string
http-request set-var(req.username_no_addition_with_password) var(req.username_no_additions),concat(':',req.password_only),base64
# set Authorization header
http-request set-header proxy-authorization %[str(),concat('Basic ',req.username_no_addition_with_password)]
http-request set-header Authorization %[str(),concat('Basic ',req.username_no_addition_with_password)]
Now if a user tries to auth with username-country-XX for example it will remove those strings. After that you can do the normal
acl auth_ok http_auth_group(L1) AuthedUsers
http-request auth realm myrealm unless auth_ok
Lukas’s part has to be inserted after that http-request auth in order for it to work