How do I set REMOTE_USER in a HTTP header? - apache

I've got an issue with my Apache settings.
I installed a web application that partly accepts external authentication:
I use Apache to manage the access to my application web pages.
If the authentication is successful, the environment variable REMOTE_USER is set with the user's name.
Then the user name is passed to my application through the HTTP header so the application opens on the user session.
This is mostly an Apache configuration for the application. I only set the name of the variable (HTTP header) that contains the username in my application config file.
Here is the issue : I can authenticate successfully (most of the time) but my HTTP header is set to null.
Some additional details :
I use Apache and the mod_perl modules (AuthenNIS + AuthzNIS + Net-NIS) to authenticate to my app with NIS account.
With the following Apache config file I have the authentication form when I try to access my application but the REMOTE_USER header is set to null.
Listen 2208
<VirtualHost *:2208>
RewriteEngine on
DocumentRoot "/path/to/static"
<Directory "/path/to/static">
Options +Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
Allow from all
AuthType Basic
AuthName "Authentifiez vous"
PerlAuthenHandler Apache2::AuthenNIS
PerlAuthzHandler Apache2::AuthzNIS
PerlSetVar AllowAlternateAuth no
require valid-user
</Directory>
RewriteEngine on
RewriteRule . - [E=RU:%{LA-U:REMOTE_USER}]
RequestHeader set REMOTE_USER %{RU}e
RewriteRule ^/apps$ /apps/ [R]
RewriteRule ^/static/style/(.*) /path/to/static/june_2007_style/blue/$1 [L]
RewriteRule ^/static/scripts/(.*) /path/to/static/scripts/packed/$1 [L]
RewriteRule ^/static/(.*) /path/to/static/$1 [L]
RewriteRule ^/favicon.ico /path/to/static/favicon.ico [L]
RewriteRule ^/robots.txt /path/to/static/robots.txt [L]
RewriteRule ^(.*) http://localhost:2209$1 [P]
</VirtualHost>
If I set RequestHeader set REMOTE_USER "username" the application opens on the corresponding user session.
To see the value of REMOTE_USER I use the Firebug Firefox module to display the values of the http header + my application has a script that displays the value of variables passed to it.
I tested an almost identical Apache configuration on an index.php page that displays the values of server variables in a http request. The difference lies in the RewriteRules.
<?PHP
foreach($_SERVER as $key_name => $key_value) {
print $key_name . " = " . $key_value . "<br>";
}
?>
In this case, I get a REMOTE_USER et HTTP_REMOTE_USER with a username value.
I don't understand where my problem lies.
Apache 2.2.31
RedHat 6.5
Thanks in advance !

do NOT use the following, because you will get into trouble with execution phases if the REMOTE_USER is set with a module like mod_authn_ntlm (ntlm with local computer, see https://support.microsoft.com/en-us/kb/896861).
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
RequestHeader set X-Remote-User %{RU}e
instead use the following methods:
RequestHeader set X-Remote-User expr=%{REMOTE_USER}
there is also a solution with mod_ssl
RequestHeader set X-Remote-User %{REMOTE_USER}s

In Apache 2.2 server we gave below configuration. We have C# ASP.NET Core 2.1 application and in our HTTP Request header we get user name like below
<LocationMatch ^/mylocation>
AuthName "NTLM Authentication"
NTLMAuth on
NTLMAuthHelper "/usr/bin/ntlm_auth --helper-protocol=squid-2.5-ntlmssp"
NTLMBasicAuthoritative on
NTLMBasicRealm xxx_yy
AuthType NTLM
require valid-user
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
RequestHeader set X-Remote-User %{RU}e
</LocationMatch>
In our C# ASP.NET Core 2.1 application application we get below in HTTP Request Header
Key: X-Remote-User, Value=xxx_yy\abcdefg

Related

Authentication with apache: pass group as header to application server

I would like to use Apache web server as a reverse proxy in front of an application server to handle authentication.
The idea is that after authentication Apache will pass on the user and group(s) to the app server in request headers.
How can I capture the group(s) of the authenticated user in an environment variable so that I can use it for setting request headers?
I've managed to write the user to a header like so:
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1,NS]
RequestHeader set X-Forwarded-User %{RU}e
I'm assuming it would be similar for groups, but I can't find what variable I should use in RewriteCond. (Or is there another way to do it?)
RewriteCond %{???} (.+) # <--- what variable should I use here
RewriteRule . - [E=RG:%1,NS]
RequestHeader set X-Forwarded-User-Groups %{RG}e
A more complete example of the configuration I'm trying to use:
<VirtualHost *:80>
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
<Location />
AuthType Basic
AuthBasicProvider file
AuthName "Restricted Content"
AuthUserFile "/path/to/userfile"
AuthGroupFile "/path/to/groupfile"
Require group users
Require group admins
RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1,NS]
RequestHeader set X-Forwarded-User %{RU}e
RewriteCond %{???} (.+)
RewriteRule . - [E=RG:%1,NS]
RequestHeader set X-Forwarded-User-Groups %{RG}e
RequestHeader unset Authorization
</Location>
</VirtualHost>
I just had the same issue, and after an extensive search and looking at the mod_authz_groupfile.c source it just doesn't seem possible with just configuration.
The group is not exposed as a variable, and there doesn't seem to be a way to use the require group statement in an expression. You could probably get the group into a variable using the RewriteMap directive to read the AuthGroupsFile again with a custom external command (the default commands like txt aren't sufficient), but that is way complicated and probably slow.
Note that using the file function to read the AuthGroupsFile within an <If> expression will not work, as the expression is evaluated before authentication and thus the value of the REMOTE_USER variable will not yet be available.

Apache ACL based on environment variable value

I have a vendor Apache module (PingFederate) that sets environment variables based on a token it receives. I would like to control access to directories based on the value of an environment variable.
For example the module sets variables like this:
[PF_AUTH_SUBJECT] => aaron
[PF_AUTH_GROUPS] => CN=Application.E18.Users,OU=Internal,DC=local,CN=Application.E17.Users,OU=Internal,DC=local
I want to secure a directory so that only users in group CN=Application.E18... can access it. My location direction conf looks like this:
<Location /example_app>
SetEnvIf %{PF_AUTH_GROUPS} ^.*CN=Application.E18.Users.*$ ALLOWED
AuthName "ACL PingFederate restricted"
AuthType PFApacheAgent
Order Deny,Allow
Deny from all
Allow from all
</Location>
This doesn't seem to work. I've tried:
SetEnvIf %{PF_AUTH_GROUPS} ^.*CN=Application.E18.Users.*$ ALLOWED
SetEnvIf %{PF_AUTH_GROUPS} ^.*Application.*$ ALLOWED
SetEnvIf %{PF_AUTH_GROUPS} ^.*A.*$ ALLOWED
The only thing that works is:
SetEnvIf %{PF_AUTH_GROUPS} ^.*$ ALLOWED
That obviously won't work.
https://issues.apache.org/bugzilla/show_bug.cgi?id=25725 somewhat intimates that SetEnvIf won't test environment variables but the docs at http://httpd.apache.org/docs/2.2/mod/mod_setenvif.html mentions "an environment variable in the list of those associated with the request", which this should be.
I've also tried mod_rewrite using this:
RewriteEngine On
<Location /example_app>
RewriteCond %{PF_AUTH_GROUPS} ^.*Application.E18.Users.*$
RewriteRule - [E=ALLOWED:1]
AuthName "ACL PingFederate restricted"
AuthType PFApacheAgent
Order Deny,Allow
Deny from all
Allow from all
</Location>
In all of these instances the ALLOWED environment variable is not set.
You'll need to make mod_rewrite execute 2 times to be able to leverage the headers produced by mod_pf, since the latter executes after the former:
RewriteEngine On
RewriteCond %{ENV:REDIRECT_PASS} !1
RewriteRule .* $1 [L,E=PASS:1]
RewriteCond %{HTTP:PF_AUTH_GROUPS} !^.*ECN.*$
RewriteRule .* $1 [L,R=401]
This is also documented here: https://ping.force.com/Support/PingIdentityArticle?id=kA340000000Gs7bCAC

Can an htpasswd apply to all URLs except one?

I have an htaccess setup for my domain, but I want one specific URL to not have htpasswd protection. That URL is a rewritten URL and doesn't have an actual directory associated with it.
Is there a way to use the root htaccess to htpasswd protect the entire site except for that one specific URL?
Edit (my code, including Jon Lin's suggestion, which isn't working for me):
RewriteCond %{SERVER_NAME} =subdomain.example.com
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
SetEnvIf Request_URI "^/messenger/parse" NOPASSWD=true
AuthUserFile /xxx/xxx/xxx/xxxxxx/subdomain.example.com/.htpasswd
AuthName "Staging Server"
AuthType Basic
Order Deny,Allow
Satisfy any
Deny from all
Require valid-user
Allow from env=NOPASSWD
You can setup something like SetEnvIf to set an environment variable for a given Request URI. Then in the auth definition, you can use the Satisfy Any and Allow from env directives to tell apache that access can be granted either by authentication or if the environment variable exists (which is only set for a specific URI). Example:
# set the NOPASSWD variable if the request is for a specific URI
SetEnvIf Request_URI "^/specific/uri/nopasswd/$" NOPASSWD=true
# Auth directives
AuthUserFile /var/www/htpasswd
AuthName "Password Protected"
AuthType Basic
Order Deny,Allow
# Any requirment satisfies
Satisfy any
# Deny all requests
Deny from all
# except if user is authenticated
Require valid-user
# or if NOPASSWD is set
Allow from env=NOPASSWD

htaccess: Conditional Authentication

How can i configure this in my apache/htaccess configuration:
I want HTTP-Authentication for all files with one exception.
The files click.php and js/clickheat.js may be accessed from 1.2.3.4 without any authentication.
I tried FilesMatch, but i can't invert it. So i can't put require valid-user in there. I thought using SetEnv, but how do i check for it later?
<FilesMatch "(click\.php|clickheat\.js)">
# what here?
</FilesMatch>
My other idea was to use mod_rewrite. Well, i can allow access to the two files from the given host and deny it from anywhere else. But how do i chain it with HTTP-Authentication?
# allows access to two files from the given IP
RewriteCond %{REMOTE_ADDR} 1\.2\.3\.4
RewriteCond %{REQUEST_URI} ^/click.php [OR]
RewriteCond %{REQUEST_URI} ^/js/clickheat\.js
RewriteRule (.*) - [L]
# denies everything else
RewriteRule (.*) - [F,L]
So my favourite solution would be enabling HTTP-Auth via RewriteCond/RewriteRule.
Background (or why i want to do this): I'm trying to secure a clickheat (http://www.labsmedia.com/clickheat/index.html) installation. And 1.2.3.4 is the remote running mod_proxy and redirecting access to these to files to our clickheat host.
Ok, i found a solution:
Order Deny,Allow
Deny from All
Satisfy Any
AuthType Basic
AuthName "clickheat"
AuthUserFile /var/www/clickheat/.htpasswd
Require valid-user
<FilesMatch "(click\.php|clickheat\.js)">
Deny from All
Allow from 1.2.3.4
</FilesMatch>
The key is the Satisfy Any which allows either IP- or Auth-based access.

Apache .htaccess redirect to HTTPS before asking for user authentication

This is my .htaccess:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
AuthUserFile /etc/hi
AuthName "hi"
AuthType Basic
require valid-user
It asks for user authentication using http, meaning that password will be sent in plain text. It will than redirect to the https version and ask the password again.
How can i fix it?
If you're running Apache 2.4 you can use configuration sections to solve this quite easily.
Eg...
# Redirect to HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
# Authenticate users only when using HTTPS
# Enable for <v2.4
# SSLRequireSSL
# ErrorDocument 403 /secure-folder/
# Enable for >v2.4
<If "%{HTTPS} == 'on'">
AuthType Basic
AuthName "Special things"
AuthUserFile /etc/blah.htpasswd
# Prevent this 'Require' directive from overriding any merged previously
<IfVersion >= 2.4>
AuthMerging And
</IfVersion>
Require valid-user
# Enable for >v2.4
</If>
I get around it this way. Just allow Non-SSL since it will be redirected then require auth once on SSL...
SetEnvIf %{SERVER_PORT} ^80$ IS_NON_SSL
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
AuthUserFile /etc/hi
AuthName "hi"
AuthType Basic
require valid-user
Allow from env=IS_NON_SSL
Thank you very much, Istador!
My Apache is of version 2.2 (Synology NAS DSM 5.1) so these two do not work on it:
RewriteOptions Inherit
IfVersion
After taking them (and the section of version >= 2.4) out. The whole thing began to work for me.
There are a lot suggestions out there for this topic, I spent two days to try them out.
But only this one works for me.
Here's what I did:
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
AuthType Basic
AuthName "private area"
AuthUserFile /path/to/file/.htdigest
Order Deny,Allow
Deny from all
Satisfy Any
Allow from env=!HTTPS
Require valid-user
So it's verified to work on Apache 2.2, Synology DSM 5.1.
The checked solution https://stackoverflow.com/a/15940387/2311074 does work on Firefox on Ubuntu 16.04, but it does not work on Firefox on Win 7.
If you want to protect your folder https://yourdomain.com/securefolder
then you need to create in that folder a .htaccess with the following content:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
SSLRequireSSL
ErrorDocument 403 https://yourdomain.com/securefolder
AuthType Basic
AuthName "Admin"
AuthUserFile /outside/your/www/folder/.htpasswd
Require user admin Admin
The way it works is that when you are calling the website through http:// instead of https:// it will redirect you to the error page. The trick is to use the correct link with the https:// as your default error page.
I'm running Apache 2.2 and none of the above solutions worked for me. I found a workaround for me here. Basically, you need to set SSLRequireSSL and use some script language in the ErrorDocument to forward users to HTTPS. Unfortunately, in my case this only works when accessing particular files on the server, it does NOT work if just the domain is provided. Here is what I did:
AuthType Basic
AuthName "Password Protected Area"
AuthUserFile /my/path/to/.htpasswd
#Require valid-user
<FilesMatch "(^(?!ssl.php).*)">
SSLRequireSSL
ErrorDocument 403 /ssl.php
Require valid-user
</FilesMatch>
The regex in FileMatch tells apache to SSLRequireSSL for all files except ssl.php - and forward the user to ssl.php if he tries to access without SSL.
My ssl.php looks like this:
if(!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "" || $_SERVER['HTTPS'] == "off")
{
$redirect = "https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
header("HTTP/1.1 301 Moved Permanently");
header("Location: $redirect");
exit;
}
What now happens:
Opening http://example.com/some/file.php forwards to
https://example.com/some/file.php and asks for username &
password.
Opening https://example.com/ connects via https and asks for u/p
Opening https://example.com/some/file.php does basically the same.
Opening http://example.com/ forwards to some default apache server page
The last point is what I am not happy with, if someone has a solution for that, I'd be glad to hear about it. Things I tried to solve this issue:
Changed the regular expression to (^$)|(^(?!ssl.php).*) to explicitly also match empty strings. Did not work
Added a rewrite rule to rewrite an empty string to index.php. Does not work either.
Our client's webapp is installed in his webuser directory. Authorisation is handled before mod_rewrite rules (https://serverfault.com/a/443185/253111), and we could not get the accepted answer to work, so mod_rewrite seemed not an option.
Eventually we explicitly required SSL and used the webapp's root over HTTPS as 403 and 404 error documents. So when one visits any page over HTTP (which is unauthorized, hence the 403) or a non existing page (404), he is being redirected to ie. https://DOMAIN.TLD/~WEBUSER/admin.
This is the .htaccess file with some extra info in the comments.
### INFO: Rewrites and redirects are handled after authorisation
### #link https://serverfault.com/a/443185/253111
### INFO: Log out of a HTPASSWD session
### This was not always possible, but Firefox and Chrome seem to end sessions
### when a new one is trying to be using ie.:
### https://logout:logout#DOMAIN.TLD/~WEBUSER/
### #link http://stackoverflow.com/a/1163884/328272
### FORCE SSL: Explicitly require the SSL certificate of a certain domain to
### disallow unsigned certificates, etc. ErrorDocument commands are used to
### redirect the user to an HTTPS URL.
### #link http://forum.powweb.com/showthread.php?t=61566
SSLOptions +StrictRequire
SSLRequireSSL
SSLRequire %{HTTP_HOST} eq "DOMAIN.TLD"
### HTPASSWD AUTHENTICATION
AuthUserFile /var/www/vhosts/DOMAIN.TLD/web_users/WEBUSER/.htpasswd
AuthType Basic
AuthName "Hello"
Require valid-user
### ERROR DOCUMENTS: Redirect user in case of a 403 / 404.
ErrorDocument 403 https://DOMAIN.TLD/~WEBUSER/admin
ErrorDocument 404 https://DOMAIN.TLD/~WEBUSER/admin
Here is the only solution that worked in one of my configurations:
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
<If "%{SERVER_PORT} != '80'">
AuthUserFile /etc/hi
AuthName "hi"
AuthType Basic
require valid-user
</If>
Notably, this is for an Apache 2.4 over which I have no control (shared hosting). It seems that the %{HTTPS} variable is not defined on this config, and any solution based on SSLRequireSSL generated a 500 Internal Server Error.
(Side note: In case you prefer a 403 Forbidden instead of a 301 Permanent Redirect when serving HTTP requests, use RewriteRule ^(.*)$ - [F,L] instead)
Molomby's solution works in 2.4 and higher, but doesn't work with the current Debian version 2.2.22.
Ben's / Chris Heald's solutions also didn't work for me in 2.2.22, but that was due to a different order/satisfy configuration. These settings have changed with 2.4 and the solution seems to be incompatible with 2.4 and above (the redirect works, but the browser is just displaying an unauthorized error without asking for credentials).
Here is a combination of both solutions that should work for versions below and above 2.4:
RewriteEngine on
RewriteOptions Inherit # rewrite rules from parent directories
RewriteCond %{HTTPS} off
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
AuthType Digest
AuthName "private area"
AuthDigestProvider file
AuthUserFile /path/to/file/.htdigest
<IfVersion < 2.4>
Order Deny,Allow
Deny from all
Satisfy Any # reset this to 'All' in custom <Files> and <Directory> directives that block access
Allow from env=!HTTPS
Require valid-user
</IfVersion>
<IfVersion >= 2.4>
<If "%{HTTPS} == 'on'">
AuthMerging And
Require valid-user
</If>
</IfVersion>
Requirements: mod_rewrite, mod_auth, mod_digest, mod_version
None of the above worked for me, but this did. My only concern is if there are certain conditions whereby the auth is not triggered allowing someone access without the credentials. I'm not sure there are, but maybe you bright people may say otherwise.
This code redirects non-www to www and http to https, with .htaccess folder auth.
This is the contents of the htaccess file in the directory you want to protect:
RewriteEngine on
# ensure www.
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/foldername/$1 [L,R=301]
# ensure https
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}/foldername/$1 [L,R=301]
# Apache 2.4 If
<If "%{HTTPS} == 'on' && %{HTTP_HOST} =~ /www/">
AuthType Basic
AuthName "Protected folder"
AuthUserFile "/home/etc/.htpasswds/public_html/foldername/passwd"
require valid-user
</If>