Skip to content

Commit

Permalink
Merge pull request #167 from everpcpc/ldap
Browse files Browse the repository at this point in the history
Support ldap auth
  • Loading branch information
claudioc committed Sep 18, 2016
2 parents 92a0bf5 + 42a0d3f commit fa51014
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 8 deletions.
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Jingo needs a config file and to create a sample config file, just run `jingo -s

This document contains also [the reference](#configuration-options-reference) for all the possible options.

If you define a `remote` to push to, then Jingo will automatically issue a push to that remote every `pushInterval` seconds. To declare a `remote` for Jingo to use, you'll need to identify the name of your local remote. The following example shows how a local remote is typically defined:
If you define a `remote` to push to, then Jingo will automatically issue a push to that remote every `pushInterval` seconds. To declare a `remote` for Jingo to use, you'll need to identify the name of your local remote. The following example shows how a local remote is typically defined:

`git remote add origin https://github.com/joeuser/jingorepo.git'`

Expand Down Expand Up @@ -108,7 +108,7 @@ If you want your wiki server to only listen to your `localhost`, set the configu
Authentication and Authorization
--------------------------------

You can enable the following strategies: _Google logins (OAuth2)_, _GitHub logins (OAuth2)_ or a simple, locally verified username/password credentials match (called "local").
You can enable the following strategies: _Google logins (OAuth2)_, _GitHub logins (OAuth2)_, _ldap logins_ or a simple, locally verified username/password credentials match (called "local").

The _Google Login_ and the _GitHub login_ uses OAuth 2 and that means that on a fresh installation you need to get a `client id` and a `client secret` from Google or GitHub and put those informations in the configuration file.

Expand All @@ -132,11 +132,13 @@ For GitHub, follow these instructions (you need to be logged in in GitHub):
* In the following page, on the top right corner, take note of the values for `Client ID` and `Client Secret`
* Now you need to copy the `Client ID` and `Client secret` in your jingo config file in the proper places

The _ldap_ method uses `url` as the ldap server url, and optionally a `bindDn` and `bindCredentials` if needed. The `searchBase` and `searchFilter` are required for searching in the tree.

The _local_ method uses an array of `username`, `passwordHash` and optionally an `email`. The password is hashed using a _non salted_ SHA-1 algorithm, which makes this method not the safest in the world but at least you don't have a clear text password in the config file. To generate the hash, use the `--hash-string` program option: once you get the hash, copy it in the config file.

You can enable all the authentications options at the same time. The `local` is disabled by default.

The _authorization_ section of the config file has three keys: `anonRead`, `validMatches` and `emptyEmailMatches`.
The _authorization_ section of the config file has three keys: `anonRead`, `validMatches` and `emptyEmailMatches`.

If `anonRead` is true, then anyone who can access the wiki can read anything. If `anonRead` is false you need to authenticate also for reading and then the email of the user _must_ match at least one of the regular expressions provided via validMatches, which is a comma separated list. There is no "anonWrite", though. To edit a page the user must be authenticated.

Expand Down Expand Up @@ -246,7 +248,7 @@ Configuration options reference
Enable [GFM line breaks](https://help.github.com/articles/github-flavored-markdown#newlines)

####application.proxyPath (string: "")

If you want jingo to work "behind" another website (for example in a /wiki directory of an already existing intranet), you need to configure it to be aware of that situation so that it can write all the outbound URLs accordingly. Use this option to pass it the name of the directory that you've configured in your proxy_pass option in nginx or apache. See also an nginx example in the /etc directory of the jingo source distribution.

Please note that jingo won't work correctly if this option is activated.
Expand Down Expand Up @@ -281,6 +283,16 @@ Configuration options reference

Specifies a custom redirect URL for OAuth2 authentication instead of the default

#### authentication.ldap.enabled (boolean: false)

Enable or disable authentication via LDAP logins

#### authentication.ldap.url
#### authentication.ldap.bindDn
#### authentication.ldap.bindCredentials
#### authentication.ldap.searchBase
#### authentication.ldap.searchFilter

#### authentication.local.enabled (boolean: false)

The Local setup allows you to specify an array of username/password/email elements that will have access to the Wiki. All the accounts must resides in the configuration `authentication.local.accounts` array
Expand Down
20 changes: 17 additions & 3 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ module.exports = (function () {

return true;
},

getError: function () {
return error;
},
Expand Down Expand Up @@ -76,6 +76,14 @@ module.exports = (function () {
clientSecret: "replace me with the real value",
redirectURL: ""
},
ldap: {
enabled: false,
url: "ldap://example.org:389",
bindDN: "",
bindCredentials: "",
searchBase: "ou=people,dc=example,dc=org",
searchFilter: "(uid={{username}})"
},
// @deprecated, use local with just an user
alone: {
enabled: false,
Expand Down Expand Up @@ -123,7 +131,7 @@ module.exports = (function () {
// For example, if the index subkey is not present the default
// would be Home, not home.

// Please note that the combination of "from filename" and "ascii only"
// Please note that the combination of "from filename" and "ascii only"
// is not really an valid option (information will be probably lost regarding
// non ASCII only caracters)
pages: {
Expand Down Expand Up @@ -155,6 +163,7 @@ module.exports = (function () {

if (!config.authentication.google.enabled &&
!config.authentication.github.enabled &&
!config.authentication.ldap.enabled &&
!config.authentication.alone.enabled &&
!config.authentication.local.enabled
) {
Expand All @@ -172,6 +181,11 @@ module.exports = (function () {
return false;
}

if (config.authentication.ldap.enabled && (!config.authentication.ldap.url || !config.authentication.ldap.searchBase || !config.authentication.ldap.searchFilter)) {
error = "Invalid or missing config for LDAP (url and/or searchBase and/or searchFilter).";
return false;
}

if (config.authentication.alone.enabled && config.authentication.local.enabled) {
error = "Alone and Local authentication cannot be used at the same time";
return false;
Expand All @@ -180,7 +194,7 @@ module.exports = (function () {
if (config.authentication.alone.enabled) {
console.warn("Deprecation: Alone authentication is deprecated and should be changed with Local.");
}

config.features = _.extend({}, this.defaults.features, config.features);

// For backward compatibility with version < 0.5, we set markitup as the
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"passport": "^0.2.0",
"passport-github": "^0.1.5",
"passport-google-oauth": "^0.1.5",
"passport-ldapauth": "^0.3.1",
"passport-local": "^1.0.0",
"semver": "^2.3.2",
"serve-favicon": "^2.1.7",
Expand Down
34 changes: 33 additions & 1 deletion routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var router = require("express").Router(),
passportLocal = require("passport-local"),
passportGoogle = require("passport-google-oauth"),
passportGithub = require("passport-github").Strategy,
passportLDAP = require("passport-ldapauth"),
tools = require("../lib/tools");

var auth = app.locals.config.get("authentication");
Expand All @@ -15,7 +16,7 @@ router.get("/logout", _getLogout);
router.post("/login", passport.authenticate("local", {
successRedirect: proxyPath + "/auth/done",
failureRedirect: proxyPath + "/login",
failureFlash: true
failureFlash: true
}));
router.get("/auth/done", _getAuthDone);

Expand All @@ -33,6 +34,12 @@ router.get("/auth/github/callback", passport.authenticate("github", {
failureRedirect: proxyPath + "/login"
}));

router.post("/auth/ldap", passport.authenticate("ldapauth", {
successRedirect: proxyPath + "/auth/done",
failureRedirect: proxyPath + "/login",
failureFlash: true
}));

if (auth.google.enabled) {
var redirectURL = auth.google.redirectURL || app.locals.baseUrl + "/oauth2callback";
passport.use(new passportGoogle.OAuth2Strategy({
Expand Down Expand Up @@ -67,6 +74,23 @@ if (auth.github.enabled) {
));
}

if (auth.ldap.enabled) {
passport.use(new passportLDAP({
server: {
url: auth.ldap.url,
bindDn: auth.ldap.bindDn,
bindCredentials: auth.ldap.bindCredentials,
searchBase: auth.ldap.searchBase,
searchFilter: auth.ldap.searchFilter
}
},
function (profile, done) {
usedAuthentication("ldap");
done(null, profile);
}
));
}

if (auth.alone.enabled) {

passport.use(new passportLocal.Strategy(
Expand Down Expand Up @@ -140,6 +164,14 @@ passport.deserializeUser(function (user, done) {
user.displayName = user.username;
}

// for ldap auth
if (!user.displayName && user.uid) {
user.displayName = user.uid;
}
if (!user.email && user.mail) {
user.email = user.mail;
}

if (!user.email) {
user.email = "jingouser";
}
Expand Down
25 changes: 25 additions & 0 deletions views/login.jade
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,31 @@ block content
p
+anchor("/", 'Cancel')

if (auth.ldap.enabled)

p
h4 Authenticate ldap

mixin errors()

form.form-horizontal(action='#{proxyPath}/auth/ldap', method='post')

.form-group
label.col-sm-2.control-label Username
.col-sm-3
input.form-control(type='text', autofocus, name='username')

.form-group
label.col-sm-2.control-label Password
.col-sm-3
input.form-control(type='password', name='password')

.form-group
.col-sm-offset-2.col-sm-3
button.btn-primary.btn(type="submit") Login
|&nbsp;or&nbsp;
+anchor("/", 'Cancel')

if (auth.alone.enabled || auth.local.enabled)

p
Expand Down

0 comments on commit fa51014

Please sign in to comment.