This repository has been archived by the owner on May 22, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RUN-2959: query desktop owner settings from RVM (#122)
* RUN-2959: Populate API policy from RVM in Message PreProcessor * RUN-2959: Populate API policy from RVM in Message PreProcessor * RUN-2959: Populate API policy from RVM in Message PreProcessor * RUN-2959: Populate API policy from RVM in Message PreProcessor
- Loading branch information
1 parent
3d85eda
commit 43882fa
Showing
2 changed files
with
156 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,25 @@ Please contact OpenFin Inc. at [email protected] to obtain a Commercial License. | |
import {MessagePackage} from '../transport_strategy/api_transport_base'; | ||
const coreState = require('../../core_state'); | ||
const electronApp = require('electron').app; | ||
const system = require('../../api/system').System; | ||
const apiProtocolBase = require('./api_protocol_base'); | ||
const rvmBus = require('../../rvm/rvm_message_bus'); // retrieve permission setting from registry | ||
const configUrlPermissionsMap : { [url: string]: any } = {}; // cached configUrl => permission object, retrieved from RVM | ||
// if a configUrl is mapped to a boolean true, request to RVM is successful | ||
// did not return permissions | ||
const CONFIG_URL_WILDCARD = 'default'; // can set as default for all applications. Checked ONLY IF permissions | ||
// for a particular URL is not defined | ||
const ENABLE_DESKTOP_OWNER_SETTINGS: string = 'enable-desktop-owner-settings'; // RVM adds this to runtime->arguments | ||
// if settings are detected in Registry | ||
const DESKTOP_OWNER_SETTINGS_TIMEOUT: string = 'desktop-owner-settings-timeout'; // timeout for requesting from RVM in ms | ||
let desktopOwnerSettingsTimeout: number = 2000; // in ms | ||
let desktopOwnerSettingEnabled: boolean = false; | ||
|
||
enum POLICY_AUTH_RESULT { | ||
Allowed = 1, | ||
Denied, | ||
NotDefined // config URL not found in policy. Check window options instead | ||
} | ||
|
||
// actionAPINameMap has all APIs that must be authorized | ||
// @todo this map should be set in group policy or some other way | ||
|
@@ -84,7 +102,7 @@ function checkWindowPermissions(apiPath: [string], windowPermissions: any, isChi | |
} | ||
level += 1; | ||
} | ||
electronApp.vlog(1, `checkWindowPermissions level ${level} value ${lastValue}`); | ||
electronApp.vlog(1, `checkWindowPermissions level ${level}`); | ||
if (level === apiPath.length && typeof lastValue === 'boolean') { | ||
permitted = !!lastValue; | ||
} | ||
|
@@ -93,19 +111,20 @@ function checkWindowPermissions(apiPath: [string], windowPermissions: any, isChi | |
} | ||
|
||
/** | ||
* Authorize the action for a window sending the action | ||
* Authorize the action for a window sending the action based on window options | ||
* | ||
* @param windowOpts window options | ||
* @param parentUuid uuid of parent app | ||
* @param action in message | ||
* @returns {boolean} true if authorized | ||
* @returns {Promise<boolean>} resolves true if authorized | ||
*/ | ||
function authorizeAction(windowOpts: any, parentUuid: string, action: string): boolean { | ||
function authorizeActionFromWindowOptions(windowOpts: any, parentUuid: string, action: string): boolean { | ||
electronApp.vlog(1, `authorizeAction ${action} for ${windowOpts.uuid} ${windowOpts.name}`); | ||
const apiPath: [string] = actionAPINameMap[action]; | ||
let allowed: boolean = true; | ||
if (actionAPINameMap.hasOwnProperty(action)) { // if listed in the map, has to be checked | ||
const isChildWindow = windowOpts.uuid !== windowOpts.name; | ||
allowed = isChildWindow; | ||
const apiPath: [string] = actionAPINameMap[action]; | ||
if (windowOpts && windowOpts.permissions) { | ||
allowed = checkWindowPermissions(apiPath, windowOpts.permissions, isChildWindow); | ||
} | ||
|
@@ -116,7 +135,8 @@ function authorizeAction(windowOpts: any, parentUuid: string, action: string): b | |
const parentOpts = parentObject._options; | ||
if (parentOpts) { | ||
electronApp.vlog(1, `authorizeAction checks parent ${parentUuid}`); | ||
allowed = authorizeAction(parentOpts, parentObject.parentUuid, action); | ||
allowed = authorizeActionFromWindowOptions(parentOpts, parentObject.parentUuid, action); | ||
return; | ||
} else { | ||
electronApp.vlog(1, `authorizeAction missing parent options ${parentUuid}`); | ||
} | ||
|
@@ -127,8 +147,58 @@ function authorizeAction(windowOpts: any, parentUuid: string, action: string): b | |
return allowed; | ||
} | ||
|
||
/** | ||
* Authorize the action for a window sending the action based on policies supplied by RVM | ||
* | ||
* @param windowOpts | ||
* @param action | ||
* @returns {Promise<boolean>} | ||
* @returns {Promise<string>} resolves with POLICY_AUTH_RESULT | ||
*/ | ||
function authorizeActionFromPolicy(windowOpts: any, action: string): Promise<POLICY_AUTH_RESULT> { | ||
electronApp.vlog(1, `authorizeActionFromPolicy ${action} for ${windowOpts.uuid} ${windowOpts.name}`); | ||
const apiPath: [string] = actionAPINameMap[action]; | ||
return new Promise((resolve, reject) => { | ||
if (desktopOwnerSettingEnabled === true) { | ||
const configUrl = coreState.getConfigUrlByUuid(windowOpts.uuid); | ||
if (configUrl) { | ||
electronApp.vlog(1, `authorizeActionFromPolicy checking with config url ${configUrl}`); | ||
requestAppPermissions(configUrl).then((resultByUrl: any) => { | ||
if (resultByUrl.permissions) { | ||
resolve(checkWindowPermissions(apiPath, resultByUrl.permissions, false) ? | ||
POLICY_AUTH_RESULT.Allowed : POLICY_AUTH_RESULT.Denied); | ||
} else { // check default permissions defined with CONFIG_URL_WILDCARD | ||
electronApp.vlog(1, `authorizeActionFromPolicy checking with RVM ${CONFIG_URL_WILDCARD}`); | ||
requestAppPermissions(CONFIG_URL_WILDCARD).then((resultByDefault: any) => { | ||
if (resultByDefault.permissions) { | ||
resolve(checkWindowPermissions(apiPath, resultByDefault.permissions, false) ? POLICY_AUTH_RESULT.Allowed : | ||
POLICY_AUTH_RESULT.Denied); | ||
} else { | ||
resolve(POLICY_AUTH_RESULT.NotDefined); // config URL not defined in policy | ||
} | ||
}).catch((error: any) => { | ||
electronApp.vlog(1, `authorizeActionFromPolicy query for permissions failed ${CONFIG_URL_WILDCARD}`); | ||
reject(false); | ||
}); | ||
} | ||
}).catch((error: any) => { | ||
electronApp.vlog(1, `authorizeActionFromPolicy query for permissions failed ${configUrl}`); | ||
reject(false); | ||
}); | ||
} else { | ||
electronApp.vlog(1, 'authorizeActionFromPolicy configUrl not defined'); | ||
resolve(POLICY_AUTH_RESULT.NotDefined); // config URL not defined in policy | ||
} | ||
} else { | ||
electronApp.vlog(1, `authorizeActionFromPolicy desktopOwnerSettingEnabled ${desktopOwnerSettingEnabled}`); | ||
resolve(POLICY_AUTH_RESULT.NotDefined); // config URL not defined in policy | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Message pre-processor | ||
* | ||
* @param msg message package to check | ||
* @param next function to call if ok to proceed | ||
*/ | ||
|
@@ -144,20 +214,84 @@ function apiPolicyPreProcessor(msg: MessagePackage, next: () => void): void { | |
const appObject = coreState.getAppObjByUuid(identity.uuid); | ||
// parentUuid for child windows is uuid of the app | ||
const parentUuid = identity.uuid === identity.name ? appObject.parentUuid : identity.uuid; | ||
if (!authorizeAction(coreState.getWindowOptionsById(originWindow.id), parentUuid, action)) { | ||
electronApp.vlog(1, `apiPolicyPreProcessor rejecting ${action} from ${identity.uuid} ${identity.name}`); | ||
authorizeActionFromPolicy(coreState.getWindowOptionsById(originWindow.id), action).then((result: POLICY_AUTH_RESULT) => { | ||
if (result === POLICY_AUTH_RESULT.Allowed) { | ||
next(); | ||
} else if (result === POLICY_AUTH_RESULT.Denied) { | ||
electronApp.vlog(1, `apiPolicyPreProcessor rejecting from policy ${action} from ${identity.uuid} ${identity.name}`); | ||
nack('Rejected, action is not authorized'); | ||
} else { | ||
if (authorizeActionFromWindowOptions(coreState.getWindowOptionsById(originWindow.id), parentUuid, action)) { | ||
next(); | ||
} else { | ||
electronApp.vlog(1, `apiPolicyPreProcessor rejecting from win opts ${action} from ${identity.uuid} ` + | ||
`${identity.name}`); | ||
nack('Rejected, action is not authorized'); | ||
} | ||
} | ||
}).catch(() => { | ||
electronApp.vlog(1, `apiPolicyPreProcessor rejecting from error ${action} from ${identity.uuid} ${identity.name}`); | ||
nack('Rejected, action is not authorized'); | ||
return; | ||
} | ||
}); | ||
} else { | ||
electronApp.vlog(1, `apiPolicyPreProcessor missing origin window ${action} from ${identity.uuid} ${identity.name}`); | ||
next(); | ||
} | ||
} else { | ||
next(); | ||
} | ||
} else { | ||
next(); | ||
} | ||
next(); | ||
} | ||
|
||
if (electronApp.getCommandLineArguments().includes('--enable-strict-api-permissions')) { | ||
electronApp.log('info', 'Installing API policy PreProcessor'); | ||
/** | ||
* Get application permissions from cache or RVM | ||
* | ||
* @param configUrl url of startup manifest | ||
* @returns {Promise<any>} resolves with permissions defined in application assets; | ||
* reject if request to RVM failed | ||
*/ | ||
function requestAppPermissions(configUrl: string): Promise<any> { | ||
electronApp.vlog(1, `requestAppPermissions ${configUrl} `); | ||
return new Promise((resolve, reject) => { | ||
if (configUrlPermissionsMap[configUrl]) { | ||
electronApp.vlog(1, `requestAppPermissions cached ${configUrl} `); | ||
resolve(configUrlPermissionsMap[configUrl]); | ||
} else { | ||
rvmBus.send('application', { | ||
action: 'get-desktop-owner-settings', | ||
sourceUrl: configUrl | ||
}, (rvmResponse: any) => { | ||
electronApp.vlog(1, `requestAppPermissions from RVM ${JSON.stringify(rvmResponse)} `); | ||
if (rvmResponse.payload && rvmResponse.payload.success === true && | ||
rvmResponse.payload.payload) { | ||
if (rvmResponse.payload.payload.permissions) { | ||
configUrlPermissionsMap[configUrl] = {permissions: rvmResponse.payload.payload.permissions}; | ||
// cache it | ||
} else { | ||
// if permissions is missing, startup URL is not defined in desktop-owner-settings. Not an error | ||
configUrlPermissionsMap[configUrl] = {}; | ||
} | ||
resolve(configUrlPermissionsMap[configUrl]); | ||
} else { | ||
system.log('error', `requestAppPermissions from RVM failed ${JSON.stringify(rvmResponse)}`); | ||
reject(rvmResponse); // false indicates request to RVM failed | ||
} | ||
}, desktopOwnerSettingsTimeout / 1000); | ||
} | ||
}); | ||
} | ||
|
||
if (coreState.argo['enable-strict-api-permissions']) { | ||
electronApp.log('info', `Installing API policy PreProcessor ${JSON.stringify(coreState.getStartManifest())}`); | ||
apiProtocolBase.getDefaultRequestHandler().addPreProcessor(apiPolicyPreProcessor); | ||
desktopOwnerSettingEnabled = !!coreState.argo[ENABLE_DESKTOP_OWNER_SETTINGS]; | ||
electronApp.vlog(1, `desktopOwnerSettingEnabled ${desktopOwnerSettingEnabled}`); | ||
if (desktopOwnerSettingEnabled === true && coreState.argo[DESKTOP_OWNER_SETTINGS_TIMEOUT]) { | ||
desktopOwnerSettingsTimeout = Number(coreState.argo[DESKTOP_OWNER_SETTINGS_TIMEOUT]); | ||
electronApp.vlog(1, `desktopOwnerSettingsTimeout ${desktopOwnerSettingsTimeout}`); | ||
} | ||
} | ||
|
||
export {apiPolicyPreProcessor}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters