UNPKG

oracle-nosqldb

Version:

Node.js driver for Oracle NoSQL Database

277 lines (255 loc) 10.8 kB
/*- * Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved. * * Licensed under the Universal Permissive License v 1.0 as shown at * https://oss.oracle.com/licenses/upl/ */ 'use strict'; /** * Defines types used for NoSQL driver authorization. */ /** * Authorization configuration for the driver provided as {@link Config}#auth * when {@link NoSQLClient} instance is created. * <p> * Every request to the server made by {@link NoSQLClient} methods requires * authorization information. The way authorization information is obtained * depends on the {@link ServiceType} used (set as * {@link Config}#serviceType): * <ul> * <li>For {@link ServiceType.CLOUD}, authorization information is obtained * using Oracle Cloud Infrastructure Identity and Access Management (IAM). To * enable authorization, you must set IAM configuration in the form of * {@link IAMConfig} as {@link AuthConfig}#iam property.</li> * <li>For {@link ServiceType.CLOUDSIM}, authorization is not required and * you do not need to specify {@link Config}#auth property.</li> * <li>For {@link ServiceType.KVSTORE}, if using secure store, you need to * specify the store authentication information such as user name and password * as {@link AuthConfig}#kvstore property in the form of * {@link KVStoreAuthConfig}. If using non-secure store, authorization is not * required and you do not need to specify {@link Config}#auth property.</li> * <li>You may also choose to implement your own authorization provider to * obtain authorization information for each request depending on the * operation performed. In this case, set this provider as * {@link AuthConfig}#provider property. If the provider is set, * {@link ServiceType} can be undefined, although it may also be possible to * have custom provider for existing service types.</li> * </ul> * <p> * Note that you may specify both {@link AuthConfig}#iam and * {@link AuthConfig}#kvstore in the same configuration object only if * {@link Config}#serviceType is set to valid {@link ServiceType}. * If {@link Config}#serviceType is not set (in which case the driver will try * to deduce service type, see {@link ServiceType}), specifying both * {@link AuthConfig}#iam and {@link AuthConfig}#kvstore will * result in error. * * @see {@link Config} * @see {@link ServiceType} * @see {@link IAMConfig} * @see {@link KVStoreAuthConfig} * @see {@link AuthorizationProvider} * @tutorial connect-cloud * @tutorial connect-on-prem * * @example //This AuthConfig object contains required properties to obtain * authorization from IAM via OCI configuration file * { * iam: { * configFile: '~/myapp/.oci/config', * profileName: 'John' * } * }; * * @example //This AuthConfig object contains required information to connect * //to secure kvstore and assumes the user credentials are stored in * //separate file credentials.json * { * kvstore: { * credentials: '/path/to/credentials.json' * } * } * * @global * @typedef {object} AuthConfig * @property {IAMConfig} [iam] IAM configuration, see {@link IAMConfig}. * Must be set to use Oracle NoSQL Cloud service * @property {KVStoreAuthConfig} [kvstore] Configuration to authenticate with * secure On-Premise NoSQL database. Must be set to connect to secure store * @property {AuthorizationProvider} [provider] Custom authorization provider */ /** * Interface to acquire authorization information. Authorization information * may be returned as a string or as an object: * <ul> * <li>If represented as a <em>string</em>, it will be used as a value of HTTP * <em>Authorization</em> header for the service request.</li> * <li>If represented as an <em>object</em>, this object's properties will be * added as HTTP headers for the service request.</li> * </ul> * The specifics depend on the authorization protocol used. * * @see {@link AuthorizationProvider} * * @global * @callback getAuthorization * @async * @param {Operation} operation NoSQL database operation that requires * authorization information, see {@link Operation} * @returns {Promise} Promise resolved with authorization <em>string</em> or * authorization <em>object</em> or rejected with an error */ /** * AuthorizationProvider is an interface to obtain authorization information * for NoSQL database operation. By default, the driver will use its own * authorization providers based on specified {@link ServiceType} and/or * presense of service-specific configurations such as {@link IAMConfig} and * {@link KVStoreAuthConfig}. Alternatively, the application may choose to * use custom authorization provider and set it as {@link AuthConfig}#provider * property. This custom provider may be specified either as a * {@link getAuthorization} function or as an object implementing * {@link getAuthorization} function. * * @global * @typedef {object|getAuthorization} AuthorizationProvider * @property {getAuthorization} getAuthorization Retrieves authorization * string for an operation * @property {function()} [close] If specified, releases any resources * associated with this provider when {@link NoSQLClient} instance is closed. * Note that this operation may be asynchronous in which case this function * should return a <em>Promise</em> (resolved value is ignored), otherwise * return value is ignored. If error occurs, the function should only log it * rather than throwing exception or causing Promise rejection */ const assert = require('assert'); const IAMAuthorizationProvider = require('./iam/auth_provider'); const KVStoreAuthorizationProvider = require('./kvstore/auth_provider'); const ServiceType = require('../constants').ServiceType; const NoSQLArgumentError = require('../error').NoSQLArgumentError; const hasOwnProperty = require('../utils').hasOwnProperty; class AuthConfig { static _str2provider(s) { return { getAuthorization() { return Promise.resolve(s); } }; } static _chkInitProvider(cfg) { if (typeof cfg.auth === 'string') { cfg.auth = { provider: this._str2provider(cfg.auth) }; return; } if (cfg.auth == null) { cfg.auth = {}; return; } if (typeof cfg.auth !== 'object') { throw new NoSQLArgumentError('Invalid value of auth', cfg); } if (typeof cfg.auth.provider === 'function') { const authProvider = cfg.auth.provider; cfg.auth.provider = { getAuthorization(req) { return authProvider(req); } }; return; } if (cfg.auth.provider != null && (typeof cfg.auth.provider !== 'object' || typeof cfg.auth.provider.getAuthorization !== 'function')) { throw new NoSQLArgumentError('Invalid auth.provider value', cfg); } } static _chkInitServiceType(cfg) { assert(cfg.auth != null && typeof cfg.auth === 'object'); const ownsAuth = hasOwnProperty(cfg, 'auth'); const isIAM = ownsAuth && hasOwnProperty(cfg.auth, 'iam'); const isKVStore = ownsAuth && hasOwnProperty(cfg.auth, 'kvstore'); const hasProvider = cfg.auth.provider != null; if ((isIAM && hasProvider) || (isKVStore && hasProvider) || (isIAM && isKVStore)) { throw new NoSQLArgumentError( 'You may only specify one of auth.iam, auth.kvstore or \ auth.provider properties', cfg); } let serviceType; if (isIAM) { if (typeof cfg.auth.iam !== 'object') { throw new NoSQLArgumentError('Invalid auth.iam value', cfg); } serviceType = ServiceType.CLOUD; } else if (isKVStore) { if (typeof cfg.auth.kvstore !== 'object') { throw new NoSQLArgumentError('Invalid auth.kvstore value', cfg); } serviceType = ServiceType.KVSTORE; } else if (cfg.serviceType == null && cfg.auth.provider == null) { serviceType = cfg.region == null ? ServiceType.CLOUDSIM : ServiceType.CLOUD; } else if (cfg.auth.provider instanceof IAMAuthorizationProvider) { serviceType = ServiceType.CLOUD; } else if (cfg.auth.provider instanceof KVStoreAuthorizationProvider) { serviceType = ServiceType.KVSTORE; } if (cfg.serviceType == null) { cfg.serviceType = serviceType; } else if (serviceType != null && cfg.serviceType !== serviceType) { throw new NoSQLArgumentError(`Incorrect service type specified: \ ${cfg.serviceType}, auth configuration specifies ${serviceType}`, cfg); } } static init(cfg) { this._chkInitProvider(cfg); this._chkInitServiceType(cfg); if (cfg.auth.provider == null) { switch(cfg.serviceType) { case ServiceType.CLOUDSIM: cfg.auth.provider = this._str2provider('Bearer TestTenant'); break; case ServiceType.CLOUD: { cfg.auth.provider = new IAMAuthorizationProvider(cfg.auth.iam, cfg); break; } case ServiceType.KVSTORE: //Create KVStoreAuthorizationProvider instance if either //credentials provider/file or user/password is specified. //Otherwise assume this is unsecure kvstore and authorization //provider is not needed. if (cfg.auth.kvstore != null && (cfg.auth.kvstore.credentials != null || cfg.auth.kvstore.user != null || cfg.auth.kvstore.password != null)) { cfg.auth.provider = new KVStoreAuthorizationProvider( cfg.auth.kvstore, cfg); } else { cfg.auth.provider = this._str2provider(null); } break; default: assert(cfg.serviceType && cfg.serviceType._isInternal); } } if (typeof cfg.auth.provider.onInit === 'function') { cfg.auth.provider.onInit(cfg); } } static close(cfg) { assert(cfg.auth && cfg.auth.provider); if (typeof cfg.auth.provider.close === 'function') { return cfg.auth.provider.close(); } } } AuthConfig.defaults = Object.freeze({ iam: IAMAuthorizationProvider.configDefaults, kvstore: KVStoreAuthorizationProvider.configDefaults }); module.exports = AuthConfig;