在 Windows 域中的 Linux 服务器上使用 NodeJS 进行单点登录
SSO with NodeJS on Linux Server in Windows domain
仅供参考
我知道有人问过 类似 的问题,例如 this,但是我在这里找不到答案,现在如果有答案这个问题,一定要纠正我,我会删除我的问题,或者其他什么!
潜在选项
根据我在网上阅读的内容,可能会使用像 kerberos and/or spenago 这样的东西,请记住我不是这些 tools/subject 问题的专家。但我想知道是否还有其他可能的选择? - 我知道如果我 做 沿着 kerberos 的路线走下去,我毫不怀疑它需要一些修补,也许需要一些试验和错误,我不确定,目前我'我还在考虑我的选择。
如果你们认为 kerberos 路由可能是我最好的选择,那么你们能给我指出一些关于我如何起床的例子吗& 运行?
在理想情况下,我可以只使用一些 NPM 包,它可以让我开箱即用,但我也没有发现任何东西可以让我这样做。
因此,在与我共事的一个人进行了大量研究之后,我们最终 找到了一个似乎对我们有用的解决方案。我不会在这里太详细介绍,如果您想阅读更多内容,那么您会发现我已经开始在我自己的网站上写更多关于它的文章,here。
我这样做不是为了偷懒,而是因为如果我试图将所有内容都塞进这个答案中,那么我觉得这就像在读一篇文章。
依赖项
$ npm i --save express kerberos activedirectory
代码
// config.js
const config = {
url: "ldap://dc.example.com",
baseDN: "dc=example,dc=come",
username: "admin@example.com",
password: "P@55W0rd!231",
group: "Admin",
service: "HTTP",
};
module.exports = config;
// isMemberOf .js
/**
* This function will be used to check that a user is
* a member of a given active directory group, a typical
* example may include 'Admin', 'Super User', etc.
* This will return a promise to allow the consuming
* code base to take advantage of async/await syntax,
* making the code more readable.
*
* @param {String} username
* @param {String} group
* @param {ActiveDirectory} activeDirectory
* @return {Promise}
*/
const isMemberOf = (username, group, activeDirectory) => {
const promise = new Promise((resolve, reject) => {
activeDirectory.isUserMemberOf(username, group, (err, isMember) => {
if (err) {
reject(err);
} else if (!isMember) {
reject(username + " is not a member of " + group);
} else {
resolve(isMember);
}
});
});
return promise;
};
module.exports = isMemberOf;
// userExists.js
/**
* This function will just be used to check that a user
* within an active directory domain. This will return
* a promise to allow the consuming code base to take
* advantage of async/await syntax, making the
* code more readable.
*
* @param {string} username
* @param {ActiveDirectory} activeDirectory
* @returns {Promise}
*/
const userExists = (username, activeDirectory) => {
const promise = new Promise((resolve, reject) => {
activeDirectory.userExists(username, (err, exists) => {
if (err) {
reject(err);
} else if (!exists) {
reject("User does not exist");
} else {
resolve(username);
}
});
});
return promise;
};
module.exports = userExists;
// sso.js
const config = require("./config");
const kerberos = require("kerberos");
const ActiveDirectory = require("activedirectory");
const userExists = require("./userExists");
const isMemberOf = require("./isMemberOf");
/**
* This method will be used to indicate that there was a problem
* with starting up the server.
*
* @param {Response} res
* @param {Error} err
*/
const forbidden = (res, err) => {
console.error("Something failed: " + err);
res.status(403).send();
};
/**
* This is some single sign on middleware that will authenticate
* a user via their SPNEGO & check to see if they're within a
* specific group.
*/
const sso = async (req, res, next) => {
const { authorization } = req.headers;
const { group } = config;
// If not authorization header exists, return with WWWW-Authenticate Negotiate.
// This will get the browser to automatically respond with a SPNEGO ticket, if the
// browser is chrome then the service may need to be whitelisted, as it won't return
// a SPNEGO ticket by default.
if (!authorization) {
res.set("WWW-Authenticate", "Negotiate");
return res.status(401).send();
}
// Get our SPNEGO ticket
const ticket = authorization.substring(10);
let server;
// This try catch block will just start start the server side
// kerberos authentication context.
try {
server = await kerberos.initializeServer(config.service);
} catch (err) {
return forbidden(res, err);
}
// This try catch block will just perform the authentication
// using the snego ticket & the configured kerberos keytab.
try {
await server.step(ticket);
} catch (err) {
return forbidden(res, err);
}
const { username } = server;
const activeDirectory = new ActiveDirectory(config);
// This try catch block will simply check that the user
// exists within the AD domain.
try {
await userExists(username, activeDirectory);
} catch (err) {
return forbidden(res, err);
}
// This try catch block will simply check that the user
// is a member of a specific AD group, i.e. 'Admin',
// 'Super User', etc.
try {
await isMemberOf(username, group, activeDirectory);
} catch (err) {
return forbidden(res, err);
}
// As we know that the user has been authenticated & is a member of the given
// active directory group, we can safely proceed through to
// execute any further business logic.
next();
};
module.exports = sso;
// index.js
const express = require("express");
const app = express();
const sso = require("./sso");
app.use(sso);
app.get("/", (req, res) => {
res.status(200).send("SSO Test - You're Logged In! :)");
});
app.listen(8080);
仅供参考
我知道有人问过 类似 的问题,例如 this,但是我在这里找不到答案,现在如果有答案这个问题,一定要纠正我,我会删除我的问题,或者其他什么!
潜在选项
根据我在网上阅读的内容,可能会使用像 kerberos and/or spenago 这样的东西,请记住我不是这些 tools/subject 问题的专家。但我想知道是否还有其他可能的选择? - 我知道如果我 做 沿着 kerberos 的路线走下去,我毫不怀疑它需要一些修补,也许需要一些试验和错误,我不确定,目前我'我还在考虑我的选择。
如果你们认为 kerberos 路由可能是我最好的选择,那么你们能给我指出一些关于我如何起床的例子吗& 运行?
在理想情况下,我可以只使用一些 NPM 包,它可以让我开箱即用,但我也没有发现任何东西可以让我这样做。
因此,在与我共事的一个人进行了大量研究之后,我们最终 找到了一个似乎对我们有用的解决方案。我不会在这里太详细介绍,如果您想阅读更多内容,那么您会发现我已经开始在我自己的网站上写更多关于它的文章,here。
我这样做不是为了偷懒,而是因为如果我试图将所有内容都塞进这个答案中,那么我觉得这就像在读一篇文章。
依赖项
$ npm i --save express kerberos activedirectory
代码
// config.js
const config = {
url: "ldap://dc.example.com",
baseDN: "dc=example,dc=come",
username: "admin@example.com",
password: "P@55W0rd!231",
group: "Admin",
service: "HTTP",
};
module.exports = config;
// isMemberOf .js
/**
* This function will be used to check that a user is
* a member of a given active directory group, a typical
* example may include 'Admin', 'Super User', etc.
* This will return a promise to allow the consuming
* code base to take advantage of async/await syntax,
* making the code more readable.
*
* @param {String} username
* @param {String} group
* @param {ActiveDirectory} activeDirectory
* @return {Promise}
*/
const isMemberOf = (username, group, activeDirectory) => {
const promise = new Promise((resolve, reject) => {
activeDirectory.isUserMemberOf(username, group, (err, isMember) => {
if (err) {
reject(err);
} else if (!isMember) {
reject(username + " is not a member of " + group);
} else {
resolve(isMember);
}
});
});
return promise;
};
module.exports = isMemberOf;
// userExists.js
/**
* This function will just be used to check that a user
* within an active directory domain. This will return
* a promise to allow the consuming code base to take
* advantage of async/await syntax, making the
* code more readable.
*
* @param {string} username
* @param {ActiveDirectory} activeDirectory
* @returns {Promise}
*/
const userExists = (username, activeDirectory) => {
const promise = new Promise((resolve, reject) => {
activeDirectory.userExists(username, (err, exists) => {
if (err) {
reject(err);
} else if (!exists) {
reject("User does not exist");
} else {
resolve(username);
}
});
});
return promise;
};
module.exports = userExists;
// sso.js
const config = require("./config");
const kerberos = require("kerberos");
const ActiveDirectory = require("activedirectory");
const userExists = require("./userExists");
const isMemberOf = require("./isMemberOf");
/**
* This method will be used to indicate that there was a problem
* with starting up the server.
*
* @param {Response} res
* @param {Error} err
*/
const forbidden = (res, err) => {
console.error("Something failed: " + err);
res.status(403).send();
};
/**
* This is some single sign on middleware that will authenticate
* a user via their SPNEGO & check to see if they're within a
* specific group.
*/
const sso = async (req, res, next) => {
const { authorization } = req.headers;
const { group } = config;
// If not authorization header exists, return with WWWW-Authenticate Negotiate.
// This will get the browser to automatically respond with a SPNEGO ticket, if the
// browser is chrome then the service may need to be whitelisted, as it won't return
// a SPNEGO ticket by default.
if (!authorization) {
res.set("WWW-Authenticate", "Negotiate");
return res.status(401).send();
}
// Get our SPNEGO ticket
const ticket = authorization.substring(10);
let server;
// This try catch block will just start start the server side
// kerberos authentication context.
try {
server = await kerberos.initializeServer(config.service);
} catch (err) {
return forbidden(res, err);
}
// This try catch block will just perform the authentication
// using the snego ticket & the configured kerberos keytab.
try {
await server.step(ticket);
} catch (err) {
return forbidden(res, err);
}
const { username } = server;
const activeDirectory = new ActiveDirectory(config);
// This try catch block will simply check that the user
// exists within the AD domain.
try {
await userExists(username, activeDirectory);
} catch (err) {
return forbidden(res, err);
}
// This try catch block will simply check that the user
// is a member of a specific AD group, i.e. 'Admin',
// 'Super User', etc.
try {
await isMemberOf(username, group, activeDirectory);
} catch (err) {
return forbidden(res, err);
}
// As we know that the user has been authenticated & is a member of the given
// active directory group, we can safely proceed through to
// execute any further business logic.
next();
};
module.exports = sso;
// index.js
const express = require("express");
const app = express();
const sso = require("./sso");
app.use(sso);
app.get("/", (req, res) => {
res.status(200).send("SSO Test - You're Logged In! :)");
});
app.listen(8080);