Open paulfitz opened 3 years ago
A common way of implementing authentication, without having to provide local authentication (similar to what @outline
does), is to make use of the Passport.js ecosystem, providing some OIDC adapters by default, with the option the extend these with other authentication adaptor plugins.
Seems reasonable @almereyda. We have SAML support on the way, for people wanting to use Grist with their SSO.
SAML support is now available. We'll need to do a write-up on how to configure it, but there is documentation at https://github.com/gristlabs/grist-core/blob/main/app/server/lib/SamlConfig.ts
Authentik looks like a decent self-hosted sso solution. I just tested it and it works well with Grist, using SAML.
I'm trying to setup grist self-hosted with authentik (docker). //docker-compose environment:
In the browser console log:
Mixed Content: The page at 'https://grist.#my-domain#.cloud/o/docs/' was loaded over HTTPS, but requested an insecure resource 'http://grist.#my-domain#.cloud:8484/o/docs/api/session/access/active'. This request has been blocked; the content must be served over HTTPS.
So the domain appears to be correct but http and port aren't .... Can I solve this issue with some configuration (env) ?
Hi @FVilli, try setting the variables mentioned in https://github.com/gristlabs/grist-core/issues/117#issuecomment-1004358045:
One thing you could try is to set environment variables APP_DOC_URL and APP_HOME_URL to whatever way your site will be accessed by the user. If your site is now at https://example.com, you would set those two variables to that (including the https).
We use LDAP and OIDC internally, would be helpful not having to setup a SAML provider
Thank you for sharing this interesting app! It already beats NocoDB and Baserow for me because it supports nested formulas. Good stuff.
I just got it working with Keycloak 17. It's a complicated beast that supports multiple multiple realms and protocols. Some things were not obvious to me (as a noob to Grist, Keycloak, and SAML)...
I already had a realm and user, so I only needed to create a Grist-specific SAML client:
https://<grist-host>/saml/metadata.xml
https://<grist-host>/*
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
Grist needs the following information from Keycloak:
https://<keycloak-host>/realms/<realm>/protocol/saml
(in Keycloak 16, it would've been https://<keycloak-host>/auth/realms/<realm>/protocol/saml
; note the /auth
)-----BEGIN RSA PRIVATE KEY-----
/-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
/-----END CERTIFICATE-----
Here's how I start Grist (behind a reverse-proxy):
URL="https://<grist-host>"
SAML="https://<keycloak-host>/realms/<realm>/protocol/saml"
docker run -d --name=grist \
-e GRIST_SINGLE_ORG=docs \
-e APP_HOME_URL="${URL}" \
-e APP_DOC_URL="${URL}" \
-e GRIST_SAML_SP_HOST="${URL}" \
-e GRIST_SAML_SP_KEY=/persist/saml/client.key \
-e GRIST_SAML_SP_CERT=/persist/saml/client.crt \
-e GRIST_SAML_IDP_LOGIN="${SAML}" \
-e GRIST_SAML_IDP_LOGOUT="${SAML}" \
-e GRIST_SAML_IDP_CERTS=/persist/saml/idp.crt \
-e GRIST_SAML_IDP_UNENCRYPTED=1 \
-v grist-data:/persist \
-p 8484:8484 \
gristlabs/grist
Oh... and if you, like me, are tempted to upgrade Keycloak from 16 to 17... it's a tarp! There are significant changes, so look before you leap.
I hope this helps someone. And yes, OIDC would be nice too, but I totally understand that you're scrambling to fix bugs after posting this on Reddit.
Thanks a lot for posting that @jyio!
It would be nice if something simple like Authelia would be supported. That would mean reading headers like Remote-User, Remote-Groups, Remote-Name, Remote-Email
from the request (preferably configurable). This would enable a wider range of integration with existing login solutions and would allow people to try grist easier. I imagine that it would be relatively little code to add and probably also result in more people to be able to try grist (and maybe less support requests because SAML is a beast).
For instance I wanted to see how far I can take self-hosted currently, but I haven't been able to figure out whether teams are supported locally or one can just share with 2 members. I guess I will manage to setup SAML at some point to check that out :)
Header-based authentication would be great. Then everyone can use the preferred reverse proxy. For me it's Caddy with caddy-security, for apollo13 it's Authelia. Most of the self-hosted admins use a reverse proxy.
@jyio can you post your complete Grist and Keycloak configuration please? I don't get a login page in Keycloak. Never used Keycloak for SAML, only some trials with OAuth (which worked). Thank you!
Edit: Finally it works also for me with Keycloak. Also for Grist I was unsure about the login url for saml. Here is my saml config for Grist:
GRIST_SAML_SP_HOST=https://grist.example.com
GRIST_SAML_SP_KEY=/saml/sp.key
GRIST_SAML_SP_CERT=/saml/sp.crt
GRIST_SAML_IDP_LOGIN=https://keycloak.example.com/auth/realms/<my grist realm>/protocol/saml
GRIST_SAML_IDP_LOGOUT=https://keycloak.example.com/auth/realms/<my grist realm>/protocol/saml # doesn't work
GRIST_SAML_IDP_UNENCRYPTED=1
GRIST_SAML_IDP_CERTS=/saml/idp.crt
In Keycloak I also needed Valid Redirect URIs
: https://grist.example.com/*
. Rest of the Keycloak configuration is default after creating a new realm and adding one test user plus the informations from jyio.
Glad you got it working, @helmut72. Thank you for sharing your config! I just added my Grist config above.
I'm relatively new to Keycloak also. Because I recently installed 17.0.0, my login and logout URLs were both https://<keycloak-host>/realms/public/protocol/saml
(note: no /auth
, which was in 16..).
The logout does work (you get logged out from Grist and Keycloak) but Keycloak doesn't know where to redirect you after logging out. I set Logout Service Redirect Binding URL to https://<grist-host>/
.
Protip: If you set Root URL to https://<grist-host>
, then Valid Redirect URIs could be just /*
and Logout Service Redirect Binding URL could be /
.
Thank you, @jyio. Now logout also works. Great experience this weekend, one is Grist, second is learning basics about SAML. Now need to dive deeper into both.
Or maybe not overcomplicate things and just "integrate" with bitwarden (client is open source; server not but there is a very good open source reimplementation https://github.com/dani-garcia/vaultwarden/ ) and other (less secure but also widely used) credentials vaults.
Of course it misses some goodies (https://github.com/w3c/webappsec-change-password-url/issues/34 , https://github.com/dani-garcia/vaultwarden/discussions/1691 ) but even then it proves to be the top approach to login management.
Bitwarden/Vaultwarden isn't an authentication product, but a password manager. Can't be used for this part.
@helmut72 that was the point. Use some whatever internal infrastructure for login & roles management but expose only the minimum - i.e. login + password
. Let everything else up to the password manager.
Are you suggesting to use vaultwarden as some sort of centralized identity store, so Grist would just collect the credentials (from a login page) and verify them against vaultwarden? That's an interesting way to use vaultwarden... do you have any references for that?
Alternatively, just integrate with LDAP or AD, which are battle-tested for this case, but admittedly "enterprisey" (if you thought SAML was complicated). Or implement OIDC/OAuth2, which opens the door to an entire world of external identity providers (such as GitHub, Twitter, or Facebook). Or -- stay with me here -- configure Keycloak to consult an LDAP/AD server or delegate to an external SAML/OIDC provider, so you outsource the login as well as the identity.
@dumblob A password manager is no user management tool. With a password manager you save login informations for your self hosted services and other services like Github or your outlook.com account or whatever, but you don't have created this user accounts in Bit/Vaultwarden.
@dumblob A password manager is no user management tool. With a password manager you save login informations for your self hosted services and other services like Github or your outlook.com account or whatever, but you don't have created this user accounts in Bit/Vaultwarden.
This was my point because Bitwarden actually does support identity management (incl. hierarchies, permissions, etc.).
This whole idea comes down to the fact, that a client anyway needs some password manager in practice. So why to run/maintain/interface_with SAML/... server (which is really complicated) if clients anyway need* a password manager with identity support (like the Bitwarden client). So in practice you either need to synchronize the identity hierarchy + permissions
The difference being you already have Grist installed & configured (password manager server like Vaultwarden doesn't need to be installed & maintained by you - it's not a requirement contrary to the SAML/... solution).
An ideal solution would be if password manager servers would support SAML, OAuth, etc. But we're not yet there.
Don't take me wrong - I totally understand Grist utterly needs an enterprise-level architecture (sooner or later). So SAML & OAuth is definitely the way to go. I've just mentioned "password managers" as an alternative for those not wanting to have the hassle with Keycloak etc.
* yes, it'd have the nice side effect of pushing Grist users to use password managers as that's generally the safest known solution to credentials management
After watching the conversation for a while, a similar discussion in another projects comes to my mind. Next to the creative attempts in rethinking use cases for password managers, derived from that other train of thought, I would second the notion that standards-compliant authentication protocals, such as SAML and OIDC, are useful for enabling generic usage of grist in standardised environments.
In the issue over at https://github.com/outline/outline/issues/1881
people have shown to provide very lean and minimal Identity and Access Management services soley for the purpose of emulating "local authentication". They are:
OIDC will prove to be a useful addition to grist, then.
I posted a template for self-hosting Grist using traefik-forward-auth. Looks like it has OIDC support. Could be worth trying hooking it up to one of @almereyda's suggestions.
Update: Grist and Dex (https://dexidp.io/) work particularly well together and allow a variety of login solutions to be configured pretty easily. I'm making a demo/template at https://github.com/gristlabs/grist-omnibus, and would be interested in feedback.
Will this also use forward auth? This means that public sharing isn't possible?
@helmut72 it uses forward auth internally, on particular login/logout related endpoints. Auth on other pages is via a cookie. So public sharing should be possible. If the forwarding were coming from an external source that is handling other web applications, or offers an independent way to login/logout, then there will be the problem of inconsistencies you hit in https://github.com/gristlabs/grist-core/issues/207, which can be fixed but at the cost of public sharing becoming awkward. A special prefix for public sharing will be important to square that circle.
it uses forward auth internally, on particular login/logout related endpoints.
Shouldn't it then also works with Caddy and Authelia? I've looked into our Omnibus: https://github.com/paulfitz/grist-omnibus/blob/main/traefik.yaml
You only catch /auth/login
and /_oauth
in Traefik to use Dex. When I do this with Caddy and Authelia and logout in Grist, user {http.reverse_proxy.header.Remote-Email}
is logged in Grist. Shouldn't it work if Grist notice that Remote-Email is empty and do whatever is needed to recognize that there isn't a signed-in user anymore?
Shouldn't it then also works with Caddy and Authelia? I've looked into our Omnibus: https://github.com/paulfitz/grist-omnibus/blob/main/traefik.yaml You only catch
/auth/login
and/_oauth
in Traefik to use Dex. When I do this with Caddy and Authelia and logout in Grist, user{http.reverse_proxy.header.Remote-Email}
is logged in Grist. Shouldn't it work if Grist notice that Remote-Email is empty and do whatever is needed to recognize that there isn't a signed-in user anymore?
@helmut72 something sounds off there. If I'm understanding correctly, when you have Grist with Caddy and Authelia, logging out using the "Sign Out" option in Grist is not working, it is leaving you logged in? There is a GRIST_FORWARD_AUTH_LOGOUT_PATH
variable that is important here. For the omnibus it gets set to _oauth/logout
, so that Grist will call traefik-forward-auth
to actually sign out. And then traefik-forward-auth
takes LOGOUT_REDIRECT=.../signed-out
to come back to Grist afterwards.
@paulfitz Thanks, interesting how it works with Traefik and Dex.
But my problem: The user called {http.reverse_proxy.header.Remote-Email}
is logged in without hitting any login or logout. I only open grist.example.com
.
I really wish Grist just supports OIDC next to SAML or header auth with an own path for public shared links.
Authentik looks like a decent self-hosted sso solution. I just tested it and it works well with Grist, using SAML.
@paulfitz I tried authentik and grist, it does indeed work, but when I sign out from grist I'm redirected to authentik login page and then is not possible to logging into grist again.
Hi @viniciusao, are your settings along the lines suggested in https://support.getgrist.com/install/saml/#example-authentik ? Particularly GRIST_SAML_IDP_LOGIN
and GRIST_SAML_IDP_LOGOUT
?
Hi @viniciusao, are your settings along the lines suggested in https://support.getgrist.com/install/saml/#example-authentik ? Particularly
GRIST_SAML_IDP_LOGIN
andGRIST_SAML_IDP_LOGOUT
?
yes, I sign out grist, then sign out authentik and did the same login process but authentik returns "Whoops! Something went wrong! Please try again later." after clicking on "redirecting to grist".
Hi @viniciusao, are your settings along the lines suggested in https://support.getgrist.com/install/saml/#example-authentik ? Particularly
GRIST_SAML_IDP_LOGIN
andGRIST_SAML_IDP_LOGOUT
?
Turns out it was the SAML provider authorization flow type, I've set to "explicit consent", now I changed to "implicit".
Hi, sorry for bringing the keycloak config question, as detailed by @jyio, back up a year later. I've configured Grist and Keycloak as listed above, but even with the correct mappers in place in Keycloak, my username is being picked up as the user identifier instead of the email. This is despite setting the userID setting in the Keycloak client to email. This then means I have to set GRIST_DEFAULT_EMAIL to my username (rather than my email) to be identified as the original team owner. Could someone share their Keycloak mappings to make sure I got them right before digging deeper ? Thanks in advance,
@Chluz The mappers in this post works for me: https://github.com/gristlabs/grist-core/issues/44#issuecomment-1043709852
Details:
@Chluz The mappers in this post works for me: #44 (comment)
Details:
Thank you, the snapshot showing the SAML Attribute name as a URI was what needed - I had previoulsy tried to use the names from #44 (comment) , not knowing URIs also could be used.
For those looking to replicate this, the easiest is to go to your "client scope" tab in keycloak, click the dedicated scope for that client, add mapper, predefined mapper, and add the 3 X500 example you have. Then edit each one to replace the SAML attribute name field with the appropriate URI from #44 (comment)
Thanks again !
This month Google posted this blog about their support for the Passkey standard alongside Apple and Microsoft: https://blog.google/technology/safety-security/the-beginning-of-the-end-of-the-password/ "And today, ahead of World Password Day, we’ve begun rolling out support for passkeys across Google Accounts on all major platforms. They’ll be an additional option that people can use to sign in, alongside passwords, 2-Step Verification (2SV), etc."
Passkey gives the option of signup and signin using Apple FaceID, Android fingerprint or Windows Hello (Face, fingerprint etc). Currently two webauthn libraries support Passkey - webauthn_rs in rust and simplewebauthn in typescript: https://passkeys.dev/docs/tools-libraries/libraries/
Here is a demo put up by webauthn_rs that let me both sign up and sign in using fingerprint on macbook: https://webauthn.firstyear.id.au/
For notebooks that don't have a fingerprint sensor you can use an Iphone FaceID or Android fingerprint sensor. The demo also supports secure Fido keys from Yubico and others: https://www.amazon.com/Yubico-YubiKey-Factor-Authentication-Security/dp/B07HBCTYP1
And then have passwords and oauth fallback for those who prefer not to get too fancy. Biometrics would be a nice way to log into grist.
And then have passwords and oauth fallback for those who prefer not to get too fancy. Biometrics would be a nice way to log into grist.
This is supported for years with the IDP Keycloak. You don't enable webauthn on apps that use modern authentication like Grist, but on the IDP.
@nycanit zitadel support webauthn / fido2 passkey standard and also SAML, i'm looking into setting it up
wondering if anyone managed to get grist working with https://github.com/logto-io/logto ? seems like it could be another option
Hello community,
I am currently working on setting up SAML-based Single Sign-On (SSO) between Grist and Keycloak. However, I am encountering issues, and I could use some assistance in troubleshooting the configuration.
Key Points:
I have obtained the SAML metadata from Keycloak, which includes the necessary information for configuring Grist.
When attempting to log in to Grist, I encounter the error: "SAML Assertion signature check failed! (checked 1 certificate(s))."
I have verified the system clocks on both Keycloak and Grist servers to ensure they are synchronized.
I have pasted the relevant sections of the Keycloak SAML metadata, and I don't see any settings in Grist's "Identity Providers" tab.
There is no option to set "Login with SAML" in the realm settings under the "Login" tab in Keycloak.
Request for Help:
Can someone guide me on the correct steps to configure Grist with the Keycloak SAML metadata? Are there specific settings in Grist that I might be missing? How can I troubleshoot and resolve the "SAML Assertion signature check failed" error? I appreciate any insights or advice from the community. Thank you!
I found a few items to look into here: https://github.com/Clever/saml2/issues/106. It's not very recent, but maybe something there could help?
Self-hosted Grist would benefit from a well-supported login solution.