2

I have a backend application behind a reverse proxy protected by an SSO. The SSO exports an HTTP header after successful authentication containing the userid. I need to pass this uid and other data to a program that will sign the all thing.

Here's how it works:

  1. Define the script with RewriteMap
  2. Set an environment var with the SSO-exported header value
  3. Call the script, get the values returned and append them to env var
  4. Check the env var and create a cookie with those values

Then the last RewriteRule directive will pass the traffic to the backend application, the thing is, as soon as I set the RewriteRule with the P flag, all the above variable affectations no longer work.

Question : How can I manage to execute all my directives and thus the cookie creation before proxying all the traffic so my cookie is available in my backend app ?

RewriteMap  cookiemap prg:/dir/cookieSign.py
RewriteRule ^ - [env=LLNGUID:%{HTTP:Test}]

RewriteCond ${cookiemap:%{REMOTE_ADDR}-%{ENV:LLNGUID}} ^(.*)\s(.*)\s(.*)\s([a-z]+)$
RewriteRule ^ - [E=SIGNATURE:%1,E=SETTIME:%2,E=SETIP:%3,E=UIDSCRIPT:%4]

RewriteCond "%{ENV:SIGNATURE}" "!^$"
RewriteCond "%{ENV:SETTIME}" "!^$"
RewriteCond "%{ENV:SETIP}" "!^$"
RewriteCond "%{ENV:UIDSCRIPT}" "!^$"
RewriteRule ^ - [CO=MY_COOKIE:userid=%{ENV:UIDSCRIPT}&sign=%{ENV:SIGNATURE}&time=%{ENV:SETTIME}&ip=%{ENV:SETIP}:.test.ltd:86400:/:true:true]

RewriteRule "^(.*)$" "http://127.0.0.1:8080$1" [P,L]

Thanks :)

2

The problem is not the order of execution - the directives are being executed in the order shown - but an issue with variable scope and cookie setting.

The environment variables you set here are not going to be available to the target server, since this is a different scope.

The cookie you are "setting" will not be available to your script in the current request. Setting a cookie (eg. with the CO flag) sets a Set-Cookie HTTP response header on the HTTP response back to the client/browser. The cookie is only sent back to your server on the next request when the browser (hopefully) sends back a Cookie HTTP request header.

If you want to send this information to your backend server for the current request then you need to use a different method. Perhaps a query string on the proxied request?

For example:

RewriteMap  cookiemap prg:/dir/cookieSign.py

RewriteRule ^ - [env=LLNGUID:%{HTTP:Test}]

RewriteCond ${cookiemap:%{REMOTE_ADDR}-%{ENV:LLNGUID}} ^([^\s]+)\s([^\s]+)\s([^\s]+)\s([a-z]+)$
RewriteRule ^ - [E=SIGNATURE:%1,E=SETTIME:%2,E=SETIP:%3,E=UIDSCRIPT:%4]

RewriteCond %{ENV:SIGNATURE} .
RewriteCond %{ENV:SETTIME} .
RewriteCond %{ENV:SETIP} .
RewriteCond %{ENV:UIDSCRIPT} .
RewriteRule ^ - [ENV=MY_QUERY:userid=%{ENV:UIDSCRIPT}&sign=%{ENV:SIGNATURE}&time=%{ENV:SETTIME}&ip=%{ENV:SETIP}]

RewriteRule (.*) http://127.0.0.1:8080$1?%{ENV:MY_QUERY} [P]

Notes:

  • Changed the regex that matches the output of the rewritemap to use [^\s]+ instead of .* to avoid unnecessary backtracking.
  • No need to surround all arguments in quotes unless they contain spaces.
  • Instead of checking for not-empty ("!^$"), it's arguably simpler to check that it is something, ie ..
  • The L flag is not required when using the P flag (it is implied).
0

Thanks for the detailed reply @MrWhite, in the meantime I found a solution that appears to work. I kept all the above configuration but instead of keeping that in the VHOST configuration I add a Location tag inside the VHOST tag :

<VirtualHost _default_:443>
#
# Some conf here
#
<LocationMatch "^/*">
        RewriteRule ^ - [env=LLNGUID:%{HTTP:Test}]

        RewriteCond ${cookiemap:%{REMOTE_ADDR}-%{ENV:LLNGUID}} ^(.*)\s(.*)\s(.*)\s([a-z]+)$
        RewriteRule ^ - [E=SIGNATURE:%1,E=SETTIME:%2,E=SETIP:%3,E=UIDSCRIPT:%4]

        RewriteCond "%{ENV:SIGNATURE}" "!^$"
        RewriteCond "%{ENV:SETTIME}" "!^$"
        RewriteCond "%{ENV:SETIP}" "!^$"
        RewriteCond "%{ENV:UIDSCRIPT}" "!^$"
        RewriteRule ^ - [CO=MY_COOKIE:userid=%{ENV:UIDSCRIPT}&sign=%{ENV:SIGNATURE}&time=%{ENV:SETTIME}&expires=480&ip=%{ENV:SETIP}:.domain.ltd:86400:/:true:true]

        RewriteRule "^(.*)$" "http://127.0.0.1:8080%{REQUEST_URI}" [P,L]
</LocationMatch>

</VirtualHost>

With this configuration, the cookie is created and available for my backend app. I'll correct what you pointed out in your comment notes.

1
  • Thanks for the feedback. However, I can't see how this would make any difference? The result of the <LocationMatch> block, is to simply merge the contained directives "late" in relation to other local directives. This won't make any difference in setting the cookie on the client? Are you sure you're not just seeing a cookie that was set on a previous request? Incidentally, the regex ^/* is incorrect. This should be ^/.* or simply ^/ (but the net result is the same). If you simply want to match all URLs then the simpler (non-regex) <Location "/"> directive would be preferable. – MrWhite Nov 25 '20 at 16:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.