@@ -4,7 +4,7 @@ const os = require('os');
44const constants = require ( 'constants' ) ;
55const { createSecureContext } = require ( 'tls' ) ;
66
7- const { AuthenticationContext } = require ( 'adal-node ' ) ;
7+ const { loginWithUsernamePassword , loginWithVmMSI , loginWithAppServiceMSI } = require ( '@azure/ms-rest-nodeauth ' ) ;
88
99const BulkLoad = require ( './bulk-load' ) ;
1010const Debug = require ( './debug' ) ;
@@ -74,8 +74,8 @@ class Connection extends EventEmitter {
7474 throw new TypeError ( 'The "config.authentication.type" property must be of type string.' ) ;
7575 }
7676
77- if ( type !== 'default' && type !== 'ntlm' && type !== 'azure-active-directory-password' && type !== 'azure-active-directory-access-token' ) {
78- throw new TypeError ( 'The "type" property must one of "default", "ntlm", "azure-active-directory-password" or "azure-active-directory-access-token".' ) ;
77+ if ( type !== 'default' && type !== 'ntlm' && type !== 'azure-active-directory-password' && type !== 'azure-active-directory-access-token' && type !== 'azure-active-directory-msi-vm' && type !== 'azure-active-directory-msi-app-service' ) {
78+ throw new TypeError ( 'The "type" property must one of "default", "ntlm", "azure-active-directory-password", "azure-active-directory-access-token", "azure-active-directory-msi-vm" or "azure-active-directory-msi-app-service ".' ) ;
7979 }
8080
8181 if ( typeof options !== 'object' || options === null ) {
@@ -130,6 +130,43 @@ class Connection extends EventEmitter {
130130 token : options . token
131131 }
132132 } ;
133+ } else if ( type === 'azure-active-directory-msi-vm' ) {
134+ if ( options . clientId !== undefined && typeof options . clientId !== 'string' ) {
135+ throw new TypeError ( 'The "config.authentication.options.clientId" property must be of type string.' ) ;
136+ }
137+
138+ if ( options . msiEndpoint !== undefined && typeof options . msiEndpoint !== 'string' ) {
139+ throw new TypeError ( 'The "config.authentication.options.msiEndpoint" property must be of type string.' ) ;
140+ }
141+
142+ authentication = {
143+ type : 'azure-active-directory-msi-vm' ,
144+ options : {
145+ clientId : options . clientId ,
146+ msiEndpoint : options . msiEndpoint
147+ }
148+ } ;
149+ } else if ( type === 'azure-active-directory-msi-app-service' ) {
150+ if ( options . clientId !== undefined && typeof options . clientId !== 'string' ) {
151+ throw new TypeError ( 'The "config.authentication.options.clientId" property must be of type string.' ) ;
152+ }
153+
154+ if ( options . msiEndpoint !== undefined && typeof options . msiEndpoint !== 'string' ) {
155+ throw new TypeError ( 'The "config.authentication.options.msiEndpoint" property must be of type string.' ) ;
156+ }
157+
158+ if ( options . msiSecret !== undefined && typeof options . msiSecret !== 'string' ) {
159+ throw new TypeError ( 'The "config.authentication.options.msiSecret" property must be of type string.' ) ;
160+ }
161+
162+ authentication = {
163+ type : 'azure-active-directory-msi-app-service' ,
164+ options : {
165+ clientId : options . clientId ,
166+ msiEndpoint : options . msiEndpoint ,
167+ msiSecret : options . msiSecret
168+ }
169+ } ;
133170 } else {
134171 if ( options . userName !== undefined && typeof options . userName !== 'string' ) {
135172 throw new TypeError ( 'The "config.authentication.options.userName" property must be of type string.' ) ;
@@ -1234,6 +1271,15 @@ class Connection extends EventEmitter {
12341271 } ;
12351272 break ;
12361273
1274+ case 'azure-active-directory-msi-vm' :
1275+ case 'azure-active-directory-msi-app-service' :
1276+ payload . fedAuth = {
1277+ type : 'ADAL' ,
1278+ echo : this . fedAuthRequired ,
1279+ workflow : 'integrated'
1280+ } ;
1281+ break ;
1282+
12371283 case 'ntlm' :
12381284 payload . sspi = createNTLMRequest ( { domain : authentication . options . domain } ) ;
12391285 break ;
@@ -1262,13 +1308,13 @@ class Connection extends EventEmitter {
12621308 } ) ;
12631309 }
12641310
1265- sendFedAuthResponsePacket ( tokenResponse ) {
1266- const accessTokenLen = Buffer . byteLength ( tokenResponse . accessToken , 'ucs2' ) ;
1311+ sendFedAuthTokenMessage ( token ) {
1312+ const accessTokenLen = Buffer . byteLength ( token , 'ucs2' ) ;
12671313 const data = Buffer . alloc ( 8 + accessTokenLen ) ;
12681314 let offset = 0 ;
12691315 offset = data . writeUInt32LE ( accessTokenLen + 4 , offset ) ;
12701316 offset = data . writeUInt32LE ( accessTokenLen , offset ) ;
1271- data . write ( tokenResponse . accessToken , offset , 'ucs2' ) ;
1317+ data . write ( token , offset , 'ucs2' ) ;
12721318 this . messageIo . sendMessage ( TYPE . FEDAUTH_TOKEN , data ) ;
12731319 // sent the fedAuth token message, the rest is similar to standard login 7
12741320 this . transitionTo ( this . STATE . SENT_LOGIN7_WITH_STANDARD_LOGIN ) ;
@@ -1892,7 +1938,7 @@ Connection.prototype.STATE = {
18921938
18931939 const { authentication } = this . config ;
18941940
1895- if ( authentication . type === 'azure-active-directory-password' ) {
1941+ if ( authentication . type === 'azure-active-directory-password' || authentication . type === 'azure-active-directory-msi-vm' || authentication . type === 'azure-active-directory-msi-app-service' ) {
18961942 this . transitionTo ( this . STATE . SENT_LOGIN7_WITH_FEDAUTH ) ;
18971943 } else if ( authentication . type === 'ntlm' ) {
18981944 this . transitionTo ( this . STATE . SENT_LOGIN7_WITH_NTLM ) ;
@@ -1920,7 +1966,7 @@ Connection.prototype.STATE = {
19201966 } ,
19211967 featureExtAck : function ( token ) {
19221968 const { authentication } = this . config ;
1923- if ( authentication . type === 'azure-active-directory-password' || authentication . type === 'azure-active-directory-access-token' ) {
1969+ if ( authentication . type === 'azure-active-directory-password' || authentication . type === 'azure-active-directory-access-token' || authentication . type === 'azure-active-directory-msi-vm' || authentication . type === 'azure-active-directory-msi-app-service' ) {
19241970 if ( token . fedAuth === undefined ) {
19251971 this . loginError = ConnectionError ( 'Did not receive Active Directory authentication acknowledgement' ) ;
19261972 this . loggedIn = false ;
@@ -2025,19 +2071,49 @@ Connection.prototype.STATE = {
20252071 } ,
20262072 message : function ( ) {
20272073 if ( this . fedAuthInfoToken && this . fedAuthInfoToken . stsurl && this . fedAuthInfoToken . spn ) {
2028- const clientId = '7f98cb04-cd1e-40df-9140-3bf7e2cea4db' ;
2029- const context = new AuthenticationContext ( this . fedAuthInfoToken . stsurl ) ;
2030- const authentication = this . config . authentication ;
2074+ const { authentication } = this . config ;
2075+
2076+ const getToken = ( callback ) => {
2077+ const getTokenFromCredentials = ( err , credentials ) => {
2078+ if ( err ) {
2079+ return callback ( err ) ;
2080+ }
2081+
2082+ credentials . getToken ( ) . then ( ( tokenResponse ) => {
2083+ callback ( null , tokenResponse . accessToken ) ;
2084+ } , callback ) ;
2085+ } ;
2086+
2087+ if ( authentication . type === 'azure-active-directory-password' ) {
2088+ loginWithUsernamePassword ( authentication . options . userName , authentication . options . password , {
2089+ clientId : '7f98cb04-cd1e-40df-9140-3bf7e2cea4db' ,
2090+ tokenAudience : this . fedAuthInfoToken . spn
2091+ } , getTokenFromCredentials ) ;
2092+ } else if ( authentication . type === 'azure-active-directory-msi-vm' ) {
2093+ loginWithVmMSI ( {
2094+ clientId : authentication . options . clientId ,
2095+ msiEndpoint : authentication . options . msiEndpoint ,
2096+ resource : this . fedAuthInfoToken . spn
2097+ } , getTokenFromCredentials ) ;
2098+ } else if ( authentication . type === 'azure-active-directory-msi-app-service' ) {
2099+ loginWithAppServiceMSI ( {
2100+ clientId : authentication . options . clientId ,
2101+ msiEndpoint : authentication . options . msiEndpoint ,
2102+ msiSecret : authentication . options . msiSecret ,
2103+ resource : this . fedAuthInfoToken . spn
2104+ } , getTokenFromCredentials ) ;
2105+ }
2106+ } ;
20312107
2032- context . acquireTokenWithUsernamePassword ( this . fedAuthInfoToken . spn , authentication . options . userName , authentication . options . password , clientId , ( err , tokenResponse ) => {
2108+ getToken ( ( err , token ) => {
20332109 if ( err ) {
20342110 this . loginError = ConnectionError ( 'Security token could not be authenticated or authorized.' , 'EFEDAUTH' ) ;
20352111 this . emit ( 'connect' , this . loginError ) ;
20362112 this . transitionTo ( this . STATE . FINAL ) ;
20372113 return ;
20382114 }
20392115
2040- this . sendFedAuthResponsePacket ( tokenResponse ) ;
2116+ this . sendFedAuthTokenMessage ( token ) ;
20412117 } ) ;
20422118 } else if ( this . loginError ) {
20432119 if ( this . loginError . isTransient ) {
0 commit comments