15736: Don't allow user to delete local/federation sessions
authorPeter Amstutz <pamstutz@veritasgenetics.com>
Tue, 5 Nov 2019 15:11:48 +0000 (10:11 -0500)
committerPeter Amstutz <pamstutz@veritasgenetics.com>
Tue, 5 Nov 2019 15:11:48 +0000 (10:11 -0500)
Also fix config loading bug where the local config was being
overwritten by remote cluster config loading which didn't fill in most
of the fields, now fills in all the fields for remote clusters (but
also doesn't reload local cluster config redundantly).

src/common/config.ts
src/store/auth/auth-action.ts
src/views/site-manager-panel/site-manager-panel-root.tsx
src/views/site-manager-panel/site-manager-panel.tsx

index 47723ae89e5d2ee622f7ae2e417d6965a7e3be31..7d974342a704198686b8e20a959e537c0e03a73c 100644 (file)
@@ -70,6 +70,21 @@ export class Config {
     clusterConfig: ClusterConfigJSON;
 }
 
+export const buildConfig = (clusterConfigJSON: ClusterConfigJSON): Config => {
+    const config = new Config();
+    config.rootUrl = clusterConfigJSON.Services.Controller.ExternalURL;
+    config.baseUrl = `${config.rootUrl}/${ARVADOS_API_PATH}`;
+    config.uuidPrefix = clusterConfigJSON.ClusterID;
+    config.websocketUrl = clusterConfigJSON.Services.Websocket.ExternalURL;
+    config.workbench2Url = clusterConfigJSON.Services.Workbench2.ExternalURL;
+    config.workbenchUrl = clusterConfigJSON.Services.Workbench1.ExternalURL;
+    config.keepWebServiceUrl = clusterConfigJSON.Services.WebDAV.ExternalURL;
+    config.loginCluster = clusterConfigJSON.Login.LoginCluster;
+    config.clusterConfig = clusterConfigJSON;
+    mapRemoteHosts(clusterConfigJSON, config);
+    return config;
+};
+
 export const fetchConfig = () => {
     return Axios
         .get<WorkbenchConfig>(WORKBENCH_CONFIG_URL + "?nocache=" + (new Date()).getTime())
@@ -83,8 +98,8 @@ export const fetchConfig = () => {
                 throw new Error(`Unable to start Workbench. API_HOST is undefined in ${WORKBENCH_CONFIG_URL} or the environment.`);
             }
             return Axios.get<ClusterConfigJSON>(getClusterConfigURL(workbenchConfig.API_HOST)).then(response => {
-                const config = new Config();
                 const clusterConfigJSON = response.data;
+                const config = buildConfig(clusterConfigJSON);
                 const warnLocalConfig = (varName: string) => console.warn(
                     `A value for ${varName} was found in ${WORKBENCH_CONFIG_URL}. To use the Arvados centralized configuration instead, \
 remove the entire ${varName} entry from ${WORKBENCH_CONFIG_URL}`);
@@ -112,17 +127,6 @@ remove the entire ${varName} entry from ${WORKBENCH_CONFIG_URL}`);
                 }
                 config.vocabularyUrl = vocabularyUrl;
 
-                config.rootUrl = clusterConfigJSON.Services.Controller.ExternalURL;
-                config.baseUrl = `${config.rootUrl}/${ARVADOS_API_PATH}`;
-                config.uuidPrefix = clusterConfigJSON.ClusterID;
-                config.websocketUrl = clusterConfigJSON.Services.Websocket.ExternalURL;
-                config.workbench2Url = clusterConfigJSON.Services.Workbench2.ExternalURL;
-                config.workbenchUrl = clusterConfigJSON.Services.Workbench1.ExternalURL;
-                config.keepWebServiceUrl = clusterConfigJSON.Services.WebDAV.ExternalURL;
-                config.loginCluster = clusterConfigJSON.Login.LoginCluster;
-                config.clusterConfig = clusterConfigJSON;
-                mapRemoteHosts(clusterConfigJSON, config);
-
                 return { config, apiHost: workbenchConfig.API_HOST };
             });
         });
index 5bac6b19b8e922051aef551e73916f2722a3dd64..bfec39be40fff276323226f14c89fc01027b62fe 100644 (file)
@@ -10,7 +10,7 @@ import { ServiceRepository } from "~/services/services";
 import { SshKeyResource } from '~/models/ssh-key';
 import { User, UserResource } from "~/models/user";
 import { Session } from "~/models/session";
-import { getClusterConfigURL, Config, ClusterConfigJSON, mapRemoteHosts } from '~/common/config';
+import { getClusterConfigURL, Config, ClusterConfigJSON, buildConfig } from '~/common/config';
 import { initSessions } from "~/store/auth/auth-action-session";
 import { cancelLinking } from '~/store/link-account-panel/link-account-panel-actions';
 import { matchTokenRoute, matchFedTokenRoute } from '~/routes/routes';
@@ -93,12 +93,7 @@ const init = (config: Config) => (dispatch: Dispatch, getState: () => RootState,
     Object.keys(config.remoteHosts).map((k) => {
         Axios.get<ClusterConfigJSON>(getClusterConfigURL(config.remoteHosts[k]))
             .then(response => {
-                const remoteConfig = new Config();
-                remoteConfig.uuidPrefix = response.data.ClusterID;
-                remoteConfig.workbench2Url = response.data.Services.Workbench2.ExternalURL;
-                remoteConfig.loginCluster = response.data.Login.LoginCluster;
-                mapRemoteHosts(response.data, remoteConfig);
-                dispatch(authActions.REMOTE_CLUSTER_CONFIG({ config: remoteConfig }));
+                dispatch(authActions.REMOTE_CLUSTER_CONFIG({ config: buildConfig(response.data) }));
             });
     });
 };
index bc2303da2358bdec8e679072587a894c5a55dc7b..223e373c58187e34bd3b3f5ea8dfce7ae1c9ec88 100644 (file)
@@ -94,6 +94,7 @@ export interface SiteManagerPanelRootActionProps {
 export interface SiteManagerPanelRootDataProps {
     sessions: Session[];
     remoteHostsConfig: { [key: string]: Config };
+    localClusterConfig: Config;
 }
 
 type SiteManagerPanelRootProps = SiteManagerPanelRootDataProps & SiteManagerPanelRootActionProps & WithStyles<CssRules> & InjectedFormProps;
@@ -120,7 +121,7 @@ export const SiteManagerPanelRoot = compose(
         }
     }),
     withStyles(styles))
-    (({ classes, sessions, handleSubmit, toggleSession, removeSession, remoteHostsConfig }: SiteManagerPanelRootProps) =>
+    (({ classes, sessions, handleSubmit, toggleSession, removeSession, localClusterConfig, remoteHostsConfig }: SiteManagerPanelRootProps) =>
         <Card className={classes.root}>
             <CardContent>
                 <Grid container direction="row">
@@ -160,9 +161,13 @@ export const SiteManagerPanelRoot = compose(
                                             {validating ? "Validating" : (session.loggedIn ? "Logged in" : "Logged out")}
                                         </Button>
                                     </TableCell>
-                                    <IconButton onClick={() => removeSession(session)}>
-                                        <TrashIcon />
-                                    </IconButton>
+                                    <TableCell>
+                                        {session.clusterId !== localClusterConfig.uuidPrefix &&
+                                            !localClusterConfig.clusterConfig.RemoteClusters[session.clusterId] &&
+                                            <IconButton onClick={() => removeSession(session)}>
+                                                <TrashIcon />
+                                            </IconButton>}
+                                    </TableCell>
                                 </TableRow>;
                             })}
                         </TableBody>
index 59897f2c4d3c35ee06c1b565a54ba1ea60291b09..da7ae4288b280acd1cdec275aa3741658661ab03 100644 (file)
@@ -15,7 +15,8 @@ import { toggleSession, removeSession } from "~/store/auth/auth-action-session";
 const mapStateToProps = (state: RootState): SiteManagerPanelRootDataProps => {
     return {
         sessions: state.auth.sessions,
-        remoteHostsConfig: state.auth.remoteHostsConfig
+        remoteHostsConfig: state.auth.remoteHostsConfig,
+        localClusterConfig: state.auth.remoteHostsConfig[state.auth.localCluster]
     };
 };