How can I access an environment variable set by a rewrite rule in an expression?

5,241

It turns out that the internal redirect caused by the last rewrite rule prefixes all variables with REDIRECT_. In order to access the variable in the expression, it needs to be accessed as REDIRECT_SFURI.

This problem was also covered at StackOverflow: When setting environment variables in Apache RewriteRule directives, what causes the variable name to be prefixed with “REDIRECT_”?

Share:
5,241

Related videos on Youtube

Chris
Author by

Chris

Updated on September 18, 2022

Comments

  • Chris
    Chris almost 2 years

    I am working on a Symfony 3.4 application which has public and private parts. However, I am currently setting up a staging system for this application which should only be accessed by authorized users, so I put an .htaccess basic authentication in front of the entire application.

    There is a single route in the application which needs to be accessed by an external app which does not supply authentication. I want to disable .htaccess authentication for this single route only. All URLs for this route are of the form /api/post-result/123 where 123 is an arbitrary ID.

    After searching around for a bit, I tried to solve this via a Require expr entry in my .htaccess which would simply match the URL. However, as Symfony does URL rewriting, REQUEST_URI always appears as "app.php" to the server (and my condition). I have tried other variables, such as QUERY_STRING or PATH_INFO, but none of them seem to contain my actual request URI. I have then tried to put the matched URI into an environment variable using a rewrite rule. However, it seems that this cannot be read by the expression.

    Here is my .htaccess file

    DirectoryIndex app.php
    
    <IfModule mod_rewrite.c>
        RewriteEngine On
    
        RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
        RewriteRule ^(.*) - [E=BASE:%1]
    
        RewriteCond %{ENV:REDIRECT_STATUS} ^$
        RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
    
        RewriteCond %{REQUEST_FILENAME} -f
        RewriteRule .? - [L]
    
        RewriteRule ^(.*)$ %{ENV:BASE}/app.php [L,E=SFURI:$1] # <-- env variable is set here
    </IfModule>
    
    <IfModule !mod_rewrite.c>
        <IfModule mod_alias.c>
            RedirectMatch 302 ^/$ /app.php/
        </IfModule>
    </IfModule>
    
    <Files "*.php">
      AuthUserFile /srv/my/app/.htuser
      AuthName "Authentication Required"
      AuthType Basic
    
      # allow access to post-result api without authentication
      # THIS DOES NOT WORK as reqenv('SFURI') is always empty
      Require expr "reqenv('SFURI') =~ m#/api/post-result/.*$#"
      # require authentication for everything else
      Require valid-user
    </Files>
    

    Looking at the Apache log, the environment variable is set correctly:

    [rewrite:trace5] [pid 11010] mod_rewrite.c(476): [...] setting env variable 'SFURI' to 'api/post-result/123'

    [rewrite:trace1] [pid 12755] mod_rewrite.c(476): [...] internal redirect with /app.php [INTERNAL REDIRECT]

    However, for some reason the variable is empty when I try to access it later. Could it be possible that all environment variables are cleared on the internal redirect caused by the last rewrite rule? The log shows that the condition doesn't match and when I change the condition so it checks whether the variable is empty, the condition comes back as true. I have also tried using the env function instead of reqenv, but the behavior is the same.

    [authz_core:trace4] [pid 11010] util_expr_eval.c(860): [...] Evaluation of expression from /srv/my/app/.htaccess:36 gave: 0

    [authz_core:debug] [pid 11010] mod_authz_core.c(809): [...] AH01626: authorization result of Require expr "reqenv('SFURI') =~ m#/api/post-result/.*$#": denied

    What can I do to make my expression find the environment variable set by the rewrite rule?