Unify auth handling in the Host class
- flatten auth config to an Authorization header when the Host is created - remove individual Authorization handling from connectors - removed incomplete support for per-request auth - use per-request headers to provide your own Authorization header per request
This commit is contained in:
23
src/lib/connectors/angular.js
vendored
23
src/lib/connectors/angular.js
vendored
@ -10,37 +10,20 @@ var _ = require('../utils');
|
|||||||
var ConnectionAbstract = require('../connection');
|
var ConnectionAbstract = require('../connection');
|
||||||
var ConnectionFault = require('../errors').ConnectionFault;
|
var ConnectionFault = require('../errors').ConnectionFault;
|
||||||
|
|
||||||
function makeAuthHeader(auth) {
|
|
||||||
return 'Basic ' + (new Buffer(auth, 'utf8')).toString('base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
function AngularConnector(host, config) {
|
function AngularConnector(host, config) {
|
||||||
ConnectionAbstract.call(this, host, config);
|
ConnectionAbstract.call(this, host, config);
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
self.headerDefaults = {};
|
|
||||||
|
|
||||||
if (self.host.auth) {
|
|
||||||
self.headerDefaults.Authorization = makeAuthHeader(self.host.auth);
|
|
||||||
}
|
|
||||||
|
|
||||||
config.$injector.invoke(['$http', '$q', function ($http, $q) {
|
config.$injector.invoke(['$http', '$q', function ($http, $q) {
|
||||||
self.$q = $q;
|
self.$q = $q;
|
||||||
self.$http = $http;
|
self.$http = $http;
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
}
|
}
|
||||||
_.inherits(AngularConnector, ConnectionAbstract);
|
_.inherits(AngularConnector, ConnectionAbstract);
|
||||||
|
|
||||||
AngularConnector.prototype.request = function (userParams, cb) {
|
AngularConnector.prototype.request = function (params, cb) {
|
||||||
var abort = this.$q.defer();
|
var abort = this.$q.defer();
|
||||||
var params = _.cloneDeep(userParams);
|
|
||||||
|
|
||||||
params.headers = _.defaults(params.headers || {}, this.headerDefaults);
|
|
||||||
if (params.auth) {
|
|
||||||
params.headers.Authorization = makeAuthHeader(params.auth);
|
|
||||||
}
|
|
||||||
|
|
||||||
// inform the host not to use the auth, by overriding it in the params
|
|
||||||
params.auth = false;
|
|
||||||
|
|
||||||
this.$http({
|
this.$http({
|
||||||
method: params.method,
|
method: params.method,
|
||||||
|
|||||||
@ -106,7 +106,6 @@ HttpConnector.prototype.makeReqParams = function (params) {
|
|||||||
var reqParams = {
|
var reqParams = {
|
||||||
method: params.method || 'GET',
|
method: params.method || 'GET',
|
||||||
protocol: host.protocol + ':',
|
protocol: host.protocol + ':',
|
||||||
auth: host.auth,
|
|
||||||
hostname: host.host,
|
hostname: host.host,
|
||||||
port: host.port,
|
port: host.port,
|
||||||
path: (host.path || '') + (params.path || ''),
|
path: (host.path || '') + (params.path || ''),
|
||||||
|
|||||||
6
src/lib/connectors/jquery.js
vendored
6
src/lib/connectors/jquery.js
vendored
@ -26,12 +26,6 @@ JqueryConnector.prototype.request = function (params, cb) {
|
|||||||
done: cb
|
done: cb
|
||||||
};
|
};
|
||||||
|
|
||||||
if (params.auth) {
|
|
||||||
var auths = params.auth.split(':');
|
|
||||||
ajax.username = auths[0];
|
|
||||||
ajax.password = auths[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
var jqXHR = jQuery.ajax(ajax)
|
var jqXHR = jQuery.ajax(ajax)
|
||||||
.done(function (data, textStatus, jqXHR) {
|
.done(function (data, textStatus, jqXHR) {
|
||||||
cb(null, data, jqXHR.statusCode(), {
|
cb(null, data, jqXHR.statusCode(), {
|
||||||
|
|||||||
@ -53,16 +53,21 @@ if (!getXhr) {
|
|||||||
XhrConnector.prototype.request = function (params, cb) {
|
XhrConnector.prototype.request = function (params, cb) {
|
||||||
var xhr = getXhr();
|
var xhr = getXhr();
|
||||||
var timeoutId;
|
var timeoutId;
|
||||||
var url = this.host.makeUrl(params);
|
var host = this.host;
|
||||||
var headers = this.host.getHeaders(params.headers);
|
|
||||||
|
|
||||||
var log = this.log;
|
var log = this.log;
|
||||||
|
|
||||||
|
var url = host.makeUrl(params);
|
||||||
|
var headers = host.getHeaders(params.headers);
|
||||||
var async = params.async === false ? false : asyncDefault;
|
var async = params.async === false ? false : asyncDefault;
|
||||||
|
|
||||||
if (params.auth) {
|
|
||||||
xhr.open(params.method || 'GET', url, async, params.auth.user, params.auth.pass);
|
|
||||||
} else {
|
|
||||||
xhr.open(params.method || 'GET', url, async);
|
xhr.open(params.method || 'GET', url, async);
|
||||||
|
|
||||||
|
if (headers) {
|
||||||
|
for (var key in headers) {
|
||||||
|
if (headers[key] !== void 0) {
|
||||||
|
xhr.setRequestHeader(key, headers[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
@ -74,14 +79,6 @@ XhrConnector.prototype.request = function (params, cb) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (headers) {
|
|
||||||
for (var key in headers) {
|
|
||||||
if (headers[key] !== void 0) {
|
|
||||||
xhr.setRequestHeader(key, headers[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xhr.send(params.body || void 0);
|
xhr.send(params.body || void 0);
|
||||||
|
|
||||||
return function () {
|
return function () {
|
||||||
|
|||||||
@ -10,13 +10,19 @@ var _ = require('./utils');
|
|||||||
|
|
||||||
var startsWithProtocolRE = /^([a-z]+:)?\/\//;
|
var startsWithProtocolRE = /^([a-z]+:)?\/\//;
|
||||||
var defaultProto = 'http:';
|
var defaultProto = 'http:';
|
||||||
|
var btoa;
|
||||||
|
|
||||||
/* jshint ignore:start */
|
/* jshint ignore:start */
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
defaultProto = window.location.protocol;
|
defaultProto = window.location.protocol;
|
||||||
|
btoa = window.btoa;
|
||||||
}
|
}
|
||||||
/* jshint ignore:end */
|
/* jshint ignore:end */
|
||||||
|
|
||||||
|
btoa = btoa || function (data) {
|
||||||
|
return (new Buffer(data, 'utf8')).toString('base64');
|
||||||
|
};
|
||||||
|
|
||||||
var urlParseFields = [
|
var urlParseFields = [
|
||||||
'protocol', 'hostname', 'pathname', 'port', 'auth', 'query'
|
'protocol', 'hostname', 'pathname', 'port', 'auth', 'query'
|
||||||
];
|
];
|
||||||
@ -42,7 +48,7 @@ Host.defaultPorts = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function Host(config, globalConfig) {
|
function Host(config, globalConfig) {
|
||||||
config = config || {};
|
config = _.clone(config || {});
|
||||||
globalConfig = globalConfig || {};
|
globalConfig = globalConfig || {};
|
||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
@ -50,7 +56,6 @@ function Host(config, globalConfig) {
|
|||||||
this.host = 'localhost';
|
this.host = 'localhost';
|
||||||
this.path = '';
|
this.path = '';
|
||||||
this.port = 9200;
|
this.port = 9200;
|
||||||
this.auth = null;
|
|
||||||
this.query = null;
|
this.query = null;
|
||||||
this.headers = null;
|
this.headers = null;
|
||||||
this.suggestCompression = !!globalConfig.suggestCompression;
|
this.suggestCompression = !!globalConfig.suggestCompression;
|
||||||
@ -97,8 +102,14 @@ function Host(config, globalConfig) {
|
|||||||
config = {};
|
config = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.auth) {
|
||||||
|
config.headers = config.headers || {};
|
||||||
|
config.headers.Authorization = 'Basic ' + btoa(config.auth);
|
||||||
|
delete config.auth;
|
||||||
|
}
|
||||||
|
|
||||||
_.forOwn(config, function (val, prop) {
|
_.forOwn(config, function (val, prop) {
|
||||||
if (val != null) this[prop] = val;
|
if (val != null) this[prop] = _.clone(val);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
// make sure the query string is parsed
|
// make sure the query string is parsed
|
||||||
@ -149,15 +160,8 @@ Host.prototype.makeUrl = function (params) {
|
|||||||
// build the query string
|
// build the query string
|
||||||
var query = qs.stringify(this.getQuery(params.query));
|
var query = qs.stringify(this.getQuery(params.query));
|
||||||
|
|
||||||
var auth = '';
|
|
||||||
if (params.auth) {
|
|
||||||
auth = params.auth + '@';
|
|
||||||
} else if (this.auth && params.auth !== false) {
|
|
||||||
auth = this.auth + '@';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.host) {
|
if (this.host) {
|
||||||
return this.protocol + '://' + auth + this.host + port + path + (query ? '?' + query : '');
|
return this.protocol + '://' + this.host + port + path + (query ? '?' + query : '');
|
||||||
} else {
|
} else {
|
||||||
return path + (query ? '?' + query : '');
|
return path + (query ? '?' + query : '');
|
||||||
}
|
}
|
||||||
|
|||||||
40
test/unit/browser_builds/angular.js
vendored
40
test/unit/browser_builds/angular.js
vendored
@ -82,44 +82,4 @@ describe('Angular esFactory', function () {
|
|||||||
return prom;
|
return prom;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('$http', function () {
|
|
||||||
bootstrap({
|
|
||||||
bluebirdPromises: true
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses the auth header provided', function () {
|
|
||||||
var authString = 'user:password';
|
|
||||||
var authHeader = 'Basic ' + (new Buffer(authString, 'utf8')).toString('base64');
|
|
||||||
var $httpParams = null;
|
|
||||||
var client = esFactory({
|
|
||||||
host: {
|
|
||||||
host: 'some-other-es-host.com',
|
|
||||||
auth: authString
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// once the client calls the $http method, flush the requests and trigger an
|
|
||||||
// error if the expected request was not made
|
|
||||||
var connection = client.transport.connectionPool.getConnections().pop();
|
|
||||||
var stub = sinon.stub(connection, '$http', function (params) {
|
|
||||||
$httpParams = params;
|
|
||||||
return Promise.resolve({
|
|
||||||
data: null,
|
|
||||||
status: 200,
|
|
||||||
headers: function () {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var prom = client.ping({
|
|
||||||
requestTimeout: 1000
|
|
||||||
});
|
|
||||||
return prom.then(function () {
|
|
||||||
expect($httpParams).to.have.property('headers');
|
|
||||||
expect($httpParams.headers).to.have.property('Authorization', authHeader);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
@ -6,9 +6,11 @@ describe('elasticsearch namespace', function () {
|
|||||||
it('is defined on the window', function () {
|
it('is defined on the window', function () {
|
||||||
expect(es).to.be.ok();
|
expect(es).to.be.ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has Client, ConnectionPool, Transport, and errors keys', function () {
|
it('has Client, ConnectionPool, Transport, and errors keys', function () {
|
||||||
expect(es).to.have.keys('Client', 'ConnectionPool', 'Transport', 'errors');
|
expect(es).to.have.keys('Client', 'ConnectionPool', 'Transport', 'errors');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can create a client', function () {
|
it('can create a client', function () {
|
||||||
var client = new es.Client({ hosts: null });
|
var client = new es.Client({ hosts: null });
|
||||||
expect(client).to.have.keys('transport');
|
expect(client).to.have.keys('transport');
|
||||||
|
|||||||
2
test/unit/browser_builds/jquery.js
vendored
2
test/unit/browser_builds/jquery.js
vendored
@ -5,9 +5,11 @@ describe('jQuery.es namespace', function () {
|
|||||||
it('is defined on the global jQuery', function () {
|
it('is defined on the global jQuery', function () {
|
||||||
expect($.es).to.be.ok();
|
expect($.es).to.be.ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has Client, ConnectionPool, Transport, and errors keys', function () {
|
it('has Client, ConnectionPool, Transport, and errors keys', function () {
|
||||||
expect($.es).to.have.keys('Client', 'ConnectionPool', 'Transport', 'errors');
|
expect($.es).to.have.keys('Client', 'ConnectionPool', 'Transport', 'errors');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can create a client', function () {
|
it('can create a client', function () {
|
||||||
var client = new $.es.Client({ hosts: null });
|
var client = new $.es.Client({ hosts: null });
|
||||||
expect(client).to.have.keys('transport');
|
expect(client).to.have.keys('transport');
|
||||||
|
|||||||
@ -9,7 +9,6 @@ var hostDefaults = {
|
|||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 9200,
|
port: 9200,
|
||||||
path: '',
|
path: '',
|
||||||
auth: null,
|
|
||||||
query: {},
|
query: {},
|
||||||
headers: null,
|
headers: null,
|
||||||
suggestCompression: false,
|
suggestCompression: false,
|
||||||
@ -44,7 +43,7 @@ describe('Host class', function () {
|
|||||||
var headers = { 'X-Special-Routing-Header': 'pie' };
|
var headers = { 'X-Special-Routing-Header': 'pie' };
|
||||||
var host = new Host({ headers: headers });
|
var host = new Host({ headers: headers });
|
||||||
|
|
||||||
expect(host.headers).to.be(headers);
|
expect(host.headers).to.eql(headers);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('from a string', function () {
|
describe('from a string', function () {
|
||||||
@ -56,7 +55,6 @@ describe('Host class', function () {
|
|||||||
host: 'pizza.com',
|
host: 'pizza.com',
|
||||||
port: 420,
|
port: 420,
|
||||||
path: '/pizza/cheese',
|
path: '/pizza/cheese',
|
||||||
auth: 'john:dude',
|
|
||||||
query: {
|
query: {
|
||||||
shrooms: 'true'
|
shrooms: 'true'
|
||||||
}
|
}
|
||||||
@ -122,7 +120,7 @@ describe('Host class', function () {
|
|||||||
expect(host.host).to.eql('pizza.com');
|
expect(host.host).to.eql('pizza.com');
|
||||||
expect(host.port).to.eql(888);
|
expect(host.port).to.eql(888);
|
||||||
expect(host.path).to.eql('/path');
|
expect(host.path).to.eql('/path');
|
||||||
expect(host.auth).to.eql('joe:diner');
|
expect(host.headers).to.eql({ Authorization: 'Basic ' + (new Buffer('joe:diner')).toString('base64') });
|
||||||
expect(host.query).to.eql({
|
expect(host.query).to.eql({
|
||||||
query: 'yes'
|
query: 'yes'
|
||||||
});
|
});
|
||||||
@ -151,9 +149,8 @@ describe('Host class', function () {
|
|||||||
path: '/this and that',
|
path: '/this and that',
|
||||||
query: {
|
query: {
|
||||||
param: 1
|
param: 1
|
||||||
},
|
}
|
||||||
auth: 'user:pass'
|
})).to.be('http://localhost:9200/prefix/this and that?user_id=123¶m=1');
|
||||||
})).to.be('http://user:pass@localhost:9200/prefix/this and that?user_id=123¶m=1');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ensures that path starts with a forward-slash', function () {
|
it('ensures that path starts with a forward-slash', function () {
|
||||||
@ -179,7 +176,7 @@ describe('Host class', function () {
|
|||||||
expect(host.makeUrl()).to.be('http://john/');
|
expect(host.makeUrl()).to.be('http://john/');
|
||||||
|
|
||||||
host = new Host({ host: 'italy', path: '/pie', auth: 'user:pass'});
|
host = new Host({ host: 'italy', path: '/pie', auth: 'user:pass'});
|
||||||
expect(host.makeUrl()).to.be('http://user:pass@italy:9200/pie');
|
expect(host.makeUrl()).to.be('http://italy:9200/pie');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('outputs valid relative urls when the host is empty', function () {
|
it('outputs valid relative urls when the host is empty', function () {
|
||||||
|
|||||||
@ -72,10 +72,10 @@ describe('Http Connector', function () {
|
|||||||
var con = new HttpConnection(host, {});
|
var con = new HttpConnection(host, {});
|
||||||
var reqParams = con.makeReqParams();
|
var reqParams = con.makeReqParams();
|
||||||
|
|
||||||
|
expect(reqParams).to.not.have.property('auth');
|
||||||
expect(reqParams).to.eql({
|
expect(reqParams).to.eql({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
protocol: 'http:',
|
protocol: 'http:',
|
||||||
auth: 'john:dude',
|
|
||||||
hostname: 'pizza.com',
|
hostname: 'pizza.com',
|
||||||
port: 9200,
|
port: 9200,
|
||||||
path: '/pizza/cheese?shrooms=true',
|
path: '/pizza/cheese?shrooms=true',
|
||||||
@ -142,7 +142,6 @@ describe('Http Connector', function () {
|
|||||||
expect(reqParams).to.eql({
|
expect(reqParams).to.eql({
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
protocol: 'http:',
|
protocol: 'http:',
|
||||||
auth: null,
|
|
||||||
hostname: 'google.com',
|
hostname: 'google.com',
|
||||||
port: 80,
|
port: 80,
|
||||||
path: '/stuff',
|
path: '/stuff',
|
||||||
|
|||||||
Reference in New Issue
Block a user