mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
Merge pull request #165 from MHOOO/reverse-proxy-auth-support
Reverse proxy auth support
This commit is contained in:
commit
a641517bb1
@ -188,6 +188,7 @@ GRIST_MANAGED_WORKERS | if set, Grist can assume that if a url targeted at a doc
|
|||||||
GRIST_MAX_UPLOAD_ATTACHMENT_MB | max allowed size for attachments (0 or empty for unlimited).
|
GRIST_MAX_UPLOAD_ATTACHMENT_MB | max allowed size for attachments (0 or empty for unlimited).
|
||||||
GRIST_MAX_UPLOAD_IMPORT_MB | max allowed size for imports (except .grist files) (0 or empty for unlimited).
|
GRIST_MAX_UPLOAD_IMPORT_MB | max allowed size for imports (except .grist files) (0 or empty for unlimited).
|
||||||
GRIST_ORG_IN_PATH | if true, encode org in path rather than domain
|
GRIST_ORG_IN_PATH | if true, encode org in path rather than domain
|
||||||
|
GRIST_PROXY_AUTH_HEADER | header which will be set by a (reverse) proxy webserver with an authorized users' email. This can be used as an alternative to a SAML service.
|
||||||
GRIST_ROUTER_URL | optional url for an api that allows servers to be (un)registered with a load balancer
|
GRIST_ROUTER_URL | optional url for an api that allows servers to be (un)registered with a load balancer
|
||||||
GRIST_SERVE_SAME_ORIGIN | set to "true" to access home server and doc workers on the same protocol-host-port as the top-level page, same as for custom domains (careful, host header should be trustworthy)
|
GRIST_SERVE_SAME_ORIGIN | set to "true" to access home server and doc workers on the same protocol-host-port as the top-level page, same as for custom domains (careful, host header should be trustworthy)
|
||||||
GRIST_SESSION_COOKIE | if set, overrides the name of Grist's cookie
|
GRIST_SESSION_COOKIE | if set, overrides the name of Grist's cookie
|
||||||
|
@ -89,6 +89,34 @@ export function isSingleUserMode(): boolean {
|
|||||||
return process.env.GRIST_SINGLE_USER === '1';
|
return process.env.GRIST_SINGLE_USER === '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a profile if it can be deduced from the request. This requires a
|
||||||
|
* header to specify the users' email address. The header to set comes from the
|
||||||
|
* environment variable GRIST_PROXY_AUTH_HEADER.
|
||||||
|
*/
|
||||||
|
export function getRequestProfile(req: Request): UserProfile|undefined {
|
||||||
|
const header = process.env.GRIST_PROXY_AUTH_HEADER;
|
||||||
|
let profile: UserProfile|undefined;
|
||||||
|
|
||||||
|
if (header && req.headers && req.headers[header]) {
|
||||||
|
const headerContent = req.headers[header];
|
||||||
|
if (headerContent) {
|
||||||
|
const userEmail = headerContent.toString();
|
||||||
|
const [userName] = userEmail.split("@", 1);
|
||||||
|
if (userEmail && userName) {
|
||||||
|
profile = {
|
||||||
|
"email": userEmail,
|
||||||
|
"name": userName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the express request object with user information added, if it can be
|
* Returns the express request object with user information added, if it can be
|
||||||
* found based on passed in headers or the session. Specifically, sets:
|
* found based on passed in headers or the session. Specifically, sets:
|
||||||
@ -245,6 +273,20 @@ export async function addRequestUser(dbManager: HomeDBManager, permitStore: IPer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mreq.userId) {
|
||||||
|
profile = getRequestProfile(mreq);
|
||||||
|
if (profile) {
|
||||||
|
const user = await dbManager.getUserByLoginWithRetry(profile.email, profile);
|
||||||
|
if(user) {
|
||||||
|
mreq.user = user;
|
||||||
|
mreq.users = [profile];
|
||||||
|
mreq.userId = user.id;
|
||||||
|
mreq.userIsAuthorized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// If no userId has been found yet, fall back on anonymous.
|
// If no userId has been found yet, fall back on anonymous.
|
||||||
if (!mreq.userId) {
|
if (!mreq.userId) {
|
||||||
const anon = dbManager.getAnonymousUser();
|
const anon = dbManager.getAnonymousUser();
|
||||||
|
@ -50,6 +50,7 @@ const {parseFirstUrlPart} = require('app/common/gristUrls');
|
|||||||
const version = require('app/common/version');
|
const version = require('app/common/version');
|
||||||
const {Client} = require('./Client');
|
const {Client} = require('./Client');
|
||||||
const {localeFromRequest} = require('app/server/lib/ServerLocale');
|
const {localeFromRequest} = require('app/server/lib/ServerLocale');
|
||||||
|
const {getRequestProfile} = require('app/server/lib/Authorizer');
|
||||||
|
|
||||||
// Bluebird promisification, to be able to use e.g. websocket.sendAsync method.
|
// Bluebird promisification, to be able to use e.g. websocket.sendAsync method.
|
||||||
Promise.promisifyAll(ws.prototype);
|
Promise.promisifyAll(ws.prototype);
|
||||||
@ -150,6 +151,20 @@ Comm.prototype._broadcastMessage = function(type, data, clients) {
|
|||||||
clients.forEach(client => client.sendMessage({type, data}));
|
clients.forEach(client => client.sendMessage({type, data}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a profile based on the request or session.
|
||||||
|
*/
|
||||||
|
Comm.prototype._getSessionProfile = function(scopedSession, req) {
|
||||||
|
const profile = getRequestProfile(req);
|
||||||
|
if (profile) {
|
||||||
|
return Promise.resolve(profile);
|
||||||
|
} else {
|
||||||
|
return scopedSession.getSessionProfile();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a per-doc message to the given client.
|
* Sends a per-doc message to the given client.
|
||||||
* @param {Object} client - The client object, as passed to all per-doc methods.
|
* @param {Object} client - The client object, as passed to all per-doc methods.
|
||||||
@ -236,7 +251,7 @@ Comm.prototype._onWebSocketConnection = async function(websocket, req) {
|
|||||||
// Delegate message handling to the client
|
// Delegate message handling to the client
|
||||||
websocket.on('message', client.onMessage.bind(client));
|
websocket.on('message', client.onMessage.bind(client));
|
||||||
|
|
||||||
scopedSession.getSessionProfile()
|
this._getSessionProfile(scopedSession, req)
|
||||||
.then((profile) => {
|
.then((profile) => {
|
||||||
log.debug(`Comm ${client}: sending clientConnect with ` +
|
log.debug(`Comm ${client}: sending clientConnect with ` +
|
||||||
`${client._missedMessages.length} missed messages`);
|
`${client._missedMessages.length} missed messages`);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user