httpd.conf(5) examples for httpd(8). I'm trying to achieve `/foo/bar/`
auth success -> block 410 & auth fail -> (block) 401; this is not
possible either by design with undocumented behavior, or due to an error
in httpd(8) logic.

```
server "foo.example" {
        listen on * port 80
        location "/foo/" {
                authenticate with "conf/foo.htpasswd"
                directory auto index
        }
        location "/foo/bar/*" {
                authenticate with "conf/foo.htpasswd"
                block return 410
        }
}
```

* `/foo/` requires auth, returns directory contents or 401 Unauthorized.
* `/foo/bar/` does not require auth, returns 410.
* `/foo/baz/` does not require auth, returns contents (403/404).

I expected `/foo/bar/` to require authentication, and then to return 401
Unauthorized or 410 Gone depending on authentication.

`/foo/` and `/foo/baz/` are behaving as written into the config.

----

```
server "foo.example" {
        listen on * port 80
        location "/foo/*" {
                authenticate with "conf/foo.htpasswd"
                directory auto index
        }
        location "/foo/bar/*" {
                authenticate with "conf/foo.htpasswd" # no-op
                block return 410
        }
}
```

* `/foo/` requires auth, returns directory autoindex or 401 Unauthorized.
* `/foo/bar/` requires auth, returns directory index or 401 Unauthorized.
* `/foo/baz/` requires auth, returns directory index (403/404) or 401
  Unauthorized.

Notice `/foo/bar/` didn't return 410. This is supposedly correct,
because:

> In case of multiple location statements in the same context, the first
> matching location statement will be put into effect, while all later
> ones will be ignored. Therefore it is advisable to match for more
> specific paths first and for generic ones later on.

----

```
server "foo.example" {
        listen on * port 80
        location "/foo/bar/*" {
                authenticate with "conf/foo.htpasswd"
                block return 410
        }
        location "/foo/*" {
                authenticate with "conf/foo.htpasswd"
                directory auto index
        }
}
```

* `/foo/` requires auth, returns directory autoindex or 401 Unauthorized.
* `/foo/bar/` does not require auth, returns 410.
* `/foo/baz/` requires auth, returns directory index (403/404) or 401
  Unauthorized.

So what just happened? I requested `/foo/bar/` to be authenticated, and
only then after authentication to return 410 Gone but no authentication
was required.

This is troubling me particularly when disclosing the existence of
`/foo/` is not sensitive, but when `/foo/bar/` may be. In my case, `bar`
name in path represented private information of a recipient's name. I
don't have plausible deniability while returning 410 Gone, but only by
removing the directory and letting the server return directory contents
(404 Not Found) without `block`.

A quick look at `server_http.c` (revision 1.135) reveals conditional
branching:

```
        if (srv_conf->flags & SRVFLAG_BLOCK) {
                server_abort_http(clt, srv_conf->return_code,
                    srv_conf->return_uri);
                return (-1);
        } else if (srv_conf->flags & SRVFLAG_AUTH &&
            server_http_authenticate(srv_conf, clt) == -1) {
                server_abort_http(clt, 401, srv_conf->auth_realm);
                return (-1);
        } else
                return (server_file(httpd, clt));
```

That behavior isn't documented, but code says it does the `block`. So I
guess it deserves either a code patch, a doc patch, or both: `block` and
`authenticate` could be documented to be exclusive of each other,
documented to be evaluated in some order, and/or `authenticate` should
be evaluated before `block` statements.

lucas@ contributed comments and acknowledged my issue (while questioning
the usefulness of auth success -> block use case).

Reply via email to