Apache rewrite rule with 1 AND and 8 OR conditions - mod-rewrite

I have a situation where I need to apply 8 rewritecond in apache and exclude 1 IP from those 8 conditions.
By default, the Rewrite condition follow [AND].
Now, how do I write the rule:
A [AND] (B [OR] C [OR] D [OR] E [OR] F [OR] G [OR] H [OR] I)
Let me know in case my question is not clear.
Thanks in advance.

Put your [OR] conditions first. Here is an example :
RewriteCond %{REQUEST_URI} /a/ [OR]
RewriteCond %{REQUEST_URI} /b/ [OR]
RewriteCond %{REQUEST_URI} /c/ [OR]
(...)
RewriteCond %{REQUEST_URI} /y/ [OR]
RewriteCond %{REQUEST_URI} /z/
RewriteCond %{REQUEST_URI} ^/glossary/
RewriteRule ^/glossary/([a-z])/ glossary.php?letter=$1 [L]
With explicit parenthesis, you've got this :
(((((((B [OR] C) [OR] D) [OR] E) [OR] F) [OR] G) [OR] H) [OR] I) [AND] A

Related

preflight OPTIONS check gives 403 with Access-Control-Allow-Origin ”*”

I have a single page app served on one subdomain and an api on another. I get a 403 Forbidden on the pre-flight check for an XHR POST to the api.
Debugging it in curl shows:
curl -H "Host: backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com" \
-H "Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type" \
-X OPTIONS --verbose http://backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com/api/users
* Trying 54.153.79.158...
* TCP_NODELAY set
* Connected to backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com (54.153.79.158) port 80 (#0)
> OPTIONS /api/users HTTP/1.1
> Host: backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
> User-Agent: curl/7.54.0
> Accept: */*
> Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: content-type
>
* HTTP 1.0, assume close after body
< HTTP/1.0 403 Forbidden
< Date: Fri, 04 May 2018 21:16:52 GMT
< Server: Apache/2.4.27 (Red Hat) OpenSSL/1.0.1e-fips
< Cache-Control: no-cache, private
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Headers: accept, access-control-allow-origin, content-type
< Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
< Content-Length: 18
< Content-Type: text/html; charset=UTF-8
< Set-Cookie: 45fe47f0bb613513b8e98d0599b628f9=dd4b5c95b51d6168419458748b392421; path=/; HttpOnly
* HTTP/1.0 connection set to keep alive!
< Connection: keep-alive
<
* Connection #0 to host backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com left intact
Origin not allowed
Yet the Access-Control-Allow-Origin: * in the response suggests that it should allow the Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com named the request.
If I drop the Origin header from the request I get a 200.
I tried explicitly setting the Access-Control-Allow-Origin on the server to match match the Origin of the request but that also gets back a 403:
curl -H "Host: backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com" \
-H "Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type" \
-X OPTIONS --verbose http://backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com/api/users
* Trying 54.153.79.158...
* TCP_NODELAY set
* Connected to backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com (54.153.79.158) port 80 (#0)
> OPTIONS /api/users HTTP/1.1
> Host: backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
> User-Agent: curl/7.54.0
> Accept: */*
> Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: content-type
>
* HTTP 1.0, assume close after body
< HTTP/1.0 403 Forbidden
< Date: Fri, 04 May 2018 21:32:52 GMT
< Server: Apache/2.4.27 (Red Hat) OpenSSL/1.0.1e-fips
< Cache-Control: no-cache, private
< Access-Control-Allow-Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
< Access-Control-Allow-Headers: accept, access-control-allow-origin, content-type
< Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
< Content-Length: 18
< Content-Type: text/html; charset=UTF-8
< Set-Cookie: 45fe47f0bb613513b8e98d0599b628f9=a913ecc9ded73c3ac76fbb38d93e15a7; path=/; HttpOnly
* HTTP/1.0 connection set to keep alive!
< Connection: keep-alive
<
* Connection #0 to host backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com left intact
Origin not allowed
On the server the .htaccess has the following configuration:
<IfModule mod_headers.c>
Header add Access-Control-Allow-Origin "http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com"
Header add Access-Control-Allow-Headers "accept, access-control-allow-origin, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
</IfModule>
Setting the Access-Control-Allow-Origin to "*" doesn't fix the issue.
Why is the response 403 forbidden when the origin seems to be allowed and how might I fix it?
Thanks!
UPDATE
Here is my latest .htaccess which is for the laravel PHP backend:
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
<IfModule mod_headers.c>
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "*"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
</IfModule>
As #roryhewitt suggested in a comment to the question this wasn't an apache .htaccess issue. The problem was the backend API laravel app was giving 403 to any CORS request.
I deleted the mod_headers.c configuration and configured the barryvdh/laravel-cors module used by the backend app using an environment variable CORS_ALLOWED_ORIGINS=frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com. This sets the allowedOrigins as shown here.

Rewrite Rule with dynamic link

I am trying rewrite rule:
From: http://example.com/login.php?new="dynamic string"
To: http://example.com/signup/?new_user="dynamic string"
My code:
RewriteRule ^login.php(.*)$ /signup/$1
But I cant get right result... I get:
http://example.com/?new_user="dynamic string"
Worked for me:
RewriteCond %{QUERY_STRING} new=(.*)
RewriteRule ^login.php(.*)$ /signup/?new_user=%1 [R=301,L]

Running a bash command from a directory

I'm encountering an issue where a command (a drush profile, to be exact) needs to be run within a created directory automatically. I can't find much advisement within the script itself running it as an argument, and the logic i've been instructed by my superiors seems to suggest this as the best approach.
Here is what the bash script does:
It creates the directory structure and some Apache2 files for a Drupal install
It creates a rudimentary Drush profile that is then used by the utility to
Autoinstall Drupal and modules by running the alias "standardprofile" within a directory containing this profile file
The actual commands I use to run the script from Bash (full scripts below) are
cd /var/www/$DOMAINNAME-dev.$URL
eval "standardprofile"
The above lines don't run the script (or anything past the first starting line, and then then bash script resumes) Is there a better way to instruct a bash script to run a command from the specified directory and then resume once any other utilities being run in the foreground finish?
#!/bin/bash
# Creates the proper staging and development environment for a site
# Init
URL=example.com #URL used in creating directories
OMIT_STAGING="n" #Set to true if omitting staging
DOMAINNAME=""
###
# FUNCTIONS
###
function generate_empty_dirs {
mkdir /var/www/$1-staging.$URL
mkdir /var/www/$1-dev.$URL
mkdir /var/www/$1-staging.$URL/logs
mkdir /var/www/$1-staging.$URL/public_html
mkdir /var/www/$1-dev.$URL/logs
mkdir /var/www/$1-dev.$URL/public_html
}
function generate_drupal_staging_apacheconf {
echo "<VirtualHost *:80>
ServerAdmin webmaster#example.com
ServerName $1-staging.$URL
DocumentRoot /var/www/$1-staging.$URL/public_html
<Directory /var/www/$1-staging.$URL/public_html>
Options -MultiViews +ExecCGI
Order allow,deny
Allow from all
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=\$1 [L,QSA]
</Directory>
LogLevel warn
ErrorLog /var/www/$1-staging.$URL/logs/error.log
CustomLog /var/www/$1-staging.$URL/logs/access.log combined
# enable PHP error logging
php_flag log_errors on
php_value error_log /var/www/$1-staging.$URL/logs/php_errors.log
# Possible LogLevel values include: debug, info, notice, warn, error, crit,
# alert, emerg.
</VirtualHost>" > /etc/apache2/sites-available/$1-staging.$URL
}
function generate_drupal_dev_apacheconf {
echo "<VirtualHost *:80>
ServerAdmin webmaster#example.com
ServerName $1-dev.$URL
DocumentRoot /var/www/$1-dev.$URL/public_html
<Directory /var/www/$1-dev.$URL/public_html>
Options -MultiViews +ExecCGI
Order allow,deny
Allow from all
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=\$1 [L,QSA]
</Directory>
LogLevel warn
ErrorLog /var/www/$1-dev.$URL/logs/error.log
CustomLog /var/www/$1-dev.$URL/logs/access.log combined
# enable PHP error logging
php_flag log_errors on
php_value error_log /var/www/$1-dev.$URL/logs/php_errors.log
# Possible LogLevel values include: debug, info, notice, warn, error, crit,
# alert, emerg.
</VirtualHost>" > /etc/apache2/sites-available/$1-dev.$URL
}
function generate_wordpress_staging_apacheconf {
echo "<VirtualHost *:80>
ServerAdmin webmaster#example.com
ServerName $1-staging.$URL
DocumentRoot /var/www/$1-staging.$URL/public_html
<Directory /var/www/$1-staging.$URL/public_html>
Options -MultiViews +ExecCGI
Order allow,deny
Allow from all
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</Directory>
LogLevel warn
ErrorLog /var/www/$1-staging.$URL/logs/error.log
CustomLog /var/www/$1-staging.$URL/logs/access.log combined
# enable PHP error logging
php_flag log_errors on
php_value error_log /var/www/$1-staging.$URL/logs/php_errors.log
# Possible LogLevel values include: debug, info, notice, warn, error, crit,
# alert, emerg.
</VirtualHost>" > /etc/apache2/sites-available/$1-staging.$URL
}
function generate_wordpress_dev_apacheconf {
echo "<VirtualHost *:80>
ServerAdmin webmaster#example.com
ServerName $1-dev.$URL
DocumentRoot /var/www/$1-dev.$URL/public_html
<Directory /var/www/$1-dev.$URL/public_html>
Options -MultiViews +ExecCGI
Order allow,deny
Allow from all
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</Directory>
LogLevel warn
ErrorLog /var/www/$1-dev.$URL/logs/error.log
CustomLog /var/www/$1-dev.$URL/logs/access.log combined
# enable PHP error logging
php_flag log_errors on
php_value error_log /var/www/$1-dev.$URL/logs/php_errors.log
# Possible LogLevel values include: debug, info, notice, warn, error, crit,
# alert, emerg.
</VirtualHost>" > /etc/apache2/sites-available/$1-dev.$URL
}
function generate_drupal_drush_dev_profile {
# Dev
echo " <?php
\$db_engine = 'mysql';
\$db_name = '$1_db';
\$db_user = '$1_user';
\$db_pw = '1password';
\$db_su = 'root';
\$db_su_pw = '';
\$site_name = '$1';
\$account_name = 'admin';
\$account_pw = 'example';
\$account_mail = 'example#example.com';
\$site_mail = \$account_mail;" > /var/www/$1-dev.$URL/installsettings.php
}
function generate_drupal_drush_staging_profile {
#Staging
echo " <?php
\$db_engine = 'mysql';
\$db_name = '$1_db';
\$db_user = '$1_user';
\$db_pw = '1password';
\$db_su = 'root';
\$db_su_pw = '';
\$site_name = '$1';
\$account_name = 'admin';
\$account_pw = 'example';
\$account_mail = 'example#example.com';
\$site_mail = \$account_mail;" > /var/www/$1-staging.$URL/installsettings.php
}
function alter_group_owner {
chown -R www-data /var/www/$1-staging.$URL
chgrp -R www-data /var/www/$1-staging.$URL
chown -R www-data /var/www/$1-dev.$URL
chgrp -R www-data /var/www/$1-dev.$URL
chown -R www-data /etc/apache2/sites-available/$1-staging.$URL
chgrp -R www-data /etc/apache2/sites-available/$1-staging.$URL
chown -R www-data /etc/apache2/sites-available/$1-dev.$URL
chgrp -R www-data /etc/apache2/sites-available/$1-dev.$URL
}
###
# BEGIN MAIN LOGIC
###
# Checks to see if user is Root or is using Sudo, otherwise exit
if [ $(id -u) != 0 ]
then
echo "You must have elevation to run this script."
exit 1
fi
# Prompts for name of site
if [ -z "$1" ]
then
read -p "Domain for the new site: " DOMAINNAME
if [ ! -z $DOMAINNAME ]
then
echo "Generating the empty directories now..."
generate_empty_dirs $DOMAINNAME
else
echo "You must provide a valid domain name"
exit 1
fi
else
generate_empty_dirs $1
DOMAINNAME=$1
fi
# Determine the kind of site being generated
read -p "Is this a (D)rupal or a (W)ordPress site? " SITETYPE
read -p "Do you need both the dev and staging sites? [Y/N] (case sensitive): " NEEDDIRS
if [ -n "$SITETYPE" ]
then
if [ "$SITETYPE" == "D" ]
then
generate_drupal_dev_apacheconf $DOMAINNAME
generate_drupal_drush_dev_profile $DOMAINNAME
rm /var/www/$DOMAINNAME-dev.$URL/public_html
rm /var/www/$DOMAINNAME-dev.$URL/logs
cd /var/www/$DOMAINNAME-dev.$URL
eval "standardprofile"
if [ "$NEEDDIRS" == "Y" ]
then
generate_drupal_staging_apacheconf $DOMAINNAME
generate_drupal_drush_staging_profile $DOMAINNAME
cd /var/www/$DOMAINNAME-staging.$URL
eval "standardprofile"
OMIT_STAGING="n"
else
OMIT_STAGING="y"
fi
elif [ "$SITETYPE" == "W" ]
then
generate_wordpress_dev_apacheconf $DOMAINNAME
if [ "$NEEDDIRS" == "Y" ]
then
generate_wordpress_staging_apacheconf $DOMAINNAME
OMIT_STAGING="n"
else
OMIT_STAGING="y"
fi
else
echo "Invalid option provided"
exit 1
fi
else
echo "No option provided"
exit 1
fi
alter_group_owner $DOMAINNAME
# Load the new confs into Apache
if [ "$OMIT_STAGING" == "y" ]
then
a2ensite $DOMAINNAME-dev.$URL
rm -rf /var/www/$DOMAINNAME-staging.$URL
else
a2ensite $DOMAINNAME-dev.$URL
a2ensite $DOMAINNAME-staging.$URL
fi
# Reload apache
service apache2 reload
# All done
echo "Sites created at domains:"
if [ "$OMIT_STAGING" == "y" ]
then
echo $DOMAINNAME-dev.$URL
else
echo $DOMAINNAME-dev.$URL
echo $DOMAINNAME-staging.$URL
fi
exit
#End of script
And the drush script
#!/usr/bin/env drush
$a = drush_get_arguments();
$current_directory = getcwd();
$profiles = substr($a[1], 0, strlen($a[1])-15) . 'standard.make';
if(file_exists($current_directory . '/installsettings.php')) {
require_once($current_directory . '/installsettings.php');
}
drush_print("Time to prepare our site install...");
if(!file_exists('logs')) {
drush_op_system('mkdir logs');
}
if(!file_exists('public_html')) {
$prev = drush_get_context('DRUSH_AFFIRMATIVE');
drush_set_context('DRUSH_AFFIRMATIVE', TRUE);
drush_invoke('make', array($profiles, 'public_html'));
drush_op_system('cp public_html/sites/all/modules/services/servers/rest_server/lib/spyc/spyc.php public_html/sites/all/modules/services/servers/rest_server/lib/spyc.php');
#drush_shell_exec('cd public_html');
#shell_exec('cd public_html');
chdir('public_html');
drush_invoke_process("#self","site-install",null,array(
'db-url' => $db_engine . "://" . $db_user . ":" . $db_pw . "#localhost/" . $db_name,
'account-name' => $account_name,
'account-pass' => $account_pw,
'account-email' => $account_mail,
'db-su' => $db_su,
'db-su-pw' => $db_su_pw,
'site-mail' => $site_mail,
'site-name' => $site_name,
'clean-url' => FALSE,
));
drush_invoke_process("#self","pm-enable",
array('ctools', 'views', 'views_ui', 'features', 'strongarm', 'fe_block',
'entity', 'token', 'module_filter', 'pathauto', 'devel', 'simplehtmldom',
'services', 'rest_server', 'entity_token', 'date', 'date_api', 'date_tools',
'date_views', 'date_popup','rules', 'rules_admin', 'views_slideshow',
'views_slideshow_cycle', 'strongarm', 'diff', 'auto_nodetitle', 'libraries',
'realname', 'views_php'),
array('root' => $current_directory . '/public_html'));
drush_set_context('DRUSH_AFFIRMATIVE', $prev);
}
Is there a better way to instruct a bash script to run a command from the specified directory and then resume once any other utilities being run in the foreground finish?
Sure:
( cd $dir && cmd )
will run cmd from the specified directory. Since the two commands are run in a subshell, the script will resume in its present directory when the subshell completes.
This should work:
cd /var/www/$DOMAINNAME-dev.$URL
/usr/bin/env drush "standardprofile"

modRewrite custom redirect

How to rewrite if %{REQUEST_URI} begins with %{HTTP_HOST} ?
i.e. http://example.com/example.com_custom_text -> http://example.com/index.php?q=special&info=example.com_custom_text
Usage of %{HTTP_HOST} is important due to universality.
Does not work:
RewriteCond %{REQUEST_URI} ^%{HTTP_HOST}
RewriteRule ^(.*)$ index.php?q=special&info=$1 [L,QSA]
You can't have % variables in the expression (the 2nd part) of a RewriteCond. But you can use a \1 to backreference the same match, and combine the URI and host, like so:
RewriteCond %{HTTP_HOST};%{REQUEST_URI} ^([^|]+);/\1
So if a request is made for: http://example.com/some_path:
%{HTTP_HOST};%{REQUEST_URI} = example.com;some_path
^([^|]+) matches example.com and \1!=some_path
If a request is made for: http://example.com/example.com_some_path:
%{HTTP_HOST};%{REQUEST_URI} = example.com;example.com_some_path
^([^|]+) matches example.com and \1 matches the beginning of example.com_some_path

RewriteRule - loop redirection

i need help with this 2 rewrite rules:
RewriteEngine On
RewriteBase /
# folder/script.php?A=1&B=2 -> xyz/1/2 (REDIRECT)
RewriteCond %{QUERY_STRING} ^A=([^&]+)&B=([^&]+)$
RewriteRule ^folder\/script\.php$ /xyz/%1/%2? [R=301,L]
# xyz/1/2 -> folder/script.php?A=1&B=2 (REWRITE)
RewriteRule ^xyz\/([^\/]+)\/([^\/]+)$ /folder/script.php?A=$1&B=$2 [L]
First I need "REDIRECT"
FROM: efectorelativo.net/folder/script.php?A=1&B=2
TO: efectorelativo.net/xyz/1/2
Then i need "REWRITE" not "REDIRECT"
FROM: efectorelativo.net/xyz/1/2
TO: efectorelativo.net/folder/script.php?A=1&B=2
EDIT: (working code, thanks to Gumbo)
RewriteEngine On
RewriteBase /
# folder/script.php?A=1&B=2 -> xyz/1/2 (REDIRECT)
RewriteCond %{THE_REQUEST} \?A=([^&]+)&B=([^\s&]+)
RewriteRule ^folder\/script\.php$ /xyz/%1/%2? [R=301,L]
# xyz/1/2 -> folder/script.php?A=1&B=2 (REWRITE)
RewriteRule ^xyz\/([^\/]+)\/([^\/]+)$ /folder/script.php?A=$1&B=$2 [L]
Inspect the request line in THE_REQUEST instead of the current URL:
# folder/script.php?A=1&B=2 -> xyz/1/2 (REDIRECT)
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /[^?\ ]*\?A=([^&]+)&B=([^&\ ]+)\
RewriteRule ^folder/script\.php$ /xyz/%1/%2? [R=301,L]

Resources