How do I get if directives to read variables from ldap? - apache

I am trying to set an SSO request based on specific variables, in a way that multiple users will have the same account.
For example If their first name is Robert then it would try to login as user robert. etc..
I have apache working in every way except the if statement seems to be seeing the variables as null.
here is what i am trying to do, but the if statement fails.
<Location "/">
AuthType Basic
...other auth ldap stuff
Require ldap-user %{variable-redacted}
RequestHeader set Name %{env:AUTHORIZE_FirstName}s
</Location>
<If "%{env:AUTHORIZE_FirstName} in { 'Robert', 'John', 'Steve' }">
RequestHeader set User "Admin"
</If>
<Else>
RequestHeader set User "User"
</Else>
So far everything works. Except the if statement evaluates false. I tried several methods here and i'm pretty sure it sees the variable as (null)
What really confuses me is if i use this:
<If "%{variableName} != 'John'">
RequestHeader set user %{variableName}s
</If>
it will actually set the request header to the variable information.
So what is happening? Why does the if statement fail, but the variable works in the failed if statement?!?!
UPDATE: I will leave this question open if some one figures it out. But in the mean time, I have found a way. Since RewriteCond and RewriteRule are handled in order, as expected, I created a solution for them.
First it sets a variable to the "least precise" username, and then if there is more details i can keep adding rules. and my final rewritecond will check if they are an admin, and correct the user. Then finally sets the requestheader based on the user variable. Once a requestheader is set, it needs to be removed to replace it. but variables can be changed over and over. - I have to say, after this, apache will not be my choice if i can avoid it.

Related

Rewrite directory path based on authentication data

I'm trying to provide my users a unique directory under one common URL (https://example.com/sync). Previously I managed this with a rewrite rule which just appended the remote users name to the root directory for "sync". Now, the users login ID differs from the directory name. As per apache documentation, authn_dbd provides additionally returned columns in extra variables with the prefix AUTHENTICATE_.
<Directory "/srv/www/sync/">
AuthDBDUserPWQuery "SELECT passphrase, identifier FROM webserver.fn_authenticate_context('SYNC') where login_id = %s"
RewriteEngine On
RewriteCond %{AUTHENTICATE_IDENTIFIER} ^(.+)$
RewriteRule ^\/(.*)$ /%{AUTHENTICATE_IDENTIFIER}/$1 [NS,L]
</Directory>
This should provide the required identifier for my rewrite rule. However, the identifier seems not to be available when rewriting occurs. Adding a header with the content to the response works and provides the content.
Activating logs up to trace8 shows that authentication is processed first and afterwards the rewrite conditions are processed but the value is still empty.
After searching around for quite a while, I found no reliable way to use the different "features" of Apache dbd. It produces variables for additionally returned columns - or not. The variables are available in CGI but not before or even not there. Errors are only logged during startup phase and later silently discarded. So if you don't get successful authentication at all, the root cause may be a permission problem. The only way to verify this is by executing the request with the credentials that dbd uses for access to the database.
The solution to my original issue is to forget about the documented option of additional columns from the authentication request and running an additional, separate request to the database. The working snippet:
### Cloud Synchronization (Web DAV service)
Define _SYNC_CLOUD_PREFIX /sync
# We need the rewrite engine here...
RewriteEngine On
# define a rewrite map which looks up the home directory for the user...
RewriteMap dbd_sync_home "dbd:SELECT dir_home FROM webserver.authorize_for_context('SYNC', %s);"
# redirect /sync to /sync/
RedirectMatch permanent ^${_SYNC_CLOUD_PREFIX}$ ${_SYNC_CLOUD_PREFIX}/
# Rewrite /sync/xxx to /srv/www/sync/<domain>/<user>/xxx
RewriteCond %{LA-U:REMOTE_USER} ^(.+)$
RewriteCond %{REQUEST_URI} ^${_SYNC_CLOUD_PREFIX}
RewriteRule ^${_SYNC_CLOUD_PREFIX}/(.*)$ /srv/www/sync/${dbd_sync_home:%{LA-U:REMOTE_USER}}/$1 [L]
# Authorize when hitting the location /sync/
<Location "${_SYNC_CLOUD_PREFIX}/">
DAV On
SSLRequireSSL
Options +FollowSymLinks
AuthType Basic
AuthName "Sync Heaven"
# To cache credentials, put socache ahead of dbd here
AuthBasicProvider socache dbd
AuthnCacheContext www-sync
AuthnCacheProvideFor dbd
# mod_authn_dbd SQL query to authenticate a user
AuthDBDUserPWQuery "SELECT passphrase FROM webserver.authorize_for_context('SYNC', %s);"
Require method OPTIONS
Require valid-user
</Location>
UnDefine _SYNC_CLOUD_PREFIX

Using two environment variables to block access in Apache .htaccess

I'm using SetEnvIf and Deny to block access to certain countries in my .htaccess.
But I need to exclude certain URLs from this blocking, and thus I'm setting another environment variable for those URLs.
How do I Deny based on a combination of variable 1 and variable 2 ?
SetEnvIf GEOIP_COUNTRY_CODE xx BlockedCountry
SetEnvIf Request_URI "^/important" NeverBlock
In pseudo code I want to do this now:
Deny from env=BlockedCountry && !NeverBlock
From Apache documentation :
Syntax: Deny from all|host|env=[!]env-variable
[host|env=[!]env-variable] ...
Which means you can combine conditions one after the other (there is no "boolean" operators in between).
So in your case, it should look like this
Deny from env=BlockedCountry env=!NeverBlock
Update
From what you said, it looks like this implies an OR condition instead of an AND (what you want). To do so, you can use this workaround
SetEnvIf GEOIP_COUNTRY_CODE xx MustBeBlocked
SetEnvIf Request_URI "^/important" !MustBeBlocked
Deny from env=MustBeBlocked
With this technique, you set/unset the environment variable depending on the case, which simulates an AND condition.

Apache 2.2 Allow from env=_variable_

I have an Apache 2.2 set up with LDAP Authorization, which is working fantastically as expected, and have also made it so that I can bypass Authentication when accessing it locally.
Allow from localIP hostnameA hostnameB, etc...
If I curl from the server, I don't get any Auth Required. So all good and working as expected.
What I need now is to make one particular URL to also bypass authorisation.
I have tried all the usual solution of using SetEnvIf;
SetEnvIf Request_URI "^/calendar/export" bypassauth=true`
Allow from env=bypassauth IP_ADDRESS HOSTNAME_A HOSTNAME_B
But this is just not working!!
Local access is still unrestricted, but remotely it is not (no change there)
If I dump out my server environment variables on that URL's script, I can see my bypassauth variable is being passed.
I just cannot for the life of me figure out why the Allow from env=bypassauth part is not working, while it still obeys the additional directive parameters.
I also tried another suggestion, using the Location directive;
<Location /calendar/export>
Satisfy Any
Allow from all
AuthType None
SetEnv WTF 123
</Location>
Again, I can see my new environmental variable (WTF) appear on this URL (when I dumped the server envs in the script), so I know that the SetEnv and SetEnvIf directives are working.
Is there anything I'm missing (any Apache2.2 quirks?), as all the solutions I've seen so far just are not working. It's as if my Allow from changes are having no effect after restarting Apache. I'm starting to feel my sanity slip.
Is there also a particular order when writing the directives for Satisfy Any, Order allow, deny and the Auth* directives, which might be effecting this?
Finally managed to figure it out!! :)
Seems my url was being processed by mod_rewrite (my environmental variable being prefixed by REWRITE_ should have rung alarm bells), which according to this post https://stackoverflow.com/a/23094842/4800587, the mod_rewrite is performed AFTER our SetEnvIf and Allow directives.
Anyway, long story short; I used the rewritten/final URL and the Location section to bypass authentication using the Allow any directive. So I changed...
<Location "/calendar/export">
Allow from all
</Location>
to..
<Location "/calendar/index.php/export">
Allow from all
</Location>
which is the final URL (after rewrite), and now works.

How to block a wildcard subdomain?

So I am able to block specific subdomains like this:
SetEnvIfNoCase Referer knownsub\.sorryspammer\.com sorryspammer
<Location />
Order Allow,Deny
Allow from all
Deny from env=sorryspammer
</Location>
which does successfully block visits to any site on my server that come from the referrer, knownsub.sorryspammer.com
So now, I am getting visits from referrers like 1.sorryspammer.com, 2.sorryspammer.com, 8.sorryspammer.com, 22.sorryspammer.com, etc., and I need to set an environment variable to block any subdomain coming from the referrer domain sorryspammer.com.
I know I need to set the same basic rule for the environment variable but with a wildcard for the subdomain part. I've tried a couple of things, most recently this:
SetEnvIfNoCase Referer (.*)\.sorryspammer\.com sorryspammer
but I am still getting visits from referrers from subdomains on sorryspammer.com. I know I'm missing something real simple. Any help is appreciated. Not sure if it matters, but keep in mind that this is not going in an .htaccess file but is going in the httpd.conf file to apply the rules server wide.

Exclude one folder in htaccess protected directory

I have a directory protected by htaccess. Here is the code I use now:
AuthName "Test Area"
Require valid-user
AuthUserFile "/***/.htpasswd"
AuthType basic
This is working fine. However, I now have a directory inside of this folder that I would like to allow anyone to access, but am not sure how to do it.
I know that it is possible to just move the files outside of the protected directory, but to make a long story short the folder needs to stay inside the protected folder, but be accessible to all.
How can I restrict access to the folder, but allow access to the subfolder?
Just create an .htaccess file in the subdirectory with the content:
Satisfy any
According to this article you can accomplish this by using SetEnvIf. You match each of the folders and files you want to grand access to and define an environment variable 'allow' for them. Then you add a condition that allows access if this environment variable is present.
You need to add the following directives to your .htaccess.
SetEnvIf Request_URI "(path/to/directory/)$" allow
SetEnvIf Request_URI "(path/to/file\.php)$" allow
Order allow,deny
Allow from env=allow
Satisfy any
The accepted answer does not seem to run well with new Apache Versions, since it stopped working as soon as Apache Updates were rolled out on some of my customers servers.
I recommend the following approach:
AuthType Basic
AuthName "NO PUBLIC ACCESS"
AuthUserFile /xxx/.htpasswd
SetEnvIf REQUEST_URI "(path/to/directory/)$" ALLOW
<RequireAny>
Require env ALLOW
Require valid-user
</RequireAny>
I don't have enough reputation to add a comment, but two of these answers use the pattern:
SetEnvIf Request_URI "(path/to/directory/)$" allow
to set an environment variable and then check to see if it exists. The part in the quotes is a regular expression. This statement is saying that any path that ENDS with "path/to/directory/" matches and should set the variable, such as "administrationpath/to/directory/", but not "path/to/directory/index.html". The "$" matches the end of the string.
A better match would be:
SetEnvIf Request_URI "^/path/to/directory/" allow
This means the URI path must begin with "/path/to/directory/" (the caret matches the start of the string) but can have additional content after the trailing slash. Note that this requires the trailing slash. To make it optional you could add two rules:
SetEnvIf Request_URI "^/path/to/directory$" allow
SetEnvIf Request_URI "^/path/to/directory/" allow
or, with more pattern matching:
SetEnvIf Request_URI "^/path/to/directory(/.*)?$" allow
The parenthesis and question mark make an optional group and ".*" means zero or more characters.
Personally, I'd either use require all granted 1 in the subfolder's .htaccess or:
require expr "%{REQUEST_URI} =~ m|^/path/to/directory(/.*)?$|" 2 in the parent's.
For Apache 2.4, create a .htaccess file with the following content:
Require all granted
Place it in the subdirectory you want to allow access to.
There is no need to create a .htaccess in the subdirectory.
Just create as many variables as you need with SetEnvIf directive, and be sure the file or path name you want to allw/deny is part of the URI regex you pass to SetEnvIf, exactly like #Sumurai8 said, but set the regex to fit your needs, for the URI should start/end/contain a set of characters............