Giter Site home page Giter Site logo

Auth about ntfy HOT 52 CLOSED

binwiederhier avatar binwiederhier commented on May 4, 2024 6
Auth

from ntfy.

Comments (52)

binwiederhier avatar binwiederhier commented on May 4, 2024 5

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:
a) The "subscription settings" are a little weird, because they only contain the login stuff right now. There will be topic-specific settings (notification sound, paused notifications, min priority, ...) too later.
b) I was thinking about visual indicators for which user a topic is using, e.g. little person indicators with a number or color. What do you think?
c) I think I definitely have to indicate in the main view when the auth fails. Right now it just says "reconnecting ..." forever.

Here's a full video of the entire flow:
https://phil.nopaste.net/7xfchbUB31?a=0zi01nlZsJ

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 5

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.

from ntfy.

aslmx avatar aslmx commented on May 4, 2024 4

πŸ‘

Interim step could be to support basic auth. Haven't tried if that would work?
Curl should support it, but would the android app?

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 4

I think I'll look at something with basic auth to begin with. Especially since that's incredibly easy to do with curl too.

from ntfy.

julianfoad avatar julianfoad commented on May 4, 2024 4

Even though you've gone down this road, I still want to record what I mentioned in the chat a few weeks ago, about how I'm disillusioned with trying to self-host services that take the Do-It-Yourself Auth approach with their own user-password database, their own rules for valid usernames, their own system of roles and permissions, their own security model, and expect me to directly expose their own security implementation to the internet while running on my home server. Mainly my concern is not about security against hackers but about my ability to manage consistent logins, usernames, password updates (and preferably single-sign-on too) across several small self-hosted services.

The best way to support self-hosting (and I mean to say this to all self-hostable projects) is to provide the simple ability to connect to standard auth mechanisms.

I wish you could even now reconsider instead to make the client compatible with external (reverse-proxy based) auth standards such as http-basic (the simplest) and (the next step up) the session-cookie based "forward auth" flow which is described well in Authelia's architecture doc page. Authelia is just one such auth front-end, not a special case.

With those kinds of auth schemes, adding awareness of "users" to the server is completely optional. You can start with a system where just "successful authentication" according to the external auth front-end is enough and once past that then whoever authenticated will have full access to the server (the old existing ntfy server before you started adding auth awareness). Then if you want to add "user accounts" to the server you don't need to add authentication code but merely look at the "Remote-User" HTTP header on every request, which is added for you by the reverse proxy in combination with the auth front-end -- explained in Authelia - How can the backend be aware of the authenticated users?

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024 4

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

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 3

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...

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 3

i would combine them but allow a user to via the cmd to pick via a flag if the system runs as a single service or as a archetype of each service .

Thank you for your response. I think you must have misunderstood my comment. I was merely talking about one sqlite database vs. two, not about two services/binaries. For now I opted to a different database for user+access management.

Here's an excerpt from the user/access management as I have implemented it currently:

# Create admin user phil
$  ntfy user add --role admin phil 
Password:
Confirm:
User phil added with role admin

# Create normal user ben
$ ntfy user add ben
Password:
Confirm:
User ben added with role user

# Grant read-write access for ben to topic mytopic
$ ntfy access ben mytopic rw
Granted read-write access to topic mytopic

User ben (user)
- read-write access to topic mytopic

# Grant read-only access for ben to topic readme
$ ntfy access ben readme read-only
Granted read-only access to topic readme

User ben (user)
- read-write access to topic mytopic
- read-only access to topic readme

# Grant access to anonymous users to announcements topic
$ ntfy access everyone announcements read-only
Granted read-only access to topic announcements

User * (anonymous)
- read-only access to topic announcements
- read-write access to all (other) topics (server config)

# Show entire access control list
$ ntfy access
User phil (admin)
- read-write access to all topics (admin role)
User ben (user)
- read-write access to topic mytopic
- read-only access to topic readme
User * (anonymous)
- read-only access to topic announcements
- read-write access to all (other) topics (server config)

# Not allowed because anonymous user does not have any permissions to any topics
$ curl -d hi localhost/mytopic
{"code":40301,"http":403,"error":"forbidden"}

# Allowed because phil is admin
$ curl -d hi -u phil:phil localhost/readme
{"id":"zdf7mRUXWD","time":1643038509,"event":"message","topic":"readme","message":"hi"}

$ curl -d "important announcement" -u phil:phil localhost/announcements
{"id":"5AgEgeBGTU","time":1643038727,"event":"message","topic":"announcements","message":"important announcement"}

# Allowed because ben has read-write permission to topic mytopic
$ curl -d hi -u ben:ben localhost/mytopic
{"id":"sxz1Wky3zW","time":1643038381,"event":"message","topic":"mytopic","message":"hi"}

# Not allowed because ben only has read permissions to topic readme
$ curl -d hi -u ben:ben localhost/readme 
{"code":40301,"http":403,"error":"forbidden

# Allowed because ben has read permissions to topic readme
$ curl -u ben:ben "localhost/readme/json?poll=1"
{"id":"zdf7mRUXWD","time":1643038509,"event":"message","topic":"readme","message":"hi"}

# Allowed because the "everyone" user has read access to announcements
$ curl "localhost/announcements/json?poll=1"
{"id":"5AgEgeBGTU","time":1643038727,"event":"message","topic":"announcements","message":"important announcement"}

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 3

Still working on this. The server side is solid and working, and I've written tests for pretty much everything. I've also started wireframing the Android changes. It's gonna be a lot of work unfortunately.

220125 11-28-56 Selection 001

220125 12-00-09 Selection 001

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 2

The only thing I need would be to have basic auth support in the client

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.

Somebody will figure out how to abuse it.

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

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 2

I gotta say Authelia and Traefik look very interesting, though this is what I found with most of these solutions:

Authelia is an open source authentication and authorization server protecting modern web applications

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

ZITADEL only needs Kubernetes for orchestration and CockroachDB as storage.

The "only" here for me is almost ironic. :-)

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024 2

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 .

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 2

Progress

220128 16-09-09 Selection 001

220128 16-08-45 Selection 001

220128 16-09-00 Selection 001

220128 16-10-16 Selection 001

220128 16-10-04 Selection 001

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 2

Progress:
220129 22-30-48 Selection 001

220129 22-31-01 Selection 001

220129 22-31-14 Selection 001

from ntfy.

aslmx avatar aslmx commented on May 4, 2024 1

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.
I guess most people will run ntfy behind nginx or Traefik, etc.

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.

from ntfy.

shadow00 avatar shadow00 commented on May 4, 2024 1

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 "Authorization" header, or by simply including a "token" field along with the message/subscription request. Note that the server would not include the token when relaying a message. For public topics this field could be omitted, or assumed/left empty by default.

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:

  • A publisher cannot send a message without providing the appropriate token.
  • A subscriber cannot subscribe to a topic without providing the appropriate token.
  • An admin can request a list of the current tokens, add a token to a specific list, remove a token from a specific list.
    • Something like https://ntfy.sh/mytopic/tokens, https://ntfy.sh/mytopic/addtoken, https://ntfy.sh/mytopic/rmtoken,

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 auth.json:

{
    "mytopic": {
        "admin": ["LhaC8heEBOu9YPVc", "XqyNlCyqUDq6g7oM"],
        "pub": ["NSgG47rbMLdDxl0L", "rppJwLr8HaEs2WtF", "1RoqplTLvIKvIAMM", "iqp5qgmKenWjd1I6"],
        "sub": ["NSgG47rbMLdDxl0L", "rppJwLr8HaEs2WtF", "1RoqplTLvIKvIAMM", "ahPaEtqoY0i8MWwN"]
    },
    "topic2": {
        "admin": [],
        "pub": ["IyWmTqwmZuLNFPxZ", "WTliVPeTp602x51L"],
        "sub": ["IyWmTqwmZuLNFPxZ", "WTliVPeTp602x51L"]
    }
}

Note how mytopic has two admin tokens, iqp5qgmKenWjd1I6 can only publish, ahPaEtqoY0i8MWwN can only subscribe, and the other three can do both.
As for topic2, there are no admin tokens - so only those two client tokens would be able to pub/sub, and nobody would be able to change that list except the server administrator.

from ntfy.

shadow00 avatar shadow00 commented on May 4, 2024 1

@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.

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 1

Just an update on the general status of this ticket: After the unified push ticket (#9), I'll work on this.

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024 1

@binwiederhier

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:


./dendrite-monolith-server
INFO[2021-12-31T12:44:07.462887000Z] [base.go:126] NewBaseDendrite
         Dendrite version 0.5.1+901adbf0.nats         
[43499] [INF] Starting nats-server
[43499] [INF]   Version:  2.6.4-beta
[43499] [INF]   Git:      [not set]
[43499] [INF]   Name:     monolith
[43499] [INF]   Node:     2VDOOQDB
[43499] [INF]   ID:       NCIKDODW6BMOBVLIBNHMWU2I6UXCCN3323BHJ7UUTLPK3U3QFXLDLYPQ
[43499] [INF] Starting JetStream
[43499] [INF]     _ ___ _____ ___ _____ ___ ___   _   __  __
[43499] [INF]  _ | | __|_   _/ __|_   _| _ \ __| /_\ |  \/  |
[43499] [INF] | || | _|  | | \__ \ | | |   / _| / _ \| |\/| |
[43499] [INF]  \__/|___| |_| |___/ |_| |_|_\___/_/ \_\_|  |_|
[43499] [INF] 
[43499] [INF]          https://docs.nats.io/jetstream
[43499] [INF] 
[43499] [INF] ---------------- JETSTREAM ----------------
[43499] [INF]   Max Memory:      6.00 GB
[43499] [INF]   Max Storage:     24.18 GB
[43499] [INF]   Store Directory: "jetstream"
[43499] [INF] -------------------------------------------
[43499] [INF]   Restored 0 messages for stream "InputRoomEvent"
[43499] [INF]   Restored 0 messages for stream "OutputClientData"
[43499] [INF]   Restored 0 messages for stream "OutputKeyChangeEvent"
[43499] [INF]   Restored 0 messages for stream "OutputReceiptEvent"
[43499] [INF]   Restored 0 messages for stream "OutputRoomEvent"
[43499] [INF]   Restored 0 messages for stream "OutputSendToDeviceEvent"
[43499] [INF]   Recovering 1 consumers for stream - "InputRoomEvent"
[43499] [INF]   Recovering 1 consumers for stream - "OutputClientData"
[43499] [INF]   Recovering 3 consumers for stream - "OutputKeyChangeEvent"
[43499] [INF]   Recovering 2 consumers for stream - "OutputReceiptEvent"
[43499] [INF]   Recovering 2 consumers for stream - "OutputRoomEvent"
[43499] [INF]   Recovering 2 consumers for stream - "OutputSendToDeviceEvent"
[43499] [INF] Server is ready
INFO[2021-12-31T12:44:07.650699000Z] [api.go:95] NewFederationInternalAPI
         Enabled perspective key fetcher               num_public_keys=2 server_name=matrix.org
INFO[2021-12-31T12:44:07.720771000Z] [base.go:423] func2
         Starting external Monolith listener on :8008 

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024 1

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.
Then NATS Jetstream solved the issues and made LiftBridge less attractive to some.

I have not kept up with LiftBridge so much.
The pure GRPC basis is definitely a nice option.
Does LIftbridge has the ability for the client to automatically connect to nearest server and then fail over to nearest etc ?

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 1

I kindly ask to move NATS discussions here: #78 :-)

from ntfy.

nmoseman avatar nmoseman commented on May 4, 2024 1

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.

from ntfy.

gc-ss avatar gc-ss commented on May 4, 2024 1

@binwiederhier, a different and dedicated sqlite database per usecase makes a lot of sense and is really appreciated.

For example, I can now apply (https://litestream.io/) to the user+access management sqlite database and have a fairly reliable user+access serdes for ntfy on less reliable commodity servers.

Still not as reliable as LiftBridge/NATS but way simpler and practically close for very low user velocity!

from ntfy.

cmeis avatar cmeis commented on May 4, 2024 1

Oops, haven't pulled over my comments from the discord, will do now:

+1 for separate databases (user auth / cache)

I would suggest making access rules with wildcards at least a possibility. For starters (to be honest: for most cases) I'd like to see an asterisk wildcard, i.e. an access rule for "datacenter1-*" matching all topics starting with "datacenter1-".

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024 1

I have also found this path for my own projects .

but I did not want to rely on any third party and wanted it to be decoupled.

So I can recommend this.

https://github.com/authzed

it’s decoupled from your project and you can stand it up and it works with your golang ( or any language ) project

it’s self hosted authz basically but decoupled !

there is also the same thing for auth if your interested.

from ntfy.

julianfoad avatar julianfoad commented on May 4, 2024 1

Actually the "forward auth" flow is documented perhaps more generically in Traefik docs.

Example, snippets from my Authelia configuration.yml:

access_control:
  rules:
    # Unauthenticated public resources
    - domain: ['blog.example.org']
      policy: bypass
    # Authentication required for my ntfy service (any user I've configured)
    - domain: ['ntfy.example.org']
      policy: one_factor
    # Stronger auth, restricted to admins, for admin services
    - domain: ['admin.example.org']
      subject: "group:admins"
      policy: two_factor

and users_database.yml:

users:
  me: { groups: ['admins'], password: '$argon2id$v=19$m=1048576,t=1,p=8$xxxxxxxx' }
  other_user: { groups: ['users'], password: '...' }

and my Traefik-2 middleware rule, which reference from the routing rule of each service that I want protected:

http:
  middlewares:
    middlewares-authelia:
      forwardAuth:
        address: "http://authelia:9091/api/verify?rd=https://{{ authelia_login_domain }}"
        trustForwardHeader: true
        authResponseHeaders:
          - "Remote-User"
          - "Remote-Groups"

from ntfy.

karmanyaahm avatar karmanyaahm commented on May 4, 2024 1

Here's a full video of the entire flow:
https://phil.nopaste.net/7xfchbUB31?a=0zi01nlZsJ

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.

from ntfy.

cmeis avatar cmeis commented on May 4, 2024 1

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).

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024 1

great work @binwiederhier .
I skimmed over the golang PR and it looks nice and standard stuff.

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024 1

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:

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024 1

well done @binwiederhier this is really coming together !!

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024

Thank you very much for the incredibly detailed suggestion. That's awesome!

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).

So technically a topic is never created actively:

  • If caching is enabled, it just exists when there are cached messages until they expire (12h)
  • If caching is turned off, a topic never really exists for longer than a split second. A message is forwarded to all of its subscribers and then the topic is destroyed immediately.

I think this is solvable though.

This could be done for example via the "Authorization" header, or by simply including a "token" field along with the message/subscription request. Note that the server would not include the token when relaying a message. For public topics this field could be omitted, or assumed/left empty by default.

.. admin token ..

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 auth

When you publish or subscribe to a topic, you can additionally send a Authorization: token ... header as you suggested, e.g.

Authorization: token xDsdAkksdjdfFBalADA

my message

or

Authorization: token xDsdAkksdjdfFBalADA
  • If an Authorization header is present and the topic is not known, the topic is reserved for topic-auth-reservation: 24h (configurable), during which time the topic will not be reaped and only requests with a valid auth can publish/subscribe
  • The topic expiration time is automatically extended as long as you are actively connected. So effectively a topic never expires as long as you are connected. And when you are disconnected, you have topic-auth-reservation to reconnect before the topic expires.

Server-wide auth

Instead of doing a topic specific Authorization, you configure a server-auth: mysecrettoken or something which applies to all topics. This would be the simplest way to make a private server.

All configs:

auth-mode: (none|server-wide|per-topic)     # defaults to none
server-auth: <token>
topic-auth-reservation: 24h 

Thoughts?

from ntfy.

shadow00 avatar shadow00 commented on May 4, 2024

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 topic-auth-reservation < cache-duration? I see the following options:

  • configuration error that prevents the server from starting (easiest to implement, but perhaps a bit limiting?)
  • topic becomes public, any previous cached message is kept but only accessible if the correct auth token is provided (too messy imo)
  • topic becomes public, any previous cached message becomes publically available (bad idea/potential security risk, defeats the purpose of authorization)
  • topic becomes public, any previous cached messages are deleted - effectively, the topic is unregistered and the server knows nothing about it anymore (this seems the best option to me)

What about making the per-topic auth duration dynamically configurable? Eg. by providing an additional (possibly optional) Reservation-period header (or maybe something with a better name). If the header is provided, use that when setting the grace period and renewing the topic; otherwise, the server-configured value is used by default. Server-side, this second parameter would be stored along with the auth token inside your reservation list.

from ntfy.

aslmx avatar aslmx commented on May 4, 2024

Haven't fully understood the last comments about tokens.
But please consider: adding API Tokens that I have to setup first for a topic will void the key selling point of ntfy for me and basically I could stick to use gotify.

from ntfy.

rigrig avatar rigrig commented on May 4, 2024

Maybe there could also be a auth-mode: publish: everybody can subscribe (if you know the topic), but you need the server-auth token to publish?

And I guess it would be nice if server-auth could be a list, so you can hand out different tokens to different publishers.

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024

@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 server-wide one pretty easily and push that out, but I think I'll need a little bit of time for the others to get it right. Please keep suggestions coming!!

from ntfy.

rigrig avatar rigrig commented on May 4, 2024

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. publish would be the same as server-wide, except you don't need a token to subscribe.)

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024

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 .

https://github.com/nats-io/nats-server

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024

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

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024

work

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?

NATS is light !! Its fast 8 million pub subs per senc on a old mac laptop if no durability.
You can embed it like here: https://github.com/simpleiot/simpleiot/blob/master/natsserver/nats-server.go so you dont have to run it as a seperate server too.
If you want durability just add a flag to use NATS jetstream if you need it too.

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.

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
https://github.com/ripienaar/piper

Also this exposes nats over http which you need i guess.
https://github.com/ripienaar/nats-roundtripper

The "Why" aspect is compelling IMHO.

Also: This ticket is about Auth, so maybe we should move this convo somewhere else. Feel free to open a NATS ticket :-D

from ntfy.

gc-ss avatar gc-ss commented on May 4, 2024

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.

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024

This WIP PR (#114) implements this approach:

sqlite> SELECT * FROM user;
user        pass                                                          role      
----------  ------------------------------------------------------------  ----------
phil        $2a$06$.4W0LI5mcxzxhpjUvpTaNeu0MhRO0T7B.CYnmAkRnlztIy7PrSODu  admin     
ben         $2a$06$skJK/AecWCUmiCjr69ke.Ow/hFA616RdvJJPxnI221zyohsRlyXL.  user      
marian      $2a$06$N/BcXR0g6XUlmWttMqciWugR6xQKm2lVj31HLid6Mc4cnzpeOMgnq  user      

sqlite> SELECT * FROM topic;
topic          anon_read   anon_write
-------------  ----------  ----------
announcements  1           0         

sqlite> SELECT * FROM topic_user;
topic       user        read        write     
----------  ----------  ----------  ----------
alerts      ben         1           1         
alerts      marian      1           0         

In this example, phil can do everything, ben can read and write only to alerts and marian can read from alerts. Anonymous users can read from announcements.

There will be the following config params:

auth-file: /var/lib/ntfy/user.db

# Defines the fallback if no entry in the database is found
auth-default-read: false
auth-default-write: false

ntfy.sh will be set to auth-default-read/write: true, since everyone can write/read from everything.

I like this design a lot. It's super simple, yet infinitely flexible.

Feedback required: What I am unsure about is

  1. whether or not to combine this SQLite database with the message cache.db. Currently there is /var/cache/ntfy/cache.db that contains messages. And now there will be /var/lib/ntfy/user.db. We could just combine them to /var/lib/ntfy/database.db.
  2. whether or not I need to write an admin CLI or web UI for this. I will eventually make a proper UI, obviously..

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024

About the PR and if you combine the DB or keep them separate

i would combine them but allow a user to via the cmd to pick via a flag if the system runs as a single service or as a archetype of each service .

so the deployment is always a single binary but you can run in either fashion.

If you boot each service individually you can scale out .

hope I explained my self well ?

here is an example of running all the services as one binary and hence one db :

https://github.com/matrix-org/dendrite/tree/master/cmd/dendrite-monolith-server

But as you can see you can also run a cmd as individual services and hence individual databases for each service

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024

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.

from ntfy.

gc-ss avatar gc-ss commented on May 4, 2024

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 - docker-compose should work right OOB now (If not, please let me know).

They also have a generous free tier.

as long as they can stand next to the no-dependency-integrated one.

That said, for something lightweight like ntfy authentik is extremely simple and more interestingly - wouldn't require ntfy to be auth aware at all (depends on what level of authz we want ntfy to support) - which checks the no-dependency-integrated box

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 docker-compose and check it out right away or jump in on the chat with any questions.

https://goauthentik.io/

from ntfy.

gc-ss avatar gc-ss commented on May 4, 2024

b) I was thinking about visual indicators for which user a topic is using, e.g. little person indicators with a number or color. What do you think?

I prefer things that are accessible to majority of people - so number over color (colorblindness)

from ntfy.

Mek101 avatar Mek101 commented on May 4, 2024

Progress: 220129 22-30-48 Selection 001

I would remove "You can also add a user when adding a topic"

from ntfy.

Mek101 avatar Mek101 commented on May 4, 2024

b) I was thinking about visual indicators for which user a topic is using, e.g. little person indicators with a number or color. What do you think?

I prefer things that are accessible to majority of people - so number over color (colorblindness)

What does the Material Design guidelines say about that?

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024

I prefer things that are accessible to majority of people - so number over color (colorblindness)

I agree. I'll do that.

When anonymous has no access to any topics, does that include write access?

There's a setting auth-default-access = [deny-all|read-only|read-write] that defines the anonymous access behavior. I could obviously also make a write-only for anonymous access, I didn't think there was a use case. Now there is one :-)

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.

A UnifiedPush topic is just a topic, so if you make it /up*, then you effectively let people use the server as if it was fully open (with a small name restriction). Right now, pattern based ACL rules are not supported, though it has been asked for by @cmeis before, and since you're effectively the second person to ask, I may just implement that.

For UP, I'd say the best we can do if you want a "private server" is what you described:

  • Set auth-default-access = deny-all in server.yml
  • Run ntfy access everyone "up*" write-only
  • Run ntfy user add --role admin myuser and assign that in the Android app (not done yet).

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024

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.

from ntfy.

gedw99 avatar gedw99 commented on May 4, 2024

Maybe you like this...

https://github.com/mikestefanello/pagoda

  • ENT DB with atlas migration.
  • simple way of managing users.

the point with Ent os developer velocity.

from ntfy.

binwiederhier avatar binwiederhier commented on May 4, 2024

Video:
https://phil.nopaste.net/YhbTac9AoL?a=YgMgHVdXRv

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:
ntfy binary: https://phil.nopaste.net/ntfy-auth-1?a=BA0OLM8HiE
ntfy Android app: https://phil.nopaste.net/ntfy-auth-app-1.apk?a=AuUjHSlgpk

# in the server.yml
auth-file: /home/pheckel/Code/ntfy/playground/user.db
auth-default-access: deny-all

from ntfy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.