github.com/minio/console@v1.4.1/web-app/src/screens/LoginPage/StrategyForm.tsx (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2022 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  import React, { Fragment, useState } from "react";
    18  import {
    19    Box,
    20    Button,
    21    DropdownSelector,
    22    Grid,
    23    InputBox,
    24    LockFilledIcon,
    25    LogoutIcon,
    26    PasswordKeyIcon,
    27    ProgressBar,
    28    Select,
    29    UserFilledIcon,
    30  } from "mds";
    31  import {
    32    setAccessKey,
    33    setDisplayEmbeddedIDPForms,
    34    setSecretKey,
    35    setSTS,
    36    setUseSTS,
    37  } from "./loginSlice";
    38  
    39  import { AppState, useAppDispatch } from "../../store";
    40  import { useSelector } from "react-redux";
    41  import { doLoginAsync } from "./loginThunks";
    42  import { RedirectRule } from "api/consoleApi";
    43  
    44  const StrategyForm = ({ redirectRules }: { redirectRules: RedirectRule[] }) => {
    45    const dispatch = useAppDispatch();
    46  
    47    const [ssoOptionsOpen, ssoOptionsSetOpen] = useState<boolean>(false);
    48    const [anchorEl, setAnchorEl] = React.useState<
    49      (EventTarget & HTMLButtonElement) | null
    50    >(null);
    51  
    52    const accessKey = useSelector((state: AppState) => state.login.accessKey);
    53    const secretKey = useSelector((state: AppState) => state.login.secretKey);
    54    const sts = useSelector((state: AppState) => state.login.sts);
    55    const useSTS = useSelector((state: AppState) => state.login.useSTS);
    56    const displaySSOForm = useSelector(
    57      (state: AppState) => state.login.ssoEmbeddedIDPDisplay,
    58    );
    59  
    60    const loginSending = useSelector(
    61      (state: AppState) => state.login.loginSending,
    62    );
    63  
    64    const formSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    65      e.preventDefault();
    66      dispatch(doLoginAsync());
    67    };
    68  
    69    let selectOptions = [
    70      {
    71        label: useSTS ? "Use Credentials" : "Use STS",
    72        value: useSTS ? "use-sts-cred" : "use-sts",
    73      },
    74    ];
    75    let ssoOptions: any[] = [];
    76  
    77    if (redirectRules.length > 0) {
    78      ssoOptions = redirectRules.map((r) => ({
    79        label: `${r.displayName}${r.serviceType ? ` - ${r.serviceType}` : ""}`,
    80        value: r.redirect,
    81        icon: <LogoutIcon />,
    82      }));
    83  
    84      selectOptions = [
    85        { label: "Use Credentials", value: "use-sts-cred" },
    86        { label: "Use STS", value: "use-sts" },
    87      ];
    88    }
    89  
    90    const extraActionSelector = (value: string) => {
    91      if (value) {
    92        if (redirectRules.length > 0) {
    93          let stsState = true;
    94  
    95          if (value === "use-sts-cred") {
    96            stsState = false;
    97          }
    98  
    99          dispatch(setUseSTS(stsState));
   100          dispatch(setDisplayEmbeddedIDPForms(true));
   101  
   102          return;
   103        }
   104  
   105        if (value.includes("use-sts")) {
   106          dispatch(setUseSTS(!useSTS));
   107          return;
   108        }
   109      }
   110    };
   111  
   112    const submitSSOInitRequest = (value: string) => {
   113      window.location.href = value;
   114    };
   115  
   116    return (
   117      <React.Fragment>
   118        {redirectRules.length > 0 && (
   119          <Fragment>
   120            <Box sx={{ marginBottom: 40 }}>
   121              <Button
   122                id={"SSOSelector"}
   123                variant={"subAction"}
   124                label={
   125                  redirectRules.length === 1
   126                    ? `${redirectRules[0].displayName}${
   127                        redirectRules[0].serviceType
   128                          ? ` - ${redirectRules[0].serviceType}`
   129                          : ""
   130                      }`
   131                    : `Login with SSO`
   132                }
   133                fullWidth
   134                sx={{ height: 50 }}
   135                onClick={(e) => {
   136                  if (redirectRules.length > 1) {
   137                    ssoOptionsSetOpen(!ssoOptionsOpen);
   138                    setAnchorEl(e.currentTarget);
   139                    return;
   140                  }
   141                  submitSSOInitRequest(`${redirectRules[0].redirect}`);
   142                }}
   143              />
   144              {redirectRules.length > 1 && (
   145                <DropdownSelector
   146                  id={"redirect-rules"}
   147                  options={ssoOptions}
   148                  selectedOption={""}
   149                  onSelect={(nValue) => submitSSOInitRequest(nValue)}
   150                  hideTriggerAction={() => {
   151                    ssoOptionsSetOpen(false);
   152                  }}
   153                  open={ssoOptionsOpen}
   154                  anchorEl={anchorEl}
   155                  useAnchorWidth={true}
   156                />
   157              )}
   158            </Box>
   159          </Fragment>
   160        )}
   161  
   162        <form noValidate onSubmit={formSubmit} style={{ width: "100%" }}>
   163          {((displaySSOForm && redirectRules.length > 0) ||
   164            redirectRules.length === 0) && (
   165            <Fragment>
   166              <Grid
   167                container
   168                sx={{
   169                  marginTop: redirectRules.length > 0 ? 55 : 0,
   170                }}
   171              >
   172                <Grid item xs={12} sx={{ marginBottom: 14 }}>
   173                  <InputBox
   174                    fullWidth
   175                    id="accessKey"
   176                    value={accessKey}
   177                    onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
   178                      dispatch(setAccessKey(e.target.value))
   179                    }
   180                    placeholder={useSTS ? "STS Username" : "Username"}
   181                    name="accessKey"
   182                    autoComplete="username"
   183                    disabled={loginSending}
   184                    startIcon={<UserFilledIcon />}
   185                  />
   186                </Grid>
   187                <Grid item xs={12} sx={{ marginBottom: useSTS ? 14 : 0 }}>
   188                  <InputBox
   189                    fullWidth
   190                    value={secretKey}
   191                    onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
   192                      dispatch(setSecretKey(e.target.value))
   193                    }
   194                    name="secretKey"
   195                    type="password"
   196                    id="secretKey"
   197                    autoComplete="current-password"
   198                    disabled={loginSending}
   199                    placeholder={useSTS ? "STS Secret" : "Password"}
   200                    startIcon={<LockFilledIcon />}
   201                  />
   202                </Grid>
   203                {useSTS && (
   204                  <Grid item xs={12}>
   205                    <InputBox
   206                      fullWidth
   207                      id="sts"
   208                      value={sts}
   209                      onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
   210                        dispatch(setSTS(e.target.value))
   211                      }
   212                      placeholder={"STS Token"}
   213                      name="STS"
   214                      autoComplete="sts"
   215                      disabled={loginSending}
   216                      startIcon={<PasswordKeyIcon />}
   217                    />
   218                  </Grid>
   219                )}
   220              </Grid>
   221  
   222              <Grid
   223                item
   224                xs={12}
   225                sx={{
   226                  textAlign: "right",
   227                  marginTop: 30,
   228                }}
   229              >
   230                <Button
   231                  type="submit"
   232                  variant="callAction"
   233                  color="primary"
   234                  id="do-login"
   235                  disabled={
   236                    (!useSTS && (accessKey === "" || secretKey === "")) ||
   237                    (useSTS &&
   238                      (accessKey === "" || secretKey === "" || sts === "")) ||
   239                    loginSending
   240                  }
   241                  label={"Login"}
   242                  sx={{
   243                    margin: "30px 0px 8px",
   244                    height: 40,
   245                    width: "100%",
   246                    boxShadow: "none",
   247                    padding: "16px 30px",
   248                  }}
   249                  fullWidth
   250                />
   251              </Grid>
   252              <Grid
   253                item
   254                xs={12}
   255                sx={{
   256                  height: 10,
   257                }}
   258              >
   259                {loginSending && <ProgressBar />}
   260              </Grid>
   261            </Fragment>
   262          )}
   263          <Grid item xs={12} sx={{ marginTop: 45 }}>
   264            <Select
   265              id="alternativeMethods"
   266              name="alternativeMethods"
   267              fixedLabel="Other Authentication Methods"
   268              options={selectOptions}
   269              onChange={extraActionSelector}
   270              value={""}
   271            />
   272          </Grid>
   273        </form>
   274      </React.Fragment>
   275    );
   276  };
   277  
   278  export default StrategyForm;