Caddy Plugin Basic Authentication

Hey there.

I have the following requirement. I have an application where I want to use Basic Authentification. But instead of manually configure credentials I want that the Basic Authentification is handled from an external server.

So instead of configure
basicauth path user password
I would configure
basicauth path ServerToAuthentificate

Is there already a plugin for that or is already someone working on an idea like that.

Thanks in advance and bests Sandro

Why not just proxy that path to the upstream server that does the authentication?

1 Like

@Sandro_Zbinden HTTP Basic Authentication against an external authentication service is possible. You just have to use a different plugin.

Iā€™m in the process of developing a basic authentication plugin that authenticates against RADIUS authentication servers, instead of statically configured files. I havenā€™t really announced it yet, as I need to add some tests and do some cleanup, but I am running it in a production system.

So if you had something like FreeRADIUS or Cisco ISE on a server to handle user authentication, my plugin would work.

Code is here caddy-radius . See the flowchart in README for how it works. It uses a local cache so as to not require a RADIUS auth on every single HTTP GET. A small amount of wiki started here

I may develop a separate LDAP plugin at some point or one integrated plugin with different backend types. TBD.

ninja edit: Iā€™m also looking to add radsec aka RADIUS over TLS support in the future to make sure credentials are TLS encrypted all the way through. radsec is supported by FreeRADIUS. Right now my plugin is only supporting PAP

@jim Thanks a lot for point out your plugin. I think I could reuse almost all your code for configuration and caching execpt that hard requirement that authentication is done with a RADIUS or Cisco ISE Server. What I want to do is use any page that uses Basic Authentication and login through this page.

I think I more or less just have to change the auth method in caddy-radius/radius.go at master Ā· jamesboswell/caddy-radius Ā· GitHub

Do you mind I fork the project. Or is that requirement something you would like to cover with your plugin anyway.

@Sandro_Zbinden feel free to copy anything you like. I definitely looked at the basicauth source code to start my own plugin. If youā€™re fundamentally changing it, Iā€™d prefer you not fork with the same name. Donā€™t want to cause any confusion name wise and what the functionality is.

RADIUS isnā€™t for everyone, but it was a gap I needed to fill to switch to Caddy. It replaces the mod_auth_xradius Apache module I was using. It does offer me some flexibility in my backend data source(s) can change while my auth protocol stays the same. I can also use multiple different data sources for users.

Iā€™m not sure I understand this statement? Do you want a login webpage, or a pop-up Basic Authentication dialog?

Iā€™m assuming Basic Authentication. If I correctly understand your original desire is to move user/password combinations out of the Caddyfile, yes? If so, where will you store the usernames? What mechanism is going to validate a users login?

Those are things you need to consider when developing your own HTTP Basic Authentication plugin.

@jim

My problem is the following. I have an application where some pages are protected with basic auth and some pages are not protected with basic auth.

Lets say

http:localhost:8080/employees ā† Not protected with basic auth.
http:localhost:8080/clients ā† Protected with basic auth.

Now I want to run the application behind a reverse proxy and use the basic auth from /clients on the /employees page.

So for the user it is as both pages would be protected with basic auth and the same credentials

These statements are in conflict. You want one path authenticated, and the other not.

Sounds like you want session management that works on both /employees and /clients ? Your application would need to handle that. Your application could use a HTTP Basic Authentication mechanism to authenticate and start a session. But managing that session, setting cookies, etc. is not something Caddy will do for you.

Now I have an application I manage that is reversed proxy behind Caddy. Similar to what you mention above.

Iā€™m using Caddy with my plugin mentioned previously, to perform HTTP basic authentication for all requests to /myapp . The app itself uses some cookies to track session state, but itā€™s not doing any authentication, itā€™s trusting the web server. In my scenario it works, but itā€™s really a simple scenario with acceptable security risks.

HTTP basic authentication is a very simple authentication mechanism. Make sure you fully understand how it works, and the pros/cons vs handling authentication directly inside your application.

2 Likes

Great comment by @jim with a lots of good points.

It will be very beneficial to have an in-depth understanding of basic auth (not that itā€™s horribly complicated or anything) before making decisions on how to possibly implement sessions and authentication.

If the goal is simply to use Caddy to extend the basic auth requirement to the second path, you would simply need to repeat the basicauth directive, targeting that second path. Be wary of the implications of authenticating twice (at the webserver and the application).

1 Like

Thanks a lot for your commentaries.

I think I do want exactly what @Whitestrake pointed out. I try to make things a little bit more concretely so you could fully understand my requirement.

I want to run a rest application behind a reverse proxy. As all is stateless I do not need any session management nor cookie managment.

The rest application that I want to run behind a reverse proxy has a documentation (html) part and the rest part.

http://application:50000/docu
http://application:50000/rest

I am unable to make any changes in the configuration of this application.

Currently the /rest part uses basic auth and checks the credentials from basic auth server side. The /docu part is accessable without basic auth.

What I am doing now is enabling basicauth in caddy. This way /docu is protected and /rest is protected. As @Whitestrake pointed out. Currently /rest is authenticationg twice. The only way to get this to work is duplication all users and passwords in the caddy file that are stored in the application.

public.restapplication.com {
 tls off
 basicauth / user1 password1 <- this user / password exists in the application:50000
 basicauth / user2 password2 <- this user / password exists in the application:50000
 proxy / application:50000 {
	header_upstream Host {host}
	header_upstream X-Real-IP {remote}
	header_upstream X-Forwarded-For {remote}
	header_upstream X-Forwarded-Proto {scheme}		
 }
}

The goal I have is to avoid duplicating a list with username / password but just always check for access at the protected area application:50000/rest

public.restapplication.com {
 tls off
 basicauth / application:50000/rest <- for all sides use basic auth from this url
 proxy / application:50000 {
	header_upstream Host {host}
	header_upstream X-Real-IP {remote}
	header_upstream X-Forwarded-For {remote}
	header_upstream X-Forwarded-Proto {scheme}		
 }
}

I hope this helps to understand the requirement. Thanks a lot for the great advice.

The only way Caddy could logically do what youā€™re asking would be if it were to make a request to application:50000/rest every time it received a request for public.restapplication.com, including the clientā€™s Authorization header, and inspect the result for signs of auth rejection - which would quickly get ridiculous, and also redundant if the client is requesting /rest anyway - just an excessive amount of complexity. Thereā€™s no mechanism by which Caddy could ā€œretrieveā€ credentials from the endpoint with which to carry out its own checks, so thatā€™d be the only way.

Right now, though, thereā€™s no functionality in Caddy to implement the above hypothetical behaviour. To perform basic auth checks, you must discretely supply credentials in plain text in the Caddyfile or via (deprecated) htpasswd files.