feat(keycloak) Optional Keycloak integration via OpenId Connect (OIDC) for Identity and Access Management (#227)
This commit is contained in:
parent
03d0798459
commit
33755f7b8b
@ -25,7 +25,9 @@ reactive-var@1.0.11
|
|||||||
reactive-dict@1.2.0
|
reactive-dict@1.2.0
|
||||||
standard-minifier-css@1.4.1
|
standard-minifier-css@1.4.1
|
||||||
standard-minifier-js@2.3.4
|
standard-minifier-js@2.3.4
|
||||||
|
accounts-base
|
||||||
|
accounts-oauth
|
||||||
|
oauth-encryption
|
||||||
|
|
||||||
# OHIF Packages
|
# OHIF Packages
|
||||||
ohif:polyfill
|
ohif:polyfill
|
||||||
@ -42,6 +44,8 @@ ohif:dicom-services
|
|||||||
ohif:dicomweb-client
|
ohif:dicomweb-client
|
||||||
ohif:hanging-protocols
|
ohif:hanging-protocols
|
||||||
ohif:metadata
|
ohif:metadata
|
||||||
|
ohif:user
|
||||||
|
ohif:user-keycloak
|
||||||
|
|
||||||
fortawesome:fontawesome
|
fortawesome:fontawesome
|
||||||
momentjs:moment@2.15.1
|
momentjs:moment@2.15.1
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
accounts-base@1.4.2
|
accounts-base@1.4.2
|
||||||
|
accounts-oauth@1.1.15
|
||||||
|
accounts-password@1.5.1
|
||||||
aldeed:collection2@2.10.0
|
aldeed:collection2@2.10.0
|
||||||
aldeed:collection2-core@1.2.0
|
aldeed:collection2-core@1.2.0
|
||||||
aldeed:schema-deny@1.1.0
|
aldeed:schema-deny@1.1.0
|
||||||
@ -38,6 +40,7 @@ ecmascript-runtime@0.7.0
|
|||||||
ecmascript-runtime-client@0.7.1
|
ecmascript-runtime-client@0.7.1
|
||||||
ecmascript-runtime-server@0.7.0
|
ecmascript-runtime-server@0.7.0
|
||||||
ejson@1.1.0
|
ejson@1.1.0
|
||||||
|
email@1.2.3
|
||||||
es5-shim@4.8.0
|
es5-shim@4.8.0
|
||||||
fastclick@1.0.13
|
fastclick@1.0.13
|
||||||
fortawesome:fontawesome@4.7.0
|
fortawesome:fontawesome@4.7.0
|
||||||
@ -77,8 +80,15 @@ momentjs:moment@2.22.2
|
|||||||
mongo@1.5.1
|
mongo@1.5.1
|
||||||
mongo-dev-server@1.1.0
|
mongo-dev-server@1.1.0
|
||||||
mongo-id@1.0.7
|
mongo-id@1.0.7
|
||||||
|
mxab:accounts-keycloak@0.0.2
|
||||||
|
mxab:keycloak-loader@0.0.2
|
||||||
|
mxab:keycloak-oauth@0.0.2
|
||||||
natestrauser:select2@4.0.3
|
natestrauser:select2@4.0.3
|
||||||
|
npm-bcrypt@0.9.3
|
||||||
npm-mongo@3.0.7
|
npm-mongo@3.0.7
|
||||||
|
oauth@1.2.3
|
||||||
|
oauth-encryption@1.3.0
|
||||||
|
oauth2@1.2.0
|
||||||
observe-sequence@1.0.16
|
observe-sequence@1.0.16
|
||||||
ohif:commands@0.0.1
|
ohif:commands@0.0.1
|
||||||
ohif:core@0.0.1
|
ohif:core@0.0.1
|
||||||
@ -98,6 +108,8 @@ ohif:studies@0.0.1
|
|||||||
ohif:study-list@0.0.1
|
ohif:study-list@0.0.1
|
||||||
ohif:themes@0.0.1
|
ohif:themes@0.0.1
|
||||||
ohif:themes-common@0.0.1
|
ohif:themes-common@0.0.1
|
||||||
|
ohif:user@0.0.1
|
||||||
|
ohif:user-keycloak@0.0.1
|
||||||
ohif:viewerbase@0.0.1
|
ohif:viewerbase@0.0.1
|
||||||
ohif:wadoproxy@0.0.1
|
ohif:wadoproxy@0.0.1
|
||||||
ordered-dict@1.1.0
|
ordered-dict@1.1.0
|
||||||
@ -113,11 +125,13 @@ retry@1.1.0
|
|||||||
routepolicy@1.0.13
|
routepolicy@1.0.13
|
||||||
service-configuration@1.0.11
|
service-configuration@1.0.11
|
||||||
session@1.1.7
|
session@1.1.7
|
||||||
|
sha@1.0.9
|
||||||
shell-server@0.3.1
|
shell-server@0.3.1
|
||||||
silentcicero:jszip@0.0.4
|
silentcicero:jszip@0.0.4
|
||||||
socket-stream-client@0.2.2
|
socket-stream-client@0.2.2
|
||||||
spacebars@1.0.15
|
spacebars@1.0.15
|
||||||
spacebars-compiler@1.1.3
|
spacebars-compiler@1.1.3
|
||||||
|
srp@1.0.10
|
||||||
standard-app-packages@1.0.9
|
standard-app-packages@1.0.9
|
||||||
standard-minifier-css@1.4.1
|
standard-minifier-css@1.4.1
|
||||||
standard-minifier-js@2.3.4
|
standard-minifier-js@2.3.4
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import { Session } from 'meteor/session';
|
import { Session } from 'meteor/session';
|
||||||
import { Router } from 'meteor/clinical:router';
|
import { Router } from 'meteor/clinical:router';
|
||||||
@ -8,7 +9,7 @@ Template.ohifViewer.onCreated(() => {
|
|||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
instance.headerClasses = new ReactiveVar('');
|
instance.headerClasses = new ReactiveVar('');
|
||||||
|
|
||||||
OHIF.header.dropdown.setItems([{
|
const headerItems = [{
|
||||||
action: () => OHIF.ui.showDialog('serverInformationModal'),
|
action: () => OHIF.ui.showDialog('serverInformationModal'),
|
||||||
text: 'Server Information',
|
text: 'Server Information',
|
||||||
icon: 'fa fa-server fa-lg',
|
icon: 'fa fa-server fa-lg',
|
||||||
@ -28,7 +29,18 @@ Template.ohifViewer.onCreated(() => {
|
|||||||
action: () => OHIF.ui.showDialog('aboutModal'),
|
action: () => OHIF.ui.showDialog('aboutModal'),
|
||||||
text: 'About',
|
text: 'About',
|
||||||
icon: 'fa fa-info'
|
icon: 'fa fa-info'
|
||||||
}]);
|
}];
|
||||||
|
|
||||||
|
if (Meteor.user()) {
|
||||||
|
items.push({
|
||||||
|
action: OHIF.user.logout,
|
||||||
|
text: 'Logout',
|
||||||
|
iconClasses: 'logout',
|
||||||
|
iconSvgUse: 'packages/ohif_viewerbase/assets/user-menu-icons.svg#logout'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
OHIF.header.dropdown.setItems(headerItems);
|
||||||
|
|
||||||
instance.autorun(() => {
|
instance.autorun(() => {
|
||||||
const currentRoute = Router.current();
|
const currentRoute = Router.current();
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Meteor } from 'meteor/meteor';
|
import { Meteor } from 'meteor/meteor';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { cornerstoneWADOImageLoader } from 'meteor/ohif:cornerstone';
|
import { cornerstoneWADOImageLoader } from 'meteor/ohif:cornerstone';
|
||||||
|
import { Accounts } from "meteor/accounts-base";
|
||||||
|
|
||||||
Meteor.startup(function() {
|
Meteor.startup(function() {
|
||||||
const maxWebWorkers = Math.max(navigator.hardwareConcurrency - 1, 1);
|
const maxWebWorkers = Math.max(navigator.hardwareConcurrency - 1, 1);
|
||||||
@ -19,4 +20,21 @@ Meteor.startup(function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
|
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
|
||||||
|
|
||||||
|
cornerstoneWADOImageLoader.configure({
|
||||||
|
beforeSend: function(xhr) {
|
||||||
|
const userId = Meteor.userId();
|
||||||
|
const accessToken = OHIF.user.getAccessToken();
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
xhr.setRequestHeader("Authorization", `Bearer ${accessToken}`);
|
||||||
|
} else {
|
||||||
|
const loginToken = Accounts._storedLoginToken();
|
||||||
|
if (userId && loginToken) {
|
||||||
|
xhr.setRequestHeader("x-user-id", userId);
|
||||||
|
xhr.setRequestHeader("x-auth-token", loginToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
7
Packages/ohif-dicomweb-client/src/getAccessToken.js
Normal file
7
Packages/ohif-dicomweb-client/src/getAccessToken.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export default function getAccessToken() {
|
||||||
|
if (!global.window || !window.sessionStorage || !sessionStorage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessionStorage.token;
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ import getModalities from './getModalities.js';
|
|||||||
import getName from './getName.js';
|
import getName from './getName.js';
|
||||||
import getNumber from './getNumber.js';
|
import getNumber from './getNumber.js';
|
||||||
import getString from './getString.js';
|
import getString from './getString.js';
|
||||||
|
import getAccessToken from './getAccessToken.js';
|
||||||
import makeRequest from './makeRequest.js';
|
import makeRequest from './makeRequest.js';
|
||||||
|
|
||||||
const DICOMWeb = {
|
const DICOMWeb = {
|
||||||
@ -17,6 +18,7 @@ const DICOMWeb = {
|
|||||||
getName,
|
getName,
|
||||||
getNumber,
|
getNumber,
|
||||||
getString,
|
getString,
|
||||||
|
getAccessToken,
|
||||||
makeRequest
|
makeRequest
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Meteor } from "meteor/meteor";
|
import { Meteor } from "meteor/meteor";
|
||||||
import URL from 'url-parse';
|
import URL from 'url-parse';
|
||||||
import 'isomorphic-fetch';
|
import 'isomorphic-fetch';
|
||||||
|
import getAccessToken from './getAccessToken.js';
|
||||||
|
|
||||||
async function makeRequest(url, options) {
|
async function makeRequest(url, options) {
|
||||||
const parsed = new URL(url);
|
const parsed = new URL(url);
|
||||||
@ -10,8 +11,7 @@ async function makeRequest(url, options) {
|
|||||||
headers: {}
|
headers: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Clean this up
|
const accessToken = getAccessToken();
|
||||||
const accessToken = false //Meteor.user().services.keycloak.accessToken;
|
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
requestOpt.headers = {
|
requestOpt.headers = {
|
||||||
Authorization: `Bearer ${accessToken}`
|
Authorization: `Bearer ${accessToken}`
|
||||||
|
|||||||
@ -255,6 +255,11 @@ export const PublicServerConfig = new SimpleSchema({
|
|||||||
label: 'Creates demo user on startup and show TestDrive button',
|
label: 'Creates demo user on startup and show TestDrive button',
|
||||||
defaultValue: true
|
defaultValue: true
|
||||||
},
|
},
|
||||||
|
userAuthenticationRoutesEnabled: {
|
||||||
|
type: Boolean,
|
||||||
|
label: 'Enables routing to /login page.',
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
ui: {
|
ui: {
|
||||||
type: UISettings,
|
type: UISettings,
|
||||||
label: 'UI Settings'
|
label: 'UI Settings'
|
||||||
|
|||||||
@ -101,8 +101,6 @@ OHIF.studies.services.QIDO.Studies = (server, filter) => {
|
|||||||
const url = filterToQIDOURL(server, filter);
|
const url = filterToQIDOURL(server, filter);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.warn(DICOMWeb);
|
|
||||||
|
|
||||||
DICOMWeb.getJSON(url, server.requestOptions).then(result => {
|
DICOMWeb.getJSON(url, server.requestOptions).then(result => {
|
||||||
const studies = resultDataToStudies(result);
|
const studies = resultDataToStudies(result);
|
||||||
|
|
||||||
|
|||||||
10
Packages/ohif-user-keycloak/client/main.js
Normal file
10
Packages/ohif-user-keycloak/client/main.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
|
||||||
|
if (!Meteor.settings.public ||
|
||||||
|
!Meteor.settings.public.custom ||
|
||||||
|
!Meteor.settings.public.custom.keycloak) {
|
||||||
|
|
||||||
|
console.log('To use the ohif-user-keycloak package, you must add relevant Keycloak settings to Meteor.settings.public.custom.keycloak (client-side).');
|
||||||
|
} else {
|
||||||
|
require('../imports/client/index.js')
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
<template name="keycloakLoginButton">
|
||||||
|
<hr/>
|
||||||
|
<button class="form-control btn js-login-keycloak">Login with Keycloak</button>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { Router } from 'meteor/clinical:router';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
import './keycloakLoginButton.html';
|
||||||
|
|
||||||
|
Template.keycloakLoginButton.events({
|
||||||
|
'click .js-login-keycloak'() {
|
||||||
|
Meteor.loginWithMeteorKeycloak({}, function(error) {
|
||||||
|
if (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Router.go('/studylist');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
25
Packages/ohif-user-keycloak/imports/client/handlers.js
Normal file
25
Packages/ohif-user-keycloak/imports/client/handlers.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Accounts } from 'meteor/accounts-base';
|
||||||
|
import { Meteor } from "meteor/meteor";
|
||||||
|
|
||||||
|
OHIF.user.getAccessToken = () => {
|
||||||
|
const user = Meteor.user();
|
||||||
|
if (!user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.services.keycloak.accessToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
Accounts.onLogin(() => {
|
||||||
|
Meteor.subscribe('user.services.keycloak', () => {
|
||||||
|
sessionStorage.token = OHIF.user.getAccessToken();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Accounts.onLogout(() => {
|
||||||
|
const authServerUrl = Meteor.settings.public.custom.keycloak.authServerUrl;
|
||||||
|
const realm = Meteor.settings.public.custom.keycloak.realmName;
|
||||||
|
const redirectUri = Meteor.absoluteUrl('login');
|
||||||
|
const logoutUrl = `${authServerUrl}/realms/${realm}/protocol/openid-connect/logout?redirect_uri=${redirectUri}`;
|
||||||
|
window.location = logoutUrl;
|
||||||
|
});
|
||||||
3
Packages/ohif-user-keycloak/imports/client/index.js
Normal file
3
Packages/ohif-user-keycloak/imports/client/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import './handlers';
|
||||||
|
import './setup.js';
|
||||||
|
import './components/keycloakLoginButton.js';
|
||||||
30
Packages/ohif-user-keycloak/imports/client/setup.js
Normal file
30
Packages/ohif-user-keycloak/imports/client/setup.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Router } from 'meteor/clinical:router';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
Router.waitOn(function() {
|
||||||
|
return [
|
||||||
|
Meteor.subscribe('user.services.keycloak'),
|
||||||
|
];
|
||||||
|
}, { except: ['userLogin'] });
|
||||||
|
|
||||||
|
Router.onBeforeAction(function() {
|
||||||
|
// Check if user is signed in
|
||||||
|
if (!Meteor.userId() && !Meteor.loggingIn()) {
|
||||||
|
this.redirect('userLogin');
|
||||||
|
} else {
|
||||||
|
this.next();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
except: ['userLogin', 'entrySignUp', 'forgotPassword', 'resetPassword']
|
||||||
|
});
|
||||||
|
|
||||||
|
OHIF.user.additionalLoginButtons = OHIF.user.additionalLoginButtons || [];
|
||||||
|
|
||||||
|
OHIF.user.additionalLoginButtons.push({
|
||||||
|
template: 'keycloakLoginButton'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!Meteor.settings.public.userAuthenticationRoutesEnabled) {
|
||||||
|
OHIF.log.error('Please set Meteor.settings.public.userAuthenticationRoutesEnabled=true');
|
||||||
|
}
|
||||||
51
Packages/ohif-user-keycloak/imports/server/setup.js
Normal file
51
Packages/ohif-user-keycloak/imports/server/setup.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { ServiceConfiguration } from 'meteor/service-configuration';
|
||||||
|
import { Accounts } from "meteor/accounts-base";
|
||||||
|
|
||||||
|
console.log('Keycloak settings were found! Enabling Keycloak integration.');
|
||||||
|
|
||||||
|
ServiceConfiguration.configurations.upsert(
|
||||||
|
{ service: 'keycloak' },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
"realm": Meteor.settings.public.custom.keycloak.realmName,
|
||||||
|
"auth-server-url": Meteor.settings.public.custom.keycloak.authServerUrl,
|
||||||
|
"auth_redirect_uri": Meteor.settings.keycloak.authRedirectUri,
|
||||||
|
"ssl-required": Meteor.settings.keycloak.sslRequired,
|
||||||
|
"resource": Meteor.settings.keycloak.clientId,
|
||||||
|
"client_id": Meteor.settings.keycloak.clientId,
|
||||||
|
"loginStyle": Meteor.settings.keycloak.loginStyle,
|
||||||
|
"secret": Meteor.settings.keycloak.clientSecret,
|
||||||
|
"realm-public-key": Meteor.settings.keycloak.realmPublicKey,
|
||||||
|
"public-client": false,
|
||||||
|
"use-resource-role-mappings": false,
|
||||||
|
"bearer-only": false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Meteor.publish('user.services.keycloak', function() {
|
||||||
|
const userId = this.userId;
|
||||||
|
if (!userId) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Meteor.users.find(userId, {
|
||||||
|
fields: {
|
||||||
|
'services.keycloak': 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Accounts.onLogout(({ user }) => {
|
||||||
|
if (!user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase any Keycloak token that exists
|
||||||
|
Meteor.users.update(user._id, {
|
||||||
|
$unset: {
|
||||||
|
'services.keycloak': 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
26
Packages/ohif-user-keycloak/package.js
Normal file
26
Packages/ohif-user-keycloak/package.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Package.describe({
|
||||||
|
name: 'ohif:user-keycloak',
|
||||||
|
summary: 'OHIF Integration with Keycloak for Identity and Access Management',
|
||||||
|
version: '0.0.1'
|
||||||
|
});
|
||||||
|
|
||||||
|
Package.onUse(function(api) {
|
||||||
|
api.versionsFrom('1.6');
|
||||||
|
|
||||||
|
api.use('templating');
|
||||||
|
api.use('ecmascript');
|
||||||
|
api.use('service-configuration');
|
||||||
|
api.use('accounts-base');
|
||||||
|
|
||||||
|
// Our custom packages
|
||||||
|
api.use('ohif:core');
|
||||||
|
api.use('ohif:user');
|
||||||
|
|
||||||
|
api.use('mxab:keycloak-oauth@0.0.2');
|
||||||
|
api.use('mxab:keycloak-loader@0.0.2');
|
||||||
|
api.use('mxab:accounts-keycloak');
|
||||||
|
|
||||||
|
// Client imports
|
||||||
|
api.mainModule('client/main.js', 'client');
|
||||||
|
api.mainModule('server/main.js', 'server');
|
||||||
|
});
|
||||||
11
Packages/ohif-user-keycloak/server/main.js
Normal file
11
Packages/ohif-user-keycloak/server/main.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
|
||||||
|
if (!Meteor.settings.public ||
|
||||||
|
!Meteor.settings.public.custom ||
|
||||||
|
!Meteor.settings.public.custom.keycloak ||
|
||||||
|
!Meteor.settings.keycloak) {
|
||||||
|
|
||||||
|
console.log('To use the ohif-user-keycloak package, you must add relevant Keycloak settings to Meteor.settings.keycloak (server-side).');
|
||||||
|
} else {
|
||||||
|
require('../imports/server/setup.js')
|
||||||
|
}
|
||||||
@ -12,6 +12,10 @@
|
|||||||
{{>section 'userLoginFieldsAfter'}}
|
{{>section 'userLoginFieldsAfter'}}
|
||||||
<hr class="m-t-0 m-b-2">
|
<hr class="m-t-0 m-b-2">
|
||||||
{{#button action='login' class='form-control btn btn-primary'}}Enter{{/button}}
|
{{#button action='login' class='form-control btn btn-primary'}}Enter{{/button}}
|
||||||
|
|
||||||
|
{{ #each additionalLoginButtons }}
|
||||||
|
{{>Template.dynamic template=template}}
|
||||||
|
{{ /each }}
|
||||||
{{/form}}
|
{{/form}}
|
||||||
</div>
|
</div>
|
||||||
{{>section 'userLoginAfter'}}
|
{{>section 'userLoginAfter'}}
|
||||||
|
|||||||
@ -33,3 +33,9 @@ Template.userLogin.onCreated(() => {
|
|||||||
|
|
||||||
instance.schema = OHIF.user.schema;
|
instance.schema = OHIF.user.schema;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Template.userLogin.helpers({
|
||||||
|
additionalLoginButtons() {
|
||||||
|
return OHIF.user.additionalLoginButtons || [];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
5
Packages/ohif-user/client/lib/getAccessToken.js
Normal file
5
Packages/ohif-user/client/lib/getAccessToken.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
OHIF.user.getAccessToken = () => {};
|
||||||
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import './data';
|
import './data';
|
||||||
import './getName';
|
import './getName';
|
||||||
|
import './getAccessToken';
|
||||||
import './login';
|
import './login';
|
||||||
import './logout';
|
import './logout';
|
||||||
import './schema';
|
import './schema';
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { Router } from 'meteor/clinical:router';
|
import { Router } from 'meteor/clinical:router';
|
||||||
|
|
||||||
Router.route('/login', function() {
|
if (Meteor.settings.public.userAuthenticationRoutesEnabled === true) {
|
||||||
this.layout('mainLayout', { data: {} });
|
Router.route('/login', function() {
|
||||||
this.render('userLogin');
|
this.layout('layout', { data: {} });
|
||||||
}, { name: 'userLogin' });
|
this.render('userLogin');
|
||||||
|
}, { name: 'userLogin' });
|
||||||
|
}
|
||||||
|
|||||||
26
Packages/ohif-viewerbase/assets/user-menu-icons.svg
Normal file
26
Packages/ohif-viewerbase/assets/user-menu-icons.svg
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<symbol id="theme" viewBox="0 0 24 24">
|
||||||
|
<title>Theme</title>
|
||||||
|
<path d="M17.484 12c0.844 0 1.5-0.656 1.5-1.5s-0.656-1.5-1.5-1.5-1.5 0.656-1.5 1.5 0.656 1.5 1.5 1.5zM14.484 8.016c0.844 0 1.5-0.656 1.5-1.5s-0.656-1.5-1.5-1.5-1.5 0.656-1.5 1.5 0.656 1.5 1.5 1.5zM9.516 8.016c0.844 0 1.5-0.656 1.5-1.5s-0.656-1.5-1.5-1.5-1.5 0.656-1.5 1.5 0.656 1.5 1.5 1.5zM6.516 12c0.844 0 1.5-0.656 1.5-1.5s-0.656-1.5-1.5-1.5-1.5 0.656-1.5 1.5 0.656 1.5 1.5 1.5zM12 3c4.969 0 9 3.609 9 8.016 0 2.766-2.25 4.969-5.016 4.969h-1.734c-0.844 0-1.5 0.656-1.5 1.5 0 0.375 0.141 0.703 0.375 0.984s0.375 0.656 0.375 1.031c0 0.844-0.656 1.5-1.5 1.5-4.969 0-9-4.031-9-9s4.031-9 9-9z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="log" viewBox="0 0 24 24">
|
||||||
|
<title>Log</title>
|
||||||
|
<path d="M9.516 14.016c2.484 0 4.5-2.016 4.5-4.5s-2.016-4.5-4.5-4.5-4.5 2.016-4.5 4.5 2.016 4.5 4.5 4.5zM15.516 14.016l4.969 4.969-1.5 1.5-4.969-4.969v-0.797l-0.281-0.281c-1.125 0.984-2.625 1.547-4.219 1.547-3.609 0-6.516-2.859-6.516-6.469s2.906-6.516 6.516-6.516 6.469 2.906 6.469 6.516c0 1.594-0.563 3.094-1.547 4.219l0.281 0.281h0.797z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="server" viewBox="0 0 24 28">
|
||||||
|
<title>Server</title>
|
||||||
|
<path d="M12 12c4.703 0 9.422-0.844 12-2.656v2.656c0 2.203-5.375 4-12 4s-12-1.797-12-4v-2.656c2.578 1.813 7.297 2.656 12 2.656zM12 24c4.703 0 9.422-0.844 12-2.656v2.656c0 2.203-5.375 4-12 4s-12-1.797-12-4v-2.656c2.578 1.813 7.297 2.656 12 2.656zM12 18c4.703 0 9.422-0.844 12-2.656v2.656c0 2.203-5.375 4-12 4s-12-1.797-12-4v-2.656c2.578 1.813 7.297 2.656 12 2.656zM12 0c6.625 0 12 1.797 12 4v2c0 2.203-5.375 4-12 4s-12-1.797-12-4v-2c0-2.203 5.375-4 12-4z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="study-list" viewBox="0 0 24 24">
|
||||||
|
<title>Study List</title>
|
||||||
|
<path d="M9 5.016h12v3.984h-12v-3.984zM9 18.984v-3.984h12v3.984h-12zM9 14.016v-4.031h12v4.031h-12zM3.984 9v-3.984h4.031v3.984h-4.031zM3.984 18.984v-3.984h4.031v3.984h-4.031zM3.984 14.016v-4.031h4.031v4.031h-4.031z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="logout" viewBox="0 0 24 28">
|
||||||
|
<title>Logout</title>
|
||||||
|
<path d="M24 14c0 6.609-5.391 12-12 12s-12-5.391-12-12c0-3.797 1.75-7.297 4.797-9.578 0.891-0.672 2.141-0.5 2.797 0.391 0.672 0.875 0.484 2.141-0.391 2.797-2.031 1.531-3.203 3.859-3.203 6.391 0 4.406 3.594 8 8 8s8-3.594 8-8c0-2.531-1.172-4.859-3.203-6.391-0.875-0.656-1.062-1.922-0.391-2.797 0.656-0.891 1.922-1.062 2.797-0.391 3.047 2.281 4.797 5.781 4.797 9.578zM14 2v10c0 1.094-0.906 2-2 2s-2-0.906-2-2v-10c0-1.094 0.906-2 2-2s2 0.906 2 2z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="password" viewBox="0 0 18 28">
|
||||||
|
<title>Password</title>
|
||||||
|
<path d="M5 12h8v-3c0-2.203-1.797-4-4-4s-4 1.797-4 4v3zM18 13.5v9c0 0.828-0.672 1.5-1.5 1.5h-15c-0.828 0-1.5-0.672-1.5-1.5v-9c0-0.828 0.672-1.5 1.5-1.5h0.5v-3c0-3.844 3.156-7 7-7s7 3.156 7 7v3h0.5c0.828 0 1.5 0.672 1.5 1.5z"></path>
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
@ -29,6 +29,7 @@ Package.onUse(function(api) {
|
|||||||
|
|
||||||
const assets = [
|
const assets = [
|
||||||
'assets/icons.svg',
|
'assets/icons.svg',
|
||||||
|
'assets/user-menu-icons.svg',
|
||||||
'assets/fonts/Roboto-Black-latin-ext.woff',
|
'assets/fonts/Roboto-Black-latin-ext.woff',
|
||||||
'assets/fonts/Roboto-Black-latin-ext.woff2',
|
'assets/fonts/Roboto-Black-latin-ext.woff2',
|
||||||
'assets/fonts/Roboto-Black-latin.woff',
|
'assets/fonts/Roboto-Black-latin.woff',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user