Previously, we configured nginx
to list directories and files in html.
Now, let’s add authentication to restrict access to specific directories and files.
Basic authentication
The simplest web authentication method is basic authentication.
It requires an Authorization
header in each request.
However, browsers don’t support setting a header on requests without javascript,
and with javascript, there’s no sane way to stream file downloads to the browser’s download manager.
So, once the initial basic auth login is validated, we'll use cookies, which browsers automatically include for each request on the same site.
Let’s start by creating a login
endpoint with nginx basic auth to verify the user/password pair and set a cookie for users with valid credentials.
...
To create entries in basic.htpasswd
, we use openssl[1]:
We can successfully login using basic auth on the login
endpoint!
Cookie set
To check that the user is authorized to access the current path and that cookies cannot be hand-crafted, we need to store the following in the cookie:
- username
- a secret, so a cookie cannot be hand crafted
- the path base the user has access to
Using nginx map module, we’ll store this information for each user:
# input output
Later, with map's include
directive we can store it into a file.
In @login_success
, assign the ngxp
cookie value.
When $username
is set with the basic auth username ($remote_user
), $user_cookie
is set with the mapped value.
Cookie check
The only thing left to do is to check if our cookie is valid and authorized for the current uri when listing files.
$cookie_ngxp
contains the http request provided cookie (from the browser).
# get username from http request's cookie
It's an untrusted user input, so we should check that it matches exactly with the one set for the username.
Since we just set $username
, $user_cookie
has the trusted cookie value for the user (if it exists),
so we check that both variables are equal:
map ${cookie_ngxp}?${user_cookie} $user_cookie_equal {
~^([^\?]+)\?\1$ 1; # if $cookie_ngxp == $user_cookie
default 0;
}
By modifying location /
slightly, we can already restrict listing and download to requests with a valid cookie:
...
Cookie access
We also want to have per path access rights, we first extract the path from $user_cookie
:
...
Using a map with two variable as input, we can check if $uri
starts with the extracted path
...
map ${user_cookie_access}?${uri} $uri_access {
~^([^\?]+)\?\1.*$ 1; # if $uri startswith $user_cookie_access
default 0;
}
Cookie authorized
Finally, ensure that both the cookie and path-based access rights are validated:
...
map ${user_cookie_equal}${uri_access} $user_authorized {
11 1; # everything good authorize
default 0;
}
In the file listing endpoint, check $user_authorized
:
...
We now have per user and path accesses!
Next time we'll see how to upload files.
You can also use htpasswd. ↩