Skip to content

Commit

Permalink
autoDetectCORS option for proxy config (geosolutions-it#3675)
Browse files Browse the repository at this point in the history
* autoDetectCORS option for proxy config

* Updated axios version to support automatic CORS detection
  • Loading branch information
mbarto authored Apr 8, 2019
1 parent 9159b11 commit 82ca81a
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"@turf/polygon-to-linestring": "4.1.0",
"ag-grid": "3.3.3",
"ag-grid-react": "3.3.1",
"axios": "0.11.1",
"axios": "0.18.0",
"b64-to-blob": "1.2.19",
"babel-polyfill": "6.8.0",
"babel-standalone": "6.7.7",
Expand Down
45 changes: 44 additions & 1 deletion web/client/libs/__tests__/ajax-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const axios = require('../ajax');
const SecurityUtils = require('../../utils/SecurityUtils');
const assign = require('object-assign');
const urlUtil = require('url');
const MockAdapter = require("axios-mock-adapter");
let mockAxios;

const userA = {
User: {
Expand Down Expand Up @@ -79,6 +81,10 @@ const authenticationRules = [

describe('Tests ajax library', () => {
afterEach(() => {
if (mockAxios) {
mockAxios.restore();
mockAxios = null;
}
expect.restoreSpies();
});

Expand Down Expand Up @@ -379,7 +385,6 @@ describe('Tests ajax library', () => {
it('does not set withCredentials on the request', (done)=> {
expect.spyOn(SecurityUtils, 'isAuthenticationActivated').andReturn(true);
expect.spyOn(SecurityUtils, 'getAuthenticationRules').andReturn(authenticationRules);

axios.get('http://www.skipBrowserCredentials.com/geoserver?parameter1=value1&parameter2=value2').then(() => {
done();
}).catch( (exception) => {
Expand All @@ -388,4 +393,42 @@ describe('Tests ajax library', () => {
done();
});
});

it('does test for CORS if autoDetectCORS is true', (done) => {
mockAxios = new MockAdapter(axios);
mockAxios.onGet().reply(200, {}, {
"allow-control-allow-origin": "*"
});
axios
.get("http://testcors/", {
proxyUrl: {
url: "/proxy/?url=",
useCORS: [],
autoDetectCORS: true
}
})
.then(response => {
expect(response.config).toExist();
expect(response.config.url).toExist();
expect(response.config.url).toNotContain("proxy/?url=");
done();
});
});

it('revert to proxy if autoDetectCORS is true but CORS is not enabled on server', (done) => {
mockAxios = new MockAdapter(axios);
axios.get('http://testcors/', {
timeout: 1,
proxyUrl: {
url: '/proxy/?url=',
useCORS: [],
autoDetectCORS: true
}
}).catch((response) => {
expect(response.config).toExist();
expect(response.config.url).toExist();
expect(response.config.url).toContain('proxy/?url=');
done();
});
});
});
24 changes: 23 additions & 1 deletion web/client/libs/ajax.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

const axios = require('axios');
const url = require('url');
const ConfigUtils = require('../utils/ConfigUtils');

const SecurityUtils = require('../utils/SecurityUtils');
Expand All @@ -31,6 +32,8 @@ function addHeaderToAxiosConfig(axiosConfig, headerName, headerValue) {
axiosConfig.headers = assign({}, axiosConfig.headers, {[headerName]: headerValue});
}

const corsDisabled = [];

/**
* Internal helper that will add to the axios config object the correct
* authentication method based on the request URL.
Expand Down Expand Up @@ -107,12 +110,15 @@ axios.interceptors.request.use(config => {
let proxyUrl = ConfigUtils.getProxyUrl(config);
if (proxyUrl) {
let useCORS = [];
let autoDetectCORS = false;
if (isObject(proxyUrl)) {
useCORS = proxyUrl.useCORS || [];
autoDetectCORS = proxyUrl.autoDetectCORS || false;
proxyUrl = proxyUrl.url;
}
const isCORS = useCORS.reduce((found, current) => found || uri.indexOf(current) === 0, false);
if (!isCORS) {
const cannotUseCORS = corsDisabled.reduce((found, current) => found || uri.indexOf(current) === 0, false);
if (!isCORS && (!autoDetectCORS || cannotUseCORS)) {
const parsedUri = urlUtil.parse(uri, true, true);
config.url = proxyUrl + encodeURIComponent(
urlUtil.format(
Expand All @@ -123,10 +129,26 @@ axios.interceptors.request.use(config => {
)
);
config.params = undefined;
} else if (autoDetectCORS) {
config.autoDetectCORS = true;
}
}
}
return config;
});

axios.interceptors.response.use(response => response, (error) => {
if (error.config && error.config.autoDetectCORS) {
const urlParts = url.parse(error.config.url);
const baseUrl = urlParts.protocol + "//" + urlParts.host + urlParts.pathname;
if (corsDisabled.indexOf(baseUrl) === -1) {
corsDisabled.push(baseUrl);
return new Promise((resolve, reject) => {
axios({ ...error.config, autoDetectCORS: false}).then(resolve).catch(reject);
});
}
}
return Promise.reject(error.response ? {...error.response, originalError: error} : error);
});

module.exports = axios;
2 changes: 1 addition & 1 deletion web/client/plugins/MetadataExplorer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const catalogSelector = createSelector([
format: newformat,
newService,
currentLocale,
records: CatalogUtils.getCatalogRecords(selectedFormat, result, options)
records: result && CatalogUtils.getCatalogRecords(selectedFormat, result, options) || []
}));

const catalogClose = () => {
Expand Down
2 changes: 1 addition & 1 deletion web/client/utils/SecurityUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const SecurityUtils = {
* Gets security state form the store.
*/
getSecurityInfo() {
return this.store.getState().security;
return this.store && this.store.getState().security || {};
},

/**
Expand Down

0 comments on commit 82ca81a

Please sign in to comment.