Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node in Corporative Environment with NODESSPI

I developed a NODE API to serve data to Angular app. The original idea is to use NODESSPI for integrated authentication as we plan to run this on a corporative environment. CORS will be needed as the API Node will be hosted on a different domain.

I'm struggling to use NODESSPI for integrated authentication of the $HTTP requests.

To test it on my computer I've created a simple js file to instantiate a node server with express to run my angular app (I know it could be done without express, but it was faster to implement). It is running on Port 5001.

'use strict';

var express = require('express');
var http = require('http');
var path = require('path');
var morgan = require('morgan'); 
var errorhandler = require('errorhandler');
var app = express();

// all environments
app.set('port', process.env.PORT || 5001);
app.set('views', path.join(__dirname, 'views'));
app.engine('html', require('ejs').renderFile);

app.use(morgan('dev'));

// serve up static assets
app.use(express.static(path.join(__dirname, 'app')));

// development only
if ('development' === app.get('env')) {
    app.use(errorhandler());
}

console.log('trying to start server...', path.join(__dirname, 'app'));

http.createServer(app).listen(app.get('port'), function () {
        console.log('App server listening on port ' + app.get('port'));
});

My Angular code is on very early stage as its purpose is just prove the concept. Note I'm not specifying any kind of headers on my $http get.

main.controller.js

'use strict';

monthApp.controller('mainPageCtrl',
    function mainPageCtrl($scope, $rootScope, $location, $rootElement, $q, $http) {
        console.log("mainPageCtrl is in control");

        $http({
            url: 'http://localhost:3000/api/',
            methof: 'GET'
        })
        .then(function(data){
            console.log(data);
        })
        .catch(function(error){
            console.log(error);
        })

    });

To run my NODE API simulating the server side, I'm also using Express and running it at the port 3000, here is the code:

//Lib Dependecies
var cookieParser    = require("cookie-parser");
var bodyParser      = require("body-parser");
var sql             = require("seriate");
var cors            = require("cors");
var express         = require("express");
var path            = require("path");
var Q               = require("q");
var oracle          = require("oracledb");
var restClient      = require("node-rest-client").Client;
var nodeSSPI        = require('node-sspi');
var ActiveDirectory = require("activedirectory");

//API Custom Modules Dependecies
var reservoirApi    = require("./reservoirApi");
var ldapApi         = require("./ldapApi");
var energyApi       = require("./energyApi");
var PIApi           = require("./PIApi");

//Express config
var app = express();
app.use ( cors() );
app.options('*', cors() );
app.use ( bodyParser.json() );
app.use ( bodyParser.urlencoded( {extended: true} ) );
app.use ( cookieParser() );
app.use ( express.static( __dirname + '/public') );


//Server config
var serverConfig = {port: 3000};

//Sql server config
var config = {
    "server":"myserver",
    "user":"myuser",
    "password":"mypass",
    "database":"mydatabase"
};

sql.setDefaultConfig(config);

//Setup endpoint routes
var router = express.Router();

//Basic Router Config
router.use(function(req, res, next){

    //Integrated Authentication for Windows
    var nodeSSPIObj = new nodeSSPI({
        retrieveGroups: true
    });

    try{
        nodeSSPIObj.authenticate(req, res, function(err){
            res.finished || next();
        });
    }
    catch(err)
    {
        res.status(500).send(JSON.stringify({status: 500, message: "URL mal formatada, verifique sua requisição HTTP", detail: err.message}));
    }
});

router.get('/', function(req, res){
    res.json({Message: 'Data Access API.', AuthUser: req.connection.user, AuthUserGroups: req.connection.userGroups });
});

app.use('/api', router);

//Modules End-Point registration
reservoirApi.register(router);
ldapApi.register(router);
energyApi.register(router);
PIApi.register(router);

//Start Server
app.listen(serverConfig.port);
console.log("SOA API Listening port at " + serverConfig.port)

The results are:

  • When using Chrome to reach the address: http://localhost:3000/api this works just fine. It detects my user account and return all windows groups I'm part of.

  • When running my angular code it returns: Object {data: "", status: 401, config: Object, statusText: "Unauthorized"}

  • When testing with Postman it also works (with authorization type = 'No Auth')

  • When removing all NodeSSPI code from my Routers, I can receive data (I've tested with other endpoints on my angular app) so CORS is properly set at the server side.

Is there anything I'm missing on the Angular side? I'm struggling to move forward from here. Appreciate any help.

like image 332
Marcelo Gonella Avatar asked Apr 19 '17 14:04

Marcelo Gonella


People also ask

Is node used for APIs?

In an API Connect platform, a Node. js application provides the endpoints that are called to get backend or system of record data to respond to requests.

What are nodes in API?

Node-API is a toolkit introduced in Node 8.0. 0 that acts as an intermediary between C/C++ code and the Node JavaScript engine. It permits C/C++ code to access, create, and manipulate JavaScript objects as if they were created by JavaScript code.


1 Answers

Ok, I finally got this working. The changes needed as follow:

At the client Angular app You need to set withCredentials to true on $http requests.

$http({
        url: 'http://localhost:3000/api',
        method: 'GET',
        withCredentials: true,
        headers : {
            'Content-Type' : 'application/json',    
            }
    })

At the node server Some response headers are needed in the response. Origin cannot be '*' and you need to allow credentials. If you need to allow dynamic origins you can find a way of doing it in the CORS documentation.

//Cors options
var corsOptions = {
    origin: 'http://localhost:5001',
    optionsSuccessStatus: 200, 
    credentials: true,
}

//Express config
var app = express();
app.use ( cors(corsOptions) );
app.use ( bodyParser.json() );
app.use ( bodyParser.urlencoded( {extended: true} ) );
app.use ( cookieParser() );
app.use ( express.static( __dirname + '/public') );
like image 107
Marcelo Gonella Avatar answered Oct 15 '22 09:10

Marcelo Gonella