snowflake-sdk
Advanced tools
Comparing version 1.12.0 to 1.13.0
@@ -85,2 +85,7 @@ /* | ||
ERR_CONN_CREATE_INVALID_DISABLE_SAML_URL_CHECK = 404051, | ||
ERR_CONN_CREATE_INVALID_CLIENT_REQUEST_MFA_TOKEN = 404052; | ||
ERR_CONN_CREATE_MISSING_HOST = 404053; | ||
ERR_CONN_CREATE_INVALID_HOST = 404054; | ||
ERR_CONN_CREATE_INVALID_PASSCODE_IN_PASSWORD = 404055; | ||
ERR_CONN_CREATE_INVALID_PASSCODE = 404056; | ||
@@ -238,2 +243,8 @@ // 405001 | ||
keepAlive?: boolean; | ||
/** | ||
* If the user wants to use their own credential manager for SSO or MFA token caching, | ||
* pass the custom credential manager to this option. | ||
*/ | ||
customCredentialManager?: object; | ||
} | ||
@@ -431,3 +442,2 @@ | ||
//Connection options Options but not on the web document. | ||
/** | ||
@@ -473,2 +483,18 @@ * Set whether the retry reason is included or not in the retry url. | ||
validateDefaultParameters?: boolean; | ||
/** | ||
* The option to set the location where the token will be saved for the token authentication (MFA and SSO). | ||
* The path must include the folder path only. | ||
*/ | ||
credentialCacheDir?: string; | ||
/** | ||
* The option to include the passcode from DUO into the password. | ||
*/ | ||
passcodeInPassword?: boolean; | ||
/** | ||
* The option to pass passcode from DUO. | ||
*/ | ||
passcode?: string | ||
} | ||
@@ -529,3 +555,3 @@ | ||
*/ | ||
getQueryStatus(queryId: string): string; | ||
getQueryStatus(queryId: string): Promise<string>; | ||
@@ -535,3 +561,3 @@ /** | ||
*/ | ||
getQueryStatusThrowIfError(queryId: string): string; | ||
getQueryStatusThrowIfError(queryId: string): Promise<string>; | ||
@@ -541,3 +567,3 @@ /** | ||
*/ | ||
getResultsFromQueryId(options: StatementOption): RowStatement | FileAndStageBindStatement; | ||
getResultsFromQueryId(options: StatementOption): Promise<RowStatement | FileAndStageBindStatement>; | ||
@@ -557,3 +583,3 @@ /** | ||
*/ | ||
serialize(): String; | ||
serialize(): string; | ||
} | ||
@@ -560,0 +586,0 @@ |
@@ -5,2 +5,4 @@ /* | ||
const mfaAuthenticator = require ('./authentication_types.js').USER_PWD_MFA_AUTHENTICATOR; | ||
/** | ||
@@ -14,17 +16,51 @@ * Creates a default authenticator. | ||
*/ | ||
function AuthDefault(password) { | ||
function AuthDefault(connectionConfig) { | ||
const password = connectionConfig.password; | ||
const mfaToken = connectionConfig.mfaToken; | ||
const passcode = connectionConfig.getPasscode(); | ||
const isPasscodeInPassword = connectionConfig.getPasscodeInPassword(); | ||
/** | ||
* Update JSON body with password. | ||
* | ||
* @param {JSON} body | ||
* | ||
* @returns {null} | ||
*/ | ||
* Update JSON body with password or token. | ||
* | ||
* @param {JSON} body | ||
* | ||
* @returns {null} | ||
*/ | ||
this.updateBody = function (body) { | ||
body['data']['PASSWORD'] = password; | ||
if (isMFAAuth()) { | ||
setMFASessionParams(body); | ||
} | ||
}; | ||
this.authenticate = async function () {}; | ||
function isMFAAuth() { | ||
return ( connectionConfig.getAuthenticator() === mfaAuthenticator || mfaToken || passcode || isPasscodeInPassword); | ||
} | ||
function setMFASessionParams(body) { | ||
body['data']['TOKEN'] = mfaToken; | ||
body['data']['AUTHENTICATOR'] = mfaAuthenticator; | ||
if (isPasscodeInPassword) { | ||
body['data']['EXT_AUTHN_DUO_METHOD'] = 'passcode'; | ||
body['data']['passcodeInPassword'] = true; | ||
} else if (passcode) { | ||
body['data']['EXT_AUTHN_DUO_METHOD'] = 'passcode'; | ||
body['data']['PASSCODE'] = passcode; | ||
} else { | ||
body['data']['EXT_AUTHN_DUO_METHOD'] = 'push'; | ||
} | ||
} | ||
this.authenticate = async function () { | ||
return; | ||
}; | ||
this.reauthenticate = async function () { | ||
return; | ||
}; | ||
} | ||
module.exports = AuthDefault; |
@@ -12,18 +12,4 @@ /* | ||
const Logger = require('../logger'); | ||
const AuthMFAToken = require('./auth_mfatoken'); | ||
const AuthenticationTypes = require('./authentication_types'); | ||
let authenticator; | ||
const authenticationTypes = | ||
{ | ||
DEFAULT_AUTHENTICATOR: 'SNOWFLAKE', // default authenticator name | ||
EXTERNAL_BROWSER_AUTHENTICATOR: 'EXTERNALBROWSER', | ||
KEY_PAIR_AUTHENTICATOR: 'SNOWFLAKE_JWT', | ||
OAUTH_AUTHENTICATOR: 'OAUTH', | ||
MFA_TOKEN_AUTHENTICATOR: 'USERNAME_PASSWORD_MFA', | ||
ID_TOKEN_AUTHENTICATOR: 'ID_TOKEN', | ||
}; | ||
exports.authenticationTypes = authenticationTypes; | ||
/** | ||
@@ -81,5 +67,5 @@ * Returns the JSON body to be sent when connecting. | ||
let auth; | ||
if (authType === authenticationTypes.DEFAULT_AUTHENTICATOR) { | ||
auth = new AuthDefault(connectionConfig.password); | ||
} else if (authType === authenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR) { | ||
if (authType === AuthenticationTypes.DEFAULT_AUTHENTICATOR || authType === AuthenticationTypes.USER_PWD_MFA_AUTHENTICATOR) { | ||
auth = new AuthDefault(connectionConfig); | ||
} else if (authType === AuthenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR) { | ||
if (connectionConfig.getClientStoreTemporaryCredential() && !!connectionConfig.idToken) { | ||
@@ -90,11 +76,5 @@ auth = new AuthIDToken(connectionConfig, httpClient); | ||
} | ||
} else if (authType === authenticationTypes.MFA_TOKEN_AUTHENTICATOR) { | ||
if (connectionConfig.getClientRequestMFAToken() && !!connectionConfig.mfaToken) { | ||
auth = new AuthMFAToken(connectionConfig); | ||
} else { | ||
auth = new AuthDefault(connectionConfig.password); | ||
} | ||
} else if (authType === authenticationTypes.KEY_PAIR_AUTHENTICATOR) { | ||
} else if (authType === AuthenticationTypes.KEY_PAIR_AUTHENTICATOR) { | ||
auth = new AuthKeypair(connectionConfig); | ||
} else if (authType === authenticationTypes.OAUTH_AUTHENTICATOR) { | ||
} else if (authType === AuthenticationTypes.OAUTH_AUTHENTICATOR) { | ||
auth = new AuthOauth(connectionConfig.getToken()); | ||
@@ -106,6 +86,4 @@ } else if (this.isOktaAuth(authType)) { | ||
Logger.getInstance().warn(`No authenticator found for '${authType}'. Using default authenticator as a fallback`); | ||
auth = new AuthDefault(connectionConfig.password); | ||
auth = new AuthDefault(connectionConfig); | ||
} | ||
authenticator = auth; | ||
return auth; | ||
@@ -123,5 +101,1 @@ }; | ||
}; | ||
exports.getCurrentAuth = function () { | ||
return authenticator; | ||
}; |
@@ -11,3 +11,3 @@ /* | ||
const Logger = require('../logger'); | ||
const { authenticationTypes } = require('../authentication/authentication'); | ||
const AuthenticationTypes = require('../authentication/authentication_types'); | ||
const Util = require('../util'); | ||
@@ -25,3 +25,3 @@ | ||
return fixedConfiguration && fixedConfiguration.authenticator && | ||
fixedConfiguration.authenticator.toUpperCase() === authenticationTypes.OAUTH_AUTHENTICATOR && | ||
fixedConfiguration.authenticator.toUpperCase() === AuthenticationTypes.OAUTH_AUTHENTICATOR && | ||
!Util.string.isNotNullOrEmpty(fixedConfiguration.token); | ||
@@ -28,0 +28,0 @@ } |
@@ -13,3 +13,3 @@ /* | ||
const GlobalConfig = require('../global_config'); | ||
const authenticationTypes = require('../authentication/authentication').authenticationTypes; | ||
const AuthenticationTypes = require('../authentication/authentication_types'); | ||
const levenshtein = require('fastest-levenshtein'); | ||
@@ -66,2 +66,4 @@ const RowMode = require('./../constants/row_mode'); | ||
'credentialCacheDir', | ||
'passcodeInPassword', | ||
'passcode', | ||
]; | ||
@@ -169,4 +171,4 @@ | ||
if (!Util.exists(options.authenticator) || | ||
(options.authenticator.toUpperCase() !== authenticationTypes.OAUTH_AUTHENTICATOR && | ||
options.authenticator.toUpperCase() !== authenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR)) { | ||
(options.authenticator.toUpperCase() !== AuthenticationTypes.OAUTH_AUTHENTICATOR && | ||
options.authenticator.toUpperCase() !== AuthenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR)) { | ||
// check for missing username | ||
@@ -185,3 +187,3 @@ Errors.checkArgumentExists(Util.exists(options.username), | ||
if (!Util.exists(options.authenticator) || | ||
options.authenticator === authenticationTypes.DEFAULT_AUTHENTICATOR) { | ||
options.authenticator === AuthenticationTypes.DEFAULT_AUTHENTICATOR) { | ||
// check for missing password | ||
@@ -281,3 +283,3 @@ Errors.checkArgumentExists(Util.exists(options.password), | ||
if (!Util.exists(authenticator)) { | ||
authenticator = authenticationTypes.DEFAULT_AUTHENTICATOR; | ||
authenticator = AuthenticationTypes.DEFAULT_AUTHENTICATOR; | ||
} else { | ||
@@ -483,11 +485,2 @@ authenticator = authenticator.toUpperCase(); | ||
if (validateDefaultParameters) { | ||
for (const [key] of Object.entries(options)) { | ||
if (!DEFAULT_PARAMS.includes(key)) { | ||
const result = levenshtein.closest(key, DEFAULT_PARAMS); | ||
Logger.getInstance().error(`'${key}' is an unknown connection parameter. Did you mean '${result}'?`); | ||
} | ||
} | ||
} | ||
let includeRetryReason = true; | ||
@@ -558,2 +551,28 @@ if (Util.exists(options.includeRetryReason)) { | ||
let passcodeInPassword = false; | ||
if (Util.exists(options.passcodeInPassword)) { | ||
Errors.checkArgumentValid(Util.isBoolean(options.passcodeInPassword), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_PASSCODE_IN_PASSWORD); | ||
passcodeInPassword = options.passcodeInPassword; | ||
} | ||
let passcode = null; | ||
if (Util.exists(options.passcode)) { | ||
Errors.checkArgumentValid(Util.isString(options.passcode), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_PASSCODE); | ||
passcode = options.passcode; | ||
} | ||
if (validateDefaultParameters) { | ||
for (const [key] of Object.entries(options)) { | ||
if (!DEFAULT_PARAMS.includes(key)) { | ||
const result = levenshtein.closest(key, DEFAULT_PARAMS); | ||
Logger.getInstance().error(`'${key}' is an unknown connection parameter. Did you mean '${result}'?`); | ||
} | ||
} | ||
} | ||
/** | ||
@@ -864,2 +883,10 @@ * Returns an object that contains information about the proxy hostname, port, | ||
this.getPasscodeInPassword = function () { | ||
return passcodeInPassword; | ||
}; | ||
this.getPasscode = function () { | ||
return passcode; | ||
}; | ||
// save config options | ||
@@ -866,0 +893,0 @@ this.username = options.username; |
@@ -17,2 +17,3 @@ /* | ||
const Authenticator = require('../authentication/authentication'); | ||
const AuthenticationTypes = require('../authentication/authentication_types'); | ||
const Logger = require('../logger'); | ||
@@ -24,3 +25,2 @@ const { isOktaAuth } = require('../authentication/authentication'); | ||
/** | ||
@@ -219,3 +219,3 @@ * Creates a new Connection instance. | ||
// external browser and okta are not compatible with connect() due to their usage of async functions | ||
if (authenticationType === Authenticator.authenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR || | ||
if (authenticationType === AuthenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR || | ||
isOktaAuth(authenticationType)) { | ||
@@ -227,3 +227,3 @@ throw Errors.createClientError( | ||
// Get authenticator to use | ||
const auth = Authenticator.getAuthenticator(connectionConfig, context.getHttpClient()); | ||
const auth = services.sf.getAuthenticator(); | ||
@@ -292,7 +292,6 @@ auth.authenticate(connectionConfig.getAuthenticator(), | ||
const self = this; | ||
const authType = Authenticator.authenticationTypes; | ||
if (connectionConfig.getClientStoreTemporaryCredential()) { | ||
const key = Util.buildCredentialCacheKey(connectionConfig.host, | ||
connectionConfig.username, Authenticator.authenticationTypes.ID_TOKEN_AUTHENTICATOR); | ||
connectionConfig.username, AuthenticationTypes.ID_TOKEN_AUTHENTICATOR); | ||
if (GlobalConfig.getCredentialManager() === null) { | ||
@@ -306,3 +305,3 @@ GlobalConfig.setCustomCredentialManager(new JsonCredentialManager(connectionConfig.getCredentialCacheDir())); | ||
const key = Util.buildCredentialCacheKey(connectionConfig.host, | ||
connectionConfig.username, authType.MFA_TOKEN_AUTHENTICATOR); | ||
connectionConfig.username, AuthenticationTypes.USER_PWD_MFA_AUTHENTICATOR); | ||
if (GlobalConfig.getCredentialManager() === null) { | ||
@@ -315,3 +314,3 @@ GlobalConfig.setCustomCredentialManager(new JsonCredentialManager(connectionConfig.getCredentialCacheDir())); | ||
// Get authenticator to use | ||
const auth = Authenticator.getAuthenticator(connectionConfig, context.getHttpClient()); | ||
const auth = services.sf.getAuthenticator(); | ||
@@ -452,5 +451,5 @@ try { | ||
const queries = queryResponse['data']['queries']; | ||
let status = QueryStatus.code.NO_DATA; // default status | ||
if (queries.length > 0) { | ||
status = queries[0]['status']; | ||
let status = QueryStatus.code.NO_QUERY_DATA; // default status | ||
if ( queries.length > 0) { | ||
status = queries[0]['status']; | ||
} | ||
@@ -480,11 +479,10 @@ | ||
this.getQueryStatusThrowIfError = async function (queryId) { | ||
const status = await this.getQueryStatus(queryId); | ||
const response = await getQueryResponse(queryId); | ||
const status = extractQueryStatus(response); | ||
let sqlState = null; | ||
let message, code, sqlState = null; | ||
if (this.isAnError(status) ) { | ||
let message = response['message'] || ''; | ||
const code = response['code'] || -1; | ||
if (this.isAnError(status)) { | ||
const response = await getQueryResponse(queryId); | ||
message = response['message'] || ''; | ||
code = response['code'] || -1; | ||
if (response['data']) { | ||
@@ -516,6 +514,7 @@ message += response['data']['queries'].length > 0 ? response['data']['queries'][0]['errorMessage'] : ''; | ||
while (queryStillExecuting) { | ||
// Check if query is still running and trigger exception if it failed | ||
// Check if query is still running. | ||
// Trigger exception if it failed or there is no query data in the server. | ||
status = await this.getQueryStatusThrowIfError(queryId); | ||
queryStillExecuting = this.isStillRunning(status); | ||
if (!queryStillExecuting) { | ||
if (!queryStillExecuting || status === QueryStatus.code.NO_QUERY_DATA) { | ||
break; | ||
@@ -544,2 +543,7 @@ } | ||
if (QueryStatus.code[status] === QueryStatus.code.NO_QUERY_DATA) { | ||
throw Errors.createClientError( | ||
ErrorCodes.ERR_GET_RESULTS_QUERY_ID_NO_DATA, true, queryId, status); | ||
} | ||
if (QueryStatus.code[status] !== QueryStatus.code.SUCCESS) { | ||
@@ -546,0 +550,0 @@ throw Errors.createClientError( |
@@ -84,2 +84,4 @@ /* | ||
exports[404054] = 'Invalid host. The specified value must be a string.'; | ||
exports[404055] = 'Invalid passcodeInPassword. The specified value must be a boolean'; | ||
exports[404056] = 'Invalid passcode. The specified value must be a string'; | ||
@@ -86,0 +88,0 @@ // 405001 |
@@ -21,2 +21,3 @@ /* | ||
code.NO_DATA = 'NO_DATA'; | ||
code.NO_QUERY_DATA = 'NO_QUERY_DATA'; | ||
@@ -23,0 +24,0 @@ // All running query statuses |
@@ -88,4 +88,5 @@ /* | ||
codes.ERR_CONN_CREATE_INVALID_HOST = 404054; | ||
codes.ERR_CONN_CREATE_INVALID_PASSCODE_IN_PASSWORD = 404055; | ||
codes.ERR_CONN_CREATE_INVALID_PASSCODE = 404056; | ||
// 405001 | ||
@@ -343,3 +344,3 @@ codes.ERR_CONN_CONNECT_INVALID_CALLBACK = 405001; | ||
code: errorCode, | ||
data: data, | ||
data: { ...data, queryId: null }, | ||
message: message, | ||
@@ -346,0 +347,0 @@ sqlState: sqlState |
@@ -36,2 +36,3 @@ /* | ||
request = axios.request(requestOptions).then(response => { | ||
sanitizeAxiosResponse(response); | ||
if (Util.isFunction(options.callback)) { | ||
@@ -44,2 +45,3 @@ return options.callback(null, normalizeResponse(response), response.data); | ||
}).catch(err => { | ||
sanitizeAxiosError(err); | ||
if (Util.isFunction(options.callback)) { | ||
@@ -81,12 +83,15 @@ if (err.response) { // axios returns error for not 2xx responses - let's unwrap it | ||
HttpClient.prototype.requestAsync = async function (options) { | ||
const requestOptions = prepareRequestOptions.call(this, options); | ||
const response = await axios.request(requestOptions); | ||
if (Util.isString(response['data']) && | ||
response['headers']['content-type'] === 'application/json') { | ||
response['data'] = JSON.parse(response['data']); | ||
try { | ||
const requestOptions = prepareRequestOptions.call(this, options); | ||
const response = await axios.request(requestOptions); | ||
if (Util.isString(response['data']) && | ||
response['headers']['content-type'] === 'application/json') { | ||
response['data'] = JSON.parse(response['data']); | ||
} | ||
sanitizeAxiosResponse(response); | ||
return response; | ||
} catch (err) { | ||
sanitizeAxiosError(err); | ||
throw err; | ||
} | ||
return response; | ||
}; | ||
@@ -184,2 +189,18 @@ | ||
function sanitizeAxiosResponse(response) { | ||
response.request = undefined; | ||
if (response.config) { | ||
response.config.data = undefined; | ||
response.config.headers = undefined; | ||
} | ||
} | ||
function sanitizeAxiosError(error) { | ||
error.request = undefined; | ||
error.config = undefined; | ||
if (error.response) { | ||
sanitizeAxiosResponse(error.response); | ||
} | ||
} | ||
function prepareRequestOptions(options) { | ||
@@ -186,0 +207,0 @@ const headers = normalizeHeaders(options.headers) || {}; |
@@ -59,5 +59,6 @@ /* | ||
const GlobalConfig = require('../global_config'); | ||
const { authenticationTypes, getCurrentAuth } = require('../authentication/authentication'); | ||
const AuthenticationTypes = require('../authentication/authentication_types'); | ||
const AuthOkta = require('../authentication/auth_okta'); | ||
const AuthKeypair = require('../authentication/auth_keypair'); | ||
const Authenticator = require('../authentication/authentication'); | ||
@@ -117,2 +118,4 @@ function isRetryableNetworkError(err) { | ||
this.authenticator = Authenticator.getAuthenticator(connectionConfig, httpClient); | ||
// create state objects for all the different states we can be in | ||
@@ -500,2 +503,6 @@ const stateOptions = | ||
this.getAuthenticator = function () { | ||
return this.authenticator; | ||
}; | ||
// if we don't have any tokens, start out as pristine | ||
@@ -580,3 +587,3 @@ if (tokenInfo.isEmpty()) { | ||
*/ | ||
function sendHttpRequest(requestOptions, httpClient) { | ||
function sendHttpRequest(requestOptions, httpClient, auth) { | ||
const realRequestOptions = | ||
@@ -650,3 +657,2 @@ { | ||
const data = body.data; | ||
const auth = getCurrentAuth(); | ||
@@ -656,3 +662,3 @@ if (body.code === GSErrors.code.ID_TOKEN_INVALID && data.authnMethod === 'TOKEN') { | ||
const key = Util.buildCredentialCacheKey(connectionConfig.host, | ||
connectionConfig.username, authenticationTypes.ID_TOKEN_AUTHENTICATOR); | ||
connectionConfig.username, AuthenticationTypes.ID_TOKEN_AUTHENTICATOR); | ||
await GlobalConfig.getCredentialManager().remove(key); | ||
@@ -693,7 +699,9 @@ await auth.reauthenticate(requestOptions.json); | ||
this.snowflakeService = options.snowflakeService; | ||
this.httpClient = options.httpClient; | ||
this.connectionConfig = options.connectionConfig; | ||
this.tokenInfo = options.tokenInfo; | ||
const connectionConfig = options.connectionConfig; | ||
const snowflakeService = options.snowflakeService; | ||
const httpClient = options.httpClient; | ||
const connectionConfig = options.connectionConfig; | ||
@@ -745,3 +753,3 @@ /////////////////////////////////////////////////////////////////////////// | ||
// issue the http request | ||
sendHttpRequest(this.requestOptions, httpClient); | ||
sendHttpRequest(this.requestOptions, httpClient, snowflakeService.getAuthenticator()); | ||
}; | ||
@@ -1150,3 +1158,3 @@ | ||
const key = Util.buildCredentialCacheKey(connectionConfig.host, | ||
connectionConfig.username, authenticationTypes.MFA_TOKEN_AUTHENTICATOR); | ||
connectionConfig.username, AuthenticationTypes.USER_PWD_MFA_AUTHENTICATOR); | ||
await GlobalConfig.getCredentialManager().write(key, body.data.mfaToken); | ||
@@ -1157,3 +1165,3 @@ } | ||
const key = Util.buildCredentialCacheKey(connectionConfig.host, | ||
connectionConfig.username, authenticationTypes.ID_TOKEN_AUTHENTICATOR); | ||
connectionConfig.username, AuthenticationTypes.ID_TOKEN_AUTHENTICATOR); | ||
await GlobalConfig.getCredentialManager().write(key, body.data.idToken); | ||
@@ -1182,3 +1190,3 @@ } | ||
const auth = getCurrentAuth(); | ||
const auth = parent.snowflakeService.getAuthenticator(); | ||
if (auth instanceof AuthOkta) { | ||
@@ -1185,0 +1193,0 @@ Logger.getInstance().debug('OKTA authentication requires token refresh.'); |
{ | ||
"name": "snowflake-sdk", | ||
"version": "1.12.0", | ||
"version": "1.13.0", | ||
"description": "Node.js driver for Snowflake", | ||
@@ -5,0 +5,0 @@ "dependencies": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
606141
17021