240 lines
7.3 KiB
JavaScript
240 lines
7.3 KiB
JavaScript
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<Object>} updates
|
|
*/
|