When a user opens my web application (JavaScript/React) they should see on the page their full name (eg. Makarov Viktor (locadm)) and a list of groups they participate in from Active Directory. Both web server and a user are in the same corporate on-premise domain which uses Active Directory. And the user at the moment of opening the application is logged on in Active Directory (when entering windows). The web server is the Node.js Express application (code attached below).
More than that I would like the user not entering login and password to the application so that it worked using Single Sign-On.
This is my first web application and Node.js server application. From the info I could find so far I assume, the main job should be done on the server-side when accepting a user's first request. The server has to identify the user and get their groups and full name from Active Directory. The web application then should just fetch this information from the server in a form of the JSON object and show it to the user on the page. Actually, the ultimate mission is not just listed groups to the user (this is for simplicity). I need to know user's groups to include them into API request to ElasticSearch as filters.
Unfortunately, I could not find suitable guidance so far. My other guess is that I should use NPM ntlm
or activedirectory
modules, but reading their documentation was no good for me.
const express = require('express'); // импортируем модуль express
//const http = require('http');
const https = require( 'https' ); // для организации https
const compression = require('compression');
const helmet = require('helmet');
const fs = require( 'fs' ); // для чтения ключевых файлов
const morgan = require('morgan'); // для логированиз апросов и ошибок
const vhost = require('vhost'); // для переадресации с имени search.aorti.ru
const path = require('path');
const rfs = require('rotating-file-stream'); // version 2.x
const ntlm = require('express-ntlm');
//задаем путь к https сертификату и ключу
httpsOptions = {
key: fs.readFileSync("D:\\RTISearch\\Node_https_server\\cert\\sr-rti-sql-12.key"), // путь к ключу
cert: fs.readFileSync("D:\\RTISearch\\Node_https_server\\cert\\sr-rti-sql-12.crt") // путь к сертификату
}
//задаем hostname и порт
const hostname = 'hostname.ru';
const port = 443;
const message = `Сервер работает по адресу https://${hostname}:${port}`;
//задаем путь к каталогу с продуктовой версией веб приложения
const filesDir = 'D:/RTISearch/search_react_app/build'
//Задаем настройки файла для логирования
var accessLogStream = rfs.createStream('access.log', {
interval: '1M', // rotate monthly
path: path.join(__dirname, 'logs')
});
//создаем новый инстанс приложения экспресс
const app = express();
//используется для сжатие файлов, отдаваемых с сервера
app.use(compression());
//app.use(ntlm());
//Настраивам с помощью Helmet Content Security Policy
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
baseUri:["'self'"],
fontSrc: ["'self'", "https:"," data:"],
frameAncestors: ["'self'"],
imgSrc: ["'self'", "data:"],
scriptSrcAttr: ["'none'"],
styleSrc: ["'self'", "https:", "'unsafe-inline'"],
connectSrc: ["'self'","https://sr-rti-sql-12.aorti.ru:9200/rti_search_file_folder/_msearch", "search.aorti.ru"],
scriptSrc: ["'self'"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
blockAllMixedContent: []
},
})
);
app.disable('x-powered-by');
//Настраиваем логирование входящих запросов с помощью Morgan
app.use(morgan(':remote-addr - :remote-user - [:date[iso]] - :method - :status - :response-time ms - :total-time[2] - :url - :res[content-length] - :url - :user-agent', { stream: accessLogStream }));
//создаем https сервер
const server = https.createServer(httpsOptions, app);
//подключаем папку с веб приложением
app.use(express.static(filesDir));
app.use((req,res,next)=>{
res.statusCode = 200;
res.setHeader('Content-Type','text/html; charset=utf-8');
res.end('<html><body><h1>Cервер Экспресс работает</h1></body></html>')
});
server.listen(port, () => {
console.log(message)
console.log("NODE_ENV = ",process.env.NODE_ENV)
})
Authenticating a user with nodejs can be complicated to set up, but when that part is done correctly, coding is the easy part. Here are the basic steps for setting up your server (the one that runs your API):
What needs to be done on the Active Directory side:
set the SPN-name for the web service in AD (following HTTP/[email protected] pattern). This will allow browsers to request a token for the given service and transfer it in the HTTP header to the backend.
configure a krb5.keytab key for the web service, which will be used by the Kerberos client to verify user tokens.
What needs to be done on the web service side:
You can use those steps to google for more details on each one, and if you run into any problems I will try and help you overcome them.
For authentication, I used this npm package: https://www.npmjs.com/package/kerberos
This is a code example for user authentication in nodejs api service, I am running it on a linux machine:
To get the user from active directory, I use this code:
There is a lot more to doing this than I can write in a single post (mostly the set up part), but as I said, if more details are needed I will try and help.