New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Auth #19
Comments
I'm not against adding optional authentication, but using Google seems a little against the selfhosting spirit, no? I'll think about this a little and do some research. I think there are a lot of difficulties implementing any auth. Maybe auth shouldn't be done by ntfy but rather by nginx or some other proxy... |
👍 Interim step could be to support basic auth. Haven't tried if that would work? |
I think I'll look at something with basic auth to begin with. Especially since that's incredibly easy to do with curl too. |
It would maybe be enough to just make sure the App supports Basic Auth - which your http library, if you use one, might already support. Then it would be up to the maintainer of the selfhosted instance to put http basic auth in the config of the reverse proxy. They all support basic auth. So that would be the "cheapest" way of achieving some kind of protection - it would protect everything in one go. |
What implementing authentication via api tokens? For example, the creator of a topic can optionally include a token, and then whoever tries to subscribe to that topic afterwards has to provide the same token (this is effectively a password-protected topic). The content of said token is completely arbitrary (though perhaps should be limited to, say 64-128 characters/bytes). This could be done for example via the More complex but more flexible variant: topic creator includes an "admin" token and a list of allowed "client" tokens. Anyone providing a valid client token can publish subscribe to the topic, and the list of allowed tokens can me changed only by providing the admin token as authentication. The list of client tokens could even be split into two, separating the clients that can publish to the topic and clients that can subscribe (the same token can be on both lists, and the two capabilities are separate - that way, we have clients that are publish-only, subscribe-only, and both). This way:
The server administrator can decide via the config if the auth tokens expire with the topic or if they are persistent (can be easily saved in a dedicated json/yaml file). Example {
"mytopic": {
"admin": ["LhaC8heEBOu9YPVc", "XqyNlCyqUDq6g7oM"],
"pub": ["NSgG47rbMLdDxl0L", "rppJwLr8HaEs2WtF", "1RoqplTLvIKvIAMM", "iqp5qgmKenWjd1I6"],
"sub": ["NSgG47rbMLdDxl0L", "rppJwLr8HaEs2WtF", "1RoqplTLvIKvIAMM", "ahPaEtqoY0i8MWwN"]
},
"topic2": {
"admin": [],
"pub": ["IyWmTqwmZuLNFPxZ", "WTliVPeTp602x51L"],
"sub": ["IyWmTqwmZuLNFPxZ", "WTliVPeTp602x51L"]
}
} Note how |
Thank you very much for the incredibly detailed suggestion. That's awesome!
So technically a topic is never created actively:
I think this is solvable though.
As you may have noticed from the rest of ntfy, I like simple things, so I am not a big fan of the admin + client token idea (for now at least). I can totally imagine this being useful eventually, but for now I think your first idea can be adapted to work with the ephemeral topics. How about this: Topic-specfic authWhen you publish or subscribe to a topic, you can additionally send a
or
Server-wide authInstead of doing a topic specific All configs:
Thoughts? |
Lol, I guess I got a little carried away. I like your idea very much - both the topic-specific auth, as well as the server-wide auth (and it doesn't preclude the implementation of some kind of authorization logic on top of it in the future ;) ) How would you handle the case of
What about making the per-topic auth duration dynamically configurable? Eg. by providing an additional (possibly optional) |
Haven't fully understood the last comments about tokens. |
@aslmx it would be an optional feature. If you want, you can create a topic that requires a custom api key to publish/subscribe. If you don't want, you can keep using ntfy the same way you can do now, without any api key. |
Maybe there could also be a And I guess it would be nice if |
@aslmx Yeah don't worry, I'll leave the "no auth" a default. Every auth option I'll add will be opt-in, just like @shadow00 said @rigrig If you read this comment from @shadow00, he had very similar ideas. I desperately want to keep things as simple as possible, and I also don't want to re-invent the wheel. I think I may need to read up on how others do auth, and how to do this properly. I don't really want to necessarily roll my own here. That said, I think I can iterate on this. I can implement the |
I understand wanting to keep it simple, I just figured it would be nice to restrict what gets published to my server without clients needing to bother with tokens. (i.e. |
You could use NATS or just copy the very simple patterns of NATS. i embed nats inside my golang server btw normally . nats has topics ( called streams in nats )and in each topic a subject like “a.b.c”. You can subscribe to the stream and only part of the subject such as “a.b.*” and so get everything “b” and below. Auth with NATS is based on an account and a user but you don’t have to use it . You can just have all the streams open and enforce your auth how you want on top. nats has http and web sockets network transports too. its insanely fast and pure golang . |
Thank you for your comment. Fascinating! NATS sounds great. Didn't know it existed. It looks like a classic pubsub implementation. I'll look at it further, but I think it's probably a little too much for this little project, don't you think? I would have to replace the guts of ntfy with NATS and for what? I am a strong believer in KISS, and this seems like the opposite of KISS. I'll mull it over a little though. Also: This ticket is about Auth, so maybe we should move this convo somewhere else. Feel free to open a NATS ticket :-D |
Just an update on the general status of this ticket: After the unified push ticket (#9), I'll work on this. |
NATS is light !! Its fast 8 million pub subs per senc on a old mac laptop if no durability.
I hear you totally. Yes maybe it's a little too much. Have a look at siot at least because its using nats and its pretty light. It also has auth and authz if you want it, but you don't have to use it. There also will be a slight learning curve but there are tons of example and he nats CLI is excellent !! Here is a little golang program by the architect of NATS that sort of does what ntfy does. Its very simple Also this exposes nats over http which you need i guess. The "Why" aspect is compelling IMHO.
|
THis might interest you. Matrix is switching over to NATS btw. Been going on for a while. https://github.com/matrix-org/dendrite/tree/nats See the imprts https://github.com/matrix-org/dendrite/blob/nats/go.mod NATS has decentralised AUTH, since this issue is about Auth and Authz. here is the output running it:
|
On the topic of NATS (yes! Definitely use it!) I have had great experience with an OSS layer on top of NATS: LiftBridge/NATS https://github.com/liftbridge-io/liftbridge Tyler and his team is fantastic and has OSS the very product he is building his company on. Just drop by on their Slack to ask any questions you have - no matter how basic. LiftBridge is a great product that makes use of NATS. |
hey @gc-ss I also used LIftBridge a little. Mostly just to try it out. When there was only NATS Streaming then LIftbridge had the advantage of multi server scaling and redundancy. I have not kept up with LiftBridge so much. |
I kindly ask to move NATS discussions here: #78 :-) |
The only thing I need would be to have basic auth support in the client. I'm going to be running it behind a proxy like nginx anyways to enforce https-only and I can use that to set auth. I have made the mistake of running things 'open' on the internet before and they just up ripe for abuse. Somebody will figure out how to abuse it. I won't do that for anything that allows people to use a service to send data. |
I have read a lot about auth these last few days and the more I read, the less I want to do anything fancy. I will likely try to iterate on this, starting with basic auth with a static key for everything. The Android app has to support it obviously, so you can't just put configs in nginx.
I don't disagree. People on the Internet are evil and auth is definitely better than no auth if it's a service just for you. That said, I have jumped through endless hoops to limit everything to the extreme: Subscription rate limits, requests per second, attachment size limits, cache size limits, topic limits, ... (see https://ntfy.sh/docs/config/#rate-limiting). And then there's also fail2ban to lock out the abusers (https://ntfy.sh/docs/config/#banning-bad-actors-fail2ban). The problem is typically though as a self-hoster, you want NO LIMITS, you want to upload a 500 MB file to your phone whenever you want, and that's obviously only possible with auth. Long story short. I get it. I'll do auth, soon :-D |
This WIP PR (#114) implements this approach:
In this example, There will be the following config params:
ntfy.sh will be set to I like this design a lot. It's super simple, yet infinitely flexible. Feedback required: What I am unsure about is
|
Actually the "forward auth" flow is documented perhaps more generically in Traefik docs. Example, snippets from my Authelia configuration.yml:
and users_database.yml:
and my Traefik-2 middleware rule, which reference from the routing rule of each service that I want protected:
|
Here is the auth https://github.com/caos/zitadel been using it and it’s great self host : https://github.com/caos/zitadel#self-hosted |
I appreciate all the input. I will review all of this later. I did do a whole lot of research and asked coworkers about what to do here. My conclusion was that there is no standard way of doing this, at least not for the use case o want. That said, the implementation I made is very easy to replace or even augment. For example, the authentication can likely be delegated entirely to another system (i e. username and password), while the authorization is kept in ntfy. I am more than happy to integrate other systems, i just didn't know which since they all didn't seem to fit. Like, for instance: oauth2 had a web based flow. If I want to support curl with user/pass, then do I return "unauthorized" with a web link in curl..?! You get the problem. I'd really appreciate detailed help on how to integrate one of these solutions. I am happy to accommodate them, as long as they can stand next to the no-dependency-integrated one. |
I gotta say Authelia and Traefik look very interesting, though this is what I found with most of these solutions:
Neither the curl use case nor the Android app are "web applications". If there is an easy way to accommodate these two, then I'd be game. I'll look some more. @julianfoad I'm also more than happy to discuss on Discord/Matrix. As for Zitadel, @gedw99, it says
The "only" here for me is almost ironic. :-) |
Pretty sure you can run Zitadelle without k8 or even docker. https://github.com/caos/zitadel/tree/main/build/local It’s just cockroach and golang ! They are saying k8 because their target audience is big enterprise . |
Concur that Zitadelle is a fantastic piece of software. There used to be issues of running it just with docker but I worked with their team to tease those issues out - They also have a generous free tier.
That said, for something lightweight like If Authelia looks like a good fit, but you need "non webapp" support - authentik should be a great solution. They don't have any getting started guides (I will be trying to fix that soon in a few months) - so just run the |
Alright folks this is "it". I am soliciting feedback now that it's feature complete. I find it a little awkward and complicated. It's definitely not the "just works" kinda thing you'd expect. Notes: Here's a full video of the entire flow: |
I prefer things that are accessible to majority of people - so number over color (colorblindness) |
What does the Material Design guidelines say about that? |
When anonymous has no access to any topics, does that include write access? If so, shouldn't all topics that are UnifiedPush have write access for anonymous (so app servers can POST messages)? Maybe giving topics /up.* anonymous write by default could solve that. |
I agree. I'll do that.
There's a setting
A UnifiedPush topic is just a topic, so if you make it For UP, I'd say the best we can do if you want a "private server" is what you described:
|
The more I think about it, the more I think I should disallow multiple users per server (in the app), i.e. you can only have one user per server and that is used for all topics. What do you think about that? It feels quite unnatural to allow multiple users for the same servers from within one app. |
Yeah, that would make sense. Thought about it a new times, and I don't come up with a situation where one might need different users to the same server (testing scenarios aside). |
great work @binwiederhier . |
Maybe you like this... https://github.com/mikestefanello/pagoda
the point with Ent os developer velocity. |
Video: Alright I am much happier with this. Now the app only supports one user per host, meaning there is no more awkward dropdown and the "login required" screen is only shown once when the user does not exist. I also removed the "Subscription settings" entirely (for now) and added the mechanism that PeterCxy suggested to avoid exposing messages for non-public Firebase topics via a "poll_request" message (not shown in the video). I think this is what i'll stick with. Now "all I need to do" is polish it a little more and add lots of docs. For those who want to test, here are binaries: # in the server.yml
auth-file: /home/pheckel/Code/ntfy/playground/user.db
auth-default-access: deny-all |
Server side auth code is released in https://github.com/binwiederhier/ntfy/releases/tag/v1.14.0 Note to future self, so I don't lose the links: |
The Android app will be released soon, so I'd consider this done for now. Thanks everyone for the fantastic discussion and the input. 👍 👍 👍 If you have any other desires regarding auth, please open another ticket. One that I would see would be "allow integrating X" to use as external auth backend, an I'll likely do it if it's reasonable. |
well done @binwiederhier this is really coming together !! |
Hey, is it possible to authenticate via my own OpenID Connect Identity Provider? |
I would like to require authentication to pub/sub to topics at least on private servers.
I think Google Identity would be a good provider here since authenticating to it is a familiar part of the types of workflows I would like to incorporate this into.
The text was updated successfully, but these errors were encountered: