mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Auth: Implement Token URL JWT Auth (#52662)
* Auth: check of auth_token in url and resolve user if present * check if auth_token is passed in url * Auth: Pass auth_token for request if present in path * no need to decode token in index * temp * use loadURLToken and set authorization header * cache token in memory and strip it from url * Use loadURLToken * Keep token in url * strip sensitive query strings from url used by context logger * adapt login by url to jwt token * add jwt iframe devenv * add jwt iframe devenv instructions * add access note * add test for cleaning request * ensure jwt token is not carried into handlers * do not reshuffle queries, might be important * add correct db dump location * prefer set token instead of cached token Co-authored-by: Ieva <ieva.vasiljeva@grafana.com> Co-authored-by: Karl Persson <kalle.persson@grafana.com> Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import { AppEvents, DataQueryErrorType } from '@grafana/data';
|
||||
import { BackendSrv as BackendService, BackendSrvRequest, config, FetchError, FetchResponse } from '@grafana/runtime';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { getConfig } from 'app/core/config';
|
||||
import { loadUrlToken } from 'app/core/utils/urlToken';
|
||||
import { DashboardSearchHit } from 'app/features/search/types';
|
||||
import { getGrafanaStorage } from 'app/features/storage/storage';
|
||||
import { TokenRevokedModal } from 'app/features/users/TokenRevokedModal';
|
||||
@@ -128,6 +129,17 @@ export class BackendSrv implements BackendService {
|
||||
|
||||
options = this.parseRequestOptions(options);
|
||||
|
||||
const token = loadUrlToken();
|
||||
if (token !== null && token !== '') {
|
||||
if (!options.headers) {
|
||||
options.headers = {};
|
||||
}
|
||||
|
||||
if (config.jwtUrlLogin && config.jwtHeaderName) {
|
||||
options.headers[config.jwtHeaderName] = `${token}`;
|
||||
}
|
||||
}
|
||||
|
||||
const fromFetchStream = this.getFromFetchStream<T>(options);
|
||||
const failureStream = fromFetchStream.pipe(this.toFailureStream<T>(options));
|
||||
const successStream = fromFetchStream.pipe(
|
||||
|
||||
13
public/app/core/utils/urlToken.ts
Normal file
13
public/app/core/utils/urlToken.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
let cachedToken = '';
|
||||
|
||||
export const loadUrlToken = (): string | null => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
const token = params.get('auth_token');
|
||||
if (token !== null && token !== '') {
|
||||
cachedToken = token;
|
||||
return token;
|
||||
}
|
||||
|
||||
return cachedToken;
|
||||
};
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
StreamingFrameOptions,
|
||||
} from '@grafana/runtime/src/services/live';
|
||||
import { BackendDataSourceResponse } from '@grafana/runtime/src/utils/queryResponse';
|
||||
import { loadUrlToken } from 'app/core/utils/urlToken';
|
||||
|
||||
import { StreamingResponseData } from '../data/utils';
|
||||
|
||||
@@ -66,7 +67,14 @@ export class CentrifugeService implements CentrifugeSrv {
|
||||
|
||||
constructor(private deps: CentrifugeSrvDeps) {
|
||||
this.dataStreamSubscriberReadiness = deps.dataStreamSubscriberReadiness.pipe(share(), startWith(true));
|
||||
const liveUrl = `${deps.appUrl.replace(/^http/, 'ws')}/api/live/ws`;
|
||||
|
||||
let liveUrl = `${deps.appUrl.replace(/^http/, 'ws')}/api/live/ws`;
|
||||
|
||||
const token = loadUrlToken();
|
||||
if (token !== null && token !== '') {
|
||||
liveUrl += '?auth_token=' + token;
|
||||
}
|
||||
|
||||
this.centrifuge = new Centrifuge(liveUrl, {
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user