Elasticsearch: Fix URL creation and allowlist for /_mapping requests (#80970)

* Elasticsearch: Fix URL creation for mapping requests

* remove leading slash by default

* add comment for es route

* hardcode `_mapping`

* update doc
This commit is contained in:
Sven Grossmann
2024-01-23 12:41:13 +01:00
committed by GitHub
parent f9b8f219e4
commit 3d033839d7
4 changed files with 26 additions and 9 deletions

View File

@ -188,9 +188,10 @@ func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceReq
logger := eslog.FromContext(ctx)
// allowed paths for resource calls:
// - empty string for fetching db version
// - ?/_mapping for fetching index mapping
// - /_mapping for fetching index mapping, e.g. requests going to `index/_mapping`
// - _msearch for executing getTerms queries
if req.Path != "" && !strings.HasSuffix(req.Path, "/_mapping") && req.Path != "_msearch" {
// - _mapping for fetching "root" index mappings
if req.Path != "" && !strings.HasSuffix(req.Path, "/_mapping") && req.Path != "_msearch" && req.Path != "_mapping" {
logger.Error("Invalid resource path", "path", req.Path)
return fmt.Errorf("invalid resource URL: %s", req.Path)
}

View File

@ -151,6 +151,15 @@ describe('ElasticDatasource', () => {
const lastCall = fetchMock.mock.calls[fetchMock.mock.calls.length - 1];
expect(lastCall[0].url).toBe(`${ELASTICSEARCH_MOCK_URL}/test-${today}/_mapping`);
});
it('should call `/_mapping` with an empty index', async () => {
const { ds, fetchMock } = getTestContext({ jsonData: { index: '' } });
await ds.testDatasource();
const lastCall = fetchMock.mock.calls[fetchMock.mock.calls.length - 1];
expect(lastCall[0].url).toBe(`${ELASTICSEARCH_MOCK_URL}/_mapping`);
});
});
describe('When issuing metric query with interval pattern', () => {

View File

@ -195,17 +195,24 @@ export class ElasticDatasource
*
* When multiple indices span the provided time range, the request is sent starting from the newest index,
* and then going backwards until an index is found.
*
* @param url the url to query the index on, for example `/_mapping`.
*/
private requestAllIndices(url: string, range = getDefaultTimeRange()) {
private requestAllIndices(range = getDefaultTimeRange()) {
let indexList = this.indexPattern.getIndexList(range.from, range.to);
if (!Array.isArray(indexList)) {
indexList = [this.indexPattern.getIndexForToday()];
}
const indexUrlList = indexList.map((index) => index + url);
const url = '_mapping';
const indexUrlList = indexList.map((index) => {
// make sure `index` does not end with a slash
index = index.replace(/\/$/, '');
if (index === '') {
return url;
}
return `${index}/${url}`;
});
const maxTraversals = 7; // do not go beyond one week (for a daily pattern)
const listLen = indexUrlList.length;
@ -708,7 +715,7 @@ export class ElasticDatasource
nested: 'nested',
histogram: 'number',
};
return this.requestAllIndices('/_mapping', range).pipe(
return this.requestAllIndices(range).pipe(
map((result) => {
const shouldAddField = (obj: any, key: string) => {
if (this.isMetadataField(key)) {

View File

@ -39,9 +39,9 @@ export function createElasticDatasource(settings: Partial<DataSourceInstanceSett
jsonData: {
timeField: '',
timeInterval: '',
index: '[test-]YYYY.MM.DD',
...jsonData,
},
database: '[test-]YYYY.MM.DD',
...rest,
};