Grist core multi user docker setup

Not sure to which logs you are referring. Is there a Grist log file that I can locate?

The error logs in apache for grist.mydomain.com have no entry for the 400 error because it doesn’t seem to be a routing problem.

The only thing I can identify that might be an issue is that the origin header is null. But the complaint
isn’t a CORS issue.

Here are the headers:

REQUEST HEADERS:
POST /saml/assert HTTP/1.1
Host: grist.mydomain.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 6846
Origin: null
DNT: 1
Connection: keep-alive
Cookie: grist_core=s%3Ag-pLvchJt1R7zppN9p1tgqv2.WW21M7bevfSGo2o%2FI6aTumH168UK0Pf37Wm3kDI5wB4
Upgrade-Insecure-Requests: 1
Sec-GPC: 1
Pragma: no-cache
Cache-Control: no-cache

REQUEST BODY:
ACSUrl	"http://grist.mydomain.com/saml/assert"
SAMLResponse	"[RESPONSE_STRING]"

RESPONSE HEADERS:
HTTP/1.1 400 Bad Request
Date: Sat, 19 Mar 2022 04:54:47 GMT
Server: Apache/2.4.53 (Ubuntu)
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 685
ETag: W/"2ad-vEECqfytTiwX3jhVG9Od24LWSfY"
Connection: close

Authentik logs an “Application authorized” event that looks like it accepts the credentials but I’m not sure if it’s logging success or just an attempt.
Here is the event object:

Context
{
    "flow": "d689989e22204f4b9cd069b485ab1edb",
    "http_request": {
        "args": {
            "query": "SAMLRequest=[REQUEST_STRING]"
        },
        "path": "/api/v3/flows/executor/default-provider-authorization-explicit-consent/",
        "method": "GET"
    },
    "authorized_application": {
        "pk": "ba49f375dfa6435cb4018f267ece2322",
        "app": "authentik_core",
        "name": "Grist App",
        "model_name": "application"
    }
}
User
{
    "pk": 1,
    "email": "myemail@gmail.com",
    "username": "Jeff Lastname"
}

Thanks for your help.

For Grist logs, I meant its console output, which (if running directly with docker) you could see with docker logs. For example, if I sign in with Authentik, I see these messages there:

2022-03-19 15:31:40.448 localhost:8484 GET /o/docs/signin?next=http%3A%2F%2Flocalhost%3A8484%2Fo%2Fdocs%2F 302 24.802 ms - 3006
2022-03-19 15:31:46.077 - info: SamlConfig: got SAML response for paul@getgrist.com () redirecting to http://localhost:8484/o/docs/
2022-03-19 15:31:46.085 localhost:8484 POST /saml/assert 302 58.638 ms - 102
2022-03-19 15:31:46.142 - debug: Auth[GET]: id 6 email paul@getgrist.com host localhost:8484 path / org docs
2022-03-19 15:31:46.142 - debug: welcoming user: paul

I’m wondering if you see anything around the time the 400 error is reported. However, I expect there won’t be anything useful.

I noticed your GRIST_SAML_IDP_LOGIN ends in /binding/init/ rather than /binding/redirect/. Can you try it with redirect? If I replace redirect with init in a test, I can replicate the error you see.

With GRIST_SAML_IDP_LOGIN changed from /binding/init/ to /binding/redirect/
I get an identical load of the Grist welcome screen.
I click [sign in] at Grist.

Instead of getting a log showing the POST and the 400 bad request status returned, the POST isn’t even attempted according to the Grist log in the console.
Instead, a GET request is logged in the browser and an error page from Athentik URL:
ht tp://auth.mydomain.com/application/saml/grist/sso/binding/redirect/?SAMLRequest=[REQUEST_STRING]

The message is:

Bad Request. Provider does not have a Validation Certificate configured. [Go to home]

So I’ll revisit the certificate setup and try again with /binding/redirect/ and let you know the results.

Details below if you want to view them

Thank you.

// NAVIGATE TO grist.mydomain.com
// BEGIN LOAD OF GRIST WELCOME SCREEN

2022-03-19 23:08:54.737 - debug: Auth[GET]: id 1 email anon@getgrist.com host grist.mydomain.com path / org
2022-03-19 23:08:54.740 - debug: Redirecting anonymous user to: http://grist.mydomain.com/o/docs/
2022-03-19 23:08:54.797 grist.mydomain.com GET / 302 19.911 ms - 122
2022-03-19 23:08:54.814 - debug: Auth[GET]: id 1 email anon@getgrist.com host grist.mydomain.com path / org docs
2022-03-19 23:08:54.860 grist.mydomain.com GET /o/docs/ 200 8.149 ms - 3381
2022-03-19 23:08:55.150 grist.mydomain.com GET /v/unknown/jqueryui/themes/smoothness/jquery-ui.css 200 8.282 ms - 36536
2022-03-19 23:08:55.208 grist.mydomain.com GET /v/unknown/bootstrap-datepicker/dist/css/bootstrap-datepicker3.min.css 200 11.304 ms - 21100
2022-03-19 23:08:55.218 grist.mydomain.com GET /v/unknown/jqueryui/jquery-ui.min.js 200 8.276 ms - 253669
2022-03-19 23:08:55.219 grist.mydomain.com GET /v/unknown/bootstrap/dist/css/bootstrap.min.css 200 15.006 ms - 122540
2022-03-19 23:08:55.223 grist.mydomain.com GET /v/unknown/bundle.css 200 14.195 ms - 75789
2022-03-19 23:08:55.224 grist.mydomain.com GET /v/unknown/icons/icons.css 200 14.618 ms - 165797
2022-03-19 23:08:55.225 grist.mydomain.com GET /v/unknown/jquery/dist/jquery.min.js 200 16.892 ms - 85630
2022-03-19 23:08:55.231 grist.mydomain.com GET /v/unknown/hljs.default.css 200 0.898 ms - 1159
2022-03-19 23:08:55.249 grist.mydomain.com GET /v/unknown/bootstrap/dist/js/bootstrap.min.js 200 0.847 ms - 36816
2022-03-19 23:08:55.274 grist.mydomain.com GET /v/unknown/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js 200 1.188 ms - 33693
2022-03-19 23:08:55.286 grist.mydomain.com GET /v/unknown/browser-check.js 200 1.740 ms - 113780
2022-03-19 23:08:55.318 grist.mydomain.com GET /v/unknown/main.bundle.js 200 0.835 ms - 3348481
2022-03-19 23:08:55.777 grist.mydomain.com GET /v/unknown/img/gplaypattern.png 200 0.918 ms - 12047
2022-03-19 23:08:56.483 - debug: Auth[OPTIONS]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /session/access/active org docs
2022-03-19 23:08:56.491 - debug: Auth[OPTIONS]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /session/access/all org docs
2022-03-19 23:08:56.541 grist.mydomain.com:8484 OPTIONS /o/docs/api/session/access/active 200 5.454 ms - 2
2022-03-19 23:08:56.591 grist.mydomain.com:8484 OPTIONS /o/docs/api/session/access/all 200 2.532 ms - 2
2022-03-19 23:08:56.624 grist.mydomain.com GET /v/unknown/icons/favicon.png 200 1.119 ms - 15365
2022-03-19 23:08:56.716 - debug: Auth[GET]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /session/access/active org docs
2022-03-19 23:08:56.729 grist.mydomain.com:8484 GET /o/docs/api/session/access/active 200 13.976 ms - 523
2022-03-19 23:08:56.730 - debug: Auth[GET]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /session/access/all org docs
2022-03-19 23:08:56.752 grist.mydomain.com:8484 GET /o/docs/api/session/access/all 200 26.556 ms - 109
2022-03-19 23:08:57.142 - debug: Auth[OPTIONS]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /orgs/0/workspaces org docs
2022-03-19 23:08:57.146 - debug: Auth[OPTIONS]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /templates org docs
2022-03-19 23:08:57.197 grist.mydomain.com:8484 OPTIONS /o/docs/api/orgs/0/workspaces?includeSupport=1 200 3.274 ms - 2
2022-03-19 23:08:57.291 grist.mydomain.com:8484 OPTIONS /o/docs/api/templates?onlyFeatured=1 200 2.214 ms - 2
2022-03-19 23:08:57.292 - debug: Auth[GET]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /orgs/0/workspaces org docs
2022-03-19 23:08:57.342 - debug: Auth[GET]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /templates org docs
2022-03-19 23:08:57.365 grist.mydomain.com:8484 GET /o/docs/api/orgs/0/workspaces?includeSupport=1 200 204.735 ms - 2
2022-03-19 23:08:57.367 grist.mydomain.com:8484 GET /o/docs/api/templates?onlyFeatured=1 404 158.348 ms - 34
 
// END LOAD OF GRIST WELCOME SCREEN WITH 404 ^^^

// CLICK [SIGN-IN] ON WELCOME SCREEN MENU

// NAVIGATES TO URL
2022-03-19 23:09:41.771 grist.mydomain.com GET /o/docs/signin?next=http%3A%2F%2Fgrist.mydomain.com%2Fo%2Fdocs%2F 302 30.617 ms - 3072

// HERE IS WHERE THE RESULTS DIFFER

++ WITH GRIST_SAML_IDP_LOGIN = /binding/redirect/

++ NO FURTHER GRIST LOGS -- NO POST OR RETURN IS LOGGED
++ GET REQUEST TO URL ht tp://auth.mydomain.com/application/saml/grist/sso/binding/redirect/?SAMLRequest=[REQUEST_STRING]
++ ERROR PAGE FROM Athentik URL DISPLAYED

-- WITH GRIST_SAML_IDP_LOGIN = /binding/init/

-- Authentik SPLASH SCREEN WITH PROMT AND [continue] PROPERLY DISPLAYED

-- // CLICK [CONTINUE] ON Authentik PROMT TO POST - ** 400 BAD REQUEST ERROR HERE **
-- 2022-03-19 23:10:25.015 grist.mydomain.com POST /saml/assert 400 25.101 ms - 685  

-- // REDIRECTS TO GRIST ERROR SCREEN
-- 2022-03-19 23:10:25.256 grist.mydomain.com GET /v/unknown/icons/icons.css 200 1.758 ms - 165797
-- 2022-03-19 23:10:25.297 grist.mydomain.com GET /v/unknown/errorPages.bundle.js 200 8.574 ms - 3246312
-- 2022-03-19 23:10:26.133 - debug: Auth[OPTIONS]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /session/access/active org
-- 2022-03-19 23:10:26.151 - debug: Auth[OPTIONS]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /session/access/all org
-- 2022-03-19 23:10:26.279 grist.mydomain.com:8484 OPTIONS /api/session/access/active 200 2.968 ms - 2
-- 2022-03-19 23:10:26.543 grist.mydomain.com GET /v/unknown/icons/favicon.png 200 0.858 ms - 15365
-- 2022-03-19 23:10:27.175 grist.mydomain.com:8484 OPTIONS /api/session/access/all 200 2.164 ms - 2
-- 2022-03-19 23:10:27.177 - debug: Auth[GET]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /session/access/active org
-- 2022-03-19 23:10:27.195 - debug: Auth[GET]: id 1 email anon@getgrist.com host grist.mydomain.com:8484 path /session/access/all org
-- 2022-03-19 23:10:27.227 grist.mydomain.com:8484 GET /api/session/access/all 200 1022.262 ms - 109
-- 2022-03-19 23:10:27.235 grist.mydomain.com:8484 GET /api/session/access/active 200 1034.314 ms - 107

Hi @Jeff_2022, I can tickle this error if I remove the verification certificate setting from the SAML Provider settings in Authentik:

Can you check you have a certificate set there? One way to create one is using the Generate button in Authentik’s Certificates section:

Before I saw this I had already deleted the certificate that was causing the error. I did have my created certificate selected in the verification certificate dropdown, but the cert was incorrect due to me completely misunderstanding the process in creating it.

I created the certificate correctly and I’m in!

And yes, if I change that setting to remove the verification cert selection from the SAML provider I reproduce the error.

Thank you very much for your help. I hope this thread comes in handy to someone else.

Jeff

2 Likes

Hello Grist team.
After many days, I was able to run Grist + Authentik (it was terrible).

# Authentik SETUP
# URL=https://authentik.app
## Certificates
### Generate grist cert *OU=Self-signed,O=authentik,CN=grist*
## Application
### Name=grist.app
### Slug=grist
### Provider=grist
## SAML Provider
### Name=grist
### Authorization flow=-implicit-
### ACS URL=https://grist.app/saml/assert
### Issuer=authentik
### Service Provider Binding=Post
### Signing Certificate=grist
### Verification Certificate=grist
# gristlabs/grist SETUP
# URL=https://grist.app
PYTHON_VERSION_ON_CREATION=3
GRIST_ORG_IN_PATH=true
GRIST_HOST=0.0.0.0
GRIST_SINGLE_PORT=true
GRIST_SERVE_SAME_ORIGIN=true
GRIST_DATA_DIR=/persist/docs
GRIST_INST_DIR=/persist
GRIST_SESSION_COOKIE=grist_core
TYPEORM_DATABASE=/persist/home.sqlite3
GRIST_DEFAULT_EMAIL=same-as-authentik-admin@mail.com
TIMEZONE=see on https://timezonedb.com
GRIST_SINGLE_ORG=docs
GRIST_ADAPT_DOMAIN=false
APP_HOME_URL=https://grist.app
APP_DOC_URL=https://grist.app
APP_DOC_INTERNAL_URL=https://grist.app
GRIST_SAML_SP_HOST=https://grist.app
GRIST_SAML_IDP_LOGIN=https://authentik.app/application/saml/grist/sso/binding/redirect/
GRIST_SAML_IDP_LOGOUT=http://authentik.app/if/session-end/grist/
GRIST_SAML_IDP_CERTS=persist/grist_certificate.pem
GRIST_SAML_IDP_UNENCRYPTED=1
GRIST_SAML_SP_KEY=persist/grist_private_key.pem
GRIST_SAML_SP_CERT=persist/grist_certificate.pem

Questions immediately arose:

  1. How to set up user invitations (emails not sending)?
  2. How to prevent guests from creating new documents, this wastes server resources and can hypothetically lead to hacks?

It’s been 6 hours and my container has crashed, how can I secure the web-accessible application?
The log of the last messages of the container:

debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path / org docs stdout
debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path /session/access/all org docs stdout
debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path /session/access/active org docs stdout
debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path /templates org docs stdout
debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path /orgs/0/workspaces org docs stdout
debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path / org docs stdout
debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path /session/access/active org docs stdout
debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path /session/access/all org docs stdout
debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path /orgs/0/workspaces org docs stdout
debug: Auth[GET]: id 1 email anon@getgrist.com host my-grist.app path /templates org docs

Authentik/SAML Provider/NameID Property Mapping
What we need setup in this field: userID or Email?

Hello.
Is possible to disallow as global settings new user create workspaces and documents?

For user invitations: self-hosted Grist doesn’t yet have built in email templates, this is a TODO (some notes at feature request: smtp settings for self hosted installation · Issue #146 · gristlabs/grist-core · GitHub).

To limit what guests can do: you could change GRIST_SINGLE_ORG=docs to anything else but docs such as bibo. When set to docs, Grist will work like docs.getgrist.com and allow people to try out Grist anonymously, which I agree doesn’t make sense for your server. When set to something else, such as bibo, Grist will create a bibo “team site” and grant access to the user with email GRIST_DEFAULT_EMAIL. That user can then grant access to others, including optionally the general public (but the public won’t have access by default).

Before changing GRIST_SINGLE_ORG, be aware that you afterwards you won’t be able to find any existing docs via the website. One option is to download them first, then re-upload afterwards.

Not sure why your container crashed, everything in the log you pasted is innocuous looking GETs.

The default worked for me. If you’re having trouble: generally, Grist identifies users by email.

1 Like

Thank you @paul-grist
I’m redoing today authentik (I have no idea how you dealt with him with such documentation, I admire you).
To rebuild Grist I use gristlabs/grist:latest image.
We have a chance with this image to use team sites in path
GRIST_ORG_IN_PATH=true
without
GRIST_SINGLE_ORG=some_org
?
BCS if I delete env variable GRIST_SINGLE_ORG
I can’t access to https://my.grist.app
When I run https://my.grist.app i redirect to http://docs.grist.app/ no chanses access to https://my.grist.app
2022-04-04 14:42:35.260 - debug: Redirecting anonymous user to: http://docs.grist.app/

@BiBo I do see a problem when using GRIST_ORG_IN_PATH without GRIST_SINGLE_ORG - working on a fix, will post when it is in. Sorry about that!

@paul-grist I must apologize for distracting you from your work.
How I admire your work, this is exactly what MS Access Online should look like, simple, understandable and as close as possible to MS Excel.

1 Like

Retry with gristlabs/grist:latest
Another attempt to solve the problem:
Docker log

info: SamlConfig: got SAML response for mail@mail.com () redirecting to http://my.grist.app/o/myorg/ stdout
21:51:09 2022-04-06 21:51:09.373 - error: ScopedSession[g-r8dXG2m6fKGpF92WkxVBLk]: Error updating sessionStore: Error: failed to load session stdout
21:51:09 2022-04-06 21:51:09.443 - debug: Auth[GET]: id 5 email mail@mail.com host my.grist.app path / org myorg
  1. I use reverse proxy https://my.grist.app to port 8484
    redirecting to http://my.grist.app/o/myorg/ stdout

Console log:

Mixed Content: The page at 'https://my.grist.app/o/myorg/' was loaded over HTTPS, but requested an insecure resource 'http://my.grist.app:8484/o/myorg/api/session/access/all'. This request has been blocked; the content must be served over HTTPS.
(anonymous) @ VM47:1
(anonymous) @ BaseAPI.ts:118
(anonymous) @ main.bundle.js:12
r @ main.bundle.js:12
request @ main.bundle.js:12
(anonymous) @ BaseAPI.ts:36
(anonymous) @ main.bundle.js:12
r @ main.bundle.js:12
i.value @ main.bundle.js:12
(anonymous) @ BaseAPI.ts:133
(anonymous) @ main.bundle.js:12
r @ main.bundle.js:12
requestJson @ main.bundle.js:12
(anonymous) @ BaseAPI.ts:36
(anonymous) @ main.bundle.js:12
r @ main.bundle.js:12
i.value @ main.bundle.js:12
(anonymous) @ UserAPI.ts:421
(anonymous) @ main.bundle.js:6
i @ main.bundle.js:6
getSessionAll @ main.bundle.js:6
(anonymous) @ AppModel.ts:164
(anonymous) @ main.bundle.js:6
i @ main.bundle.js:6
_fetchUsersAndOrgs @ main.bundle.js:6
v @ AppModel.ts:100
create @ dispose.ts:136
C @ App.ts:75
create @ dispose.ts:136
(anonymous) @ app.js:31
i @ jquery.min.js:2
fireWith @ jquery.min.js:2
ready @ jquery.min.js:2
J @ jquery.min.js:2
Show 4 more frames
GristWSConnection.ts:94 GristWSConnection not activating for hosted grist page with no document present
AppModel.ts:157 getSessionActive() failed: TypeError: Failed to fetch
errors.ts:82 ERROR: TypeError: Failed to fetch
    at <anonymous>:1:876
    at u.<anonymous> (BaseAPI.ts:118:29)
    at Generator.next (<anonymous>)
    at main.bundle.js:12:562303
    at new Promise (<anonymous>)
    at r (main.bundle.js:12:562048)
    at u.request (main.bundle.js:12:563823)
    at u.<anonymous> (BaseAPI.ts:36:57)
    at Generator.next (<anonymous>)
    at main.bundle.js:12:562303
    at new Promise (<anonymous>)
    at r (main.bundle.js:12:562048)
    at u.i.value (main.bundle.js:12:563017)
    at u.<anonymous> (BaseAPI.ts:133:24)
    at Generator.next (<anonymous>)
    at main.bundle.js:12:562303
f @ errors.ts:82
Promise.catch (async)
v @ AppModel.ts:100
create @ dispose.ts:136
C @ App.ts:75
create @ dispose.ts:136
(anonymous) @ app.js:31
i @ jquery.min.js:2
fireWith @ jquery.min.js:2
ready @ jquery.min.js:2
J @ jquery.min.js:2
...

Looks like the page, after loading, is requesting something at the wrong port and with the wrong url. Can you try setting APP_HOME_URL=https://my.grist.app?

Thanks, it helped and everything worked, but in vain, when I try to create a team site, I go to the page Grist
Thank you for the help, hope has died now.
GRIST_ORG_IN_PATH=true
without
GRIST_SINGLE_ORG=some_org
Doesn’t make sense.

When you use GRIST_SINGLE_ORG=some_org, it will create that team for you and set you up as an owner of it. You can repeat with several GRIST_SINGLE_ORGs, and then switch to GRIST_ORG_IN_PATH to access the teams you have created. Not user-friendly, but it should work.

Team site creation is being reworked, it should get easier in future.

@paul-grist Thank you.
I could not even think that GRIST_SINGLE_ORG can be used several times. I went to try.
Try:
GRIST_SINGLE_ORG=org1
GRIST_SINGLE_ORG=org2
GRIST_ORG_IN_PATH=true
Not working
GET https://my.grist.app/o/org1/api/templates?onlyFeatured=1 404
Have access only for org1

Thanks to this thread, I’ve successfully deployed grist and authentik to my VPS using reverse proxy. Everything has worked fine until now, though I encounter a small issue with the GRIST_SINGLE_ORG, it doesn’t present in the url.
It looks like https://my.example.com/kLzquuZKrbrG/data while it should be https://my.example.com/o/myorganization/data

I have included both lines in the grist env:

GRIST_SINGLE_ORG=myorganization
GRIST_ORG_IN_PATH=true
2 Likes

https://my.example.com/o/myorganization/data

I think it does not make sense since the organization is one.
So far I haven’t found a way to make multiple organizations.