Authenticating with SharePoint 2013 from node.js - javascript

I have a command-line script written in JavaScript which needs to connect to a REST Api on a remote SharePoint site, but I cannot figure out how to authenticate. I can log on in a browser using forms authentication, and by inspecting the request I should be able to reproduce it in node.js to get the appropriate auth cookie or token. However, I actually get a 403 Forbidden. I don't know if this is the best way of doing it, but I can't find very much info on it. Here is my script:
var http = require('http');
var querystring = require('querystring');
var postData = querystring.stringify({
'ctl00$PlaceHolderMain$signInControl$UserName': 'restapi',
'ctl00$PlaceHolderMain$signInControl$password': 'my_password',
'ctl00$PlaceHolderMain$signInControl$login': 'Sign In'
});
var options = {
hostname: 'sharepoint.example.com',
port: 80,
path: '/_layouts/15/Authenticate.aspx?Source=%2F',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ', res.headers);
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write(postData);
req.end();
And the response headers are:
{ 'cache-control': 'private',
'content-type': 'text/plain; charset=utf-8',
server: 'Microsoft-IIS/8.5',
'x-sharepointhealthscore': '0',
'x-aspnet-version': '4.0.30319',
sprequestguid: '366d149d-79af-b07c-1764-dec7001b46a2',
'request-id': '366d149d-79af-b07c-1764-dec7001b46a2',
'x-frame-options': 'SAMEORIGIN',
sprequestduration: '7',
spiislatency: '0',
'x-forms_based_auth_required': 'http://sharepoint.example.com/_login/default.aspx?ReturnUrl=/_layouts/15/error.aspx&Source=%2f_layouts%2f15%2fAuthenticate.aspx%3fSource%3d%252F',
'x-forms_based_auth_return_url': 'http://sharepoint.example.com/_layouts/15/error.aspx',
'x-msdavext_error': '917656; Access denied. Before opening files in this location, you must first browse to the web site and select the option to login automatically.',
'x-powered-by': 'ASP.NET',
microsoftsharepointteamservices: '15.0.0.4569',
'x-content-type-options': 'nosniff',
'x-ms-invokeapp': '1; RequireReadOnly',
date: 'Sat, 27 Jun 2015 10:53:28 GMT',
connection: 'close',
'content-length': '13' }
Any suggestions?

Are you sure that REST API allows CORS? because a 403 Forbidden might mean that you are not allowed to contact that endpoint from outside.
Does that remote SharePoint app use AD for authentication?
if so you might need to check this package https://www.npmjs.com/package/activedirectory

Related

How to load JSON/API data using https.request and Node.JS

I'm trying to load weather data. I have front end code that was doing this perfectly but I need to move this to back end. I moved a library of my functions over to Node.JS. I was using $.getJSON but was told I should use https.request for the new version. Here's my code:
getTextWeatherUsingStationUsingRequest: function(theStation){
const http = require("http");
const https = require("https");
thePath = 'stations/' + theStation + '/observations/current';
// theURL = 'https://api.weather.gov/stations/' + theStation + '/observations/current';
function requestTheData(){
var options = {
protocol: "https:",
hostname: "https://api.weather.gov/",
path: thePath,
port: 80,
method: "GET"
};
var instaRequest = https.request(options);
instaRequest.on("response", function(res){
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
console.log("response");
console.log(res.statusCode);
console.log(res.statusMessage);
});
instaRequest.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
instaRequest.end();
}
requestTheData();
I'm getting this error and can't figure out what's going on:
problem with request: getaddrinfo ENOTFOUND https://api.weather.gov/stations/ https://api.weather.gov/stations/:80
HTTPS generally uses port 443, so lets change that. Also, the API shows the hostname should be the raw URL and the path should be the remainder of the route (with a leading slash) similar to this:
thePath = '/stations/' + theStation + '/observations/current';
...
var options = {
hostname: "api.weather.gov",
path: thePath,
port: 443,
method: "GET"
};
Before even seeing any answers I got it working by:
protocol: "https:",
hostname: "api.weather.gov",
but then I was getting a STATUS:
403 Forbidden You don't have permission to access
"http://api.weather.gov/" on this server.
I seemed to remember that you are required to pass something in through headers so I added this under "method: "GET","
method: "GET",
headers: {
'Accept' : 'application/json',
'Content-Type': 'application/json',
'User-Agent' : 'MY-UA-STRING'
}
And, voila, now I'm getting JSON weather data. It didn't work until I added the 'User-Agent'. Do you guys know what this needs to be (and/or point me to a place that describes this)?

get call status in nodejs from grandstream phone

I am trying to fetch the call status of a grandstream phone by a nodejs script. But I've run in some trouble. The first request is going all fine, and returning that I am authenticated. The second request isn't going well, it says that I'm not authenticated.
How do I set the credentials or the cookie from the first request in the second request, so it knows that I'm loggedin?
First request response:
Response=Success
Message=Authentication accepted
Needchange=0
Ver=1.0.3.92
First request response headers:
{
'status': '200',
'content-length': '79',
'content-location': 'http://192.168.0.1/manager?action=login&username=XXXXXX&secret=XXXXXX',
'set-cookie': 'phonecookie="XXXXXX";HttpOnly, type=admin;, Version="1";, Max-Age=900',
'server': 'Enterprise Phone',
'pragma': 'no-cache',
'cache-control': 'no-cache',
'date': 'Wed, 14 Jun 2017 10:22:29 GMT',
'content-type': 'text/plain'
}
Second request response:
Response=Error
Message=Authentication Required
App.js Script:
var fetch = require('node-fetch');
var host = '192.168.0.1';
var loginUrl = "/manager?action=login&username=XXXXXX&secret=XXXXXX";
var statusUrl = "/manager?action=lineStatus&line=0";
function makeRequest(url)
{
fetch("http://" + host + loginUrl).then(function(resultLogin) {
var resultAuth = result.body();
fetch("http://" + host + statusUrl, {method: 'GET').then(function(resultStatus) {
var resultStatus = resultStatus.body();
});
});
}
makeRequest();
Use fetch-cookie to let node-fetch store and send back cookies according to the url.
var fetch = require('fetch-cookie')(require('node-fetch'))

How to use the node.js 'request' library with this http request?

I was trying to make a simple request to site. it should get html text, but it gets ' '
NPM module here: github.com/request/request
Code:
var fs = require('fs');
var request = require('request');
var options = {
url:'https://sample.site/phpLoaders/getInventory/getInventory.php',
encoding : 'utf8',
gzip : true,
forever: true,
headers: {
'Host': 'sample.site',
'Connection': 'keep-alive',
'Content-Length': '58',
'Cache-Control': 'max-age=0',
'Accept': '*/*',
'Origin': 'https://csgosell.com',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Referer': 'https://sample.site/',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4',
'Cookie': 'my-cookies from browser'
},
form: {
stage:'bot',
steamId:76561198284997423,
hasBonus:false,
coins:0
}
};
request.post(options,
function(error, response, body){
console.log(response.statusCode);
if (!error) {
fs.writeFileSync('site.html', body);
}
else{
console.log(error);
}
}
);
Chrome request: https://i.stack.imgur.com/zKQo5.png
Nodejs request:https://i.stack.imgur.com/yH9U3.png
the difference is in headers:
:authority:csgosell.com
:method:POST :path:/phpLoaders/getInventory/getInventory.php :scheme:https
after some googling, I anderstood that it is http2, and tried to put it inow another agent's options, but nothing changed.
var spdy = require('spdy');
var agent = spdy.createAgent({
host: 'sample.site',
port: 443,
spdy: {
ssl: true,
}
}).once('error', function (err) {
this.emit(err);
});
options.agent = agent;
To answer your question i will copy/paste a part of my code that enable you to receive a post request from your frontend application(angularJS) to your backend application (NodeJS), and another function that enable you to do the inverse send a post request from nodeJS to another application (that might consume it):
1) receive a request send from angularJS or whatever inside your nodeJS app
//Import the necessary libraries/declare the necessary objects
var express = require("express");
var myParser = require("body-parser");
var app = express();
// we will need the following imports for the inverse operation
var https = require('https')
var querystring = require('querystring')
// we need these variables for the post request:
var Vorname ;
var Name ;
var e_mail ;
var Strasse ;
app.use(myParser.urlencoded({extended : true}));
// the post request is send from http://localhost:8080/yourpath
app.post("/yourpath", function(request, response ) {
// test the post request
if (!request.body) return res.sendStatus(400);
// fill the variables with the user data
Vorname =request.body.Vorname;
Name =request.body.Name;
e_mail =request.body.e_mail;
Strasse =request.body.Strasse;
response.status(200).send(request.body.title);
});
2) Do the inverse send a POST request from a nodeJS application to another application
function sendPostRequest()
{
// prepare the data that we are going to send to anymotion
var jsonData = querystring.stringify({
"Land": "Land",
"Vorname": "Vorname",
"Name": "Name",
"Strasse": Strasse,
});
var post_options = {
host: 'achref.gassoumi.de',
port: '443',
method: 'POST',
path: '/api/mAPI',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': jsonData.length
}
};
// request object
var post_req = https.request(post_options, function(res) {
var result = '';
res.on('data', function (chunk) {
result += chunk;
console.log(result);
});
res.on('end', function () {
// show the result in the console : the thrown result in response of our post request
console.log(result);
});
res.on('error', function (err) {
// show possible error while receiving the result of our post request
console.log(err);
})
});
post_req.on('error', function (err) {
// show error if the post request is not succeed
console.log(err);
});
// post the data
post_req.write(jsonData);
post_req.end();
// ps : I used a https post request , you could use http if you want but you have to change the imported library and some stuffs in the code
}
So finally , I hope this answer will helps anyone who is looking on how to get a post request in node JS and how to send a Post request from nodeJS application.
For further details about how to receive a post request please read the npm documentation for body-parser library : npm official website documentation

node socket hang up error with http

I followed the node http document to write a delete request to the local server, but receive the socket hang up error, similar question I checked are:
NodeJS - What does “socket hang up” actually mean?
Error: socket hang up using node v0.12.0
but no one actually work for my scenario.
I believe it is the code error because I use postman it works for me, following is my code
var options = {
hostname: 'localhost',
port: 3000,
path: '/accounts/abc'
method: 'DELETE',
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};
var order = {
"secret": "abc_secret"
};
var content = JSON.stringify(order);
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
res.on('data', function(chunk) {
console.log('resp: ' + chunk);
});
});
req.on('error', function(err) {
console.error('error: ' , err.stack.split("\n"));
});
req.write(content);
req.end();
and the errors are:
error: [ 'Error: socket hang up',
' at createHangUpError (_http_client.js:215:15)',
' at TLSSocket.socketOnEnd (_http_client.js:300:23)',
' at TLSSocket.emit (events.js:129:20)',
' at _stream_readable.js:908:16',
' at process._tickCallback (node.js:355:11)' ]
Apparently, the request header does not have content length. Therefore, whatever you wrote in the write function will be ignored. Hope this is the root cause.
for me - solved by add Content-Length header.
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': Buffer.byteLength(JSON.stringify(order))
}

post request to mediawiki api

I'm trying to post data to the mediawiki API and it's not recognising the token I am sending.
var data = querystring.stringify({
action: "createaccount",
name: "sean",
email: "xxx",
password: "test",
token: "66cde5ad831521fe9d0fe4df3a2db25f"
});
var options = {
host: '54.201.91.132',
port: 80,
path: '/wiki/api.php',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(data)
}
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log("body: " + chunk);
});
});
req.write(data);
req.end();
I have tried sending the same data using the Postman chrome extension and this works fine.
POST /wiki/api.php HTTP/1.1
Host: 54.201.91.132
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
action=createaccount&name=shamus&email=xxx&password=test&token=5dc9c943ac3255f87dc7782c24f61ac6&format=json
{
"createaccount": {
"username": "Shamus",
"userid": 22,
"token": "c3744c0f19ea62f6baf89b10f7c86f7f",
"result": "success"
}
}
Any ideas what I'm doing wrong?
In addition to token, you must pass it the cookies you received with it. Of course, the token must not be hardcoded and be acquired dynamically.

Categories

Resources