Updated OpenID UX (#3050)

- Display ENV variables set in configuration
- Removed Password empty placeholders
- Added notification to re-enter password when modifying OpenID configuration

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2023-09-22 13:50:41 -06:00
committed by GitHub
parent 1ce2846c95
commit 300ebfa19f
5 changed files with 195 additions and 63 deletions

View File

@@ -218,7 +218,9 @@ const EditEndpointModal = ({
<Tooltip
tooltip={
overrideValues.enable
? `This value is set from the ${overrideValues.enable.overrideEnv} environment variable`
? `This value is set from the ${
overrideValues.enable?.overrideEnv || "N/A"
} environment variable`
: ""
}
placement={"left"}
@@ -245,7 +247,9 @@ const EditEndpointModal = ({
<Tooltip
tooltip={
overrideValues.enable
? `This value is set from the ${overrideValues.endpoint.overrideEnv} environment variable`
? `This value is set from the ${
overrideValues.endpoint?.overrideEnv || "N/A"
} environment variable`
: ""
}
placement={"left"}
@@ -272,7 +276,9 @@ const EditEndpointModal = ({
<Tooltip
tooltip={
overrideValues.enable
? `This value is set from the ${overrideValues.auth_token.overrideEnv} environment variable`
? `This value is set from the ${
overrideValues.auth_token?.overrideEnv || "N/A"
} environment variable`
: ""
}
placement={"left"}

View File

@@ -14,21 +14,26 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { Fragment, useEffect, useState } from "react";
import React, { Fragment, useCallback, useEffect, useState } from "react";
import {
BackLink,
Box,
breakPoints,
Button,
ConsoleIcon,
EditIcon,
FormLayout,
Grid,
HelpBox,
InputBox,
PageLayout,
RefreshIcon,
TrashIcon,
Box,
Grid,
Switch,
InputBox,
FormLayout,
breakPoints,
ScreenTitle,
Switch,
Tooltip,
TrashIcon,
ValuePair,
WarnIcon,
} from "mds";
import { useNavigate, useParams } from "react-router-dom";
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
@@ -42,7 +47,6 @@ import {
import api from "../../../common/api";
import useApi from "../Common/Hooks/useApi";
import DeleteIDPConfigurationModal from "./DeleteIDPConfigurationModal";
import LabelValuePair from "../Common/UsageBarWrapper/LabelValuePair";
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
import HelpMenu from "../HelpMenu";
@@ -74,10 +78,12 @@ const IDPConfigurationDetails = ({
const [loading, setLoading] = useState<boolean>(true);
const [isEnabled, setIsEnabled] = useState<boolean>(false);
const [fields, setFields] = useState<any>({});
const [overrideFields, setOverrideFields] = useState<any>({});
const [originalFields, setOriginalFields] = useState<any>({});
const [record, setRecord] = useState<any>({});
const [editMode, setEditMode] = useState<boolean>(false);
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
const [envOverride, setEnvOverride] = useState<boolean>(false);
const onSuccess = (res: any) => {
dispatch(setServerNeedsRestart(res.restart === true));
@@ -102,6 +108,40 @@ const IDPConfigurationDetails = ({
onEnabledError,
);
const parseFields = useCallback(
(record: any) => {
let fields: any = {};
let overrideFields: any = {};
let totEnv = 0;
if (record.info) {
record.info.forEach((item: any) => {
if (item.key === "enable") {
setIsEnabled(item.value === "on");
}
if (item.isEnv) {
overrideFields[
item.key
] = `MINIO_IDENTITY_OPENID_${item.key.toUpperCase()}${
configurationName !== "_" ? `_${configurationName}` : ""
}`;
totEnv++;
}
fields[item.key] = item.value;
});
if (totEnv > 0) {
setEnvOverride(true);
}
}
setFields(fields);
setOverrideFields(overrideFields);
},
[configurationName],
);
const toggleEditMode = () => {
if (editMode) {
parseFields(record);
@@ -109,19 +149,6 @@ const IDPConfigurationDetails = ({
setEditMode(!editMode);
};
const parseFields = (record: any) => {
let fields: any = {};
if (record.info) {
record.info.forEach((item: any) => {
if (item.key === "enable") {
setIsEnabled(item.value === "on");
}
fields[item.key] = item.value;
});
}
setFields(fields);
};
const parseOriginalFields = (record: any) => {
let fields: any = {};
if (record.info) {
@@ -157,7 +184,7 @@ const IDPConfigurationDetails = ({
if (loading) {
loadRecord();
}
}, [dispatch, loading, configurationName, endpoint]);
}, [dispatch, loading, configurationName, endpoint, parseFields]);
const validSave = () => {
for (const [key, value] of Object.entries(formFields)) {
@@ -255,6 +282,27 @@ const IDPConfigurationDetails = ({
}}
>
<Grid container>
{editMode ? (
<Grid item xs={12} sx={{ marginBottom: 15 }}>
<HelpBox
title={
<Box
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
flexGrow: 1,
}}
>
Client Secret must be re-entered to change OpenID
configurations
</Box>
}
iconComponent={<WarnIcon />}
help={null}
/>
</Grid>
) : null}
<Grid xs={12} item>
{Object.entries(formFields).map(([key, value]) =>
renderFormField(key, value),
@@ -298,26 +346,72 @@ const IDPConfigurationDetails = ({
const renderViewForm = () => {
return (
<Box
withBorders
sx={{
display: "grid",
gridTemplateColumns: "1fr",
gridAutoFlow: "dense",
gap: 3,
padding: "15px",
border: "1px solid #eaeaea",
[`@media (min-width: ${breakPoints.sm}px)`]: {
gridTemplateColumns: "2fr 1fr",
gridAutoFlow: "row",
},
}}
>
{Object.entries(formFields).map(([key, value]) => (
<LabelValuePair
key={key}
label={value.label}
value={fields[key] ? fields[key] : ""}
/>
))}
{Object.entries(formFields).map(([key, value]) => {
if (!value.editOnly) {
let label: React.ReactNode = value.label;
let val: React.ReactNode = fields[key] ? fields[key] : "";
if (value.type === "toggle" && fields[key]) {
if (val !== "on") {
val = "Off";
} else {
val = "On";
}
}
if (overrideFields[key]) {
label = (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: 5,
"& .min-icon": {
height: 20,
width: 20,
},
"& span": {
height: 20,
display: "flex",
alignItems: "center",
},
}}
>
<span>{value.label}</span>
<Tooltip
tooltip={`This value is set from the ${overrideFields[key]} environment variable`}
placement={"right"}
>
<span className={"muted"}>
<ConsoleIcon />
</span>
</Tooltip>
</Box>
);
val = (
<i>
<span className={"muted"}>{val}</span>
</i>
);
}
return <ValuePair key={key} label={label} value={val} />;
}
return null;
})}
</Box>
);
};
@@ -351,32 +445,58 @@ const IDPConfigurationDetails = ({
actions={
<Fragment>
{configurationName !== "_" && (
<Button
id={"delete-idp-config"}
onClick={() => {
setDeleteOpen(true);
}}
label={"Delete Configuration"}
icon={<TrashIcon />}
variant={"secondary"}
/>
<Tooltip
tooltip={
envOverride
? "This configuration cannot be deleted using this module as this was set using OpenID environment variables."
: ""
}
>
<Button
id={"delete-idp-config"}
onClick={() => {
setDeleteOpen(true);
}}
label={"Delete Configuration"}
icon={<TrashIcon />}
variant={"secondary"}
disabled={envOverride}
/>
</Tooltip>
)}
{!editMode && (
<Button
id={"edit"}
type="button"
variant={"callAction"}
icon={<EditIcon />}
onClick={toggleEditMode}
label={"Edit"}
/>
<Tooltip
tooltip={
envOverride
? "Configuration cannot be edited in this module as OpenID environment variables are set for this MinIO instance."
: ""
}
>
<Button
id={"edit"}
type="button"
variant={"callAction"}
icon={<EditIcon />}
onClick={toggleEditMode}
label={"Edit"}
disabled={envOverride}
/>
</Tooltip>
)}
<Button
id={"is-configuration-enabled"}
onClick={() => toggleConfiguration(!isEnabled)}
label={isEnabled ? "Disable" : "Enable"}
disabled={loadingEnabledSave}
/>
<Tooltip
tooltip={
envOverride
? "Configuration cannot be disabled / enabled in this module as OpenID environment variables are set for this MinIO instance."
: ""
}
>
<Button
id={"is-configuration-enabled"}
onClick={() => toggleConfiguration(!isEnabled)}
label={isEnabled ? "Disable" : "Enable"}
disabled={loadingEnabledSave || envOverride}
/>
</Tooltip>
<Button
id={"refresh-idp-config"}
onClick={() => setLoading(true)}

View File

@@ -59,6 +59,7 @@ export const openIDFormFields = {
placeholder:
"https://identity-provider-url/.well-known/openid-configuration",
type: "text",
editOnly: false,
},
client_id: {
required: true,
@@ -69,6 +70,7 @@ export const openIDFormFields = {
tooltip: "Identity provider Client ID",
placeholder: "Enter Client ID",
type: "text",
editOnly: false,
},
client_secret: {
required: true,
@@ -79,6 +81,7 @@ export const openIDFormFields = {
tooltip: "Identity provider Client Secret",
placeholder: "Enter Client Secret",
type: "password",
editOnly: true,
},
claim_name: {
required: false,
@@ -87,6 +90,7 @@ export const openIDFormFields = {
placeholder: "Enter Claim Name",
type: "text",
hasError: (s: string, editMode: boolean) => "",
editOnly: false,
},
display_name: {
required: false,
@@ -95,6 +99,7 @@ export const openIDFormFields = {
placeholder: "Enter Display Name",
type: "text",
hasError: (s: string, editMode: boolean) => "",
editOnly: false,
},
claim_prefix: {
required: false,
@@ -103,6 +108,7 @@ export const openIDFormFields = {
placeholder: "Enter Claim Prefix",
type: "text",
hasError: (s: string, editMode: boolean) => "",
editOnly: false,
},
scopes: {
required: false,
@@ -111,6 +117,7 @@ export const openIDFormFields = {
placeholder: "openid,profile,email",
type: "text",
hasError: (s: string, editMode: boolean) => "",
editOnly: false,
},
redirect_uri: {
required: false,
@@ -119,6 +126,7 @@ export const openIDFormFields = {
placeholder: "https://console-endpoint-url/oauth_callback",
type: "text",
hasError: (s: string, editMode: boolean) => "",
editOnly: false,
},
role_policy: {
required: false,
@@ -127,6 +135,7 @@ export const openIDFormFields = {
placeholder: "readonly",
type: "text",
hasError: (s: string, editMode: boolean) => "",
editOnly: false,
},
claim_userinfo: {
required: false,
@@ -135,6 +144,7 @@ export const openIDFormFields = {
placeholder: "Claim User Info",
type: "toggle",
hasError: (s: string, editMode: boolean) => "",
editOnly: false,
},
redirect_uri_dynamic: {
required: false,
@@ -143,6 +153,7 @@ export const openIDFormFields = {
placeholder: "Redirect URI Dynamic",
type: "toggle",
hasError: (s: string, editMode: boolean) => "",
editOnly: false,
},
};

View File

@@ -29,12 +29,6 @@ import { RedirectRule } from "api/consoleApi";
import { redirectRules } from "./login.utils";
import { setHelpName } from "../../systemSlice";
export interface LoginStrategyPayload {
accessKey: string;
secretKey: string;
sts?: string;
}
export const getTargetPath = () => {
let targetPath = "/browser";
if (

View File

@@ -198,6 +198,7 @@ func getIDPConfiguration(ctx context.Context, idpType, name string, client Minio
if err != nil {
return nil, err
}
return &models.IdpServerConfiguration{
Name: config.Name,
Type: config.Type,