apache: basic authentication before rewrite - apache

I have an Apache in frontend that should redirect a request via a RewriteRule.
I have to put a basic authentication before the request is redirected, so I put this in the config file:
<VirtualHost *:443>
ServerAdmin xxxxxx
DocumentRoot /var/www/html/
ServerName xxxxxxx
RewriteEngine on
ErrorLog logs/error.log
CustomLog logs/access_log common
<Directory /var/www/html/>
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
RewriteRule ^/(.*) http://xxxxxx:xxx/$1 [P,L]
</Directory>
</VirtualHost>
But it doesn't work.
Any suggestions?
UPDATE: I would expect that all requests after authentication would be redirected with the rule RewriteRule ^/(.*) xxxxxx:xxx/$1 [P,L] but this doesn't happen. Apache search the page under /var/www/html

In general, Apache does the rewrite phase before the authorization phase, which is why your code performs the rewrite without ever asking for user to authenticate.
You can get around this with the LA-U:REMOTE_USER variable. Preface your RewriteRule with a condition which looks ahead ("LA") to the authorization phase:
RewriteCond %{LA-U:REMOTE_USER} !^$
RewriteRule ^/(.*) http://xxxxxx:xxx/$1 [L]
See notes about this in http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritecond
As other posters point out, it's also better to take the RewriteRule directives out of the block so they are more reliable.

I solved putting the rewrite condition and rewrite rule outside the Locatio directive:
<Location />
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
</Location>
RewriteCond %{LA-U:REMOTE_USER} !^$
RewriteRule ^/(.*) http://xxxxxx:xxx/$1 [P,L]
many thanks to h0tw1r3 for the suggestion
*Keep in mind that Location directives operate on URLs, and not directories. That means that if someone creates an alias to the document root, they'll completely bypass these authentication rules. (See http://httpd.apache.org/docs/2.0/mod/core.html#location for more.)

Update: Implicit directory rule ensures validation is always required before the rewrite is done. Found that different combinations of apache modules changed the behavior, thus the accepted answer may not always work.
<Location />
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
</Location>
<Directory /documentroot>
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule (.*) http://xxxxxx:xxx/$1 [P,L]
</Directory>

<Directory /var/www/html/>
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
RewriteRule ^/(.*) http://xxxxxx:xxx/$1 [P,L]
</Directory>
There are 2 issues here that will prevent your RewriteRule from doing anything:
You need to enable the rewrite engine inside the <Directory> container (a directory context). You've (incorrectly) enabled the rewrite engine in the outer <VirtualHost> container (a virtualhost context) - in which you don't have any mod_rewrite directives. The <VirtualHost> and <Directory> containers work in different contexts. If you don't enable the rewrite engine inside the <Directory> container then the directives will simply be ignored.
RewriteEngine On
When used in a directory context (<Directory> and .htaccess) the URL-path matched by the RewriteRule pattern does not start with a slash, since the directory-prefix (that ends in a slash) has been removed. So, you need to remove the slash prefix from the regex, otherwise, it will simply never match in a directory context:
RewriteRule (.*) http://xxxxxx:xxx/$1 [P,L]
(The ^ prefix on the pattern then becomes superfluous.)
Summary
Actioning the above points, this becomes:
<Directory /var/www/html/>
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
RewriteEngine On
RewriteRule (.*) http://xxxxxx:xxx/$1 [P,L]
</Directory>
Alternatively, you move the RewriteRule directive outside of the <Directory> container and use this directly inside the <VirtualHost> container in which you've already enabled the rewrite engine.
However, in this context, the mod_rewrite directives will execute before the authorisation directives inside the <Directory> container, so you will need the additional condition that checks the REMOTE_USER via a look-ahead (ie. LA-U:REMOTE_USER), as mentioned in the other answers.

Related

Exclude a file in a directory from apache .htaccess password protected site

I have password protect my application directory but for some reason i have to give a public access to a file in a folder. i research and tried many ways but its not working. Following is my code.
# Welcome to your htaccess file.
# Remember that modifying this file can break the entire website
# so please edit carefully.
RewriteEngine On
RewriteBase /cms
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /cms/index.php/$1 [L]
<IfModule mod_env.c>
SetEnv CI_ENV production
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /home/root/.htpasswd
require valid-user
# allow public access to the following resources
#SetEnvIf Request_URI "(folder/)$" allow
#SetEnvIf Request_URI "(path/folder\file.php)$" allow-Uri
# Deny by default
# Order deny,allow
# Deny from all
Order allow,deny
#Allow from env=allow-Uri
<Files "path\to\file.php">
Allow from all
</Files>
Satisfy ANY
My project folder structure is as follow:
root-folder
--sub-folder
--file.php
ScreenShot:
https://ibb.co/R9j0QTW
Here is how it should be done:
SetEnvIfNoCase Request_URI "^/path/to/file\.php" ALLOW_URI
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /home/root/.htpasswd
Require valid-user
Satisfy any
Order deny,allow
Deny from all
Allow from env=ALLOW_URI

.htaccess RewriteRule php redirect folder to another

I have a folder test. If a person navigates to the folder test, I want the browser to display new.
The folder new doesn't exist on the server, I just want it to be displayed as new, which on the server is linked to the folder test.
This is my config (httpd-vhosts.conf):
<VirtualHost server.com>
DocumentRoot "c:/www/"
ServerName server.com
Alias /new "c:/www/test"
<Directory "c:/www/">
Options +Indexes +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
So, to be clear, if someone browses to:
server.com/test (the server uses folder test, but server.com/new is shown in the browser.
server.com/ (the same as above => server.com/new is shown in the browser)
server.com/index.php (the server uses index.php from folder test, browser shows server.com/new/index.php
server.com/test/index.php (the same as above)
server.com/test/folder2/index.php?variable=1 (the server uses index.php from folder test/folder2 and gives the variables to the php file. browser shows server.com/new/folder2/index.php?variable=1)
I have tried different .htaccess rewrites, but I can't get it working.
Maybe I don't have to use the alias?
Don't just give me a link to the apache manual, because I've read it, but can't get it to work...
You don't need Alias for this so comment out:
Alias /new "c:/www/test"
Then have these rules:
<VirtualHost server.com>
DocumentRoot "c:/www/"
ServerName server.com
<Directory "c:/www/">
Options +Indexes +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
DirectoryIndex index.php
RewriteEngine On
RewriteRule ^/?$ /new/ [L,R=301]
RewriteCond %{THE_REQUEST} \s/+test(\S*)\s [NC]
RewriteRule ^ /new%1 [R=301,NE,L]
RewriteRule ^/?new(/.*)?$ /test$1 [L,NC]
</VirtualHost>

Redirect all to https://www.example.com

OK, so I know that nearly every variety of this question has been asked and answered on this forum, and many others, but I just can't seem to get it right. My hope is that if I provide enough specifics, including the process I'm following, that someone will be able to spot my error and correct me. Here goes!
The Specifics
Drupal multi-site
Apache web server
Sites provisioned by Aegir
What I want to accomplish vs what I have accomplished
I want to direct all http and https traffic to https://www.example.com. The following examples marked with a + have been accomplished; the one marked with - eludes me:
+ http://example.com -> https://www.example.com
+ http://www.example.com -> https://www.example.com
+ https://www.example.com -> https://www.example.com #redundant, but at least we know it works
- https://example.com -> https://www.example.com
What I'm doing
Each site has a vhost file generated by Aegir, and each of these vhost files contains two VirtualHost directives:
<VirtualHost 0.0.0.0:443>
<VirtualHost *:80>
I've modified example.com's vhost file to include the following code under the <VirtualHost *:80> directive, which has successfully achieved the three working examples above:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule (.*) https://www.example.com$1 [R=301,L]
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</IfModule>
The Problem
What I can't seem to figure out is how to enact the https://example.com -> https://www.example.com rewrite. I've tried many examples found on the Internet under both the <VirtualHost 0.0.0.0:443> and <VirtualHost *:80> directives with no luck.
Also, I'm reloading Apache and clearing my browser's cache after each edit of the vhost file. Any insight, guidance or correction would be much appreciated.
Thanks to all!
Edit:
Below is a redacted version of my vhost file:
<VirtualHost 0.0.0.0:443>
DocumentRoot /var/www/drupal
ServerName example
SetEnv db_type mysql
SetEnv db_name example
SetEnv db_user example
SetEnv db_passwd 1234567
SetEnv db_host somedb
SetEnv db_port 1234
# Enable SSL handling.
SSLEngine on
SSLCertificateFile /ssl.d/example/example.crt
SSLCertificateKeyFile /ssl.d/example/example.key
SSLCertificateChainFile /ssl.d/example/example_chain.crt
ServerAlias example.com
ServerAlias www.example.com
<IfModule mod_rewrite.c>
RewriteEngine on
# this isn't working; neither has anything else that I've tried here.
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
# Extra configuration from modules:
# Error handler for Drupal > 4.6.7
<Directory "/var/www/drupal/sites/example/files">
<Files *>
SetHandler This_is_a_Drupal_security_line_do_not_remove
</Files>
Options None
Options +FollowSymLinks
# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
php_flag engine off
</IfModule>
</Directory>
# Prevent direct reading of files in the private dir.
# This is for Drupal7 compatibility, which would normally drop
# a .htaccess in those directories, but we explicitly ignore those
<Directory "/var/www/drupal/sites/example/private/" >
<Files *>
SetHandler This_is_a_Drupal_security_line_do_not_remove
</Files>
Deny from all
Options None
Options +FollowSymLinks
# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
php_flag engine off
</IfModule>
</Directory>
</VirtualHost>
<VirtualHost *:80>
DocumentRoot /var/www/drupal
ServerName example
SetEnv db_type mysql
SetEnv db_name example
SetEnv db_user example
SetEnv db_passwd 1234567
SetEnv db_host somedb
SetEnv db_port 1234
ServerAlias example.com
ServerAlias www.example.com
<IfModule mod_rewrite.c>
# these rules work for everything except:
# https://example.com -> https://www.example.com
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule (.*) https://www.example.com$1 [R=301,L]
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</IfModule>
# Extra configuration from modules:
# Error handler for Drupal > 4.6.7
<Directory "/var/www/drupal/sites/example/files">
<Files *>
SetHandler This_is_a_Drupal_security_line_do_not_remove
</Files>
Options None
Options +FollowSymLinks
# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
php_flag engine off
</IfModule>
</Directory>
# Prevent direct reading of files in the private dir.
# This is for Drupal7 compatibility, which would normally drop
# a .htaccess in those directories, but we explicitly ignore those
<Directory "/var/www/drupal/sites/example/private/" >
<Files *>
SetHandler This_is_a_Drupal_security_line_do_not_remove
</Files>
Deny from all
Options None
Options +FollowSymLinks
# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
php_flag engine off
</IfModule>
</Directory>
</VirtualHost>
OK now I get it with the content of your virtualhost.
This is not valid:
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Actually you can't use %{HTTP_HOST} or %{REQUEST_URI} in the RewriteRule part
That's why it's redirecting you to a non-existent host, hence the connection refused error.
You should use this rule in the ssl virtualhost:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule (.*) https://www.example.com$1 [R=301,L]
And this one in the non ssl one:
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule (.*) https://www.example.com$1 [R=301,L]
HTH

How to make Basic Auth exclude a rewritten URL

I have a Basic Authentication setup on a development server. It is setup inside my httpd.conf file for the VirtualHost of the website. I've had to set up it to exclude certain directories, which has caused no problems and all works fine.
The issue has been with excluding a URL that has been through my mod_rewrite rules in the .htaccess file. My set up is that I have all URLs going through my index.php file and from there the relevant code is found and ran. I tried adding the URL that I wanted to exclude (/businesses/upload_logo) like I did the others but it still requires authentication. This is what I currently have:
...
<Location />
SetEnvIf Request_URI "/businesses/upload_logo" noauth=1
SetEnvIf Request_URI "/api/.*" noauth=1
AuthType Basic
AuthName "Private"
AuthUserFile ****
Require valid-user
Order deny,allow
Satisfy any
Deny from all
Allow from env=noauth
</Location>
....
I have found questions that are similar to mine here & here but the answers only give me what I'm already trying.
I have thought of possible other solutions as well, but these will be last resort things. I want to see if it's possible the way I'm currently doing it:
Set up the basic auth inside my php code instead
Too much hassle at the moment
Put the authentication in my .htaccess file instead
Didn't want to do this just yet as I only want the authentication to happen on one of 3 servers. I'm aware that I could use some more SetEnvIf HOST ... but I'm looking to see if it can be fixed this way or not first.
The mod_rewrite rule:
...
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php [L,QSA]
Try adding
Allow from env=REDIRECT_noauth
For me something like this works like a charm:
<location />
SetEnvIf Request_URI "/businesses/upload_logo" REDIRECT_noauth=1
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/passwords/passwords
Order Deny,Allow
Satisfy any
Deny from all
Allow from env=REDIRECT_noauth
Require user yournickname
</location>
based on what you have given it should work, unless there is a conflicting directive somewhere else in your configuration.
i have made a similar working setup , just i have used filesystem path instead of URI
i am adding it here, hoping you may find it useful
<VirtualHost *:8989 >
<IfModule mod_auth_basic.c>
<Directory /var/www/html/vella-8989>
# the auth block
AuthType Basic
AuthName "Please login."
AuthUserFile /var/www/html/vella-8989/.htpasswd
require valid-user
Order Deny,Allow
Satisfy any
Deny from all
Require valid-user
Allow from env=noauth
</Directory>
</IfModule>
# set an environtment variable "noauth" if the request has "/callbacks/"
SetEnvIf Request_URI "/callbacks/" noauth=1
ServerName vella.com
ServerSignature off
</VirtualHost>

Apache + Tomcat with mod_proxy - redirect to www not working

I have a problem trying to rewrite the root of my web from mywebsite.com/mywebsite to www.mywebsite.com/mywebsite.
The problem is related to the use of mod_proxy to invoke Tomcat
File proxy.conf
<ifmodule mod_proxy.c>
ProxyRequests Off
ProxyPreserveHost On
<proxy *>
AddDefaultCharset off
Order deny,allow
Allow from all
</proxy>
ProxyVia On
ProxyPass /mywebsite ajp://91.222.222.222:8009/mywebsite
ProxyPassReverse /mywebsite ajp://91.222.222.222:8009/mywebsite
<location miaplicacion>
Order allow,deny
Allow from all
</location>
</ifmodule>
File .htaccess
RewriteCond %{HTTP_HOST} !^www.mywebsite.com [NC]
RewriteRule ^(.*)$ http://www.mywebsite.com/$1 [NC,L,R=301]
The point is that the rule works OK if I write mywebsite.com/something. In this case it's correctly redirected to www.mywebsite.com/something
However It seems as if the proxy has preference over what is written in the rewrite rules. That is to say, when it finds mywebsite.com/mywebsite, instead of rewriting it to www.mywebsite.com/mywebsite and then invoke Tomcat, it calls it inmediately without touching the URL.
Do you know any way to force the rewriting of the URL before proxying to Tomcat?
Try this as your first line:
RewriteCond %{HTTP_HOST} ^mywebsite.com$ [NC]