feat: Support for OpenID Connect (#2431)

* feat: Add OpenID Connect support, speed up docker rebuilds

* fix: Switch Google Cloud API URL to v1

* chore: Remove redux-oidc and use our own components instead
This commit is contained in:
Erik Ziegler authored and GitHub committed 2021-06-23 20:41:27 +02:00
1 parent 5643f8f6d2
commit e7b32cc51e
50 files changed
+2746 -2109

No files matched your search

+1
View File
@@ -41,6 +41,7 @@
"dicomweb-client": "^0.6.0",
"isomorphic-base64": "^1.0.2",
"lodash.merge": "^4.6.1",
"lodash.clonedeep": "^4.5.0",
"moment": "^2.24.0",
"mousetrap": "^1.6.3",
"query-string": "^6.14.0",
@@ -10,7 +10,7 @@ import user from '../user';
* @param {string|function} [server.requestOptions.auth]
* @returns {Object} { Authorization }
*/
export default function getAuthorizationHeader({ requestOptions } = {}) {
export default function getAuthorizationHeader({ requestOptions } = {}, user) {
const headers = {};
// Check for OHIF.user since this can also be run on the server
@@ -64,11 +64,11 @@ describe('getAuthorizationHeader', () => {
it('should return an Authorization with accessToken when server is not defined and there is an accessToken', () => {
user.getAccessToken.mockImplementationOnce(() => 'MOCKED_TOKEN');
const authentication = getAuthorizationHeader({});
const exptecteHeaderBasedOnUserAccessToekn = {
const authentication = getAuthorizationHeader({}, user);
const expectedHeaderBasedOnUserAccessToken = {
Authorization: 'Bearer MOCKED_TOKEN',
};
expect(authentication).toEqual(exptecteHeaderBasedOnUserAccessToekn);
expect(authentication).toEqual(expectedHeaderBasedOnUserAccessToken);
});
});
@@ -439,7 +439,7 @@ class MetadataProvider {
_getUIDsFromImageID(imageId) {
if (imageId.includes('wadors:')) {
const strippedImageId = imageId.split('studies/')[1];
const strippedImageId = imageId.split('/studies/')[1];
const splitImageId = strippedImageId.split('/');
return {
@@ -277,13 +277,16 @@ export default class ExtensionManager {
};
_initDataSourcesModule(extensionModule, extensionId, dataSources = []) {
const { UserAuthenticationService } = this._servicesManager.services;
extensionModule.forEach(element => {
const namespace = `${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`;
dataSources.forEach(dataSource => {
if (dataSource.namespace === namespace) {
const dataSourceInstance = element.createDataSource(
dataSource.configuration
dataSource.configuration,
UserAuthenticationService
);
if (this.dataSourceMap[dataSource.sourceName]) {
@@ -15,6 +15,10 @@ describe('ExtensionManager.js', () => {
};
servicesManager = {
registerService: jest.fn(),
services: {
// Required for DataSource Module initiation
UserAuthenticationService: jest.fn(),
},
};
appConfig = {
testing: true,
@@ -100,7 +104,6 @@ describe('ExtensionManager.js', () => {
extensionManager.registerExtension(undefinedExtension);
}).toThrow('Attempting to register a null/undefined extension.');
expect(() => {
extensionManager.registerExtension(nullExtension);
}).toThrow('Attempting to register a null/undefined extension.');
@@ -185,7 +188,7 @@ describe('ExtensionManager.js', () => {
hotkeysManager: undefined,
appConfig,
configuration: extensionConfiguration,
extensionManager
extensionManager,
});
}
});
@@ -220,7 +223,7 @@ describe('ExtensionManager.js', () => {
},
getContextModule: () => {
return [{}];
}
},
};
extensionManager.registerExtension(extension);
+3
View File
@@ -26,6 +26,7 @@ import {
ViewportGridService,
HangingProtocolService,
pubSubServiceInterface,
UserAuthenticationService,
} from './services';
import IWebApiDataSource from './DataSources/IWebApiDataSource';
@@ -66,6 +67,7 @@ const OHIF = {
ToolBarService, // TODO: TYPO
ViewportGridService,
HangingProtocolService,
UserAuthenticationService,
IWebApiDataSource,
DicomMetadataStore,
pubSubServiceInterface,
@@ -101,6 +103,7 @@ export {
ToolBarService,
ViewportGridService,
HangingProtocolService,
UserAuthenticationService,
IWebApiDataSource,
DicomMetadataStore,
pubSubServiceInterface,
+2 -1
View File
@@ -34,9 +34,10 @@ describe('Top level exports', () => {
'ToolBarService',
'ViewportGridService',
'HangingProtocolService',
'UserAuthenticationService',
'IWebApiDataSource',
'DicomMetadataStore',
'pubSubServiceInterface'
'pubSubServiceInterface',
].sort();
const exports = Object.keys(OHIF).sort();
@@ -1,4 +1,4 @@
import { cloneDeep } from 'lodash';
import cloneDeep from 'lodash.clonedeep';
import pubSubServiceInterface from '../_shared/pubSubServiceInterface';
import sortBy from '../../utils/sortBy.js';
import ProtocolEngine from './ProtocolEngine';
@@ -0,0 +1,94 @@
const name = 'UserAuthenticationService';
const publicAPI = {
name,
getState: _getState,
setUser: _setUser,
getUser: _getUser,
getAuthorizationHeader: _getAuthorizationHeader,
handleUnauthenticated: _handleUnauthenticated,
setServiceImplementation,
reset: _reset,
set: _set,
};
const serviceImplementation = {
_getState: () => console.warn('getState() NOT IMPLEMENTED'),
_setUser: () => console.warn('_setUser() NOT IMPLEMENTED'),
_getUser: () => console.warn('_setUser() NOT IMPLEMENTED'),
_getAuthorizationHeader: () =>
console.warn('_getAuthorizationHeader() NOT IMPLEMENTED'),
_handleUnauthenticated: () =>
console.warn('_handleUnauthenticated() NOT IMPLEMENTED'),
_reset: () => console.warn('reset() NOT IMPLEMENTED'),
_set: () => console.warn('set() NOT IMPLEMENTED'),
};
function _getState() {
return serviceImplementation._getState();
}
function _setUser(user) {
return serviceImplementation._setUser(user);
}
function _getUser() {
return serviceImplementation._getUser();
}
function _getAuthorizationHeader() {
const user = serviceImplementation._getUser();
return serviceImplementation._getAuthorizationHeader(user);
}
function _handleUnauthenticated() {
return serviceImplementation._handleUnauthenticated();
}
function _set(state) {
return serviceImplementation._set(state);
}
function _reset() {
return serviceImplementation._reset({});
}
function setServiceImplementation({
getState: getStateImplementation,
setUser: setUserImplementation,
getUser: getUserImplementation,
getAuthorizationHeader: getAuthorizationHeaderImplementation,
handleUnauthenticated: handleUnauthenticatedImplementation,
reset: resetImplementation,
set: setImplementation,
}) {
if (getStateImplementation) {
serviceImplementation._getState = getStateImplementation;
}
if (setUserImplementation) {
serviceImplementation._setUser = setUserImplementation;
}
if (getUserImplementation) {
serviceImplementation._getUser = getUserImplementation;
}
if (getAuthorizationHeaderImplementation) {
serviceImplementation._getAuthorizationHeader = getAuthorizationHeaderImplementation;
}
if (handleUnauthenticatedImplementation) {
serviceImplementation._handleUnauthenticated = handleUnauthenticatedImplementation;
}
if (resetImplementation) {
serviceImplementation._reset = resetImplementation;
}
if (setImplementation) {
serviceImplementation._set = setImplementation;
}
}
export default {
name,
create: ({ configuration = {} }) => {
return publicAPI;
},
};
@@ -0,0 +1,3 @@
import UserAuthenticationService from './UserAuthenticationService';
export default UserAuthenticationService;
+2
View File
@@ -11,6 +11,7 @@ import ViewportGridService from './ViewportGridService';
import CineService from './CineService';
import HangingProtocolService from './HangingProtocolService';
import pubSubServiceInterface from './_shared/pubSubServiceInterface';
import UserAuthenticationService from './UserAuthenticationService';
export {
MeasurementService,
@@ -26,4 +27,5 @@ export {
HangingProtocolService,
CineService,
pubSubServiceInterface,
UserAuthenticationService,
};