Conditional auth_basic_user_file depending on the request path
I would like to authorize users depending on the requested path. For example, only user1
and user2
should have access to /projects/1
.
My /etc/nginx/.htpasswd
looks like this:
user1:$hashed_psswd1
user2:$hashed_psswd2
user3:$hashed_psswd3
...
Here's the location
block in nginx config:
location ~ /projects(/.*) {
auth_basic "Please provide credentials";
auth_basic_user_file /etc/nginx/.htpasswd;
include /var/www/html/myapp.com/config/nginx/git-http-backend.conf;
}
And the rails action:
def git
redirect_to "#{Rails.configuration.x.domain}/projects/#{@project.id}"
end
The authentication seems to work:
$ git clone http://localhost:3000/projects/1
Cloning into '1'...
Username for 'http://localhost:3001': user1
Password for 'http://deploy@localhost:3001':
remote: Enumerating objects: 94, done.
# ... it successfully clones the git repo...
The problem is that user3
is able to clone project 1
, but he shouldn't be able to clone such project.
So how could I authorize users in nginx + rails depending on the requested path?
Solution 1:
Here is a config I've just tested with OpenResty 1.17.8.2 (based on nginx 1.17.8 core) and can confirm that it is workable:
map $uri $realm {
~^/projects/ "Protected projects";
~^/images/ "Protected images";
default off;
}
map $uri $authfile {
~^/projects/ /path/to/.htpasswd_projects;
~^/images/ /path/to/.htpasswd_images;
}
server {
...
auth_basic $realm;
auth_basic_user_file $authfile;
...
}
.htpasswd_projects
and .htpasswd_images
files contains each own user/password list. With the above config every URI started with /projects/
prefix is protected with basic authorization and available only for users listed in the htpasswd_projects
file, every URI started with /images/
is protected with basic authorization and available only for users listed in the htpasswd_images
file, and rest of the URIs are available without authorization for everyone.
Update
Here is another example, using dynamically generated .htpasswd
path depending on the requested URI:
location ~ ^/projects/(?<project_id>[^/]+) {
if (!-f /var/www/projects/$project_id/.htpasswd) {
# '.htpasswd' file for the requested project does not exists
# assuming wrong project ID is given, returning HTTP 404 Not found
return 404;
}
auth_basic "Please provide credentials for project $1";
auth_basic_user_file /var/www/projects/$project_id/.htpasswd;
...
}
This one would work with the following .htpasswd
files tree:
/var/www/projects
├── 1
│ └── .htpasswd
├── 2
│ └── .htpasswd
...
You can place this projects
directory wherever you want, it isn't dependent on web server root.