Commit 72c3257d by Hugo Häggmark Committed by GitHub

BackendSrv: Uses credentials and defaults to same-origin (#27385)

Co-authored-by: Liu Yang yangliuyu@163.com
parent b6d76cdb
...@@ -62,8 +62,12 @@ export type BackendSrvRequest = { ...@@ -62,8 +62,12 @@ export type BackendSrvRequest = {
params?: Record<string, any>; params?: Record<string, any>;
/** /**
* Indicates whether or not cross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates. Setting withCredentials has no effect on same-site requests. * The credentials read-only property of the Request interface indicates whether the user agent should send cookies from the other domain in the case of cross-origin requests.
* In addition, this flag is also used to indicate when cookies are to be ignored in the response. */
credentials?: RequestCredentials;
/**
* @deprecated withCredentials is deprecated in favor of credentials
*/ */
withCredentials?: boolean; withCredentials?: boolean;
}; };
......
...@@ -2,6 +2,7 @@ import 'whatwg-fetch'; // fetch polyfill needed for PhantomJs rendering ...@@ -2,6 +2,7 @@ import 'whatwg-fetch'; // fetch polyfill needed for PhantomJs rendering
import { import {
isContentTypeApplicationJson, isContentTypeApplicationJson,
parseBody, parseBody,
parseCredentials,
parseHeaders, parseHeaders,
parseInitFromOptions, parseInitFromOptions,
parseUrlFromOptions, parseUrlFromOptions,
...@@ -27,17 +28,18 @@ describe('parseUrlFromOptions', () => { ...@@ -27,17 +28,18 @@ describe('parseUrlFromOptions', () => {
describe('parseInitFromOptions', () => { describe('parseInitFromOptions', () => {
it.each` it.each`
method | data | withCredentials | expected method | data | withCredentials | credentials | expected
${undefined} | ${undefined} | ${undefined} | ${{ method: undefined, headers: { map: { accept: 'application/json, text/plain, */*' } }, body: undefined }} ${undefined} | ${undefined} | ${undefined} | ${undefined} | ${{ method: undefined, headers: { map: { accept: 'application/json, text/plain, */*' } }, body: undefined, credentials: 'same-origin' }}
${'GET'} | ${undefined} | ${undefined} | ${{ method: 'GET', headers: { map: { accept: 'application/json, text/plain, */*' } }, body: undefined }} ${'GET'} | ${undefined} | ${undefined} | ${undefined} | ${{ method: 'GET', headers: { map: { accept: 'application/json, text/plain, */*' } }, body: undefined, credentials: 'same-origin' }}
${'POST'} | ${{ id: '0' }} | ${undefined} | ${{ method: 'POST', headers: { map: { 'content-type': 'application/json', accept: 'application/json, text/plain, */*' } }, body: '{"id":"0"}' }} ${'POST'} | ${{ id: '0' }} | ${undefined} | ${undefined} | ${{ method: 'POST', headers: { map: { 'content-type': 'application/json', accept: 'application/json, text/plain, */*' } }, body: '{"id":"0"}', credentials: 'same-origin' }}
${'PUT'} | ${{ id: '0' }} | ${undefined} | ${{ method: 'PUT', headers: { map: { 'content-type': 'application/json', accept: 'application/json, text/plain, */*' } }, body: '{"id":"0"}' }} ${'PUT'} | ${{ id: '0' }} | ${undefined} | ${undefined} | ${{ method: 'PUT', headers: { map: { 'content-type': 'application/json', accept: 'application/json, text/plain, */*' } }, body: '{"id":"0"}', credentials: 'same-origin' }}
${'monkey'} | ${undefined} | ${undefined} | ${{ method: 'monkey', headers: { map: { accept: 'application/json, text/plain, */*' } }, body: undefined }} ${'monkey'} | ${undefined} | ${undefined} | ${'omit'} | ${{ method: 'monkey', headers: { map: { accept: 'application/json, text/plain, */*' } }, body: undefined, credentials: 'omit' }}
${'GET'} | ${undefined} | ${true} | ${{ method: 'GET', headers: { map: { accept: 'application/json, text/plain, */*' } }, body: undefined, credentials: 'include' }} ${'GET'} | ${undefined} | ${true} | ${undefined} | ${{ method: 'GET', headers: { map: { accept: 'application/json, text/plain, */*' } }, body: undefined, credentials: 'include' }}
${'GET'} | ${undefined} | ${true} | ${'omit'} | ${{ method: 'GET', headers: { map: { accept: 'application/json, text/plain, */*' } }, body: undefined, credentials: 'omit' }}
`( `(
"when called with method: '$method', data: '$data' and withCredentials: '$withCredentials' then result should be '$expected'", "when called with method: '$method', data: '$data', withCredentials: '$withCredentials' and credentials: '$credentials' then result should be '$expected'",
({ method, data, withCredentials, expected }) => { ({ method, data, withCredentials, credentials, expected }) => {
expect(parseInitFromOptions({ method, data, withCredentials, url: '' })).toEqual(expected); expect(parseInitFromOptions({ method, data, withCredentials, credentials, url: '' })).toEqual(expected);
} }
); );
}); });
...@@ -100,3 +102,28 @@ describe('parseBody', () => { ...@@ -100,3 +102,28 @@ describe('parseBody', () => {
} }
); );
}); });
describe('parseCredentials', () => {
it.each`
options | expected
${undefined} | ${undefined}
${{}} | ${'same-origin'}
${{ credentials: undefined }} | ${'same-origin'}
${{ credentials: undefined, withCredentials: undefined }} | ${'same-origin'}
${{ credentials: undefined, withCredentials: false }} | ${'same-origin'}
${{ credentials: undefined, withCredentials: true }} | ${'include'}
${{ credentials: 'invalid' }} | ${'invalid'}
${{ credentials: 'invalid', withCredentials: undefined }} | ${'invalid'}
${{ credentials: 'invalid', withCredentials: false }} | ${'invalid'}
${{ credentials: 'invalid', withCredentials: true }} | ${'invalid'}
${{ credentials: 'omit' }} | ${'omit'}
${{ credentials: 'omit', withCredentials: undefined }} | ${'omit'}
${{ credentials: 'omit', withCredentials: false }} | ${'omit'}
${{ credentials: 'omit', withCredentials: true }} | ${'omit'}
`(
"when called with options: '$options' then the result should be '$expected'",
({ options, isAppJson, expected }) => {
expect(parseCredentials(options)).toEqual(expected);
}
);
});
import { BackendSrvRequest } from '@grafana/runtime'; import { BackendSrvRequest } from '@grafana/runtime';
import omitBy from 'lodash/omitBy'; import omitBy from 'lodash/omitBy';
import { deprecationWarning } from '@grafana/data';
export const parseInitFromOptions = (options: BackendSrvRequest): RequestInit => { export const parseInitFromOptions = (options: BackendSrvRequest): RequestInit => {
const method = options.method; const method = options.method;
const headers = parseHeaders(options); const headers = parseHeaders(options);
const isAppJson = isContentTypeApplicationJson(headers); const isAppJson = isContentTypeApplicationJson(headers);
const body = parseBody(options, isAppJson); const body = parseBody(options, isAppJson);
const credentials = parseCredentials(options);
if (options?.withCredentials) {
return {
method,
headers,
body,
credentials: 'include',
};
}
return { return {
method, method,
headers, headers,
body, body,
credentials,
}; };
}; };
...@@ -114,3 +108,20 @@ export const parseUrlFromOptions = (options: BackendSrvRequest): string => { ...@@ -114,3 +108,20 @@ export const parseUrlFromOptions = (options: BackendSrvRequest): string => {
const serializedParams = serializeParams(cleanParams); const serializedParams = serializeParams(cleanParams);
return options.params && serializedParams.length ? `${options.url}?${serializedParams}` : options.url; return options.params && serializedParams.length ? `${options.url}?${serializedParams}` : options.url;
}; };
export const parseCredentials = (options: BackendSrvRequest): RequestCredentials => {
if (!options) {
return options;
}
if (options.credentials) {
return options.credentials;
}
if (options.withCredentials) {
deprecationWarning('BackendSrvRequest', 'withCredentials', 'credentials');
return 'include';
}
return 'same-origin';
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment