mssql 9.2.0 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/lib/base/connection-pool.js +70 -7
- package/lib/tedious/connection-pool.js +56 -41
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -574,11 +574,50 @@ In addition to configuration object there is an option to pass config as a conne
|
|
|
574
574
|
|
|
575
575
|
##### Classic Connection String
|
|
576
576
|
|
|
577
|
+
###### Standard configuration using tedious driver
|
|
578
|
+
|
|
577
579
|
```
|
|
578
580
|
Server=localhost,1433;Database=database;User Id=username;Password=password;Encrypt=true
|
|
581
|
+
```
|
|
582
|
+
###### Standard configuration using msnodesqlv8 driver
|
|
583
|
+
```
|
|
579
584
|
Driver=msnodesqlv8;Server=(local)\INSTANCE;Database=database;UID=DOMAIN\username;PWD=password;Encrypt=true
|
|
580
585
|
```
|
|
581
586
|
|
|
587
|
+
##### Azure Active Directory Authentication Connection String
|
|
588
|
+
|
|
589
|
+
Several types of Azure Authentication are supported:
|
|
590
|
+
|
|
591
|
+
###### Authentication using Active Directory Integrated
|
|
592
|
+
```
|
|
593
|
+
Server=*.database.windows.net;Database=database;Authentication=Active Directory Integrated;Client secret=clientsecret;Client Id=clientid;Tenant Id=tenantid;Encrypt=true
|
|
594
|
+
```
|
|
595
|
+
Note: Internally, the 'Active Directory Integrated' will change its type depending on the other parameters you add to it. On the example above, it will change to azure-active-directory-service-principal-secret because we supplied a Client Id, Client secret and Tenant Id.
|
|
596
|
+
|
|
597
|
+
If you want to utilize Authentication tokens (azure-active-directory-access-token) Just remove the unnecessary additional parameters and supply only a token parameter, such as in this example:
|
|
598
|
+
|
|
599
|
+
```
|
|
600
|
+
Server=*.database.windows.net;Database=database;Authentication=Active Directory Integrated;token=token;Encrypt=true
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
Finally if you want to utilize managed identity services such as managed identity service app service you can follow this example below:
|
|
604
|
+
```
|
|
605
|
+
Server=*.database.windows.net;Database=database;Authentication=Active Directory Integrated;msi endpoint=msiendpoint;Client Id=clientid;msi secret=msisecret;Encrypt=true
|
|
606
|
+
```
|
|
607
|
+
or if its managed identity service virtual machines, then follow this:
|
|
608
|
+
```
|
|
609
|
+
Server=*.database.windows.net;Database=database;Authentication=Active Directory Integrated;msi endpoint=msiendpoint;Client Id=clientid;Encrypt=true
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
We can also utilizes Active Directory Password but unlike the previous examples, it is not part of the Active Directory Integrated Authentication.
|
|
613
|
+
|
|
614
|
+
###### Authentication using Active Directory Password
|
|
615
|
+
```
|
|
616
|
+
Server=*.database.windows.net;Database=database;Authentication=Active Directory Password;User Id=username;Password=password;Client Id=clientid;Tenant Id=tenantid;Encrypt=true
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
For more reference, you can consult [here](https://tediousjs.github.io/tedious/api-connection.html#function_newConnection). Under the authentication.type parameter.
|
|
620
|
+
|
|
582
621
|
## Drivers
|
|
583
622
|
|
|
584
623
|
### Tedious
|
|
@@ -99,6 +99,28 @@ class ConnectionPool extends EventEmitter {
|
|
|
99
99
|
return this._parseConnectionString(connectionString)
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
static _parseAuthenticationType (type, entries) {
|
|
103
|
+
switch (type.toLowerCase()) {
|
|
104
|
+
case 'active directory integrated':
|
|
105
|
+
if (entries.includes('token')) {
|
|
106
|
+
return 'azure-active-directory-access-token'
|
|
107
|
+
} else if (['client id', 'client secret', 'tenant id'].every(entry => entries.includes(entry))) {
|
|
108
|
+
return 'azure-active-directory-service-principal-secret'
|
|
109
|
+
} else if (['client id', 'msi endpoint', 'msi secret'].every(entry => entries.includes(entry))) {
|
|
110
|
+
return 'azure-active-directory-msi-app-service'
|
|
111
|
+
} else if (['client id', 'msi endpoint'].every(entry => entries.includes(entry))) {
|
|
112
|
+
return 'azure-active-directory-msi-vm'
|
|
113
|
+
}
|
|
114
|
+
return 'azure-active-directory-default'
|
|
115
|
+
case 'active directory password':
|
|
116
|
+
return 'azure-active-directory-password'
|
|
117
|
+
case 'ntlm':
|
|
118
|
+
return 'ntlm'
|
|
119
|
+
default:
|
|
120
|
+
return 'default'
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
102
124
|
static _parseConnectionString (connectionString) {
|
|
103
125
|
const parsed = parseSqlConnectionString(connectionString, true, true)
|
|
104
126
|
return Object.entries(parsed).reduce((config, [key, value]) => {
|
|
@@ -115,6 +137,9 @@ class ConnectionPool extends EventEmitter {
|
|
|
115
137
|
case 'attachdbfilename':
|
|
116
138
|
break
|
|
117
139
|
case 'authentication':
|
|
140
|
+
Object.assign(config, {
|
|
141
|
+
authentication_type: this._parseAuthenticationType(value, Object.keys(parsed))
|
|
142
|
+
})
|
|
118
143
|
break
|
|
119
144
|
case 'column encryption setting':
|
|
120
145
|
break
|
|
@@ -134,6 +159,16 @@ class ConnectionPool extends EventEmitter {
|
|
|
134
159
|
break
|
|
135
160
|
case 'context connection':
|
|
136
161
|
break
|
|
162
|
+
case 'client id':
|
|
163
|
+
Object.assign(config, {
|
|
164
|
+
clientId: value
|
|
165
|
+
})
|
|
166
|
+
break
|
|
167
|
+
case 'client secret':
|
|
168
|
+
Object.assign(config, {
|
|
169
|
+
clientSecret: value
|
|
170
|
+
})
|
|
171
|
+
break
|
|
137
172
|
case 'current language':
|
|
138
173
|
Object.assign(config.options, {
|
|
139
174
|
language: value
|
|
@@ -173,9 +208,11 @@ class ConnectionPool extends EventEmitter {
|
|
|
173
208
|
port,
|
|
174
209
|
server
|
|
175
210
|
})
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
211
|
+
if (instanceName) {
|
|
212
|
+
Object.assign(config.options, {
|
|
213
|
+
instanceName
|
|
214
|
+
})
|
|
215
|
+
}
|
|
179
216
|
break
|
|
180
217
|
}
|
|
181
218
|
case 'encrypt':
|
|
@@ -204,6 +241,16 @@ class ConnectionPool extends EventEmitter {
|
|
|
204
241
|
min: value
|
|
205
242
|
})
|
|
206
243
|
break
|
|
244
|
+
case 'msi endpoint':
|
|
245
|
+
Object.assign(config, {
|
|
246
|
+
msiEndpoint: value
|
|
247
|
+
})
|
|
248
|
+
break
|
|
249
|
+
case 'msi secret':
|
|
250
|
+
Object.assign(config, {
|
|
251
|
+
msiSecret: value
|
|
252
|
+
})
|
|
253
|
+
break
|
|
207
254
|
case 'multipleactiveresultsets':
|
|
208
255
|
break
|
|
209
256
|
case 'multisubnetfailover':
|
|
@@ -231,6 +278,16 @@ class ConnectionPool extends EventEmitter {
|
|
|
231
278
|
break
|
|
232
279
|
case 'replication':
|
|
233
280
|
break
|
|
281
|
+
case 'tenant id':
|
|
282
|
+
Object.assign(config, {
|
|
283
|
+
tenantId: value
|
|
284
|
+
})
|
|
285
|
+
break
|
|
286
|
+
case 'token':
|
|
287
|
+
Object.assign(config, {
|
|
288
|
+
token: value
|
|
289
|
+
})
|
|
290
|
+
break
|
|
234
291
|
case 'transaction binding':
|
|
235
292
|
Object.assign(config.options, {
|
|
236
293
|
enableImplicitTransactions: value.toLowerCase() === 'implicit unbind'
|
|
@@ -253,10 +310,16 @@ class ConnectionPool extends EventEmitter {
|
|
|
253
310
|
domain = domainUser[1]
|
|
254
311
|
user = domainUser[2]
|
|
255
312
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
313
|
+
if (domain) {
|
|
314
|
+
Object.assign(config, {
|
|
315
|
+
domain
|
|
316
|
+
})
|
|
317
|
+
}
|
|
318
|
+
if (user) {
|
|
319
|
+
Object.assign(config, {
|
|
320
|
+
user
|
|
321
|
+
})
|
|
322
|
+
}
|
|
260
323
|
break
|
|
261
324
|
}
|
|
262
325
|
case 'user instance':
|
|
@@ -8,6 +8,61 @@ const shared = require('../shared')
|
|
|
8
8
|
const ConnectionError = require('../error/connection-error')
|
|
9
9
|
|
|
10
10
|
class ConnectionPool extends BaseConnectionPool {
|
|
11
|
+
_config () {
|
|
12
|
+
const cfg = {
|
|
13
|
+
server: this.config.server,
|
|
14
|
+
options: Object.assign({
|
|
15
|
+
encrypt: typeof this.config.encrypt === 'boolean' ? this.config.encrypt : true,
|
|
16
|
+
trustServerCertificate: typeof this.config.trustServerCertificate === 'boolean' ? this.config.trustServerCertificate : false
|
|
17
|
+
}, this.config.options),
|
|
18
|
+
authentication: Object.assign({
|
|
19
|
+
type: this.config.domain !== undefined ? 'ntlm' : this.config.authentication_type !== undefined ? this.config.authentication_type : 'default',
|
|
20
|
+
options: Object.entries({
|
|
21
|
+
userName: this.config.user,
|
|
22
|
+
password: this.config.password,
|
|
23
|
+
domain: this.config.domain,
|
|
24
|
+
clientId: this.config.clientId,
|
|
25
|
+
clientSecret: this.config.clientSecret,
|
|
26
|
+
tenantId: this.config.tenantId,
|
|
27
|
+
token: this.config.token,
|
|
28
|
+
msiEndpoint: this.config.msiEndpoint,
|
|
29
|
+
msiSecret: this.config.msiSecret
|
|
30
|
+
}).reduce((acc, [key, val]) => {
|
|
31
|
+
if (typeof val !== 'undefined') {
|
|
32
|
+
return { ...acc, [key]: val }
|
|
33
|
+
}
|
|
34
|
+
return acc
|
|
35
|
+
}, {})
|
|
36
|
+
}, this.config.authentication)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
cfg.options.database = cfg.options.database || this.config.database
|
|
40
|
+
cfg.options.port = cfg.options.port || this.config.port
|
|
41
|
+
cfg.options.connectTimeout = cfg.options.connectTimeout ?? this.config.connectionTimeout ?? this.config.timeout ?? 15000
|
|
42
|
+
cfg.options.requestTimeout = cfg.options.requestTimeout ?? this.config.requestTimeout ?? this.config.timeout ?? 15000
|
|
43
|
+
cfg.options.tdsVersion = cfg.options.tdsVersion || '7_4'
|
|
44
|
+
cfg.options.rowCollectionOnDone = cfg.options.rowCollectionOnDone || false
|
|
45
|
+
cfg.options.rowCollectionOnRequestCompletion = cfg.options.rowCollectionOnRequestCompletion || false
|
|
46
|
+
cfg.options.useColumnNames = cfg.options.useColumnNames || false
|
|
47
|
+
cfg.options.appName = cfg.options.appName || 'node-mssql'
|
|
48
|
+
|
|
49
|
+
// tedious always connect via tcp when port is specified
|
|
50
|
+
if (cfg.options.instanceName) delete cfg.options.port
|
|
51
|
+
|
|
52
|
+
if (isNaN(cfg.options.requestTimeout)) cfg.options.requestTimeout = 15000
|
|
53
|
+
if (cfg.options.requestTimeout === Infinity || cfg.options.requestTimeout < 0) cfg.options.requestTimeout = 0
|
|
54
|
+
|
|
55
|
+
if (!cfg.options.debug && this.config.debug) {
|
|
56
|
+
cfg.options.debug = {
|
|
57
|
+
packet: true,
|
|
58
|
+
token: true,
|
|
59
|
+
data: true,
|
|
60
|
+
payload: true
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return cfg
|
|
64
|
+
}
|
|
65
|
+
|
|
11
66
|
_poolCreate () {
|
|
12
67
|
return new shared.Promise((resolve, reject) => {
|
|
13
68
|
const resolveOnce = (v) => {
|
|
@@ -18,49 +73,9 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
18
73
|
reject(e)
|
|
19
74
|
resolve = reject = () => {}
|
|
20
75
|
}
|
|
21
|
-
const cfg = {
|
|
22
|
-
server: this.config.server,
|
|
23
|
-
options: Object.assign({
|
|
24
|
-
encrypt: typeof this.config.encrypt === 'boolean' ? this.config.encrypt : true,
|
|
25
|
-
trustServerCertificate: typeof this.config.trustServerCertificate === 'boolean' ? this.config.trustServerCertificate : false
|
|
26
|
-
}, this.config.options),
|
|
27
|
-
authentication: Object.assign({
|
|
28
|
-
type: this.config.domain !== undefined ? 'ntlm' : 'default',
|
|
29
|
-
options: {
|
|
30
|
-
userName: this.config.user,
|
|
31
|
-
password: this.config.password,
|
|
32
|
-
domain: this.config.domain
|
|
33
|
-
}
|
|
34
|
-
}, this.config.authentication)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
cfg.options.database = cfg.options.database || this.config.database
|
|
38
|
-
cfg.options.port = cfg.options.port || this.config.port
|
|
39
|
-
cfg.options.connectTimeout = cfg.options.connectTimeout ?? this.config.connectionTimeout ?? this.config.timeout ?? 15000
|
|
40
|
-
cfg.options.requestTimeout = cfg.options.requestTimeout ?? this.config.requestTimeout ?? this.config.timeout ?? 15000
|
|
41
|
-
cfg.options.tdsVersion = cfg.options.tdsVersion || '7_4'
|
|
42
|
-
cfg.options.rowCollectionOnDone = cfg.options.rowCollectionOnDone || false
|
|
43
|
-
cfg.options.rowCollectionOnRequestCompletion = cfg.options.rowCollectionOnRequestCompletion || false
|
|
44
|
-
cfg.options.useColumnNames = cfg.options.useColumnNames || false
|
|
45
|
-
cfg.options.appName = cfg.options.appName || 'node-mssql'
|
|
46
|
-
|
|
47
|
-
// tedious always connect via tcp when port is specified
|
|
48
|
-
if (cfg.options.instanceName) delete cfg.options.port
|
|
49
|
-
|
|
50
|
-
if (isNaN(cfg.options.requestTimeout)) cfg.options.requestTimeout = 15000
|
|
51
|
-
if (cfg.options.requestTimeout === Infinity || cfg.options.requestTimeout < 0) cfg.options.requestTimeout = 0
|
|
52
|
-
|
|
53
|
-
if (!cfg.options.debug && this.config.debug) {
|
|
54
|
-
cfg.options.debug = {
|
|
55
|
-
packet: true,
|
|
56
|
-
token: true,
|
|
57
|
-
data: true,
|
|
58
|
-
payload: true
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
76
|
let tedious
|
|
62
77
|
try {
|
|
63
|
-
tedious = new tds.Connection(
|
|
78
|
+
tedious = new tds.Connection(this._config())
|
|
64
79
|
} catch (err) {
|
|
65
80
|
rejectOnce(err)
|
|
66
81
|
return
|