1
0
Fork 0

Add SpoofedNodeHttpImpl

Session spoofing is needed for making authenticated requests.
master
Mike Gerwitz 2017-06-28 14:54:34 -04:00
parent d47d77bb5e
commit 65ab92f701
7 changed files with 188 additions and 6 deletions

View File

@ -98,9 +98,10 @@ module.exports = Class( 'DataApiManager' )
'private _apis': {}, 'private _apis': {},
__construct: function( api_factory ) __construct: function( api_factory, apis )
{ {
this._dataApiFactory = api_factory; this._dataApiFactory = api_factory;
this.setApis( apis || {} );
}, },

View File

@ -47,5 +47,9 @@ module.exports = Interface( 'HttpImpl',
* *
* @return {HttpImpl} self * @return {HttpImpl} self
*/ */
'public requestData': [ 'url', 'method', 'data', 'callback' ] 'public requestData': [ 'url', 'method', 'data', 'callback' ],
// TODO: temporary to work around class extension bug; see
// SpoofedNodeHttpImpl
'public setOptions': [],
} ); } );

View File

@ -98,7 +98,7 @@ module.exports = Class( 'NodeHttpImpl' )
throw Error( `No handler for ${protocol}` ); throw Error( `No handler for ${protocol}` );
} }
this._setOptions( options, method, data ); this.setOptions( options, method, data );
let forbid_end = false; let forbid_end = false;
@ -152,13 +152,16 @@ module.exports = Class( 'NodeHttpImpl' )
/** /**
* Set request options * Set request options
* *
* TODO: public to work around a class extension trait bug; make
* protected once fixed
*
* @param {Object} options request options * @param {Object} options request options
* @param {string} method HTTP method * @param {string} method HTTP method
* @param {string} data request data * @param {string} data request data
* *
* @return {Object} request headers * @return {Object} request headers
*/ */
'private _setOptions'( options, method, data ) 'virtual public setOptions'( options, method, data )
{ {
const { headers = {} } = options; const { headers = {} } = options;

View File

@ -0,0 +1,78 @@
/**
* Node-based HTTP client with session spoofing
*
* Copyright (C) 2017 R-T Specialty, LLC.
*
* This file is part of the Liza Data Collection Framework.
*
* liza is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
const { Trait } = require( 'easejs' );
const HttpImpl = require( './HttpImpl' );
/**
* Spoof user session during request
*
* TODO: Implementing HttpImpl instead of overriding NodeHttpImpl to work
* around a class extension bug; change once fixed.
*/
module.exports = Trait( 'SpoofedNodeHttpImpl' )
.implement( HttpImpl )
.extend(
{
/**
* Session to spoof
* @type {UserSession}
*/
'private _request': null,
/**
* Use session for spoofing requests
*
* @param {UserSession} session session to spoof
*/
__mixin( session )
{
this._request = session;
},
/**
* Set request options to spoof session
*
* @param {Object} options request options
* @param {string} method HTTP method
* @param {string} data request data
*
* @return {Object} request headers
*/
'virtual abstract override public setOptions'( options, method, data )
{
const cookie = this._request.getSessionIdName() + '=' +
this._request.getSessionId();
options.headers = {
'User-Agent': this._request.getUserAgent(),
'X-Forwarded-For': this._request.getRemoteAddr(),
'Cookie': cookie,
};
return this.__super( options, method, data );
}
} );

View File

@ -279,5 +279,11 @@ module.exports = Class( 'XhrHttpImpl' )
e.status = req.status; e.status = req.status;
callback( e, req.responseText ); callback( e, req.responseText );
},
'public setOptions'()
{
// TOOD: remove (see HttpImpl)
} }
} ); } );

View File

@ -27,7 +27,11 @@ var dapi = require( '../../../' ).dapi,
dummy_url = 'http://foo', dummy_url = 'http://foo',
dummy_impl = Class dummy_impl = Class
.implement( dapi.http.HttpImpl ) .implement( dapi.http.HttpImpl )
.extend( { requestData: function( _, __, ___, ____ ) {} } )(), .extend(
{
requestData: function( _, __, ___, ____ ) {},
setOptions() {},
} )(),
dummy_sut = Sut( dummy_url, 'GET', dummy_impl ); dummy_sut = Sut( dummy_url, 'GET', dummy_impl );
@ -86,7 +90,9 @@ describe( 'HttpDataApi', function()
{ {
this.provided = arguments; this.provided = arguments;
c( this.err, this.data ); c( this.err, this.data );
} },
setOptions() {},
} )(); } )();

View File

@ -0,0 +1,84 @@
/**
* Tests Node-based HTTP client with session spoofing
*
* Copyright (C) 2017 R-T Specialty, LLC.
*
* This file is part of the Liza Data Collection Framework.
*
* liza is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
const { expect } = require( 'chai' );
const {
SpoofedNodeHttpImpl: Sut,
NodeHttpImpl,
} = require( '../../../' ).dapi.http;
describe( 'SpoofNodeHttpImpl', () =>
{
it( "adds session headers", done =>
{
const user_agent = 'Agent Foo';
const forward_for = '::1';
const sessname = 'FOOSESSID';
const sessid = '12345';
const protos = {
http: {
request( given )
{
expect( given.headers[ 'User-Agent' ] )
.to.equal( user_agent );
expect( given.headers[ 'X-Forwarded-For' ] )
.to.equal( forward_for );
expect( given.headers.Cookie )
.to.contain( sessname + '=' + sessid );
done();
},
},
};
const url = {
parse: () => ( {
protocol: 'http',
} )
};
const session = getStubSession( {
agent: user_agent,
forward_for: forward_for,
sessname: sessname,
sessid: sessid,
} );
const given = NodeHttpImpl.use( Sut( session ) )( protos, url )
.requestData( '', '', {}, ()=>{} );
} );
} );
function getStubSession( { agent, forward_for, sessname, sessid } )
{
return {
getUserAgent: () => agent,
getRemoteAddr: () => forward_for,
getSessionIdName: () => sessname,
getSessionId: () => sessid,
};
}