Commit 51f8dd80 authored by Nelson Gonçalves's avatar Nelson Gonçalves
Browse files

Check pad access using service API

parent 31d89657
......@@ -18,11 +18,10 @@ fi
if [ -z "$SSO_URL" ]; then
export SSO_URL="$BASE_URL"
fi
REPLACE_VARS='DB_HOST DB_PORT DB_USER DB_NAME DB_PASSWORD APIKEY AUTH_URL SSO_URL BASE_URL'
REPLACE_VARS='DB_HOST DB_PORT DB_USER DB_NAME DB_PASSWORD APIKEY AUTH_URL SSO_URL BASE_URL APP_ID APP_KEY'
# check if needed vars are present
if [ -z "$DB_PASSWORD" ] || [ -z "$APIKEY" ] ; then
if [ -z "$DB_PASSWORD" ] || [ -z "$APIKEY" ] || [ -z "$APP_ID" ] || [ -z "$APP_KEY" ]; then
echo "Error: The following environment variables MUST be defined."
echo " - DB_PASSWORD: database password"
echo " - APIKEY: Etherpad secret API key"
......
......@@ -5,12 +5,15 @@
const request = require('request');
const cheerio = require("cheerio");
const authorManager = require('ep_etherpad-lite/node/db/AuthorManager');
// const readOnlyManager = require('ep_etherpad-lite/node/db/ReadOnlyManager');
const log4js = require('log4js');
const fs = require("fs");
const jsonminify = require("jsonminify");
let ssoURL = '';
let baseURL = '';
let appKey = '';
let appId = '';
const configPath = `${__dirname}/config.json`;
try {
......@@ -28,6 +31,15 @@ try {
else
throw "ssoURL not found";
if(config.appKey)
appKey = config.appKey;
else
throw "appKey not found";
if(config.appId)
appId = config.appId;
else
throw "appId not found";
laclasseLogger.info(`Config file read from: "${configPath}"`);
} catch(e) {
laclasseLogger.error(`Config file not found or not valid:`,e.message);
......@@ -35,7 +47,7 @@ try {
laclasseLogger = log4js.getLogger("ep_laclasse");
exports.authorize = function (hook_name, context, cb) {
exports.authorize = async function (hook_name, context, cb) {
// NOTE: statics in /^\/(static|javascripts|pluginfw|api)/ are always authorized. See webaccess.js
laclasseLogger.info('authorize: for', context.resource);
......@@ -49,9 +61,35 @@ exports.authorize = function (hook_name, context, cb) {
// protect the admin routes
if (context.resource.indexOf('/admin') === 0 && !context.req.session.user.is_admin) return cb([false]);
// check if user has access to pad
const padID = (req.path.match(/^\/p\/(.*)$/) || [])[1];
if (padID == null) return cb([false]);
const rights = await padRightsForUser(padID, user.uid).then(body => {
const rights = JSON.parse(body);
return rights;
}).catch(err => {
return false;
});
laclasseLogger.info('rights: ', rights)
if(rights === false || rights.Read == false) {
return cb([false]);
}
laclasseLogger.info('authorize: authorized');
cb([true]);
// if(rights.Write) {
// const padURL = new URL(`/pads${context.req.path}`,baseURL);
// context.res.redirect(padURL.toString());
// } else {
// const readonlyId = await readOnlyManager.getReadOnlyId();
// const padURL = new URL(`/pads/p/${readonlyId}`,baseURL);
// laclasseLogger.info('authenticate: redirect to readonly URL', padURL.toString());
// context.res.redirect(padURL.toString());
// }
return cb([true]);
};
function getServiceURL(request) {
......@@ -62,7 +100,7 @@ function getServiceURL(request) {
function serviceValidate(ticket,service) {
return new Promise(function(resolve, reject) {
const validateURL = new URL('sso/serviceValidate',ssoURL);
const validateURL = new URL('/sso/serviceValidate',ssoURL);
const urlParams = new URLSearchParams({
ticket: ticket, service: service
});
......@@ -94,11 +132,44 @@ function getUserFromTicket(ticket) {
}
}
/**
* Calls service to check if user has access to pad
* @param {number} id
* @param {{username:string}} user
*/
function padRightsForUser(id,userId) {
return new Promise(function(resolve, reject) {
const rightsURL = new URL(`/api/docs/${id}/rights`,baseURL);
const urlParams = new URLSearchParams({ seenBy: userId});
const url = `${rightsURL.toString()}?${urlParams.toString()}`;
laclasseLogger.info('ep_laclasse.padRightsForUser: ', url);
request(url, {
'auth': {
'user': appId,
'pass': appKey
}
},function (er, response, body) {
if (er) return reject(er);
try {
return resolve(body);
} catch (err) {
return reject(err);
}
});
});
}
var ticket = null;
exports.authenticate = async function (hook_name, context, cb) {
laclasseLogger.info('authenticate');
laclasseLogger.info('authenticate: current session: ', context.req.session);
if(!context.req.session && !context.req.session.user) {
return cb([false]);
}
//TODO Don't check again if session exists and is valid
if(!context.req.query.ticket) {
return cb([false]);
}
......@@ -124,20 +195,18 @@ exports.authenticate = async function (hook_name, context, cb) {
context.req.session.user = {
username: user.uid,
display_name: `${user.firstname} ${user.lastname}`,
is_admin: true
is_admin: false
};
// once logged in, redirect to the resource without the ticket
context.res.redirect(getServiceURL(context.req));
laclasseLogger.info('authenticate: successful authentication', context.req.session.user);
//laclasseLogger.info('authenticate: successful authentication', context.req.session.user);
return cb([false]);
return cb([true]);
}
exports.authFailure = function(hook_name, context, cb) {
const baseUrl = new URL('sso/login',baseURL);
const loginURL = new URL('/sso/login',baseURL);
const urlParams = new URLSearchParams({ service: getServiceURL(context.req) });
const url = `${baseUrl.toString()}?${urlParams.toString()}`;
const url = `${loginURL.toString()}?${urlParams.toString()}`;
// redirect to the auth url
try {
......
......@@ -3,5 +3,11 @@
"ssoURL": "${SSO_URL}",
// The public URL to be redirected to
"baseURL": "${BASE_URL}"
"baseURL": "${BASE_URL}",
// The public URL to be redirected to
"appKey": "${APP_KEY}",
// The public URL to be redirected to
"appId": "${APP_ID}"
}
......@@ -63,7 +63,7 @@
"requireSession" : false,
/* Users may edit pads but not create new ones. Pad creation is only via the API. This applies both to group pads and regular pads. */
"editOnly" : false,
"editOnly" : true,
/* Users, who have a valid session, automatically get granted access to password protected pads */
"sessionNoPassword" : false,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment