HTTP Authentication

1. Caddy version (caddy version):

v2.0.0 h1:pQSaIJGFluFvu8KDGDODV8u4/QRED/OPyIR+MWYYse8=

2. How I run Caddy:

a. System environment:

OpenWrt 19.07.0, r10860-a3ffeb413b (x64)

b. Command:

caddy run

c. Service/unit/compose file:

cat /etc/rc.local

caddy run

exit0

d. My complete Caddyfile or JSON config:

www.mydomain.cc {
reverse_proxy * 10.0.0.1:8888
}
sub1.mydomain.cc {
reverse_proxy * 10.0.0.1:8082
}
sub2.mydomain.cc {
reverse_proxy * 10.0.0.2:1880
}
sub3.mydomain.cc {
reverse_proxy * 10.0.0.2:81
}
sub4.mydomain.cc {
reverse_proxy * 10.0.0.3:8081
}
sub5.mydomain.cc {
basicauth admin YWRtaW4= {
realm “Restricted”
/*
}
reverse_proxy https://10.0.0.3:8443 {
transport http {
tls
tls_insecure_skip_verify
}
}
}

3. The problem I’m having:

I am trying to put basic password authentication on a problematic HTTPS backend. See sub5 in the Caddyfile. As per my post yesterday the syntax and naming of the modules/directives is killing me yet again.

Also is it possible to reuse the authentication directive over multiple sites via a snippet? Yes I know it is bad security practice to hardcode “admin” as a username and password but this is merely a test for now. More advanced username and password schemas would be appreciated.

Further is there a way to get a full listing of directives and syntax outputs from Caddy via the command line? It would be great to have a better grip on this.and a complete list of the directives available from each module.

4. Error messages and/or full log output:

2020/05/13 17:42:07.633 INFO using adjacent Caddyfile
reload: sending configuration to instance: caddy responded with error: HTTP 400: {“error”:“loading config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 5: loading handler modules: position 0: loading module ‘subroute’: provision http.handlers.subroute: setting up subroutes: route 0: loading handler modules: position 0: loading module ‘authentication’: provision http.handlers.authentication: loading authentication providers: module name ‘http_basic’: provision http.authentication.providers.http_basic: base64-decoding password: illegal base64 data at input byte 4”}

5. What I already tried:

Base 64 Encode on password, multiple different syntaxes, orders, and reconfigurations. The results:

2020/05/13 11:40:08.268 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘reverse_proxy’: Caddyfile:22 - Error during parsing: unrecognized subdirective {
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 11:42:20.123 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘reverse_proxy’: Caddyfile:22 - Error during parsing: unrecognized subdirective {
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 12:41:41.821 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘reverse_proxy’: Caddyfile:22 - Error during parsing: unrecognized subdirective {
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 12:42:25.934 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘reverse_proxy’: Caddyfile:22 - Error during parsing: unrecognized subdirective {
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 12:43:21.400 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘reverse_proxy’: Caddyfile:21 - Error during parsing: unrecognized subdirective http.authentication.providers.http_basic
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 12:54:19.276 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘reverse_proxy’: Caddyfile:21 - Error during parsing: unrecognized subdirective basicauth
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 13:07:26.584 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘basicauth’: Caddyfile:17 - Error during parsing: Wrong argument count or unexpected line ending after ‘admin’
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 13:08:21.455 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘basicauth’: Caddyfile:17 - Error during parsing: Wrong argument count or unexpected line ending after ‘admin’
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 13:11:32.586 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘basicauth’: Caddyfile:17 - Error during parsing: Wrong argument count or unexpected line ending after ‘admin’
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 13:12:41.877 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘basicauth’: Caddyfile:17 - Error during parsing: Wrong argument count or unexpected line ending after ‘admin’
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 13:14:49.327 INFO using adjacent Caddyfile
reload: sending configuration to instance: caddy responded with error: HTTP 400: {“error”:“loading config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 5: loading handler modules: position 0: loading module ‘subroute’: provision http.handlers.subroute: setting up subroutes: route 0: loading handler modules: position 0: loading module ‘authentication’: provision http.handlers.authentication: loading authentication providers: module name ‘http_basic’: provision http.authentication.providers.http_basic: base64-decoding password: illegal base64 data at input byte 4”}

root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 14:19:07.084 INFO using adjacent Caddyfile
reload: sending configuration to instance: caddy responded with error: HTTP 400: {“error”:“loading config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 5: loading handler modules: position 0: loading module ‘subroute’: provision http.handlers.subroute: setting up subroutes: route 0: loading handler modules: position 0: loading module ‘authentication’: provision http.handlers.authentication: loading authentication providers: module name ‘http_basic’: provision http.authentication.providers.http_basic: base64-decoding password: illegal base64 data at input byte 4”}

root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 14:21:35.395 INFO using adjacent Caddyfile
reload: sending configuration to instance: caddy responded with error: HTTP 400: {“error”:“loading config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 5: loading handler modules: position 0: loading module ‘subroute’: provision http.handlers.subroute: setting up subroutes: route 0: loading handler modules: position 0: loading module ‘authentication’: provision http.handlers.authentication: loading authentication providers: module name ‘http_basic’: provision http.authentication.providers.http_basic: base64-decoding password: illegal base64 data at input byte 4”}

root@TMIWRT:~# caddy reload
2020/05/13 14:23:00.065 INFO using adjacent Caddyfile
reload: sending configuration to instance: caddy responded with error: HTTP 400: {“error”:“loading config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 5: loading handler modules: position 0: loading module ‘subroute’: provision http.handlers.subroute: setting up subroutes: route 0: loading handler modules: position 0: loading module ‘authentication’: provision http.handlers.authentication: loading authentication providers: module name ‘http_basic’: provision http.authentication.providers.http_basic: base64-decoding password: illegal base64 data at input byte 4”}

root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 14:40:16.859 INFO using adjacent Caddyfile
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 17:39:53.406 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘basicauth’: Caddyfile:20 - Error during parsing: username and password cannot be empty or missing
root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 17:42:07.633 INFO using adjacent Caddyfile
reload: sending configuration to instance: caddy responded with error: HTTP 400: {“error”:“loading config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 5: loading handler modules: position 0: loading module ‘subroute’: provision http.handlers.subroute: setting up subroutes: route 0: loading handler modules: position 0: loading module ‘authentication’: provision http.handlers.authentication: loading authentication providers: module name ‘http_basic’: provision http.authentication.providers.http_basic: base64-decoding password: illegal base64 data at input byte 4”}

root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 17:42:45.310 INFO using adjacent Caddyfile
reload: sending configuration to instance: caddy responded with error: HTTP 400: {“error”:“loading config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 5: loading handler modules: position 0: loading module ‘subroute’: provision http.handlers.subroute: setting up subroutes: route 0: loading handler modules: position 0: loading module ‘authentication’: provision http.handlers.authentication: loading authentication providers: module name ‘http_basic’: provision http.authentication.providers.http_basic: base64-decoding salt: illegal base64 data at input byte 1”}

root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 17:47:12.124 INFO using adjacent Caddyfile
reload: sending configuration to instance: caddy responded with error: HTTP 400: {“error”:“loading config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 5: loading handler modules: position 0: loading module ‘subroute’: provision http.handlers.subroute: setting up subroutes: route 0: loading handler modules: position 0: loading module ‘authentication’: provision http.handlers.authentication: loading authentication providers: module name ‘http_basic’: provision http.authentication.providers.http_basic: base64-decoding password: illegal base64 data at input byte 4”}

root@TMIWRT:~# nano Caddyfile
root@TMIWRT:~# caddy reload
2020/05/13 17:49:09.621 INFO using adjacent Caddyfile
reload: adapting config using caddyfile: parsing caddyfile tokens for ‘basicauth’: Caddyfile:17 - Error during parsing: Wrong argument count or unexpected line ending after ‘YWRtaW4=’
root@TMIWRT:~#

6. Links to relevant resources:

For Humor:

2 Likes

Please use ``` on the lines before and after your config to use code formatting, it’s very difficult to read otherwise! You can also use the caddy fmt command to automatically fix your Caddyfile formatting!

That said; your syntax for the basicauth directive is incorrect. The username and password pairs must go inside the { } brackets, each on their own line.

See the example from the docs:

basicauth /secret/* {
	Bob JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
}

It’s all very well explained in the docs! Also, you can’t just base64 encode the password, they need to be hashed. The default hash algorithm is bcrypt, and as explained in the docs, you can use the caddy hash-password command to generate the password hashes.

Note that currently, it’s not possible to configure the realm via Caddyfile, that’ll come in v2.1!

1 Like

Okay let us dig deeper into a practical example that is still not working correctly:

sub5.mydomain.cc {
basicauth /*/ {
admin JDJhJDEwJERJZzNtRW5haVJOZTV5YWpCQUg4dC4uWG8xaFFrdnRLQmtqRkFJaUdaZ21WRmZGV1g4Smxt
}
reverse_proxy https://10.0.0.3:8443 {
transport http {
tls
tls_insecure_skip_verify
}
}
}

The password authentication comes up but the site being reverse proxied does not return any data. In other words I am attempting to password protect one site that is being reverse proxied. How is this to be accomplished?

This example from the documentation is not applicable nor immediately helpful because it does not expound on the overall syntax of the Caddyfile in regard to directives and how Caddy interprets its informational flows. Am I looking at password authenticating a whole directory or am I just matching the entire site via use of wildcards?

I spent an entire day yesterday trying to get this to partioally work based on the assumption that a Base64 only hash was supported. Vis a vis the documentation:

basicauth [<matcher>] [<hash_algorithm>] {
	<username> <hashed_password_base64> [<salt_base64>]
	...
}

It might be easier to update the documentation to advise using Caddy’s inbuilt hashing utility for passwords before setting up the directive. I would volunteer to rewrite the wiki entry.

I think you should take a look at the matcher documentation:

It’s explained right below the syntax:

  • <hashed_password_base64> is the base-64 encoding of the hashed password.

base64 is not a hashing algorithm. It’s an encoding. It’s just an alternate representation of the bytes. bcrypt is hashing algorithm designed for password hashing (i.e. it’s intentionally quite slow so that if your hashes are leaked then bad actors would need to spend a lot of computing resources to try and brute-force a match). The Caddyfile syntax requires essentially base64_encode(bcrypt(plaintext_password)).

[<salt_base64>] is for hashing algorithms that may require an external salt. bcrypt does not, but scrypt (the other built-in hashing algo) does.

That’s already there! Right above the syntax, there’s this paragraph:

Caddy configuration does not accept plaintext passwords; you MUST hash them before putting them into the configuration. The caddy hash-password command can help with this.

This just sounds like you need to spend more time reading the various pages in the documentation. All the information is there, you just need to spend the time to understand it.

3 Likes

Just to reiterate @francislavoie’s point about matchers, this matcher will have basicauth operating on requests like:

  • /foo/
  • /foobarstuff/
  • /abc_xyz/

But will not operate on any of the following requests:

  • /
  • /foo
  • /foo/bar

I suspect this is not the desired behaviour.

Overall Caddyfile syntax is explained in the Caddyfile documentation: Caddyfile Concepts — Caddy Documentation

Matchers are also touched on in this documentation. General Caddyfile flow and the use of matchers are universal, not specific to any directive. I don’t believe it makes sense to elaborate on these higher level concepts specifically within documentation for any single directive.

Again reading the documentation does not necessarily improve comprehension. A little observation and the occasional amount of brute force is requisite for comprehension. Expounding on yeterday’s iteration of the task but modifying for what little I can glean from the documentation on matchers:

sub5.mydomain.cc {
basicauth * {
admin JDJhJDEwJERJZzNtRW5haVJOZTV5YWpCQUg4dC4uWG8xaFFrdnRLQmtqRkFJaUdaZ21WRmZGV1g4Smxt
}
reverse_proxy https://10.0.0.3:8443 {
transport http {
tls
tls_insecure_skip_verify
}
}
}

This simple but dirty example correctly performs basic authentication on an HTTPS site with a self signed certificate. I am certain that this is not the most efficient method nor the most functional.

If we were to shut the tab and reopen it within the same browser we would still be authenticated and this would represent an interesting hole in security. This works in Chrome, FIrefox, and Edge. Would there be a clever way to prevent this using the existing directives?

I am still very much interested in compacting this config and optimizing its function.

@francislavoie

In regards to your bad actor scenario it is very unlikely that someone will use hashcat and to break into my APC power strip but they are welcome to try.

As I said before:

Also, that config looks exactly right. I don’t think there’s anything “dirty” about it (other than the fast that you didn’t use code formatting, making it harder to read).

The only suggestions I have to improve your Caddyfile are to remove the * matcher for basicauth, because * is implied if you omit the matcher. Just looks slightly nicer. Also, you can remove the tls line in the proxy transport, because if you specify https:// as the upstream’s scheme, then tls will be automatically enabled for you.

Like this:

sub5.mydomain.cc {
	basicauth {
		admin JDJhJDEwJERJZzNtRW5haVJOZTV5YWpCQUg4dC4uWG8xaFFrdnRLQmtqRkFJaUdaZ21WRmZGV1g4Smxt
	}
	reverse_proxy https://10.0.0.3:8443 {
		transport http {
			tls_insecure_skip_verify
		}
	}
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.