175 lines
6.9 KiB
JavaScript
175 lines
6.9 KiB
JavaScript
// Copyright (c) 2025, Oracle and/or its affiliates.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// This software is dual-licensed to you under the Universal Permissive License
|
|
// (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
|
// 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
|
// either license.
|
|
//
|
|
// If you elect to accept the software under the Apache License, Version 2.0,
|
|
// the following applies:
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
'use strict';
|
|
const oracledb = require('oracledb');
|
|
const identitydataplane = require("oci-identitydataplane");
|
|
const common = require("oci-common");
|
|
const { generateKeyPair } = require('crypto');
|
|
const fs = require('fs');
|
|
|
|
async function getToken(params) {
|
|
switch (params.authType.toLowerCase()) {
|
|
case 'configfilebasedauthentication':
|
|
return await configFileBasedAuthentication(params);
|
|
case 'simpleauthentication':
|
|
return await simpleAuthentication(params);
|
|
default:
|
|
throwErr(`Invalid authentication type ${params.authType} in extensionOci plugins.`);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// throwErr()
|
|
//---------------------------------------------------------------------------
|
|
function throwErr(message) {
|
|
throw new Error(message);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Generates a public-private key pair for proof of possession when token
|
|
// requested by this provider is presented for validation.
|
|
//---------------------------------------------------------------------------
|
|
async function _getKeyPair() {
|
|
return await new Promise((resolve, reject) => {
|
|
generateKeyPair('rsa', {
|
|
modulusLength: 4096,
|
|
publicKeyEncoding: {
|
|
type: 'spki',
|
|
format: 'pem'
|
|
},
|
|
privateKeyEncoding: {
|
|
type: 'pkcs8',
|
|
format: 'pem',
|
|
}
|
|
}, (err, publicKey, privateKey) => {
|
|
if (err) return reject(err);
|
|
resolve({publicKey, privateKey});
|
|
});
|
|
});
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// User defined function for reading token and private key values
|
|
// generated by the OCI SDK.
|
|
// Returns the OCI SDK's token request details object for the given
|
|
// config parameters, where a scope parameter specifies the
|
|
// scope of requested access. The request will specify a public key
|
|
// as being paired with a private key that the presenter of the token must
|
|
// prove to be in possession of.
|
|
//---------------------------------------------------------------------------
|
|
async function configFileBasedAuthentication(accessTokenConfig) {
|
|
const provider =
|
|
new common.ConfigFileAuthenticationDetailsProvider(accessTokenConfig.configFileLocation, accessTokenConfig.profile);
|
|
const client = new identitydataplane.DataplaneClient({authenticationDetailsProvider: provider});
|
|
const keyPair = await _getKeyPair();
|
|
const generateScopedAccessTokenDetails = {
|
|
scope: "urn:oracle:db::id::*",
|
|
publicKey: keyPair.publicKey
|
|
};
|
|
|
|
const generateScopedAccessTokenRequest = {
|
|
generateScopedAccessTokenDetails: generateScopedAccessTokenDetails
|
|
};
|
|
const generateScopedAccessTokenResponse =
|
|
await client.generateScopedAccessToken(generateScopedAccessTokenRequest);
|
|
const obj = {
|
|
token: generateScopedAccessTokenResponse.securityToken.token,
|
|
privateKey: keyPair.privateKey
|
|
};
|
|
return obj;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// simpleAuthentication()
|
|
//---------------------------------------------------------------------------
|
|
async function simpleAuthentication(accessTokenConfig) {
|
|
const tenancy = accessTokenConfig.tenancy ??
|
|
throwErr("Token based authentication config parameter tenancy is missing for simpleauthentication in extensionOci plugins.");
|
|
const user = accessTokenConfig.user ??
|
|
throwErr("Token based authentication config parameter user is missing for simpleauthentication in extensionOci plugins.");
|
|
const fingerprint = accessTokenConfig.fingerprint ??
|
|
throwErr("Token based authentication config parameter fingerprint is missing for simpleauthentication in extensionOci plugins.");
|
|
const passphrase = accessTokenConfig.passphrase |= null; // optional
|
|
const privateKeyLocation = accessTokenConfig.privateKeyLocation ??
|
|
throwErr("Token based authentication config parameter privateKeyLocation is missing for simpleauthentication in extensionOci plugins.");
|
|
const privateKey = fs.readFileSync(privateKeyLocation, 'utf-8'); // ~/.oci/oci_api_key.pem
|
|
const regionId = accessTokenConfig.regionId ?? // ex : us-ashburn-1
|
|
throwErr("Token based authentication config parameter regionId is missing for simpleauthentication in extensionOci plugins.");
|
|
|
|
let region;
|
|
const regionsList = common.Region.values();
|
|
regionsList.forEach(regions => {
|
|
if (regions.regionId === regionId) {
|
|
region = regions;
|
|
return;
|
|
}
|
|
});
|
|
const provider = new common.SimpleAuthenticationDetailsProvider(
|
|
tenancy,
|
|
user,
|
|
fingerprint,
|
|
privateKey,
|
|
passphrase,
|
|
region
|
|
);
|
|
const client = new identitydataplane.DataplaneClient({
|
|
authenticationDetailsProvider: provider
|
|
});
|
|
const keyPair = await _getKeyPair();
|
|
const generateScopedAccessTokenDetails = {
|
|
scope: "urn:oracle:db::id::*",
|
|
publicKey: keyPair.publicKey
|
|
};
|
|
const generateScopedAccessTokenRequest = {
|
|
generateScopedAccessTokenDetails: generateScopedAccessTokenDetails
|
|
};
|
|
|
|
const generateScopedAccessTokenResponse = await client.generateScopedAccessToken(
|
|
generateScopedAccessTokenRequest
|
|
);
|
|
|
|
const obj = {
|
|
token: generateScopedAccessTokenResponse.securityToken.token,
|
|
privateKey: keyPair.privateKey
|
|
};
|
|
return obj;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// hookFn()
|
|
// hookFn will get registerd to driver while loading plugins.
|
|
//---------------------------------------------------------------------------
|
|
function hookFn(options) {
|
|
if (options.tokenAuthConfigOci) {
|
|
// eslint-disable-next-line no-unused-vars
|
|
options.accessToken = async function callbackFn(refresh, config) {
|
|
return await getToken(config);
|
|
};
|
|
options.accessTokenConfig = options.tokenAuthConfigOci;
|
|
}
|
|
}
|
|
oracledb.registerProcessConfigurationHook(hookFn);
|