Skip to content

Commit 5044a00

Browse files
SNOW-1825478- Support for Oauth PAT
1 parent 556e783 commit 5044a00

File tree

20 files changed

+406
-8
lines changed

20 files changed

+406
-8
lines changed

.github/workflows/build-test.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ jobs:
9090
nodeVersion: ['18.x', '20.x', '22.x']
9191
steps:
9292
- uses: actions/checkout@v4
93+
- uses: actions/setup-java@v4
94+
with:
95+
distribution: 'temurin'
96+
java-version: '17'
97+
java-package: 'jre'
9398
- uses: actions/setup-node@v4
9499
with:
95100
node-version: ${{ matrix.nodeVersion }}

ci/_init.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export DRIVER_NAME=nodejs
1818
BUILD_IMAGE_VERSION=1
1919

2020
# Test Images
21-
TEST_IMAGE_VERSION=1
21+
TEST_IMAGE_VERSION=2
2222

2323
declare -A BUILD_IMAGE_NAMES=(
2424
[$DRIVER_NAME-chainguard-node18]=$DOCKER_REGISTRY_NAME/client-$DRIVER_NAME-chainguard-node18-build:$BUILD_IMAGE_VERSION

ci/container/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010
},
1111
"devDependencies": {
1212
"async": "^3.2.3",
13+
"https-proxy-agent": "^7.0.2",
1314
"mocha": "^10.2.0",
1415
"mock-require": "^3.0.3",
1516
"nyc": "^15.1.0",
16-
"test-console": "^2.0.0"
17+
"test-console": "^2.0.0",
18+
"wiremock": "^3.10.0",
19+
"wiremock-rest-client": "^1.11.0"
1720
},
1821
"author": "Snowflake, Inc.",
1922
"license": "ISC"

ci/image/Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ FROM $IMAGE
33

44
USER root
55

6-
RUN apk update && apk add python3 jq aws-cli gosu
6+
RUN apk update && apk add python3 python3-dev py3-pip jq aws-cli gosu openjdk-17
77
RUN pip install -U snowflake-connector-python
88

9+
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk
10+
911
# workspace
1012
RUN mkdir -p /home/user && \
1113
chmod 777 /home/user

ci/test_authentication.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ docker run \
1313
-v $(cd $THIS_DIR/.. && pwd):/mnt/host \
1414
-v $WORKSPACE:/mnt/workspace \
1515
--rm \
16-
nexus.int.snowflakecomputing.com:8086/docker/snowdrivers-test-external-browser:3 \
16+
nexus.int.snowflakecomputing.com:8086/docker/snowdrivers-test-external-browser:7 \
1717
"/mnt/host/ci/container/test_authentication.sh"

lib/authentication/auth_oauth_pat.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const Util = require('../util');
2+
/**
3+
* Creates an oauth PAT authenticator.
4+
*
5+
* @param {String} token
6+
* @param {String} password
7+
*
8+
* @returns {Object}
9+
* @constructor
10+
*/
11+
function AuthOauthPAT(token, password) {
12+
/**
13+
* Update JSON body with token.
14+
*
15+
* @param {JSON} body
16+
*
17+
* @returns {null}
18+
*/
19+
this.updateBody = function (body) {
20+
if (Util.exists(token)) {
21+
body['data']['TOKEN'] = token;
22+
} else if (Util.exists(password)) {
23+
body['data']['TOKEN'] = password;
24+
}
25+
};
26+
27+
this.authenticate = async function () {};
28+
}
29+
module.exports = AuthOauthPAT;

lib/authentication/authentication.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const AuthDefault = require('./auth_default');
22
const AuthWeb = require('./auth_web');
33
const AuthKeypair = require('./auth_keypair');
44
const AuthOauth = require('./auth_oauth');
5+
const AuthOauthPAT = require('./auth_oauth_pat');
56
const AuthOkta = require('./auth_okta');
67
const AuthIDToken = require('./auth_idtoken');
78
const Logger = require('../logger');
@@ -58,7 +59,6 @@ exports.formAuthJSON = function formAuthJSON(
5859
*/
5960
exports.getAuthenticator = function getAuthenticator(connectionConfig, httpClient) {
6061
const authType = connectionConfig.getAuthenticator();
61-
const openExternalBrowserCallback = connectionConfig.openExternalBrowserCallback; // Important for SSO in the Snowflake VS Code extension
6262
let auth;
6363
if (authType === AuthenticationTypes.DEFAULT_AUTHENTICATOR || authType === AuthenticationTypes.USER_PWD_MFA_AUTHENTICATOR) {
6464
auth = new AuthDefault(connectionConfig);
@@ -70,8 +70,10 @@ exports.getAuthenticator = function getAuthenticator(connectionConfig, httpClien
7070
}
7171
} else if (authType === AuthenticationTypes.KEY_PAIR_AUTHENTICATOR) {
7272
auth = new AuthKeypair(connectionConfig);
73-
} else if (authType === AuthenticationTypes.OAUTH_AUTHENTICATOR) {
73+
} else if (authType === AuthenticationTypes.OAUTH_AUTHENTICATOR ) {
7474
auth = new AuthOauth(connectionConfig.getToken());
75+
} else if (authType === AuthenticationTypes.PROGRAMMATIC_ACCESS_TOKEN ) {
76+
auth = new AuthOauthPAT(connectionConfig.getToken(), connectionConfig.password);
7577
} else if (this.isOktaAuth(authType)) {
7678
auth = new AuthOkta(connectionConfig, httpClient);
7779
} else {

lib/authentication/authentication_types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const AuthenticationTypes =
66
OAUTH_AUTHENTICATOR: 'OAUTH',
77
USER_PWD_MFA_AUTHENTICATOR: 'USERNAME_PASSWORD_MFA',
88
ID_TOKEN_AUTHENTICATOR: 'ID_TOKEN',
9+
PROGRAMMATIC_ACCESS_TOKEN: 'PROGRAMMATIC_ACCESS_TOKEN'
910
};
1011

1112
module.exports = AuthenticationTypes;

lib/connection/connection_config.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ function ConnectionConfig(options, validateCredentials, qaMode, clientInfo) {
165165
// username is not required for oauth and external browser authenticators
166166
if (!Util.exists(options.authenticator) ||
167167
(options.authenticator.toUpperCase() !== AuthenticationTypes.OAUTH_AUTHENTICATOR &&
168-
options.authenticator.toUpperCase() !== AuthenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR)) {
168+
options.authenticator.toUpperCase() !== AuthenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR &&
169+
options.authenticator.toUpperCase() !== AuthenticationTypes.PROGRAMMATIC_ACCESS_TOKEN)) {
169170
// check for missing username
170171
Errors.checkArgumentExists(Util.exists(options.username),
171172
ErrorCodes.ERR_CONN_CREATE_MISSING_USERNAME);
@@ -188,6 +189,22 @@ function ConnectionConfig(options, validateCredentials, qaMode, clientInfo) {
188189
Errors.checkArgumentValid(Util.isString(options.password),
189190
ErrorCodes.ERR_CONN_CREATE_INVALID_PASSWORD);
190191
}
192+
if (!Util.exists(options.authenticator) ||
193+
options.authenticator === AuthenticationTypes.PROGRAMMATIC_ACCESS_TOKEN) {
194+
// PASSWORD or TOKEN is needed
195+
Errors.checkArgumentExists(Util.exists(options.password) || Util.exists(options.token),
196+
ErrorCodes.ERR_CONN_CREATE_MISSING_PASSWORD);
197+
198+
if (Util.exists(options.password)) {
199+
// check for invalid password
200+
Errors.checkArgumentValid(Util.isString(options.password),
201+
ErrorCodes.ERR_CONN_CREATE_INVALID_PASSWORD);
202+
}
203+
if (Util.exists(options.token)) {
204+
Errors.checkArgumentValid(Util.isString(options.token),
205+
ErrorCodes.ERR_CONN_CREATE_INVALID_OAUTH_TOKEN);
206+
}
207+
}
191208

192209
consolidateHostAndAccount(options);
193210
}

lib/constants/error_messages.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ exports[404053] = 'A host must be specified.';
8080
exports[404054] = 'Invalid host. The specified value must be a string.';
8181
exports[404055] = 'Invalid passcodeInPassword. The specified value must be a boolean';
8282
exports[404056] = 'Invalid passcode. The specified value must be a string';
83+
exports[404057] = 'A password or token must be specified.';
84+
8385

8486
// 405001
8587
exports[405001] = 'Invalid callback. The specified value must be a function.';

0 commit comments

Comments
 (0)