Added validation for users to not delete their own account (#633)

Also Implemented an option to show / hide actions in table wrapper

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2021-03-08 23:38:19 -06:00
committed by GitHub
parent ebab2e1648
commit 81087ae910
15 changed files with 77 additions and 16 deletions

View File

@@ -1,25 +1,25 @@
{
"files": {
"main.css": "/static/css/main.a19f3d53.chunk.css",
"main.js": "/static/js/main.0e3d4f4a.chunk.js",
"main.js.map": "/static/js/main.0e3d4f4a.chunk.js.map",
"main.js": "/static/js/main.35167004.chunk.js",
"main.js.map": "/static/js/main.35167004.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.f48e99e5.js",
"runtime-main.js.map": "/static/js/runtime-main.f48e99e5.js.map",
"static/css/2.76b14b73.chunk.css": "/static/css/2.76b14b73.chunk.css",
"static/js/2.fa5f1dc1.chunk.js": "/static/js/2.fa5f1dc1.chunk.js",
"static/js/2.fa5f1dc1.chunk.js.map": "/static/js/2.fa5f1dc1.chunk.js.map",
"static/js/2.9510b4a1.chunk.js": "/static/js/2.9510b4a1.chunk.js",
"static/js/2.9510b4a1.chunk.js.map": "/static/js/2.9510b4a1.chunk.js.map",
"index.html": "/index.html",
"static/css/2.76b14b73.chunk.css.map": "/static/css/2.76b14b73.chunk.css.map",
"static/css/main.a19f3d53.chunk.css.map": "/static/css/main.a19f3d53.chunk.css.map",
"static/js/2.fa5f1dc1.chunk.js.LICENSE.txt": "/static/js/2.fa5f1dc1.chunk.js.LICENSE.txt",
"static/js/2.9510b4a1.chunk.js.LICENSE.txt": "/static/js/2.9510b4a1.chunk.js.LICENSE.txt",
"static/media/minio_console_logo.0837460e.svg": "/static/media/minio_console_logo.0837460e.svg",
"static/media/minio_operator_logo.1312b7c9.svg": "/static/media/minio_operator_logo.1312b7c9.svg"
},
"entrypoints": [
"static/js/runtime-main.f48e99e5.js",
"static/css/2.76b14b73.chunk.css",
"static/js/2.fa5f1dc1.chunk.js",
"static/js/2.9510b4a1.chunk.js",
"static/css/main.a19f3d53.chunk.css",
"static/js/main.0e3d4f4a.chunk.js"
"static/js/main.35167004.chunk.js"
]
}

View File

@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="MinIO Console"/><link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><link rel="manifest" href="/manifest.json"/><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="/static/css/2.76b14b73.chunk.css" rel="stylesheet"><link href="/static/css/main.a19f3d53.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="/static/js/2.fa5f1dc1.chunk.js"></script><script src="/static/js/main.0e3d4f4a.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="MinIO Console"/><link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><link rel="manifest" href="/manifest.json"/><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="/static/css/2.76b14b73.chunk.css" rel="stylesheet"><link href="/static/css/main.a19f3d53.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="/static/js/2.9510b4a1.chunk.js"></script><script src="/static/js/main.35167004.chunk.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -27,6 +27,7 @@ import {
} from "@material-ui/core";
import { Table, Column, AutoSizer, InfiniteLoader } from "react-virtualized";
import { createStyles, withStyles } from "@material-ui/core/styles";
import CircularProgress from "@material-ui/core/CircularProgress";
import ViewColumnIcon from "@material-ui/icons/ViewColumn";
import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown";
import ArrowDropUpIcon from "@material-ui/icons/ArrowDropUp";
@@ -45,6 +46,8 @@ interface ItemActions {
onClick?(valueToSend: any): any;
to?: string;
sendOnlyId?: boolean;
hideButtonFunction?: (itemValue: any) => boolean;
showLoaderFunction?: (itemValue: any) => boolean;
}
interface IColumns {
@@ -267,6 +270,19 @@ const styles = () =>
".text-right": {
textAlign: "right",
},
".progress-enabled": {
paddingTop: 3,
display: "inline-block",
margin: "0 10px",
position: "relative",
width: 18,
height: 18,
},
".progress-enabled > .MuiCircularProgress-root": {
position: "absolute",
left: 0,
top: 3,
},
},
...checkboxIcons,
...radioIcons,
@@ -413,6 +429,30 @@ const elementActions = (
return null;
}
const vlSend =
typeof valueToSend === "string" ? valueToSend : valueToSend[idField];
if (action.hideButtonFunction) {
if (action.hideButtonFunction(vlSend)) {
return null;
}
}
if (action.showLoaderFunction) {
if (action.showLoaderFunction(vlSend)) {
return (
<div className={"progress-enabled"}>
<CircularProgress
color="primary"
size={18}
variant="indeterminate"
key={`actions-loader-${action.type}-${index.toString()}`}
/>
</div>
);
}
}
return (
<TableActionButton
type={action.type}

View File

@@ -174,6 +174,8 @@ const Menu = ({ userLoggedIn, classes, pages, operatorMode }: IMenuProps) => {
const deleteSession = () => {
clearSession();
userLoggedIn(false);
localStorage.setItem("userLoggedIn", "");
history.push("/login");
};
api

View File

@@ -168,10 +168,16 @@ const Users = ({ classes, setErrorSnackMessage }: IUsersProps) => {
setSelectedUser(selectionElement);
};
const userLoggedIn = atob(localStorage.getItem("userLoggedIn") || "");
const tableActions = [
{ type: "view", onClick: viewAction },
{ type: "description", onClick: setPolicyAction },
{ type: "delete", onClick: deleteAction },
{
type: "delete",
onClick: deleteAction,
hideButtonFunction: (topValue: any) => topValue === userLoggedIn,
},
];
return (

View File

@@ -242,6 +242,10 @@ const Login = ({ classes, userLoggedIn }: ILoginProps) => {
.then(() => {
// We set the state in redux
userLoggedIn(true);
if (loginStrategy.loginStrategy === loginStrategyType.form) {
localStorage.setItem("userLoggedIn", btoa(accessKey));
}
history.push("/");
})
.catch((err) => {

View File

@@ -197,6 +197,10 @@ func getRemoveUserResponse(session *models.Principal, params admin_api.RemoveUse
return prepareError(err)
}
if session.AccountAccessKey == params.Name {
return prepareError(errAvoidSelfAccountDelete)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := adminClient{client: mAdmin}

View File

@@ -34,6 +34,7 @@ var (
errChangePassword = errors.New("unable to update password, please check your current password")
errInvalidLicense = errors.New("invalid license key")
errLicenseNotFound = errors.New("license not found")
errAvoidSelfAccountDelete = errors.New("logged in user cannot be deleted by itself")
)
// prepareError receives an error object and parse it against k8sErrors, returns the right error code paired with a generic error message
@@ -105,6 +106,10 @@ func prepareError(err ...error) *models.Error {
errorCode = 404
errorMessage = errInvalidLicense.Error()
}
if errors.Is(err[0], errAvoidSelfAccountDelete) {
errorCode = 403
errorMessage = errAvoidSelfAccountDelete.Error()
}
if madmin.ToErrorResponse(err[0]).Code == "InvalidAccessKeyId" {
errorCode = 401
errorMessage = errorGenericInvalidSession.Error()