foundryvtt / foundryvtt

Public issue tracking and documentation for Foundry Virtual Tabletop - software connecting RPG gamers in a shared multiplayer environment with an intuitive interface and powerful API.
https://foundryvtt.com/
198 stars 10 forks source link

[Feature Request] Support an option for HTTP authentication for additional security or application integrations #3568

Open aaclayton opened 3 years ago

aaclayton commented 3 years ago

Originally in GitLab by @jorge100

Feature Summary

Many apps similar to foundry in node hosted mode offer some mechanism for third party apps to perform logins/manage users. An example of a good use case of this would be for someone to build an app that allows users to sign in with Discord SSO and link discord users to specific foundry users.

One of the largest benefits of this would be that those of us who run foundry as a node hosted app would have an easier time securing the app against trolls/malicious actors/etc. The current password system isn't very strong, and I think by offering this feature (rather than trying to design a bullet-proof encrypted password/login scheme) it would be much easier to run a more secure foundry site.

User Experience

From a developer's perspective there are a variety of possible designs for such a feature, the simplest I can think of would be to offer a small token based HTTP API that allows for some form of a user auth or login token to be created, which can then be used as part of a URL parameter to the /join endpoint. There are some security downsides in this approach but it might reasonably split the difference between complexity and offering an improvement.

Priority/Importance

I think improvements to the security of node hosted foundry apps is very important. If it hasn't already happened it really only takes one or two foundry sites getting horribly trolled for there to be some really angry customers.

If a feature like this were added it should be possible for others to build simple SSO integration modules for their preferred login service (Facebook/Google/Discord/etc) thus enhancing the security of a hosted foundry app substantially. If you need help designing such a feature I have some experience in the area and could be interested in helping with the design.

aaclayton commented 2 years ago

Originally in GitLab by @ishtanzar

Authentication mechanisms could be optional and configurable with options.json. For offline instances no need to setup anything, but the moment you go online you need something. Grafana has a pretty nice authentication configuration system, offering various basic OAuth providers and a generic one to ease integration. While not offering EVERYTHIN at once, Foundry could offer basic & generic OAuth and offer Facebook, Google SSO over time. I recently included Discord SSO into Foundry with a combination of server & client modules (still a work in progress at the time of this writing) but it was farily simple to create:

aaclayton commented 3 years ago

marked this issue as related to #4462

aaclayton commented 3 years ago

Originally in GitLab by @damccull

I just thought of a second concern with headers that needs to be addressed if the devs go this route. I'm sure it's already been noticed, but I don't want to take the chance it hasn't been. Headers are notoriously easy to spoof. I can set any header I desire with a simple browser extension, many of which are one-click installable from various browser extension stores.

If the header option is to be official, there needs to be some guard in place to authenticate that the header was set by the second-layer security application rather than being passed straight through to the application by the reverse proxy. Proxies do, after all, pass headers through.

A simple, though not necessarily truly secure, option would be to have the security application hash a pre-shared password with some deterministic time-based data and prepend that to the data in the header. Then foundry would need to verify that its own copy of the pre-shared key will hash into the same result before taking the header's username from the payload.

aaclayton commented 3 years ago

Originally in GitLab by @damccull

Well, even with an oauth2 based solution, the app would still need to track the session based on cookies. The difference would be in how the authentication is handled on the back side. I would argue that the header option, while great for external security tools to shadow the program, would simply require a second authentication mechanism to co-exist with the current password/cookie based mechanism. You can't simply remove the existing in favor of headers because not everyone will be using a reverse proxy, and those people will still need some kind of authentication capability.

Either of our solutions would require significant architecture changes. For headers, the application would need to have the ability to identify the user passed in via headers, match it to a foundry-held database anyways, and then disable the password mechanism for that user on a session-by-session basis. In this case the app is already trusting a 3rd party authenticator, just like it would be doing with the OIDC implementation, except that now a custom protocol needs to be designed pass the user information from the authenticator to foundry.

The best-case scenario would give us both the headers and the OIDC solutions. Obviously, I'm biased toward the OIDC solution, but that's because it's a known protocol that's fairly easy to implement, and it interoperates with thousands of existing authenticators where people already have accounts. In addition, having foundry include its own, built-in OIDC provider can handle the locally username/password case by default while still allowing that outside integration all in a single stack. Even with this option, foundry could still be reverse proxied without an issue. Except that the proxy wouldn't handle authentication.

aaclayton commented 3 years ago

Originally in GitLab by @neunzehnhundert97

I think your are right when pointing out the usefulness of OpenID Connect and also when arguing that the complexity would be hidden for users, both DMs and players. On the other hand, I think it would be much more difficult to implement it safely. There are countless pitfalls to be taken into account.

Of course, I am biased towards my own suggestion using headers, but I presume it would be a lot easier to implement. Currently (as far as I can see), foundry uses cookies to track sessions. Switching to a header or multiple ones is comparably easier than implementing OIDC, which is a whole new protocol. The nice thing about delegating the security to a proxy, is that foundry remains agnostic and can work with whatever one wants to use.

In the end, any means of security need some effort by the deploying party and I would argue that a person knowing and caring about OpenID Connect is capable of setting up a proxy to handle it for them.

aaclayton commented 3 years ago

Originally in GitLab by @damccull

I think the complexity might be easily hidden, to be honest. The GM and player flows don't need to be complex, especially if using the built-in provider I described. On the core developer side, I agree it would add complexity, but I don't think it'd add any more complexity than the header forwarding they're already talking about, and it would definitely be easier on the users than the header forwarding with a reverse proxy they need to manually set up.

aaclayton commented 3 years ago

Originally in GitLab by @foresto

OpenID Connect could indeed be useful to some folks, but even as someone who has coded and administered identity providers and relying parties, I would view such a requirement as an unwelcome level of complexity in Foundry. OIDC works well in certain situations, but it just doesn't fit everywhere.

aaclayton commented 3 years ago

Originally in GitLab by @damccull

Personally, I would like to see the foundry server just require an openidconnect (or oauth2 minimum) authorization.

This suggestion would see the application include: 1) Existing web server that now requires an oauth2/openidConnect login 2) A small openidConnect provider with user administration through the admin console 3) The admin console set up to handle the creation/management/deletion of users to the oauth2 service (this can be also be represented in the GM panel in worlds), as well as any other oauth2 federations the server owner desires through a simple control panel. 4) Solves the single sign on issue without requiring proxies and pass-through headers, making it far more simple for a customer to set up. 5) Allows all of this to work with the native installer as well as the headless server.

This would give the following benefits:

  1. Supply the security the OP asked for by providing the choice between locally managing users/passwords or offloading that to another provider that can be more secure and by removing the the currently existing simplistic security.
  2. Make the user experience for logging in simple and familiar to the rest of the internet (log in with google button, for example).
  3. The web app can trust the the user is who they say they are, assuming the openidConnect layer on top of oauth2.

In the admin panel, admins would see a tab for user/login management. Clicking on it would bring them to an interface where users can be managed.

New user accounts can be created internally and onetime or multi-use tokens can be created and used to invite new users to the system. The users would be given a URL, input the token, and be asked to either:

  1. Login with a social media provider OR
  2. Create a local username and password (if the server owner enables this)

Upon registering with the token and logging in successfully, the user account the admin created will be linked to the username/password, or to the social login. (Optionally provide a way for multiple openidconnect providers to be linked, and for a password to exist on the same account).

The admin would then create or open an existing world, and when opening the world's "users" panel, could just use checkboxes to select the users that will be allow to participate in this particular world. All authentication is handled by the underlying auth system, and no new usernames or passwords need to be distributed, yet only the selected players will be able to log into a loaded world.

Best of all, oauth2 with openidConnect is already supported by most of the internet, providers exist everywhere, and it's a perfect fit to allow federation. This would also easily allow systems like Forge to run their own oauth2 provider for their clients, and users who purchase services from them may be able to just select users that exist in Forge's database to add directly to their games.

aaclayton commented 3 years ago

Originally in GitLab by @foresto

Another Foundry user here, currently with nginx as the internet-facing part of the stack. +1 for Foundry accepting authentication from an upstream component.

This would be useful not only for the external/federated identity providers that are common with medium-to-large organizations, but also for small private hosts that want to put multiple web apps behind a single login form. For example, I could present a single login page for my users to access Foundry, our wiki, and our forum or calendar site, and appear as the same username on all of them. That would be much more convenient than having to maintain three passwords and log in thrice to use our campaign tools.

It would also allow those of us who care about good security practices to move away from passwords stored in cleartext, and would relieve me from the embarrassment of explaining to my tech-savvy users why I'm asking them to tell me their passwords, without burdening Foundry with implementing things like key derivation functions and password recovery procedures.

aaclayton commented 3 years ago

From @neunzehnhundert97

Feature Summary

Foundry itself only has a small range of authentication options, currently only user/password is available. By using another layer in front of foundry itself (e.g nginx as reverse proxy), the host can deploy many more means for protecting the access. The problem is that the front layer cannot relay any information about the authorization to the foundry server. So after authenticating as user X, the user has to do this step again on foundry's login page. The easy solution is not setting any passwords in foundry's layer, but this allows for players to login as other players.

By adding an HTTP header as optional feature, that is set by the front layer, foundry could forgo its own login page and directly proceed to the game. This header would simply contain the user name and would be checked against the list of known users. If a direct match is found, the user is logged in, otherwise, he is rejected. When no game world is started yet, a special user should be globally defined as admin who can start game worlds and access all other configurations.

The following steps would have to be implemented

User Experience

For players:

Currently, when accessing a foundry instance protected by another layer, a user has to authenticate twice, once for the first layer and a second time for foundry. If the first layer already involves a username, the second time seems very superfluous, even with no additional password. With the proposed feature, the second stage completely vanishes and improves the user experience.

For DMs/Hosts:

The host only needs to take care of one layer of authentication. It feels a bit pointless to enforce a strong authentication in the first layer, when the second layer involves an obligatory second authentication. Otherwise, if the host does not care, because she hosts foundry on her PC and it is only active when she is actively using it, she may simply not use the option.

Priority/Importance

As I don't know how many other DMs use authentication in a layer in front of foundry itself (and care about it), this request has a low priority. In the end, I think it would be nice to have, nothing more or less.

aaclayton commented 3 years ago

Originally in GitLab by @jorge100

Yep I totally understand the access control system isn't intended to provide a high level of security, and I can see how it would probably distract from much more interesting and directly valuable work to put a lot of focus on making substantial improvements to the access control mechanisms that exist.

If foundry were only ever run on a single machine or in an offline network it really wouldn't matter so much, but as things stand there are instructions online for how to set up a hosted foundry instance which some number of people will follow. Those people will end up owning servers out on the public internet that could fairly easily be abused, and I think the Foundry team has a responsibility to at least make it possible for users to protect themselves when running the app this way. You can argue that it is on users to protect themselves properly, but that seems like kind of a harsh and uncaring way to look at it.

One simple example of the kind of abuse that could occur is that someone could discover that foundry exists and has easily accessible mechanisms to upload/download images. A malicious entity could decide to start searching for open foundry servers to start using this functionality to store and distribute illegal images. A best this creates some nasty billing headaches for the server owner and at worst maybe even some serious legal problems. This type of thing has happened in the past, the classic example is WordPress. Their original stance on this kind of security concern was basically "who wants to mess with someone's tiny blog, there's no way this security stuff matters much". The result was that WordPress became infamous for some of its early security bugs.

A simple optional federated access API would make it simpler for the community to develop tools to put foundry behind any number of already existing SSO solutions. From the amount of community support this project seems to have I suspect there would be at least a few community implementations out there that would make it much easier for less experienced individuals to set up their own hosted foundry instances safely.

Finally, I'd really like to make clear that if any of this feedback seems harsh I don't mean it that way. Quite the contrary I'm happy with most of what I've seen with Foundry so far and I'm really excited to use it for our games. I also realize the software is still in really early days given it is so new and just can't support every use case perfectly out of the box. I'm not intending to criticize, only point out that this may be a more important area than it has previously been considered.

aaclayton commented 3 years ago

I don't share your opinion on this - the access control system for Foundry Virtual Tabletop is not intended to provide the level of security you advocate for.

It's possible that I will add configurable options for different auth models in the future. The current approach to access keys and auth is an intentional choice rather than an oversight.

aaclayton commented 3 years ago

Originally in GitLab by @jorge100

My biggest concern really is that the current auth mechanisms are really ripe for abuse. The only workaround for now is just to put some authentication layer in front of the entire app. It's not the best user experience but it is an improvement.

In general, security things like this tend to look less important than they are until something goes wrong. It's worth considering other ways to improve the access control for this app if this is too much work to be worth the benefit.

aaclayton commented 3 years ago

One of the key reasons I haven't offered any sort of federated login options for use with Foundry is the requirement that the app can be used offline.

Certainly such a system could be optional, where the server host would opt-in to that authentication mode, but this is a case of it not feeling like enough of a natural fit or a high enough priority.

There's good aspects of the idea though, happy to let it marinate a bit and see whether it becomes a recurring request.