koltyakov / sppull

📎 Download files from SharePoint document libraries using Node.js without hassles
MIT License
46 stars 16 forks source link

Error in operations.getFolderContent: 401 - undefined #13

Closed raghuureddy closed 7 years ago

raghuureddy commented 7 years ago

Hi, i am facing below error when i use this.

I am connecting to SharePoint 2013 OnPrem (NTLM).

Folders proceeding: 0 out of 0 [reqursive scanning...] Error in operations.getFolderContent: 401 - undefined

On IIS event logs, i could see audit failed for first time, but subsequent audit success msgs are available.

Can you please suggest?

koltyakov commented 7 years ago

Hi @raghuureddy,

Could you share your config file? On-prem config should contain username, password and domain parameters. I guess that you have domain parameter missed.

raghuureddy commented 7 years ago

@koltyakov thank you for reply.

I do have domain parameter.

_private.conf.json { "domain": "eb", "password": "d2dsafdsafdsa241fdsafadsf54e1f2a82bc6380fa2437a3d4452asdaaaa205b9e7983b85855f90cb5ae365e59e710d10b2fadsfasdff0b3164978285sadfsafsd077de67dalrsGS5Uy1oKmcsY6iBADLQ==", "username": "user", "siteUrl": "http://sp2013" }

I am seeing this domain is being passed as well & i could see on Audit Failure log on SharePoint server event viewer.

koltyakov commented 7 years ago

My guess that you are using sppull in the project created with sppp generator and cpass for passwords securing. Also, you probably created the config on one machine and try running it on another.

With this in mind and having an unauthorized request I would recommend to try the following:

var Cpass = require("cpass");
var cpass = new Cpass();

var secured = "d2dsafdsafdsa241fdsafadsf54e1f2a82bc6380fa2437a3d4452asdaaaa205b9e7983b85855f90cb5ae365e59e710d10b2fadsfasdff0b3164978285sadfsafsd077de67dalrsGS5Uy1oKmcsY6iBADLQ==" // your actual hash from config file;
var unsecured = cpass.decode(secured);
conlsole.log(unsecured); // password string which is actually used when auth
var Cpass = require("cpass");
var cpass = new Cpass();

var password = "password";

var secured = cpass.encode(password);
console.log(secured);
raghuureddy commented 7 years ago

I tried with just sppull & tried with sppp generator as well. Both return exact same message.

As you suggested, i printed password on console & i see the correct password is being printed.

Also, i tried the URL on browser & it does work. I even tried from Firefox browser where it asks me to enter details, username / password, this also works.

Tried clearning password & it did asked me to enter all the details. Even then it failed.

koltyakov commented 7 years ago

What if to try using another user as an experiment?

To experiment with user/password access issues it's better to switch to lower level:

var spauth = require('node-sp-auth');

var url = "http://weburl";
var credentialOptions = {
    username: "username",
    password: "password",
    domain: "domain"
};

spauth.getAuth(url, credentialOptions).then(function(options) { console.log("AUTH cookie:", options.headers.Authorization); console.log("Please check if password is the same here:", credentialOptions); }); // in one line to easier copy & paste to the node js console

And debug if you receive an auth cookie or an error.

Also, please check if you have the recent node-sp-auth version installed.

raghuureddy commented 7 years ago

Tried with same user / other user & receiving cookie & password is correct in both the cases. Below is the output.

AUTH cookie: NTLM TlRMTVNTUAADAAAAGAAYAFwAAAAYABgAdAAAAAQABABIAAAAEAAQAEwAAAAAAAAAXAAAAAAAAACMAAAABYKIogUBKAoAAAAPVwBCAHcAYgAzADUAMAA1ADgAMgD9V30d15KWfAAAAAAAAAAAAAAAAAAAAABI8XzWR1AySIzV+SQXAsWZky15+hJpGkw= Please check if password is the same here: { username: 'user', password: 'Passwordiscorrect', domain: 'eb', workstation: '' }

koltyakov commented 7 years ago

Will any sp-request work?

var request = require("sp-request");

var context = {
    siteUrl: "http://weburl",
    username: "username",
    password: "password",
    domain: "domain"
};

var spr = request.create(context);

var restUrl = context.siteUrl + "/_api/Web/Lists";

spr.get(restUrl)
    .then(function(response) { console.log("Success", response); })
    .catch(function(err) { console.log("Error", err); });

Btw, can it be that the Kerberos is used in SharePoint web application?

koltyakov commented 7 years ago

It can be related to this case https://github.com/s-KaiNet/spsave/issues/19

raghuureddy commented 7 years ago

Below is the detailed error message for sp-request.

Error { StatusCodeError: 401 - undefined at new StatusCodeError (C:\Raghu\work\srvchlpdsk\node_modules\request-promise\lib\errors.js:32:15) at Request.RP$callback [as _callback] (C:\Raghu\work\srvchlpdsk\node_modules\request-promise\lib\rp.js:77:29) at Request.self.callback (C:\Raghu\work\srvchlpdsk\node_modules\request\request.js:186:22) at emitTwo (events.js:106:13) at Request.emit (events.js:191:7) at Request.<anonymous> (C:\Raghu\work\srvchlpdsk\node_modules\request\request.js:1081:10) at emitOne (events.js:96:13) at Request.emit (events.js:188:7) at IncomingMessage.<anonymous> (C:\Raghu\work\srvchlpdsk\node_modules\request\request.js:1001:12) at IncomingMessage.g (events.js:291:16) at emitNone (events.js:91:20) at IncomingMessage.emit (events.js:185:7) at endReadableNT (_stream_readable.js:974:12) at _combinedTickCallback (internal/process/next_tick.js:74:11) at process._tickCallback (internal/process/next_tick.js:98:9) name: 'StatusCodeError', statusCode: 401, message: '401 - undefined', error: undefined, options: { method: 'GET', url: 'http://sp13:1001/servicehelpdesk/_api/Web/Lists', resolveWithFullResponse: true, simple: true, headers: { Accept: 'application/json;odata=verbose', 'Content-Type': 'application/json;odata=verbose', Connection: 'Close', Authorization: 'NTLM TlRMTVNTUAADAAAAGAAYAFwAAAAYABgAdAAAAAQABABIAAAAEAAQAEwAAAAAAAAAXAAAAAAAAACMAAAABYKIogUBKAoAAAAPVwBCAHcAYgAzADUAMAA1ADgAMgDJ0iAsDCIu0QAAAAAAAAAAAAAAAAAAAABPmCUmof9Moo2aNH7m2VNbMZDGnnQH5Rc=' }, json: true, strictSSL: false, agent: Agent { domain: null, _events: [Object], _eventsCount: 1, _maxListeners: undefined, defaultPort: 80, protocol: 'http:', options: [Object], requests: {}, sockets: {}, freeSockets: {}, keepAliveMsecs: 1000, keepAlive: true, maxSockets: Infinity, maxFreeSockets: 256 }, callback: undefined, transform: undefined }, response: IncomingMessage { _readableState: ReadableState { objectMode: false, highWaterMark: 16384, buffer: [Object], length: 0, pipes: null, pipesCount: 0, flowing: true, ended: true, endEmitted: true, reading: false, sync: true, needReadable: false, emittedReadable: false, readableListening: false, resumeScheduled: false, defaultEncoding: 'utf8', ranOut: false, awaitDrain: 0, readingMore: false, decoder: null, encoding: null }, readable: false, domain: null, _events: { end: [Object], close: [Object], data: [Function], error: [Function] }, _eventsCount: 4, _maxListeners: undefined, socket: Socket { connecting: false, _hadError: false, _handle: null, _parent: null, _host: 'sp13', _readableState: [Object], readable: false, domain: null, _events: [Object], _eventsCount: 8, _maxListeners: undefined, _writableState: [Object], writable: false, allowHalfOpen: false, destroyed: true, _bytesDispatched: 601, _sockname: null, _pendingData: null, _pendingEncoding: '', server: null, _server: null, parser: null, _httpMessage: [Object], read: [Function], _consuming: true, _idleNext: null, _idlePrev: null, _idleTimeout: -1 }, connection: Socket { connecting: false, _hadError: false, _handle: null, _parent: null, _host: 'sp13', _readableState: [Object], readable: false, domain: null, _events: [Object], _eventsCount: 8, _maxListeners: undefined, _writableState: [Object], writable: false, allowHalfOpen: false, destroyed: true, _bytesDispatched: 601, _sockname: null, _pendingData: null, _pendingEncoding: '', server: null, _server: null, parser: null, _httpMessage: [Object], read: [Function], _consuming: true, _idleNext: null, _idlePrev: null, _idleTimeout: -1 }, httpVersionMajor: 1, httpVersionMinor: 1, httpVersion: '1.1', complete: true, headers: { server: 'Microsoft-IIS/8.0', sprequestguid: 'c659ca9d-e039-f06a-b69a-c8db27477edb', 'request-id': 'c659ca9d-e039-f06a-b69a-c8db27477edb', 'x-frame-options': 'SAMEORIGIN', sprequestduration: '17', spiislatency: '0', 'www-authenticate': 'NTLM', 'x-powered-by': 'ASP.NET', microsoftsharepointteamservices: '15.0.0.4727', 'x-content-type-options': 'nosniff', 'x-ms-invokeapp': '1; RequireReadOnly', date: 'Thu, 12 Jan 2017 16:07:58 GMT', connection: 'close', 'content-length': '0' }, rawHeaders: [ 'Server', 'Microsoft-IIS/8.0', 'SPRequestGuid', 'c659ca9d-e039-f06a-b69a-c8db27477edb', 'request-id', 'c659ca9d-e039-f06a-b69a-c8db27477edb', 'X-FRAME-OPTIONS', 'SAMEORIGIN', 'SPRequestDuration', '17', 'SPIisLatency', '0', 'WWW-Authenticate', 'NTLM', 'X-Powered-By', 'ASP.NET', 'MicrosoftSharePointTeamServices', '15.0.0.4727', 'X-Content-Type-Options', 'nosniff', 'X-MS-InvokeApp', '1; RequireReadOnly', 'Date', 'Thu, 12 Jan 2017 16:07:58 GMT', 'Connection', 'close', 'Content-Length', '0' ], trailers: {}, rawTrailers: [], upgrade: false, url: '', method: null, statusCode: 401, statusMessage: 'Unauthorized', client: Socket { connecting: false, _hadError: false, _handle: null, _parent: null, _host: 'sp13', _readableState: [Object], readable: false, domain: null, _events: [Object], _eventsCount: 8, _maxListeners: undefined, _writableState: [Object], writable: false, allowHalfOpen: false, destroyed: true, _bytesDispatched: 601, _sockname: null, _pendingData: null, _pendingEncoding: '', server: null, _server: null, parser: null, _httpMessage: [Object], read: [Function], _consuming: true, _idleNext: null, _idlePrev: null, _idleTimeout: -1 }, _consuming: true, _dumped: false, req: ClientRequest { domain: null, _events: [Object], _eventsCount: 5, _maxListeners: undefined, output: [], outputEncodings: [], outputCallbacks: [], outputSize: 0, writable: true, _last: true, upgrading: false, chunkedEncoding: false, shouldKeepAlive: false, useChunkedEncodingByDefault: false, sendDate: false, _removedHeader: [Object], _contentLength: 0, _hasBody: true, _trailer: '', finished: true, _headerSent: true, socket: [Object], connection: [Object], _header: 'GET /servicehelpdesk/_api/Web/Lists HTTP/1.1\r\nAccept: application/json;odata=verbose\r\nContent-Type: application/json;odata=verbose\r\nConnection: Close\r\nAuthorization: NTLM TlRMTVNTUAADAAAAGAAYAFwAAAAYABgAdAAAAAQABABIAAAAEAAQAEwAAAAAAAAAXAAAAAAAAACMAAAABYKIogUBKAoAAAAPVwBCAHcAYgAzADUAMAA1ADgAMgDJ0iAsDCIu0QAAAAAAAAAAAAAAAAAAAABPmCUmof9Moo2aNH7m2VNbMZDGnnQH5Rc=\r\nhost: sp13:1001\r\n\r\n', _headers: [Object], _headerNames: [Object], _onPendingData: null, agent: [Object], socketPath: undefined, timeout: undefined, method: 'GET', path: '/servicehelpdesk/_api/Web/Lists', _ended: true, parser: null, res: [Circular] }, request: Request { domain: null, _events: [Object], _eventsCount: 5, _maxListeners: undefined, method: 'GET', resolveWithFullResponse: true, simple: true, headers: [Object], strictSSL: false, agent: [Object], readable: true, writable: true, explicitMethod: true, _qs: [Object], _auth: [Object], _oauth: [Object], _multipart: [Object], _redirect: [Object], _tunnel: [Object], _rp_resolve: [Function], _rp_reject: [Function], _rp_promise: [Object], _rp_callbackOrig: undefined, callback: [Function], _rp_options: [Object], setHeader: [Function], hasHeader: [Function], getHeader: [Function], removeHeader: [Function], localAddress: undefined, pool: {}, dests: [], __isRequestRequest: true, _callback: [Function: RP$callback], uri: [Object], rejectUnauthorized: false, proxy: null, tunnel: false, setHost: true, originalCookieHeader: undefined, _disableCookies: true, _jar: undefined, port: '1001', host: 'sp13', path: '/servicehelpdesk/_api/Web/Lists', _json: true, httpModule: [Object], _started: true, href: 'http://sp13:1001/servicehelpdesk/_api/Web/Lists', req: [Object], ntick: true, response: [Circular], originalHost: 'sp13:1001', originalHostHeaderName: 'host', responseContent: [Circular], _ended: true, _callbackCalled: true }, toJSON: [Function: responseToJSON], caseless: Caseless { dict: [Object] }, read: [Function] } }

Also its Windows Authentication with NTLM as shown below.

image

Thank you for your prompt response & hope we can find a solution to this.

raghuureddy commented 7 years ago

Just in case if it helps, i tried the URL on firefox browser & under network tab i could see 3 requests. http://sp13:1001/servicehelpdesk/_api/Web/Lists

First 2 requests retrurned with 401 unauthorized, but the 3rd request is 200 success.

image

After the first 401, firefox prompted me to enter username/password, after entering it loaded fine, but i see total 3 requests in firefox.

koltyakov commented 7 years ago

It looks like something is wrong with your environment it's an abnormal situation.

raghuureddy commented 7 years ago

I am not sure if its environment issue as the same thing is happening across all environemnts (dev/sit/qa/prod), NTLM is being challenged & then authenticated successfully.

NTLM handshake [3 requests] - http://sharepoint.stackexchange.com/questions/104883/avoid-ntlm-authorization-handshake-on-every-request-to-the-rest-api

Looks like it might need some more digging, so i will go ahead with add-in auth mechanism for now. Add-in is not needed for me but as NTLM is not working, i dont have other option being a complete client side SP project.

Will post the results of add-in auth.

Thank you for the help so far.

raghuureddy commented 7 years ago

After debugging further, my SharePoint server supports only NTLMv2 & i am not sure if ntlm npm supports only NTLMv1. I have raised an issue there & waiting for the reply. #https://github.com/SamDecrock/node-http-ntlm/issues/59

koltyakov commented 7 years ago

Thank for the info and research, Raghu. I have subscribed to the node-http-ntlm thread too.

s-KaiNet commented 7 years ago

@raghuureddy thanks for your in-depth analysis on this issue. Really appreciate it.
Since you identified that this is most probably ntlm V2 issue, may be you can help me to reproduce it.
Can you answer on the following questions:

raghuureddy commented 7 years ago

@s-KaiNet sure.

Please check on the registry for the below key value. On my SP server it is '5'. LmCompatibilityLevel https://technet.microsoft.com/en-us/library/cc960646.aspx

If i change this key value to any value less than 2, then the format of hash keys generated by browsers & ntlmhttp are same. But when it was 5, then the format was different. Used fiddler to check the generated hash keys by nodejs & by browser.

When this key is set to '2', then from the browser also SP site was not being authenticated & it was returning exact same error message. (401)

Hope you will be able to reproduce.

koltyakov commented 7 years ago

Closing due inactivity.