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 -1
View File
@@ -57,7 +57,7 @@ function ExampleContextProvider({ children }) {
return (
<ExampleContext.Provider value={{ example: 'value' }}>
{children}
</TrackedMeasurementsContext.Provider>
</ExampleContext.Provider>
);
}
+7 -5
View File
@@ -63,9 +63,8 @@ All use the `ACTIVE_VIEWPORT::CORNERSTONE` context.
## Viewport Module
Our Viewport wraps [cornerstonejs/react-cornerstone-viewport][react-viewport]
and is connected the redux store. This module is the most prone to change as we
hammer out our Viewport interface.
Our Viewport wraps [cornerstonejs/react-cornerstone-viewport][react-viewport].
This module is the most prone to change as we hammer out our Viewport interface.
## Tool Configuration
@@ -87,10 +86,12 @@ Tools can be configured through extension configuration using the tools key:
## Annotate Tools Configuration
*We currently support one property for annotation tools.*
_We currently support one property for annotation tools._
### Hide handles
This extension configuration allows you to toggle on/off handle rendering for all annotate tools:
This extension configuration allows you to toggle on/off handle rendering for
all annotate tools:
```js
...
@@ -119,3 +120,4 @@ This extension configuration allows you to toggle on/off handle rendering for al
[cornerstone-tools]: https://github.com/cornerstonejs/cornerstoneTools
[cornerstone]: https://github.com/cornerstonejs/cornerstone
<!-- prettier-ignore-end -->
```
+4 -1
View File
@@ -5,7 +5,7 @@ import csTools from 'cornerstone-tools';
import merge from 'lodash.merge';
import getTools, { toolsGroupedByType } from './utils/getTools.js';
import initCornerstoneTools from './initCornerstoneTools.js';
import './initWADOImageLoader.js';
import initWADOImageLoader from './initWADOImageLoader.js';
import getCornerstoneMeasurementById from './utils/getCornerstoneMeasurementById';
import measurementServiceMappingsFactory from './utils/measurementServiceMappings/measurementServiceMappingsFactory';
import { setEnabledElement } from './state';
@@ -69,6 +69,7 @@ export default function init({
MeasurementService,
DisplaySetService,
ToolBarService,
UserAuthenticationService,
} = servicesManager.services;
const tools = getTools();
@@ -275,6 +276,8 @@ export default function init({
cs.metaData.addProvider(metadataProvider.get.bind(metadataProvider), 9999);
initWADOImageLoader(UserAuthenticationService);
// ~~
const defaultCsToolsConfig = csToolsConfig || {
globalToolSyncEnabled: false, // hold on to your pants!
@@ -2,17 +2,40 @@ import cornerstone from 'cornerstone-core';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
import dicomParser from 'dicom-parser';
//import { initWebWorkers } from './utils/index.js';
let initialized = false;
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
function initWebWorkers() {
const config = {
maxWebWorkers: Math.max(navigator.hardwareConcurrency - 1, 1),
startWebWorkersOnDemand: true,
taskConfiguration: {
decodeTask: {
initializeCodecsOnStartup: false,
usePDFJS: false,
strict: false,
},
},
};
cornerstoneWADOImageLoader.configure({
beforeSend: function(xhr) {
/*const headers = OHIF.DICOMWeb.getAuthorizationHeader();
if (!initialized) {
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
initialized = true;
}
}
if (headers.Authorization) {
xhr.setRequestHeader('Authorization', headers.Authorization);
}*/
},
});
export default function initWADOImageLoader(UserAuthenticationService) {
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
cornerstoneWADOImageLoader.configure({
beforeSend: function(xhr) {
const headers = UserAuthenticationService.getAuthorizationHeader();
if (headers && headers.Authorization) {
xhr.setRequestHeader('Authorization', headers.Authorization);
}
},
});
initWebWorkers();
}
@@ -1,22 +0,0 @@
import { redux } from '@ohif/core';
const { setLayout } = redux.actions;
/**
* Update the current layout with a simple Cornerstone one
*
* @return void
*/
const setCornerstoneLayout = () => {
const layout = {
numRows: 1,
numColumns: 1,
viewports: [{ plugin: 'cornerstone' }],
};
const action = setLayout(layout);
window.store.dispatch(action);
};
export default setCornerstoneLayout;
@@ -38,7 +38,7 @@ const EXPLICIT_VR_LITTLE_ENDIAN = '1.2.840.10008.1.2.1';
* @param {bool} supportsReject - Whether the server supports reject calls (i.e. DCM4CHEE)
* @param {bool} lazyLoadStudy - "enableStudyLazyLoad"; Request series meta async instead of blocking
*/
function createDicomWebApi(dicomWebConfig) {
function createDicomWebApi(dicomWebConfig, UserAuthenticationService) {
const {
qidoRoot,
wadoRoot,
@@ -46,15 +46,17 @@ function createDicomWebApi(dicomWebConfig) {
supportsFuzzyMatching,
supportsWildcard,
supportsReject,
requestOptions,
} = dicomWebConfig;
const qidoConfig = {
url: qidoRoot,
// headers: DICOMWeb.getAuthorizationHeader(server),
headers: UserAuthenticationService.getAuthorizationHeader(),
};
const wadoConfig = {
url: wadoRoot,
headers: UserAuthenticationService.getAuthorizationHeader(),
};
// TODO -> Two clients sucks, but its better than 1000.
@@ -78,7 +80,12 @@ function createDicomWebApi(dicomWebConfig) {
query: {
studies: {
mapParams: mapParams.bind(),
search: async function (origParams) {
search: async function(origParams) {
const headers = UserAuthenticationService.getAuthorizationHeader();
if (headers) {
qidoDicomWebClient.headers = headers;
}
const { studyInstanceUid, seriesInstanceUid, ...mappedParams } =
mapParams(origParams, {
supportsFuzzyMatching,
@@ -98,7 +105,12 @@ function createDicomWebApi(dicomWebConfig) {
},
series: {
// mapParams: mapParams.bind(),
search: async function (studyInstanceUid) {
search: async function(studyInstanceUid) {
const headers = UserAuthenticationService.getAuthorizationHeader();
if (headers) {
qidoDicomWebClient.headers = headers;
}
const results = await seriesInStudy(
qidoDicomWebClient,
studyInstanceUid
@@ -109,14 +121,20 @@ function createDicomWebApi(dicomWebConfig) {
// processResults: processResults.bind(),
},
instances: {
search: (studyInstanceUid, queryParameters) =>
search: (studyInstanceUid, queryParameters) => {
const headers = UserAuthenticationService.getAuthorizationHeader();
if (headers) {
qidoDicomWebClient.headers = headers;
}
qidoSearch.call(
undefined,
qidoDicomWebClient,
studyInstanceUid,
null,
queryParameters
),
);
},
},
},
retrieve: {
@@ -125,6 +143,11 @@ function createDicomWebApi(dicomWebConfig) {
// Conduct query, return a promise like others
// Await this call and add to DicomMetadataStore after receiving result
metadata: (queryParams, callback) => {
const headers = UserAuthenticationService.getAuthorizationHeader();
if (headers) {
wadoDicomWebClient.headers = headers;
}
let { StudyInstanceUIDs } = urlUtil.parse(queryParams, true);
StudyInstanceUIDs = urlUtil.paramString.parseParam(StudyInstanceUIDs);
@@ -164,6 +187,11 @@ function createDicomWebApi(dicomWebConfig) {
},
store: {
dicom: async dataset => {
const headers = UserAuthenticationService.getAuthorizationHeader();
if (headers) {
wadoDicomWebClient.headers = headers;
}
const meta = {
FileMetaInformationVersion:
dataset._meta.FileMetaInformationVersion.Value,
@@ -196,6 +224,11 @@ function createDicomWebApi(dicomWebConfig) {
sortFunction,
madeInClient = false,
} = {}) => {
const headers = UserAuthenticationService.getAuthorizationHeader();
if (headers) {
wadoDicomWebClient.headers = headers;
}
if (!StudyInstanceUID) {
throw new Error(
'Unable to query for SeriesMetadata without StudyInstanceUID'
@@ -2,7 +2,9 @@ async function getStudiesForPatientByStudyInstanceUID(
dataSource,
StudyInstanceUID
) {
if (StudyInstanceUID === undefined) return;
if (StudyInstanceUID === undefined) {
return;
}
// TODO: The `DicomMetadataStore` should short-circuit both of these requests
// Data _could_ be here from route query, or if using JSON data source
// We could also force this to "await" these values being available in the DICOMStore?
@@ -1,37 +0,0 @@
import React, { useState } from 'react';
const HelloWorldContext = React.createContext({
message: 'HelloWorldContextTesting',
setMessage: () => { },
});
HelloWorldContext.displayName = 'HelloWorldContext';
function HelloWorldContextProvider({ children }) {
const [message, setMessage] = useState('HelloWorldContextTesting');
return (
<HelloWorldContext.Provider
value={{
message,
setMessage,
}}
>
{children}
</HelloWorldContext.Provider>
);
}
function getContextModule() {
return [
{
name: 'HelloWorldContext',
context: HelloWorldContext,
provider: HelloWorldContextProvider,
},
];
}
export { HelloWorldContext };
export default getContextModule;
-2
View File
@@ -1,4 +1,3 @@
import getContextModule from './getContextModule.js';
import getDataSourcesModule from './getDataSourcesModule.js';
import getLayoutTemplateModule from './getLayoutTemplateModule.js';
import getPanelModule from './getPanelModule.js';
@@ -13,7 +12,6 @@ export default {
* Only required property. Should be a unique value across all extensions.
*/
id,
getContextModule,
getDataSourcesModule,
getHangingProtocolModule,
getLayoutTemplateModule,
@@ -2,7 +2,9 @@ async function getStudiesForPatientByStudyInstanceUID(
dataSource,
StudyInstanceUID
) {
if (StudyInstanceUID === undefined) return;
if (StudyInstanceUID === undefined) {
return;
}
// TODO: The `DicomMetadataStore` should short-circuit both of these requests
// Data _could_ be here from route query, or if using JSON data source
// We could also force this to "await" these values being available in the DICOMStore?