Skip to content
Snippets Groups Projects
Commit aeed1c83 authored by Zoltan Runyo's avatar Zoltan Runyo
Browse files

ICSHWI-8186: Basic access control logic

parent 878b03ac
No related branches found
No related tags found
1 merge request!81Icshwi 7851 access levels
Pipeline #99719 failed
......@@ -38,7 +38,7 @@ export const userContext = createContext({ user: null, userRoles:[], getUserRole
export function UserProvider({ children }) {
const [user, setUser] = useState();
const [userRoles, getUserRoles] = useUserRoles();
const [userRoles, getUserRoles, resetUserRoles] = useUserRoles();
const [userInfo, getUserInfo] = useUserInfo();
const [loginResponse, loginFcn] = useLogin();
const logoutFcn = useLogout();
......@@ -50,9 +50,12 @@ export function UserProvider({ children }) {
useEffect(getUserInfo, [Boolean(loginResponse), getUserInfo]);
useEffect(() => userInfo && setUser(userInfo), [setUser, userInfo]);
useEffect(getUserRoles, [Boolean(loginResponse), getUserRoles]);
const logout = async () => {
console.log("Logging out!")
setUser(null);
resetUserRoles();
logoutFcn();
}
......@@ -403,7 +406,7 @@ export function useUserInfo() {
}
export function unpackUserRoles(roles) {
return { ...roles };
return roles;
}
export function useUserRoles() {
......
import React, {useContext} from 'react';
import { userContext } from "../../api/SwaggerApi";
import AccessDenied from "./AccessDenied";
const checkPermissions = (userRoles, allowedRoles) => {
if (allowedRoles.length === 0) {
return true;
}
return userRoles?.some(role =>
allowedRoles.includes(role)
);
};
export default function AccessControl({ allowedRoles, children, renderNoAccess}) {
const { userRoles } = useContext(userContext);
const permitted = checkPermissions(userRoles, allowedRoles);
if (permitted) {
return children;
}
if (!renderNoAccess) {
return(
<AccessDenied/>
);
}
return renderNoAccess();
}
\ No newline at end of file
import React from 'react';
import {
Paper,
Typography,
Box,
Button,
IconButton,
makeStyles
} from "@material-ui/core";
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
import { useHistory } from "react-router-dom";
import { RootContainer } from "../../components/common/Container/RootContainer";
const useStyles = makeStyles((theme) => ({
paper: {
maxWidth: "80%",
padding: theme.spacing(4),
},
}));
export default function AccessDenied() {
const classes = useStyles();
const history = useHistory();
const goHome = () =>{
history.push("/home");
}
const goBack = () => {
history.goBack();
};
return (
<RootContainer>
<Paper className={classes.paper}>
<IconButton color="inherit" onClick={goBack}>
<ArrowBackIcon />
</IconButton>
<Box display="flex" justifyContent="center" p={2} m={1}>
<Typography variant="h4">
Access denied
</Typography>
</Box>
<Box display="flex" justifyContent="center">
<Typography variant="body1">
You do not have permission to access this page. Please contact an administrator to request access.
</Typography>
</Box>
<Box display="flex" justifyContent="center" p={2} m={1}>
<Button variant="contained" color="secondary" onClick={goHome} >Return to Home</Button>
</Box>
</Paper>
</RootContainer>
);
}
\ No newline at end of file
......@@ -35,6 +35,7 @@ import { useWindowDimensions } from "../../common/Helper";
import { CCCEControlSymbol } from '../../../icons/CCCEControlSymbol';
import Login from "../../auth/Login";
import { SimpleModal } from "../../common/SimpleModal/SimpleModal";
import AccessControl from "../../auth/AccessControl";
const useStyles = makeStyles((theme) => ({
root: {
......@@ -349,7 +350,7 @@ export function GlobalAppBar({ children }) {
const notifications = NotificationMenu();
const makeLink = (text, url, icon) => ({ text, url, icon });
const menuItems = [
const menuItemsAll = [
makeLink("Explore IOCs", "/iocs", <CCCEControlSymbol />),
makeLink("Explore IOC hosts", "/hosts", <Storage />),
makeLink("Deployment log", "/deployments", <Assignment />),
......@@ -357,12 +358,25 @@ export function GlobalAppBar({ children }) {
makeLink("Help", "/help", <HelpIcon />)
]
const menuItemsVisitor = [
makeLink("Explore IOCs", "/iocs", <CCCEControlSymbol />),
makeLink("Explore IOC hosts", "/hosts", <Storage />),
makeLink("Statistics", "/statistics", <TrendingUp />),
makeLink("Help", "/help", <HelpIcon />)
]
return (
<>
<ButtonAppBar homeUrl="/home" homeClick={handleLeftMenuItemClick} title={title} button={button} profileButton={profile} notificationsButton={notifications} />
<MenuDrawer open={drawerOpen} toggleDrawer={toggleDrawer}>
<MenuListItems menuItems={menuItems} selectedUrl={selectedUrl}
handleListItemClick={handleLeftMenuItemClick} drawerOpen={drawerOpen} />
<AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}
renderNoAccess={() =>
<MenuListItems menuItems={menuItemsVisitor} selectedUrl={selectedUrl}
handleListItemClick={handleLeftMenuItemClick} drawerOpen={drawerOpen} />
}>
<MenuListItems menuItems={menuItemsAll} selectedUrl={selectedUrl}
handleListItemClick={handleLeftMenuItemClick} drawerOpen={drawerOpen} />
</AccessControl>
</MenuDrawer>
<GlobalAppBarContext.Provider value={value}>
<div style={{ ...theme.mixins.toolbar }} />
......
......@@ -6,6 +6,7 @@ import { IOCLiveStatus } from "../../components/IOC/IOCLiveStatus";
import { IOCManage } from "../../components/IOC/IOCManage";
import { RootContainer } from "../../components/common/Container/RootContainer";
import { useHistory } from "react-router-dom";
import AccessControl from "../../components/auth/AccessControl";
export function IOCDetailsView({ match }) {
const id = parseInt(match.params.id);
......@@ -26,38 +27,40 @@ export function IOCDetailsView({ match }) {
}
}, [ioc, firstTime]);
const handleClick = (event) => {
const handleClick = () => {
history.goBack();
};
return (
<RootContainer data-testid="ioc-details-container">
<Paper>
<Grid container spacing={1}>
<Grid item xs={1}>
<IconButton color="inherit" onClick={handleClick}>
<ArrowBackIcon />
</IconButton>
</Grid>
<Grid item xs={11}>
<Grid container justify="center">
<Tabs
value={selectedTab}
onChange={handleTabChange}
indicatorColor="primary"
textColor="primary"
>
{ioc && ioc.activeDeployment && <Tab label={<Typography variant="h5">Live Status</Typography>} value="Live Status" />}
{ioc && <Tab label={<Typography variant="h5">Manage deployment</Typography>} value="Manage deployment" />}
</Tabs>
<AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}>
<Paper>
<Grid container spacing={1}>
<Grid item xs={1}>
<IconButton color="inherit" onClick={handleClick}>
<ArrowBackIcon />
</IconButton>
</Grid>
<Grid item xs={11}>
<Grid container justify="center">
<Tabs
value={selectedTab}
onChange={handleTabChange}
indicatorColor="primary"
textColor="primary"
>
{ioc && ioc.activeDeployment && <Tab label={<Typography variant="h5">Live Status</Typography>} value="Live Status" />}
{ioc && <Tab label={<Typography variant="h5">Manage deployment</Typography>} value="Manage deployment" />}
</Tabs>
</Grid>
</Grid>
<Grid item xs={12} style={{paddingBottom: 0}}>
{selectedTab === "Live Status" && <IOCLiveStatus ioc={ioc} getIOC={getIOC} />}
{selectedTab === "Manage deployment" && <IOCManage ioc={ioc} getIOC={getIOC} />}
</Grid>
</Grid>
<Grid item xs={12} style={{paddingBottom: 0}}>
{selectedTab === "Live Status" && <IOCLiveStatus ioc={ioc} getIOC={getIOC} />}
{selectedTab === "Manage deployment" && <IOCManage ioc={ioc} getIOC={getIOC} />}
</Grid>
</Grid>
</Paper>
</Paper>
</AccessControl>
</RootContainer>
);
}
\ No newline at end of file
......@@ -6,6 +6,7 @@ import { useDeployment } from '../../api/SwaggerApi';
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
import { useHistory } from "react-router-dom";
import { RootContainer } from "../../components/common/Container/RootContainer";
import AccessControl from "../../components/auth/AccessControl";
export function DeploymentDetailsView({ match }) {
const id = parseInt(match.params.id);
......@@ -18,18 +19,20 @@ export function DeploymentDetailsView({ match }) {
console.log(deployment);
const handleClick = (event) => {
history.goBack();
};
const handleClick = () => {
history.goBack();
};
return (
<RootContainer data-testid="deployment-details-container">
<Paper>
<IconButton color="inherit" onClick={handleClick}>
<ArrowBackIcon />
</IconButton>
{deployment && <DeploymentDetails deployment={deployment} getDeployment={getDeployment} onDeploymentStart={()=>{}} startButtonDisabled={true} />}
</Paper>
<AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}>
<Paper>
<IconButton color="inherit" onClick={handleClick}>
<ArrowBackIcon />
</IconButton>
{deployment && <DeploymentDetails deployment={deployment} getDeployment={getDeployment} onDeploymentStart={()=>{}} startButtonDisabled={true} />}
</Paper>
</AccessControl>
</RootContainer>
);
}
......@@ -7,6 +7,7 @@ import { SearchableDeploymentsTable } from "../../components/deployments/Deploym
import { SearchableDeploymentsList } from "../../components/deployments/DeploymentsList";
import { useGlobalAppBar } from "../../components/navigation/GlobalAppBar/GlobalAppBar";
import { useDeploymentSearch, userContext } from '../../api/SwaggerApi';
import AccessControl from "../../components/auth/AccessControl";
const useStyles = makeStyles((theme) => ({
root: {
......@@ -74,31 +75,33 @@ export function DeploymentsView() {
return (
<Container className={classes.root}>
<Paper className={classes.paper}>
<Grid container spacing={1} justify="flex-start">
<Grid item xs={12} md={10}>
<Tabs
value={selectedTab}
onChange={handleTabChange}
indicatorColor="primary"
textColor="primary">
<Tab label={<Typography variant="h5">All</Typography>} />
<Tab label={<Typography variant="h5">Running</Typography>} />
<Tab label={<Typography variant="h5">Finished</Typography>} />
<Tab label={<Typography variant="h5">Queued</Typography>} />
</Tabs>
<AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}>
<Paper className={classes.paper}>
<Grid container spacing={1} justify="flex-start">
<Grid item xs={12} md={10}>
<Tabs
value={selectedTab}
onChange={handleTabChange}
indicatorColor="primary"
textColor="primary">
<Tab label={<Typography variant="h5">All</Typography>} />
<Tab label={<Typography variant="h5">Running</Typography>} />
<Tab label={<Typography variant="h5">Finished</Typography>} />
<Tab label={<Typography variant="h5">Queued</Typography>} />
</Tabs>
</Grid>
<Grid item xs={8} md={2}>
<FormControlLabel className={classes.formControl}
control={<Switch checked={ownOnly} onChange={handleChangeOwn} />}
label={<Typography variant="h5">My deployments</Typography>}
/>
</Grid>
<Grid item xs={12} md={12}>
{content}
</Grid>
</Grid>
<Grid item xs={8} md={2}>
<FormControlLabel className={classes.formControl}
control={<Switch checked={ownOnly} onChange={handleChangeOwn} />}
label={<Typography variant="h5">My deployments</Typography>}
/>
</Grid>
<Grid item xs={12} md={12}>
{content}
</Grid>
</Grid>
</Paper>
</Paper>
</AccessControl>
</Container>
);
}
......@@ -7,6 +7,7 @@ import { SearchableIOCTable } from "../../components/IOC/IOCTable";
import { SimpleModal } from "../../components/common/SimpleModal/SimpleModal";
import { useCreateIOC, useIOCSearch, userContext } from "../../api/SwaggerApi";
import { makeStyles } from '@material-ui/core/styles';
import AccessControl from "../../components/auth/AccessControl";
const useStyles = makeStyles((theme) => ({
root: {
......@@ -18,7 +19,7 @@ export function HomeView() {
const [iocs, getIocs] = useIOCSearch();
const [query, setQuery] = useState();
const [iocFormOpen, setIOCFormOpen] = useState(false);
const {user, userRoles} = useContext(userContext);
const {user} = useContext(userContext);
const classes = useStyles();
useEffect(() => getIocs(`${query}`), [query, getIocs]);
......@@ -34,8 +35,6 @@ export function HomeView() {
function preFilter(iocs) {
console.log(iocs);
console.log(user);
console.log(userRoles);
const abcIOCs = iocs.filter((ioc) => ioc.owner === user?.loginName).sort((a, b) => a.latestVersion.namingName.localeCompare(b.latestVersion.namingName));
return abcIOCs;
}
......@@ -54,8 +53,19 @@ export function HomeView() {
return (
<Container>
<Paper className={classes.root}>
{ user
?
<AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}
renderNoAccess={() =>
<Grid container spacing={1} justify="flex-end">
<Grid item xs={12}>
<Box display="flex" flexDirection="row" p={2} m={1}>
<Typography variant="h2">
Home
</Typography>
</Box>
</Grid>
</Grid>
}
>
<Grid container spacing={1} justify="flex-end">
<Grid item xs={10}>
<Box display="flex" flexDirection="row" p={2} m={1}>
......@@ -76,17 +86,7 @@ export function HomeView() {
<CreateIOC open={iocFormOpen} setOpen={setIOCFormOpen} isUpdateIoc={false} submitCallback={closeModal} hook={useCreateIOC} title="Create new IOC" buttonText="Create"/>
</SimpleModal>
</Grid>
:
<Grid container spacing={1} justify="flex-end">
<Grid item xs={12}>
<Box display="flex" flexDirection="row" p={2} m={1}>
<Typography variant="h2">
Home
</Typography>
</Box>
</Grid>
</Grid>
}
</AccessControl>
</Paper>
</Container>
);
......
......@@ -22,6 +22,7 @@ import { LokiPanel } from '../../components/common/Loki/LokiPanel';
import { useHistory } from "react-router-dom";
import { formatDate } from '../../components/common/Helper';
import { RootContainer } from "../../components/common/Container/RootContainer";
import AccessControl from "../../components/auth/AccessControl";
const useStyles = makeStyles((theme) => ({
secondItem: {
......@@ -63,6 +64,7 @@ export function HostDetailsView({ match }) {
return (
<RootContainer data-testid="host-details-container">
<AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}>
<Paper>
<IconButton color="inherit" onClick={handleClick}>
<ArrowBackIcon />
......@@ -99,6 +101,7 @@ export function HostDetailsView({ match }) {
{host && <KeyValueTable obj={renderHost} variant="table" />}
</SimpleAccordion>
</Paper>
</AccessControl>
</RootContainer>
);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment