var _ = require('lodash'), sdk = require('postman-collection'), createAuthInterface = require('./auth-interface'), AUTH_TYPE_PROP = '__auth_type', AuthLoader, authorizeRequest; /** * This object manages loading and finding Handlers for auth. * * @type AuthLoader */ AuthLoader = { /** * Houses list of available Authentication handlers. * * @property {Object} */ handlers: {}, /** * Finds the Handler for an Auth type. * * @param name * * @returns {AuthHandler} */ getHandler: function (name) { return AuthLoader.handlers[name]; }, /** * Adds a Handler for use with given Auth type. * * @param Handler * @param name */ addHandler: function (Handler, name) { if (!_.isFunction(Handler.init)) { throw new Error('The handler for "' + name + '" does not have an "init" function, which is necessary'); } if (!_.isFunction(Handler.pre)) { throw new Error('The handler for "' + name + '" does not have a "pre" function, which is necessary'); } if (!_.isFunction(Handler.post)) { throw new Error('The handler for "' + name + '" does not have a "post" function, which is necessary'); } if (!_.isFunction(Handler.sign)) { throw new Error('The handler for "' + name + '" does not have a "sign" function, which is necessary'); } Object.defineProperty(Handler, AUTH_TYPE_PROP, { value: name, configurable: false, enumerable: false, writable: false }); AuthLoader.handlers[name] = Handler; }, /** * Removes the Handler for the Auth type. * * @param name */ removeHandler: function (name) { AuthLoader.handlers[name] && (delete AuthLoader.handlers[name]); } }; // Create a Handler from each Signer that the SDK provides. Basically, we augment the signers with extra // helper functions which take over the job of preparing a request for signing. _.forEach({ noauth: require('./noauth'), awsv4: require('./aws4'), basic: require('./basic'), bearer: require('./bearer'), digest: require('./digest'), hawk: require('./hawk'), oauth1: require('./oauth1'), oauth2: require('./oauth2'), ntlm: require('./ntlm'), apikey: require('./apikey'), edgegrid: require('./edgegrid') }, AuthLoader.addHandler); /** * Creates a copy of request, with the appropriate auth headers or parameters added. * * @note This function does not take care of resolving variables. * * @param {Request} request * @param done * * @returns {Request} */ authorizeRequest = function (request, done) { if (!request.auth) { return done(); } var clonedReq = new sdk.Request(request.toJSON()), auth = clonedReq.auth, authInterface = createAuthInterface(auth), handler = AuthLoader.getHandler(auth.type); if (handler) { handler.sign(authInterface, clonedReq, function () { return done(null, clonedReq); }); } else { return done(new Error('runtime~authorizeRequest: could not find handler for auth type ' + auth.type)); } }; module.exports = { AuthLoader: AuthLoader, authorizeRequest: authorizeRequest }; // Interface /** * Interface for implementing auth handlers * * @interface AuthHandlerInterface */ // Interface functions /** * Defines the behaviour of an Auth Handler. This way the handler allows to statically analyse * any changes the Handler will make ahead of time. * * @member {AuthHandlerInterface~AuthManifest} AuthHandlerInterface#manifest */ /** * This hook decides whether all the required parameters are present in the auth or not. * What happens next is dependent upon how the `done` callback is called. * Check {@link AuthHandlerInterface~authPreHookCallback} for all the possible ways the callback can be called. * * @function * @name AuthHandlerInterface#pre * * @param {AuthInterface} auth * @param {AuthHandlerInterface~authPreHookCallback} done * Callback function which takes error, success, and request as arguments */ /** * This hook is called with the response from the intermediate request, which was requested from the * [pre]{@link AuthHandlerInterface#pre} hook. * Here the `auth` can be modified using the response. After this [pre]{@link AuthHandlerInterface#pre} hook will be * called again to verify the required parameters. * * @function * @name AuthHandlerInterface#init * * @param {AuthInterface} auth * @param {Response} response * @param {AuthHandlerInterface~authInitHookCallback} done Callback function which takes error as the only argument */ /** * This hook signs the `request` using the `auth`. * * @function * @name AuthHandlerInterface#sign * * @param {AuthInterface} auth * @param {Request} request * @param {AuthHandlerInterface~authSignHookCallback} done Callback function which takes error as the only argument */ /** * This hook is called after the request is made. It receives the response using which it can determine whether * it was a failure or success. It can also modify the `auth` and ask to replay the `request`. * For this it has to call the [done]{@link AuthHandlerInterface~authPostHookCallback} callback with `success` as false. * * @function * @name AuthHandlerInterface#post * * @param {AuthInterface} auth * @param {Response} response * @param {AuthHandlerInterface~authPostHookCallback} done Callback function which takes error and success as arguments */ // Callbacks /** * This callback is called in the `pre` hook of the auth handler * Depending on what parameters are passed in this callback, one of the following flows will be executed: * 1. return (err): The request will be stopped and the error will be bubbled up * 2. return (null, true): The request will be signed and sent * 3. return (null, false): The request will be sent without being signed * 4. return (null, false, `request`): * - send the intermediate request * - invoke the auth's [init]{@link AuthHandlerInterface#init} hook with the response of the intermediate request * - invoke the auth's [pre]{@link AuthHandlerInterface#pre} hook * @callback AuthHandlerInterface~authPreHookCallback * @param {?Error} err * @param {Boolean} success Defines whether the [pre]{@link AuthHandlerInterface#pre} hook was successful. * @param {Request~definition|String} [request] It can be either request definition or request URL */ /** * This callback is called in the `init` hook of the auth handler * @callback AuthHandlerInterface~authInitHookCallback * @param {?Error} err */ /** * This callback is called in the `sign` hook of the auth handler * @callback AuthHandlerInterface~authSignHookCallback * @param {?Error} err */ /** * This callback is called in the `post` hook of the auth handler * @callback AuthHandlerInterface~authPostHookCallback * @param {?Error} err * @param {Boolean} success Defines whether the request was successful or not. If not, it will be replayed. */ /** * Structure of an Auth Manifest. See {@link AuthHandlerInterface#manifest} for description. * * @typedef {Object} AuthHandlerInterface~AuthManifest * * @property {Object} info * @property {String} info.name * @property {String} info.version * @property {Array} updates */