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')
}, 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<Object>} updates
*/