Skip to content
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

Closed
dwmccheyne opened this issue Nov 24, 2021 · 53 comments
Closed

Auth #19

dwmccheyne opened this issue Nov 24, 2021 · 53 comments
Labels
android-app ntfy Android app enhancement New feature or request 🔥 HOT Lots of people want this in-progress 🏃 I'm working on this right now unified-push UnifiedPush feature or bug

Comments

@dwmccheyne
Copy link

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.

@binwiederhier binwiederhier added enhancement New feature or request android-app ntfy Android app labels Nov 24, 2021
@binwiederhier
Copy link
Owner

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

@aslmx
Copy link

aslmx commented Nov 25, 2021

👍

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

@binwiederhier
Copy link
Owner

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

@aslmx
Copy link

aslmx commented Nov 26, 2021

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.

@shadow00
Copy link

shadow00 commented Dec 1, 2021

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.

@binwiederhier
Copy link
Owner

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?

@shadow00
Copy link

shadow00 commented Dec 2, 2021

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.

@aslmx
Copy link

aslmx commented Dec 2, 2021

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.

@shadow00
Copy link

shadow00 commented Dec 2, 2021

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

@rigrig
Copy link

rigrig commented Dec 3, 2021

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.

@binwiederhier
Copy link
Owner

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

@rigrig
Copy link

rigrig commented Dec 3, 2021

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

@binwiederhier binwiederhier added the 🔥 HOT Lots of people want this label Dec 16, 2021
@gedw99
Copy link

gedw99 commented Dec 29, 2021

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

@binwiederhier
Copy link
Owner

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

@binwiederhier
Copy link
Owner

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

@gedw99
Copy link

gedw99 commented Dec 30, 2021

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

@binwiederhier binwiederhier changed the title Offer Authentication for self hosted instances Authentication/Authorization Dec 30, 2021
@gedw99
Copy link

gedw99 commented Dec 31, 2021

@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 

@gc-ss
Copy link

gc-ss commented Dec 31, 2021

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.

@gedw99
Copy link

gedw99 commented Jan 1, 2022

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 ?

@binwiederhier
Copy link
Owner

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

@binwiederhier binwiederhier mentioned this issue Jan 1, 2022
Closed
@nmoseman
Copy link

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.

@binwiederhier
Copy link
Owner

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

@binwiederhier
Copy link
Owner

binwiederhier commented Jan 22, 2022

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

@julianfoad
Copy link

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"

@gedw99
Copy link

gedw99 commented Jan 27, 2022

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

@binwiederhier
Copy link
Owner

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.

@binwiederhier
Copy link
Owner

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

@gedw99
Copy link

gedw99 commented Jan 27, 2022

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 .

@gc-ss
Copy link

gc-ss commented Jan 27, 2022

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/

@binwiederhier
Copy link
Owner

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

@binwiederhier
Copy link
Owner

Progress:
220129 22-30-48 Selection 001

220129 22-31-01 Selection 001

220129 22-31-14 Selection 001

@binwiederhier binwiederhier changed the title Authentication/Authorization Auth Jan 31, 2022
@binwiederhier
Copy link
Owner

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

@gc-ss
Copy link

gc-ss commented Jan 31, 2022

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)

@Mek101
Copy link

Mek101 commented Jan 31, 2022

Progress: 220129 22-30-48 Selection 001

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

@Mek101
Copy link

Mek101 commented Jan 31, 2022

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?

@karmanyaahm
Copy link
Contributor

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.

@binwiederhier
Copy link
Owner

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

@binwiederhier
Copy link
Owner

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.

@cmeis
Copy link
Contributor

cmeis commented Jan 31, 2022

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

@gedw99
Copy link

gedw99 commented Jan 31, 2022

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

@gedw99
Copy link

gedw99 commented Jan 31, 2022

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.

@binwiederhier
Copy link
Owner

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

@binwiederhier
Copy link
Owner

binwiederhier commented Feb 4, 2022

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:

@binwiederhier
Copy link
Owner

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.

@gedw99
Copy link

gedw99 commented Feb 5, 2022

well done @binwiederhier this is really coming together !!

@Kranzes
Copy link

Kranzes commented Mar 14, 2024

Hey, is it possible to authenticate via my own OpenID Connect Identity Provider?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android-app ntfy Android app enhancement New feature or request 🔥 HOT Lots of people want this in-progress 🏃 I'm working on this right now unified-push UnifiedPush feature or bug
Projects
None yet
Development

No branches or pull requests