Lars-Daniel Weber
Lars-Daniel Weber

Reputation: 51

Apache 2.4: Can I use variables for conditionals in requests?

tl;dr

In NGINX, you can define variables and evaluate them in each request. I'm not possible to reproduce this in Apache v2.4. Can I use variables for conditionals in requests at all?

What I want

${docroot}/dev/api.php contains an API, which should never be reached by direct access, but by location /api only.

  1. user visits example.org/dev/api.php and get gets an error 404 or "Authorization required"
  2. user visits example.org./api/endpoint, which falls back to /dev/api.php internally.

In NGINX, I can use a variable for this. If the user visits the location, the variable is TRUE, otherwise (e.g. direct access) it's false and he get's the error.

Code

<VirtualHost *:8443>
    Define docroot /var/www/html/test
    Define fromAPI false # default is: no access
 
    ServerName    shop.example.org
    ServerAdmin   [email protected]
    DocumentRoot  ${docroot}
    Protocols h2 http/1.1
 
    # that's the location of the API (there is no directory named "api")
    <Location /api>
        AllowOverride None
        Define fromAPI true # user has access
        FallbackResource /dev/api.php
    </Location>
 
    # The API code is living here.
    # When user visits it "${fromAPI} == false", it should end up in error 404.
    # When API visits it "${fromAPI} == true", the access should be granted.
    <Directory ${docroot}/dev>
        # <If "-T env('fromAPI')">
        # <If "-T env('fromAPI')">
        # <If "${fromAPI}">
        # <If "-T '${fromAPI}'">
            Redirect 404 /dev/
        </If>
    </Directory>
  
    SSLEngine on
    SSLProtocol -all +TLSv1.2 
    SSLCertificateFile    /etc/letsencrypt/live/example.org/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.org/privkey.pem
 
    # HTTP Strict Transport Security (mod_headers is required) (31536000 seconds)
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

Upvotes: 1

Views: 139

Answers (1)

MrWhite
MrWhite

Reputation: 45829

# that's the location of the API (there is no directory named "api")
<Location /api>
    AllowOverride None
    Define fromAPI true # user has access
    FallbackResource /dev/api.php
</Location>

# The API code is living here.
# When user visits it "${fromAPI} == false", it should end up in error 404.
# When API visits it "${fromAPI} == true", the access should be granted.
<Directory ${docroot}/dev>
    # <If "-T env('fromAPI')">
    # <If "-T env('fromAPI')">
    # <If "${fromAPI}">
    # <If "-T '${fromAPI}'">
        Redirect 404 /dev/
    </If>
</Directory>

I'm not sure that this pattern would work, since <Location> sections are merged after <Directory> sections.

You could do this using mod_rewrite instead in the main <Directory> section for the ${docroot}.

For example:

<Directory ${docroot}>
    Require all granted
    AllowOverride None

    RewriteEngine On

    # Block direct access to "/dev/"
    RewriteRule ^dev/ - [R=404]

    # Rewrite "/api/<something>" to "/dev/api.php"
    RewriteRule ^api/. dev/api.php [END]
</Directory>

I used mod_rewrite, instead of FallbackResource in order to specifically target requests for /api/<something> only.

The END flag prevents all further processing of the rewrite engine in this context. (So the preceding rule that blocks access does not need a condition to prevent blocking the rewritten request.)

Upvotes: 1

Related Questions