Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support basic auth header solr #143

Merged
merged 7 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions factories/solrSearcherFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
'activeQueries',
'defaultSolrConfig',
'solrSearcherPreprocessorSvc',
'esUrlSvc',
SolrSearcherFactory
]);

function SolrSearcherFactory(
$q, $log,
SolrDocFactory, SearcherFactory, transportSvc,
activeQueries, defaultSolrConfig,
solrSearcherPreprocessorSvc
solrSearcherPreprocessorSvc, esUrlSvc
) {
var Searcher = function(options) {
SearcherFactory.call(this, options, solrSearcherPreprocessorSvc);
Expand All @@ -34,8 +35,7 @@
Searcher.prototype.search = search;
Searcher.prototype.explainOther = explainOther;
Searcher.prototype.queryDetails = {};



function addDocToGroup (groupedBy, group, solrDoc) {
/*jslint validthis:true*/
var self = this;
Expand Down Expand Up @@ -235,11 +235,22 @@
if (self.config && self.config.apiMethod) {
apiMethod = self.config.apiMethod;
}
var proxyUrl = self.config.proxyUrl;

var headers = null;
var proxyUrl = self.config.proxyUrl;

var transport = transportSvc.getTransport({apiMethod: apiMethod, proxyUrl: proxyUrl});

if (apiMethod === 'JSONP'){
// JSONP is weird. You don't get headers, and you must embed basic auth IN the url
}
else {
let uri = esUrlSvc.parseUrl(url);
url = esUrlSvc.buildUrl(uri);
headers = esUrlSvc.getHeaders(uri, self.config.customHeaders);
}

transport.query(url, null, null)
transport.query(url, null, headers)
.then(function success(resp) {
var solrResp = resp.data;
activeQueries.count--;
Expand Down
65 changes: 40 additions & 25 deletions test/mock/mockHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,44 @@ window.parseUrlParams = function(queryString) {
return parsedParams;
};

window.urlHasBasicAuth = function() {
return {
test: function(requestedUrl) {
try {
const uri = new URL(requestedUrl);
if (uri.username !== '' && uri.password !== ''){
return true;
}
else {
console.error('Expected username: ' + uri.username + ' and password: ' + uri.password + ' to both be embedded in url ' + requestedUrl);
return false;
}
} catch (error) {
return false; // Invalid URL
}
}
}
}

window.urlHasNoBasicAuth = function() {
return {
test: function(requestedUrl) {
try {
const uri = new URL(requestedUrl);
if (uri.username === '' && uri.password === ''){
return true;
}
else {
console.error('Expected username: ' + uri.username + ' and password: ' + uri.password + ' to both be missing from url ' + requestedUrl);
return false;
}
} catch (error) {
return false; // Invalid URL
}
}
}
}

window.arrayContains = function(list, value) {
var contains = false;
angular.forEach(list, function(listValue) {
Expand All @@ -41,7 +79,7 @@ window.urlContainsParams = function(url, params) {
if (values instanceof Array) {
angular.forEach(values, function(value) {
if (!arrayContains(parsedParams[param], value)) {
console.log('Expected param: ' + param + ' missing');
console.error('Expected param: ' + param + ' missing');
missingParam = true;
}
});
Expand All @@ -67,7 +105,7 @@ window.urlMissingParams = function(url, params) {
if (values instanceof Array) {
angular.forEach(values, function(value) {
if (arrayContains(parsedParams[param], value)) {
console.log('Param: ' + param + ' should be missing, but found');
console.error('Param: ' + param + ' should be missing, but found');
found = true;
}
});
Expand All @@ -77,26 +115,3 @@ window.urlMissingParams = function(url, params) {
}
};
}

window.mockSolrUrl = "http://example.com:1234/solr/example";

window.expectedSolrUrl = function(expected) {
return {
test: function(url) {
if (expected === undefined) {
expected = window.mockSolrUrl;
}
return url.indexOf(expected) === 0;
}
};
};

window.mockResults = {
response: {
numFound: 2,
docs : [
{id: 'doc1', field1: 'doc1field1val', field2: 'doc1field2val'},
{id: 'doc2', field1: 'doc2field1val', field2: 'doc2field2val'}
]
}
};
1 change: 0 additions & 1 deletion test/spec/esSearchSvc.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ describe('Service: searchSvc: ElasticSearch', function() {

$httpBackend.expectPOST(mockEsUrl, rowsValidator(expectedParams))
.respond(200, mockES7Results);
console.log("DOING ES")
searcher.search();
$httpBackend.flush();
});
Expand Down
59 changes: 51 additions & 8 deletions test/spec/solrSearchSvc.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe('Service: searchSvc: Solr', function () {
$httpBackend.verifyNoOutstandingExpectation();
});

it('sets the proper headers for auth', function() {
it('strips out username and password from url and converts to header property', function() {
var authSolrUrl = 'http://username:password@example.com:1234/solr/select';
var searcher = searchSvc.createSearcher(
mockFieldSpec,
Expand All @@ -78,14 +78,57 @@ describe('Service: searchSvc: Solr', function () {
'solr'
);

// The headers need to be removed from the URL, which we accomplish
// using the esUrlSvc.
var targetUrl = solrUrlSvc.buildUrl(solrUrlSvc.parseSolrUrl(authSolrUrl))
$httpBackend.expectGET(targetUrl, undefined, function(headers) {
return headers['Authorization'] == 'Basic ' + btoa('username:password');
}).
respond(200, mockResults);
var expectedHeaders = {
'Accept': 'application/json, text/plain, */*',
'Authorization': 'Basic ' + btoa('username:password')
};

$httpBackend.expectGET(urlHasNoBasicAuth(), expectedHeaders).respond(200, mockResults);
searcher.search();
$httpBackend.flush();
$httpBackend.verifyNoOutstandingExpectation();
expect(searchSvc.activeQueries()).toEqual(0);
});

it('With JSONP, it preserves the username and password in the URL and does NOT add it to header property', function() {
var authSolrUrl = 'http://username:password@example.com:1234/solr/select';
var searcher = searchSvc.createSearcher(
mockFieldSpec,
authSolrUrl,
mockSolrParams,
mockQueryText,
{ apiMethod: 'JSONP' },
'solr'
);

$httpBackend.expectJSONP(urlHasBasicAuth()).respond(200, mockResults);
searcher.search();
$httpBackend.flush();
$httpBackend.verifyNoOutstandingExpectation();
expect(searchSvc.activeQueries()).toEqual(0);
});

it('Pass basic auth through the headers', function() {
var searcher = searchSvc.createSearcher(
mockFieldSpec,
mockSolrUrl,
mockSolrParams,
mockQueryText,
{ apiMethod: 'GET', customHeaders: '{\n "Authorization": "Basic ' + btoa('username:password') + '"\n}'},
'solr'
);

var expectedHeaders = {
'Accept': 'application/json, text/plain, */*',
'Authorization': 'Basic ' + btoa('username:password')
};

$httpBackend.expectGET(urlHasNoBasicAuth(), expectedHeaders).respond(200, mockResults);
searcher.search();
$httpBackend.flush();
$httpBackend.verifyNoOutstandingExpectation();
expect(searchSvc.activeQueries()).toEqual(0);
});



Expand Down