Mobile app version of vmapp.org
Login or Join
Nimeshi995

: Apache 2.4 with regexp - is the alternation operator broken, or am I confused? I have several document root directories, /opt/lampp/htdocs/proj1, /opt/lampp/proj2, etc, that have AuthType Basic

@Nimeshi995

Posted in: #Apache2 #HttpdConf #RegularExpression

I have several document root directories, /opt/lampp/htdocs/proj1, /opt/lampp/proj2, etc, that have AuthType Basic password protection. I want their uploads sub-directory trees not to require a password. Except that the private sub-directory tree of uploads should not allow any access at all. According to httpd.apache.org/docs/current/mod/core.html#directory :


Regular expressions are not considered until after all of the normal
sections have been applied. Then all of the regular expressions are
tested in the order they appeared in the configuration file.


So I used these directives:

#==========================================================
# regexp enables access to images without login (needed for wp_sideload_image)
<Directory ~ "/opt/lampp/htdocs/[^/]*/public/(uploads|wp/wp-content/uploads)">
Require all granted
</Directory>

#==========================================================
# regexp protects private uploads unconditionally
# regexps processed in source order, so MUST BE AFTER ENABLING IMAGES
<Directory ~ "/opt/lampp/htdocs/[^/]*/public/uploads/private">
Require all denied
</Directory>


What I found was that the Require all denied directive was not effective, everything below uploads could be accessed without a password, including things below private. Just for fun I tried removing the alternation expression, making the first block:

<Directory ~ "/opt/lampp/htdocs/[^/]*/public/uploads">
Require all granted
</Directory>


And much to my surprise (and delight), things worked as I wanted. So I can get the effect of the original regular expression by adding another <Directory>:

<Directory ~ "/opt/lampp/htdocs/[^/]*/public/wp/wp-content/uploads">
Require all granted
</Directory>


While that does work, I might as well use normal <Directory> blocks with a '*' wildcard for the level below htdocs. I thought it would be more concise to use the regexp form. I still want to use regexp for the private section, though, since I need that to be processed after the directives that grant access.

Can anyone explain why the original code doesn't work? The Apache docs say they use PCRE, and the expression using alternation works fine with egrep. Plus I don't see how that expression could affect the subsequent Require all denied, since they are both regexps, which are supposed to be processed in source order. So the denied directive should override no matter what, shouldn't it? That's what happens when I replace the alternation with two separate regexp directives. What am I missing?


EDIT: At the time I posted this, I was obviously having a brain fart
moment thinking that the non-regexp rule of "shortest path first"
meant that I needed to use a regexp to ensure that the "Require all denied"
would be processed late enough. But clearly, while there could be longer
paths below "uploads" than those below "uploads/private", in those cases
there wouldn't be a match on "uploads/private", so those paths
shouldn't be forbidden anyway. Thus I believe the "best" solution for my
actual situation is simply to eliminate the use of "regexp" matching
entirely and use three normal "<Directory>" directives with wildcards similar
to the ones shown with regexps above,
but replacing the "[^/]*" regexp with the shell wildcard
"*". That works just fine, and likely is microseconds faster :-)

However, I'd still like to know why my original code did not work. It
still seems to me that Apache's treatment of the directive containing
the "|" regexp operator was incorrect.

10.02% popularity Vote Up Vote Down


Login to follow query

More posts by @Nimeshi995

2 Comments

Sorted by latest first Latest Oldest Best

 

@Gonzalez347

That question made me mix quite some things. This one works as expected according to what I tested, with | operator, taking advantage of the possibility in Apache 2.4 to use the $ sign as line ending:

<DirectoryMatch "/opt/lampp/htdocs/[^/]*/public/(uploads(/[^/]*)?|(wp/wp-content/uploads(/[^/]*)?))$">
Require all granted
</DirectoryMatch>
<DirectoryMatch "/opt/lampp/htdocs/[^/]*/public/uploads/private">
Require all denied
</DirectoryMatch>


I thought I understood partly why this behavior, but in fact I didn't understand it. I guess this is something I'll ask to the Apache mailing list.

10% popularity Vote Up Vote Down


 

@Heady270

My only suggestion would be try adding more parenthesis to the regular expression:

<Directory ~ "/opt/lampp/htdocs/[^/]*/public/(uploads|(wp/wp-content/uploads))">


The order of operations with | and / could be part of the issue.

10% popularity Vote Up Vote Down


Back to top | Use Dark Theme