11// Copyright (c) Microsoft. All rights reserved.
22// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33
4- import VsoBaseInterfaces = require( '../interfaces/common/VsoBaseInterfaces' ) ;
4+ import ifm = require( '../interfaces/common/VsoBaseInterfaces' ) ;
5+ import * as resthandlers from 'typed-rest-client/Handlers' ;
56
6- import http = require( "http" ) ;
7- import https = require( "https" ) ;
8- var _ = require ( "underscore" ) ;
9- var ntlm = require ( "../opensource/node-http-ntlm/ntlm" ) ;
10-
11- export class NtlmCredentialHandler implements VsoBaseInterfaces . IRequestHandler {
12- username : string ;
13- password : string ;
14- workstation : string ;
15- domain : string ;
16-
17- constructor ( username : string , password : string , workstation ?: string , domain ?: string ) {
18- this . username = username ;
19- this . password = password ;
20- if ( workstation !== undefined ) {
21- this . workstation = workstation ;
22- }
23- if ( domain !== undefined ) {
24- this . domain = domain ;
25- }
26- }
27-
28- prepareRequest ( options :any ) : void {
29- // No headers or options need to be set. We keep the credentials on the handler itself.
30- // If a (proxy) agent is set, remove it as we don't support proxy for NTLM at this time
31- if ( options . agent ) {
32- delete options . agent ;
33- }
34- }
35-
36- canHandleAuthentication ( res : VsoBaseInterfaces . IHttpResponse ) : boolean {
37- if ( res && res . statusCode === 401 ) {
38- // Ensure that we're talking NTLM here
39- // Once we have the www-authenticate header, split it so we can ensure we can talk NTLM
40- var wwwAuthenticate = res . headers [ 'www-authenticate' ] ;
41- if ( wwwAuthenticate !== undefined ) {
42- var mechanisms = wwwAuthenticate . split ( ', ' ) ;
43- var idx = mechanisms . indexOf ( "NTLM" ) ;
44- if ( idx >= 0 ) {
45- // Check specifically for 'NTLM' since www-authenticate header can also contain
46- // the Authorization value to use in the form of 'NTLM TlRMTVNT....AAAADw=='
47- if ( mechanisms [ idx ] . length == 4 ) {
48- return true ;
49- }
50- }
51- }
52- }
53- return false ;
54- }
55-
56- // The following method is an adaptation of code found at https://github.com/SamDecrock/node-http-ntlm/blob/master/httpntlm.js
57- handleAuthentication ( httpClient , protocol , options , objs , finalCallback ) : void {
58- // Set up the headers for NTLM authentication
59- var ntlmOptions = _ . extend ( options , {
60- username : this . username ,
61- password : this . password ,
62- domain : this . domain || '' ,
63- workstation : this . workstation || ''
64- } ) ;
65- var keepaliveAgent ;
66- if ( httpClient . isSsl === true ) {
67- keepaliveAgent = new https . Agent ( { } ) ;
68- } else {
69- keepaliveAgent = new http . Agent ( { keepAlive : true } ) ;
70- }
71- let self = this ;
72- // The following pattern of sending the type1 message following immediately (in a setImmediate) is
73- // critical for the NTLM exchange to happen. If we removed setImmediate (or call in a different manner)
74- // the NTLM exchange will always fail with a 401.
75- this . sendType1Message ( httpClient , protocol , ntlmOptions , objs , keepaliveAgent , function ( err , res ) {
76- if ( err ) {
77- return finalCallback ( err , null , null ) ;
78- }
79- setImmediate ( function ( ) {
80- self . sendType3Message ( httpClient , protocol , ntlmOptions , objs , keepaliveAgent , res , finalCallback ) ;
81- } ) ;
82- } ) ;
83- }
84-
85- // The following method is an adaptation of code found at https://github.com/SamDecrock/node-http-ntlm/blob/master/httpntlm.js
86- private sendType1Message ( httpClient , protocol , options , objs , keepaliveAgent , callback ) : void {
87- var type1msg = ntlm . createType1Message ( options ) ;
88- var type1options = {
89- headers : {
90- 'Connection' : 'keep-alive' ,
91- 'Authorization' : type1msg
92- } ,
93- timeout : options . timeout || 0 ,
94- agent : keepaliveAgent ,
95- // don't redirect because http could change to https which means we need to change the keepaliveAgent
96- allowRedirects : false
97- } ;
98- type1options = _ . extend ( type1options , _ . omit ( options , 'headers' ) ) ;
99- httpClient . requestInternal ( protocol , type1options , objs , callback ) ;
100- }
101-
102- // The following method is an adaptation of code found at https://github.com/SamDecrock/node-http-ntlm/blob/master/httpntlm.js
103- private sendType3Message ( httpClient , protocol , options , objs , keepaliveAgent , res , callback ) : void {
104- if ( ! res . headers [ 'www-authenticate' ] ) {
105- return callback ( new Error ( 'www-authenticate not found on response of second request' ) ) ;
106- }
107- // parse type2 message from server:
108- var type2msg = ntlm . parseType2Message ( res . headers [ 'www-authenticate' ] ) ;
109- // create type3 message:
110- var type3msg = ntlm . createType3Message ( type2msg , options ) ;
111- // build type3 request:
112- var type3options = {
113- headers : {
114- 'Authorization' : type3msg
115- } ,
116- allowRedirects : false ,
117- agent : keepaliveAgent
118- } ;
119- // pass along other options:
120- type3options . headers = _ . extend ( type3options . headers , options . headers ) ;
121- type3options = _ . extend ( type3options , _ . omit ( options , 'headers' ) ) ;
122- // send type3 message to server:
123- httpClient . requestInternal ( protocol , type3options , objs , callback ) ;
7+ export class NtlmCredentialHandler extends resthandlers . NtlmCredentialHandler implements ifm . IRequestHandler {
8+ constructor ( username : string , password : string , workstation ?: string , domain ?: string ) {
9+ super ( username , password , workstation , domain ) ;
12410 }
125- }
11+ }
0 commit comments