diff --git a/README.md b/README.md index 0ff9da8e..92479609 100644 --- a/README.md +++ b/README.md @@ -395,6 +395,29 @@ Configuration options reference If the endpoint doesn't provide the email address for the user, allow empty emails to authenticate anyway. Note that GitHub authentication usually requires this to be `true` (unless all wiki users have public email addresses on their GitHub accounts). +#### authorization.moderatorsFile (string: "") + + Absolute path for your moderators YAML file. If used, this file must contain a list of `usernames` and `emails` for users who have write access to the wiki. A user who has a match in either the `usernames` or `emails` list will have right access. The moderators file may also include an attribute and value for managing moderators via LDAP roles. + + Example moderators YAML file: + + ``` +--- +# A list of moderators usernames and emails +usernames: + - 'admin1' + - 'admin2' +emails: + - 'admin@email.com' + - 'anotheradmin@email.com' +# LDAP moderator role +ldap: + attribute: 'businessCategory' + value: 'A' + ``` + + If this field is left blank, all logged in users will have write access to the wiki. + #### pages.index (string: "Home") Defines the page name for the index of the wiki diff --git a/lib/app.js b/lib/app.js index f60304b0..daad962b 100644 --- a/lib/app.js +++ b/lib/app.js @@ -201,7 +201,23 @@ module.exports.initialize = function (config) { } } - app.all('/pages/*', requireAuthentication) + function requireModerator (req, res, next) { + requireAuthentication(req, res, function(){ + if (!res.locals.user.moderator) { + res.locals.title = '403 - Permission denied' + res.statusCode = 403 + res.render('403.pug') + } else { + next() + } + }) + } + + if (app.locals.config.get('authorization').moderators) { + app.all('/pages/*', requireModerator) + } else { + app.all('/pages/*', requireAuthentication) + } if (!app.locals.config.get('authorization').anonRead) { app.all('/wiki', requireAuthentication) diff --git a/lib/config.js b/lib/config.js index 23a97061..e950bda9 100644 --- a/lib/config.js +++ b/lib/config.js @@ -36,6 +36,11 @@ module.exports = (function () { } } + // Load moderators from moderatorsFile + if (config.authorization.moderatorsFile){ + config.authorization.moderators = yaml.load(fs.readFileSync(config.authorization.moderatorsFile).toString()) + } + return true }, @@ -124,7 +129,8 @@ module.exports = (function () { anonRead: true, validMatches: '.+', // Breaking changes in Jingo 1.5 (when this parameter has been added): the default for new servers is to NOT allow empty emails to validate - emptyEmailMatches: false + emptyEmailMatches: false, + moderatorsFile: '' }, // Defaults for the pages key are compatible with Jingo < 1 (which means diff --git a/routes/auth.js b/routes/auth.js index c1f0834c..68f59d8f 100644 --- a/routes/auth.js +++ b/routes/auth.js @@ -193,6 +193,22 @@ passport.deserializeUser(function (user, done) { user.email = 'jingouser' } + // Check moderator status + user.moderator = false + var moderators = app.locals.config.get('authorization').moderators + if (moderators){ + if (moderators.usernames.indexOf(user.displayName) > -1 || + moderators.emails.indexOf(user.email) > -1){ + user.moderator = true + } else if (moderators.ldap && auth.ldap.enabled && + user[moderators.ldap.attribute] == moderators.ldap.value){ + user.moderator = true; + } + } else { + // If no moderators file supplied everyone is a 'moderator' + user.moderator = true + } + user.asGitAuthor = user.displayName + ' <' + user.email + '>' done(undefined, user) }) diff --git a/views/403.pug b/views/403.pug new file mode 100644 index 00000000..03d19b7e --- /dev/null +++ b/views/403.pug @@ -0,0 +1,7 @@ +extends layout + +block content + #content + .jumbotron + h2 #{title} + p You do not have permission to perform this action