3

We have a drupal website a.com that is password protected. I want all a.com/api/... URIs not to be, though. So I've read about SetEnvIf:

AuthName "Stage"
AuthType Basic
AuthUserFile ~/.htpasswd
SetEnvIf Request_URI ".*data_sheets.*\.pdf" noauth
SetEnvIf Request_URI "/api/.+" noauth
SetEnvIfNoCase Request_Method OPTIONS noauth
Order Deny,Allow
Deny from all
Require valid-user
Allow from env=noauth
Satisfy Any

The /api/foobar URIs are still asking for a password though. Since it's a Drupal website, with the help of anubhava we figured it has to do with how the request is handled by index.php.

How to deal with that?

Edit

Adding

RewriteCond %{REQUEST_URI} ^/api/ [NC]
RewriteRule ^ - [E=noauth]

right after

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ index.php [L]

didnt help

Alex
  • 9,911
  • 5
  • 33
  • 52
  • Can you show your full .htaccess here? – anubhava Feb 20 '18 at 15:04
  • @anubhava I've actually created a folder just for testing but it didnt work. its a regular drupal 8 htaccess: https://www.drupal.org/project/drupal/releases/8.4.4 – Alex Feb 20 '18 at 15:05
  • So `/api/...` is being rewritten to `/index.php` somewhere in this .htaccess? – anubhava Feb 20 '18 at 15:06
  • @anubhava sure, but the auth module runs *before* the rewrite module does, as I learned. also, you cant read the query string in the setenv stuff, so at the moment I could set noauth via modrewrite the auth stuff is already over – Alex Feb 20 '18 at 15:07
  • There are 3 different modules in play here.. `mod_auth`, `mod_setenv` and `mod_rewrite`. Ordering of those modules may be an issue here – anubhava Feb 20 '18 at 15:10
  • @anubhava i thought the same, yup – Alex Feb 20 '18 at 15:11
  • 1
    I have just tried this snippet in my Apache 2.4 and it worked fine and didn't ask for auth while visiting `/api/foobar/` – anubhava Feb 20 '18 at 15:24
  • 1
    @anubhava youre right, removing all the other htaccess stuff is giving me a not found. i guess ill have to change the question then – Alex Feb 20 '18 at 15:29
  • 1
    Instead of `RewriteCond %{REQUEST_URI} ^/api/ [NC]` can you try `RewriteCond %{THE_REQUEST} /api/ [NC]` – anubhava Feb 20 '18 at 15:45
  • @anubhava no luck :/ – Alex Feb 20 '18 at 16:11
  • 1
    Problem is that I can't reproduce this problem on my Apache. – anubhava Feb 20 '18 at 16:55
  • @anubhava i see. it must have to do something with the rest of the drupal htaccess, which i cant just remove, so there must be a solution. i wont be able to find it myself, though, probably :( – Alex Feb 21 '18 at 10:20
  • 1
    You’ll want to use `FallbackResource /index.php` instead of using mod_rewrite. – Daniel Jun 11 '20 at 01:37

3 Answers3

3

This works for me:

AuthName "Stage"
AuthType Basic
AuthUserFile /var/www/html/.htpasswd
SetEnvIf Request_URI ".*data_sheets.*\.pdf" noauth
SetEnvIf Request_URI "/api/.+" noauth
SetEnvIfNoCase Request_Method OPTIONS noauth

RewriteEngine On
RewriteCond %{THE_REQUEST} \s/api/
RewriteRule ^ - [E=noauth:1]

Order Deny,Allow
Deny from all
Require valid-user
Allow from env=noauth
Allow from env=rewritten
Satisfy Any

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ /index.html [L]
Dusan Bajic
  • 10,249
  • 3
  • 33
  • 43
  • is `\s` making sense? isnt this a blank? – Alex Feb 20 '18 at 16:13
  • 1
    `THE_REQUEST` contains the full HTTP request line sent by the browser to the server (e.g., `GET /index.html HTTP/1.1`), therefore the blank before `/api/` – Dusan Bajic Feb 20 '18 at 21:05
  • 1
    Also note that `%{THE_REQUEST}` will, in case there are internal rewrites, preserve the value of initial request (which is not the case for `%{REQUEST_URI}`) – Dusan Bajic Feb 21 '18 at 10:37
2

I’m two years late but I’ve worked out a thorough explanation of what’s going on and how you can work around it. The short version:

RewriteRule is fulfilled by a subrequest. The SetEnvIf module doesn’t inherit the REQUEST_URI variable in subrequests. Your noauth variable ends up as undefined in these subrequests.

Use <Location> and <LocationMatch> blocks together with mod_core’s SetEnv instead of relying on mod_setenvif.

Daniel
  • 4,525
  • 3
  • 38
  • 52
1

I am visiting this question after 3 years for some reason and attempting to post a working solution that should work in any Apache version.

You may try these rules in your site root .htaccess with Drupal rules:

DirectoryIndex index.php
RewriteEngine on

# remove /index.php from URLs
RewriteCond %{THE_REQUEST} /index\.php [NC]
RewriteCond %{REQUEST_URI} ^(.*/)index\.php$ [NC]
RewriteRule ^ %1 [L,R=301,NE]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ index.php [L]

# allow anything that starts with /api/
SetEnvIfNoCase Request_URI ^/api/ noauth

<FilesMatch "^(?!index\.php$).*$">
   AuthType Basic
   AuthName "Stage"
   AuthUserFile ~/.htpasswd
   Require valid-user
   Order   Deny,Allow
   Deny from  all
   Allow from env=noauth
   Satisfy any
</FilesMatch>
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    thanks for your help, the question is so old though I dont even remember the project ;) – Alex Aug 05 '21 at 07:28
  • yes I know it was old but problem remained unanswered so I thought I would post a working answer to help future visitors to your question – anubhava Aug 05 '21 at 08:48