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?
Best Answer
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 asREDIRECT_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_”?