NGINX - Limit access to folder to a list of user from ldap authentication - authentication

A have an nginx reverse proxy behind ldap authentication.
I can read username in php from variable $_SERVER['PHP_AUTH_USER']. I think this means that username is passed from ldap to nginx and than to php.
Is it possible in nginx configuration to allow access to a folder only to a list of users?
UPDATE
In nginx the user is stored in $remote_user variable. Is it possible to compare $remote_user with a list of users stored in a file? And then deny or allow access to a folder?
UPDATE
Probably I have to use map directive, for example:
map $remote_user $allowed_user {
default 0;
user1 1;
user2 1;
}
and then test it in the appropriate location:
location /folder/ {
if($allowed_user != 1){
return 403;
}
proxy_pass http://site;
}
but when I do sudo nginx -t, I receive the following error:
nginx: [emerg] unknown directive "if($allowed_user" in /etc/nginx/nginx.conf:104
nginx: configuration file /etc/nginx/nginx.conf test failed

You can do it via map directive (please note that map translate definitions block should be placed in the http context outside the server block):
map $remote_user $deny
username1 0;
username2 0;
...
usernameN 0;
default 1;
}
server {
...
location /folder/ {
if ($deny) { return 403; }
...
}
}
You can pre-generate users list in the above form (username1 0; username 2 0; ...) and then include this list to the nginx configuration:
map $remote_user $deny {
include /path/userlist.txt;
default 1;
}
Whenever this user list file get changed you'd need to reload nginx configuration (nginx -s reload).

Related

Nginx - variable usage (set vs map) context and usage

In Nginx configurations,
I do not know when / where I can use map or set.
I want to do something like this:
I tried using map:
map $host $proxy_destination_include {
default '/etc/nginx/conf.d/params/proxy.params/proxy_params_destination.conf';
}
Or tried using set:
server {
### I want to use this as either a variable / map ###
set $proxy_destination_include /etc/nginx/conf.d/params/proxy.params/proxy_params_destination.conf;
root /var/www/html;
location / {
set_proxy_header X-Forwarded-Location-Site 'static-value';
include $proxy_destination_include;
}
location /otherlocation {
set_proxy_header X-Forwarded-Location-Site 'static-value-2';
include $proxy_destination_include;
}
}
But I think map can only be used when a 'site request' is done? So since it has not been mapped Nginx cannot successfully compile its settings - sudo nginx -t fails
Is there any way to do this using Nginx and 'variables'?

nginx authorization based on client certificates

I have SSL enabled in nginx with the client certificate enabled in my browser. With this I'm able to hit my site via HTTPS through port 443.
What I'm looking for now is to use this information about the client to allow access to different parts of the API (URLs) but deny access to other parts. I can do this using IP address and the ngx_http_access_module with something like the following:
location /allowed/loc {
allow 192.168.1.0/24;
}
location /protected/loc {
allow 192.168.1.10;
deny all;
}
What I'm looking for is some way to allow/deny based on the certificate of the client instead of on the IP address, ie something akin to this:
location /authorize/by/cert {
allow client-cert-serial;
deny all;
}
Is there a way to do this in nginx, or do I need to use something else? Or am I thinking about this all wrong?
Thanks for the help.
For access check you can use if directive and ssl module variables: $ssl_client_s_dn, $ssl_client_serial. Example
location /not/for/jhon/ {
if ($ssl_client_s_dn ~ Jhon) {
return 403;
}
}
Good way to maintain list of allowed certificated the map directive. Example
map $ssl_client_s_dn $ssl_access {
default 0;
01 1;
02 1;
}
server {
...
location /authorize/by/cert {
if ($ssl_access = 0) {
return 403;
}
}
}
or, rules can be more complicated
map $ssl_client_s_dn $ssl_access {
default "";
01 -a-b-c-;
02 -b-e-;
}
server {
...
location /authorize/by/cert/a {
if ($ssl_access !~ -a-) {
return 403;
}
}
location /authorize/by/cert/b {
if ($ssl_access !~ -b-) {
return 403;
}
}
}
But read this article before https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/. Use if only with return or rewrite ... last; directives.

restricting access with nginx

I'm having trouble requiring authorization to use view my site using nginx. I wonder if anyone can help.
I created a password using htpasswd. It created a file called htpasswd which is stored in Conf/ directly next to nginx.conf
The Conf directory is a sibling of hello_world and child of the scta folder seen below in the listed root path.
After restarting the server, my browser asks me for a password. I enter the information, the dialogue box goes away and the browser simply says not authorized. After that, the browser doesn't even give me an opportunity to re-enter my username and password.
I'm not sure what I'm doing wrong.
UPDATE, i realized i'm actually successfully getting through, because when I type in the wrong password I get a 401 error. But when I type in the correct password, I'm moving past the 401 error and instead getting a 403 error.
server {
listen 28005;
passenger_enabled on;
root /home/me/app/scta/hello_world/public;
server_name localhost;
location / {
auth_basic "closed site";
auth_basic_user_file conf/htpasswd;
}
}
}
You have to check whether the remote_user exists or not, if it exists, it means it is authenicated, so assuming the user is "admin", you would do the following check.
server {
listen 28005;
passenger_enabled on;
root /home/me/app/scta/hello_world/public;
server_name localhost;
location / {
auth_basic "closed site";
auth_basic_user_file conf/htpasswd;
if ($remote_user ~ ^$) { break; }
set $ok "no";
if ($remote_user = 'admin') { set $ok "yes"; }
if ($ok != "yes") {
return 403;
}
}
}

Nginx config: how to use auth_basic authentication if ssl_client_certificate none provided?

I'm trying to set up Nginx server as follows:
First, the server should check whether the user provides the client SSL certificate (via ssl_client_certificate).
If the SSL certificate is provided, then give access to the site,
If the SSL certificate is NOT provided, then ask the user to enter a password and logs through auth_basic.
I was able to configure both the authentication method at the same time. But this config is superfluous.
To make check, whether the user provides its SSL certificate I try the config like this:
18: if ($ssl_client_verify != SUCCESS) {
19: auth_basic "Please login";
20: auth_basic_user_file .passfile;
21: }
But Nginx returns an error:
"auth_basic" directive is not allowed here in .../ssl.conf:19
How can I to set the condition in this case?
You can set auth_basic configuration in the if clause like this:
server {
listen 443;
auth_basic_user_file .htpasswd;
ssl_client_certificate ca.cert;
ssl_verify_client optional;
...
location / {
...
if ($ssl_client_verify = SUCCESS) {
set $auth_basic off;
}
if ($ssl_client_verify != SUCCESS) {
set $auth_basic Restricted;
}
auth_basic $auth_basic;
}
}
Now, authentication falls back to HTTP Basic if no client certificate has been provided (or if validation failed).
I'm unable to test this currently, but would something like this work?
server {
listen 80;
server_name www.example.com example.com;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443;
...
if ($ssl_client_verify != SUCCESS) {
rewrite ^ http://auth.example.com/ permanent;
}
location / {
...
}
}
server {
listen 80;
server_name auth.example.com;
location / {
auth_basic "Please login";
auth_basic_user_file .passfile;
}
}
So basically:
- Accept all initial request (on port 80 for whatever name you're using) and rewrite to ssl
- Check if there's an the client is verified.
- If not, rewrite to an alternate domain that uses basic auth
Like I said, I can't test it right now, but I'll try to get around to it! Let me know if it helps, I'm interested to see if it works.
You may try using a map.
map $ssl_client_verify $var_auth_basic {
default off;
SUCCESS "Please login";
}
server {
....
auth_basic $var_auth_basic;
auth_basic_user_file .passfile;
that way the value depends on $ssl_client_verify but is alsa always defined and auth_basic and auth_basic_user_file is always inside server { block.
Nginx provides no way to fall back to basic authentication when client cert fails. As an alternative you can use variables to restrict access:
location / {
if ($ssl_client_verify = "SUCCESS") {
set $authorized 1;
}
if ($authorized != 1) {
error_page 401 #basicauth;
return 401;
}
}
location #basicauth {
auth_basic "Please login";
auth_basic_user_file .passfile;
set $authorized 1;
rewrite /(.*) /$1;
}
*keep in mind that IfIsEvil and these rules may work incorrectly or interfere with other parts of a larger configuration.
Forget about it, it won't work.
The reason why it fails is because if is not part of the general configuration module as one should believe. if is part of the rewrite module and auth_basic is another module. You just cannot have dynamic vhosts with basic auth.
On the other hand...
You can have dynamic vhosts with their own error pages. The following example is designed for a custom 404 page but you can implement it into your code.
server {
listen 80;
server_name _;
set $site_root /data/www/$host;
location / {
root $site_root;
}
error_page 404 =404 /404.html;
location /404.html {
root $site_root/error_files;
internal;
error_page 404 =404 #fallback_404;
}
location #fallback_404 {
root /var/www/;
try_files /404.html =404;
internal;
}
error_log /var/log/nginx/error.log info;
access_log /var/log/nginx/access.log;
}
What happens...
you are telling Nginx to use /404.html in case of HTTP_NOT_FOUND.
changing the location root to match the Web site error_pages directory.
internal redirection
returning a 404 http code
configure the fallback 404 page in location #fallback_404: In this location, the root is changed to /var/www/ so it will read files from that path instead of $site_root
at the last stage the code returns /var/www/404.html if it exists with a 404 http code.
NOTE: According to Nginx documentation :
Specifies that a given location can only be used for internal
requests. For external requests, the client error 404 (Not Found) is
returned. Internal requests are the following:
requests redirected by the error_page, index, random_index, and try_files directives;
requests redirected by the “X-Accel-Redirect” response header field from an upstream server;
subrequests formed by the “include virtual” command of the ngx_http_ssi_module module and by the ngx_http_addition_module module
directives;
requests changed by the rewrite directive.
Also:
There is a limit of 10 internal redirects per request to prevent
request processing cycles that can occur in incorrect configurations.
If this limit is reached, the error 500 (Internal Server Error) is
returned. In such cases, the “rewrite or internal redirection cycle”
message can be seen in the error log.
Check this link for more, hope that helps.

Configuring squid with custom authentication helper in accelerator mode (reverse proxy)

I need to configure Squid as a reverse proxy with a custom authentication helper for each incoming requests. Every request to Squid is assumed to be with basic authentication. Any connection which fails the authentication, should be terminated. I am a newbie in Squid. Following is the configuration script I have used. This sample is to access "mindofaprogrammer.blog.com",
acl all src all
acl manager proto cache_object
http_port 80 accel defaultsite=mindofaprogrammer.blog.com
cache_peer mindofaprogrammer.blog.com parent 80 0 no-query originserver name=myAccel
acl myblog dstdomain mindofaprogrammer.blog.com
http_access allow myblog
cache_peer_access myAccel allow myblog
cache_peer_access myAccel deny all
auth_param basic program C:/wamp/bin/php/php5.3.0/php.exe "c:/squid/libexec/authhelper.php"
auth_param basic children 2
auth_param basic realm eReader
auth_param basic credentialsttl 5 hours
acl AuthUsers proxy_auth REQUIRED
http_access allow AuthUsers
access_log c:/squid/var/logs/access.log squid
coredump_dir c:/squid/var/cache
I have written the custom authentication helper in a PHP script. The listing of the same is as follows,
<?php
$f = fopen("php://stdin", "r");
while ($line = fgets($f)) {
$line = trim($line);
$fields = explode(' ', $line);
$username = rawurldecode($fields[0]); //1738
$password = rawurldecode($fields[1]); //1738
if ($username == 'hello'
and $password == 'world') {
fwrite(STDOUT, "OK\n");
} else if ($username == 'fo'
and $password == 'bar') {
fwrite(STDOUT, "OK\n");
} else {
// failed miserably
fwrite(STDOUT, "ERR\n");
}
}
?>
The problem I am facing is, even after configuring this, only the reverse proxy settings are working not the authentication. Am I doing something wrong here?
I think you first need to add a http_access deny all at the very bottom.
Then you should combine the two http_access'es into one single line (as the "AND" operator) like this:
http_access allow AuthUsers myblog
Remember that Squid always uses the first line it matches and stops processing further, which in your line http_access allow myblog simply accepts all requests and stops moving down to the authentication part.