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:
@@ -218,7 +218,9 @@ const EditEndpointModal = ({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
tooltip={
|
tooltip={
|
||||||
overrideValues.enable
|
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"}
|
placement={"left"}
|
||||||
@@ -245,7 +247,9 @@ const EditEndpointModal = ({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
tooltip={
|
tooltip={
|
||||||
overrideValues.enable
|
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"}
|
placement={"left"}
|
||||||
@@ -272,7 +276,9 @@ const EditEndpointModal = ({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
tooltip={
|
tooltip={
|
||||||
overrideValues.enable
|
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"}
|
placement={"left"}
|
||||||
|
|||||||
@@ -14,21 +14,26 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// 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 {
|
import {
|
||||||
BackLink,
|
BackLink,
|
||||||
|
Box,
|
||||||
|
breakPoints,
|
||||||
Button,
|
Button,
|
||||||
|
ConsoleIcon,
|
||||||
EditIcon,
|
EditIcon,
|
||||||
|
FormLayout,
|
||||||
|
Grid,
|
||||||
|
HelpBox,
|
||||||
|
InputBox,
|
||||||
PageLayout,
|
PageLayout,
|
||||||
RefreshIcon,
|
RefreshIcon,
|
||||||
TrashIcon,
|
|
||||||
Box,
|
|
||||||
Grid,
|
|
||||||
Switch,
|
|
||||||
InputBox,
|
|
||||||
FormLayout,
|
|
||||||
breakPoints,
|
|
||||||
ScreenTitle,
|
ScreenTitle,
|
||||||
|
Switch,
|
||||||
|
Tooltip,
|
||||||
|
TrashIcon,
|
||||||
|
ValuePair,
|
||||||
|
WarnIcon,
|
||||||
} from "mds";
|
} from "mds";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||||
@@ -42,7 +47,6 @@ import {
|
|||||||
import api from "../../../common/api";
|
import api from "../../../common/api";
|
||||||
import useApi from "../Common/Hooks/useApi";
|
import useApi from "../Common/Hooks/useApi";
|
||||||
import DeleteIDPConfigurationModal from "./DeleteIDPConfigurationModal";
|
import DeleteIDPConfigurationModal from "./DeleteIDPConfigurationModal";
|
||||||
import LabelValuePair from "../Common/UsageBarWrapper/LabelValuePair";
|
|
||||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||||
import HelpMenu from "../HelpMenu";
|
import HelpMenu from "../HelpMenu";
|
||||||
|
|
||||||
@@ -74,10 +78,12 @@ const IDPConfigurationDetails = ({
|
|||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [isEnabled, setIsEnabled] = useState<boolean>(false);
|
const [isEnabled, setIsEnabled] = useState<boolean>(false);
|
||||||
const [fields, setFields] = useState<any>({});
|
const [fields, setFields] = useState<any>({});
|
||||||
|
const [overrideFields, setOverrideFields] = useState<any>({});
|
||||||
const [originalFields, setOriginalFields] = useState<any>({});
|
const [originalFields, setOriginalFields] = useState<any>({});
|
||||||
const [record, setRecord] = useState<any>({});
|
const [record, setRecord] = useState<any>({});
|
||||||
const [editMode, setEditMode] = useState<boolean>(false);
|
const [editMode, setEditMode] = useState<boolean>(false);
|
||||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||||
|
const [envOverride, setEnvOverride] = useState<boolean>(false);
|
||||||
|
|
||||||
const onSuccess = (res: any) => {
|
const onSuccess = (res: any) => {
|
||||||
dispatch(setServerNeedsRestart(res.restart === true));
|
dispatch(setServerNeedsRestart(res.restart === true));
|
||||||
@@ -102,6 +108,40 @@ const IDPConfigurationDetails = ({
|
|||||||
onEnabledError,
|
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 = () => {
|
const toggleEditMode = () => {
|
||||||
if (editMode) {
|
if (editMode) {
|
||||||
parseFields(record);
|
parseFields(record);
|
||||||
@@ -109,19 +149,6 @@ const IDPConfigurationDetails = ({
|
|||||||
setEditMode(!editMode);
|
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) => {
|
const parseOriginalFields = (record: any) => {
|
||||||
let fields: any = {};
|
let fields: any = {};
|
||||||
if (record.info) {
|
if (record.info) {
|
||||||
@@ -157,7 +184,7 @@ const IDPConfigurationDetails = ({
|
|||||||
if (loading) {
|
if (loading) {
|
||||||
loadRecord();
|
loadRecord();
|
||||||
}
|
}
|
||||||
}, [dispatch, loading, configurationName, endpoint]);
|
}, [dispatch, loading, configurationName, endpoint, parseFields]);
|
||||||
|
|
||||||
const validSave = () => {
|
const validSave = () => {
|
||||||
for (const [key, value] of Object.entries(formFields)) {
|
for (const [key, value] of Object.entries(formFields)) {
|
||||||
@@ -255,6 +282,27 @@ const IDPConfigurationDetails = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Grid container>
|
<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>
|
<Grid xs={12} item>
|
||||||
{Object.entries(formFields).map(([key, value]) =>
|
{Object.entries(formFields).map(([key, value]) =>
|
||||||
renderFormField(key, value),
|
renderFormField(key, value),
|
||||||
@@ -298,26 +346,72 @@ const IDPConfigurationDetails = ({
|
|||||||
const renderViewForm = () => {
|
const renderViewForm = () => {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
withBorders
|
||||||
sx={{
|
sx={{
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: "1fr",
|
gridTemplateColumns: "1fr",
|
||||||
gridAutoFlow: "dense",
|
gridAutoFlow: "dense",
|
||||||
gap: 3,
|
gap: 3,
|
||||||
padding: "15px",
|
padding: "15px",
|
||||||
border: "1px solid #eaeaea",
|
|
||||||
[`@media (min-width: ${breakPoints.sm}px)`]: {
|
[`@media (min-width: ${breakPoints.sm}px)`]: {
|
||||||
gridTemplateColumns: "2fr 1fr",
|
gridTemplateColumns: "2fr 1fr",
|
||||||
gridAutoFlow: "row",
|
gridAutoFlow: "row",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Object.entries(formFields).map(([key, value]) => (
|
{Object.entries(formFields).map(([key, value]) => {
|
||||||
<LabelValuePair
|
if (!value.editOnly) {
|
||||||
key={key}
|
let label: React.ReactNode = value.label;
|
||||||
label={value.label}
|
let val: React.ReactNode = fields[key] ? fields[key] : "";
|
||||||
value={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>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -351,32 +445,58 @@ const IDPConfigurationDetails = ({
|
|||||||
actions={
|
actions={
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{configurationName !== "_" && (
|
{configurationName !== "_" && (
|
||||||
<Button
|
<Tooltip
|
||||||
id={"delete-idp-config"}
|
tooltip={
|
||||||
onClick={() => {
|
envOverride
|
||||||
setDeleteOpen(true);
|
? "This configuration cannot be deleted using this module as this was set using OpenID environment variables."
|
||||||
}}
|
: ""
|
||||||
label={"Delete Configuration"}
|
}
|
||||||
icon={<TrashIcon />}
|
>
|
||||||
variant={"secondary"}
|
<Button
|
||||||
/>
|
id={"delete-idp-config"}
|
||||||
|
onClick={() => {
|
||||||
|
setDeleteOpen(true);
|
||||||
|
}}
|
||||||
|
label={"Delete Configuration"}
|
||||||
|
icon={<TrashIcon />}
|
||||||
|
variant={"secondary"}
|
||||||
|
disabled={envOverride}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{!editMode && (
|
{!editMode && (
|
||||||
<Button
|
<Tooltip
|
||||||
id={"edit"}
|
tooltip={
|
||||||
type="button"
|
envOverride
|
||||||
variant={"callAction"}
|
? "Configuration cannot be edited in this module as OpenID environment variables are set for this MinIO instance."
|
||||||
icon={<EditIcon />}
|
: ""
|
||||||
onClick={toggleEditMode}
|
}
|
||||||
label={"Edit"}
|
>
|
||||||
/>
|
<Button
|
||||||
|
id={"edit"}
|
||||||
|
type="button"
|
||||||
|
variant={"callAction"}
|
||||||
|
icon={<EditIcon />}
|
||||||
|
onClick={toggleEditMode}
|
||||||
|
label={"Edit"}
|
||||||
|
disabled={envOverride}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Tooltip
|
||||||
id={"is-configuration-enabled"}
|
tooltip={
|
||||||
onClick={() => toggleConfiguration(!isEnabled)}
|
envOverride
|
||||||
label={isEnabled ? "Disable" : "Enable"}
|
? "Configuration cannot be disabled / enabled in this module as OpenID environment variables are set for this MinIO instance."
|
||||||
disabled={loadingEnabledSave}
|
: ""
|
||||||
/>
|
}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
id={"is-configuration-enabled"}
|
||||||
|
onClick={() => toggleConfiguration(!isEnabled)}
|
||||||
|
label={isEnabled ? "Disable" : "Enable"}
|
||||||
|
disabled={loadingEnabledSave || envOverride}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
id={"refresh-idp-config"}
|
id={"refresh-idp-config"}
|
||||||
onClick={() => setLoading(true)}
|
onClick={() => setLoading(true)}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export const openIDFormFields = {
|
|||||||
placeholder:
|
placeholder:
|
||||||
"https://identity-provider-url/.well-known/openid-configuration",
|
"https://identity-provider-url/.well-known/openid-configuration",
|
||||||
type: "text",
|
type: "text",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
client_id: {
|
client_id: {
|
||||||
required: true,
|
required: true,
|
||||||
@@ -69,6 +70,7 @@ export const openIDFormFields = {
|
|||||||
tooltip: "Identity provider Client ID",
|
tooltip: "Identity provider Client ID",
|
||||||
placeholder: "Enter Client ID",
|
placeholder: "Enter Client ID",
|
||||||
type: "text",
|
type: "text",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
client_secret: {
|
client_secret: {
|
||||||
required: true,
|
required: true,
|
||||||
@@ -79,6 +81,7 @@ export const openIDFormFields = {
|
|||||||
tooltip: "Identity provider Client Secret",
|
tooltip: "Identity provider Client Secret",
|
||||||
placeholder: "Enter Client Secret",
|
placeholder: "Enter Client Secret",
|
||||||
type: "password",
|
type: "password",
|
||||||
|
editOnly: true,
|
||||||
},
|
},
|
||||||
claim_name: {
|
claim_name: {
|
||||||
required: false,
|
required: false,
|
||||||
@@ -87,6 +90,7 @@ export const openIDFormFields = {
|
|||||||
placeholder: "Enter Claim Name",
|
placeholder: "Enter Claim Name",
|
||||||
type: "text",
|
type: "text",
|
||||||
hasError: (s: string, editMode: boolean) => "",
|
hasError: (s: string, editMode: boolean) => "",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
display_name: {
|
display_name: {
|
||||||
required: false,
|
required: false,
|
||||||
@@ -95,6 +99,7 @@ export const openIDFormFields = {
|
|||||||
placeholder: "Enter Display Name",
|
placeholder: "Enter Display Name",
|
||||||
type: "text",
|
type: "text",
|
||||||
hasError: (s: string, editMode: boolean) => "",
|
hasError: (s: string, editMode: boolean) => "",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
claim_prefix: {
|
claim_prefix: {
|
||||||
required: false,
|
required: false,
|
||||||
@@ -103,6 +108,7 @@ export const openIDFormFields = {
|
|||||||
placeholder: "Enter Claim Prefix",
|
placeholder: "Enter Claim Prefix",
|
||||||
type: "text",
|
type: "text",
|
||||||
hasError: (s: string, editMode: boolean) => "",
|
hasError: (s: string, editMode: boolean) => "",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
scopes: {
|
scopes: {
|
||||||
required: false,
|
required: false,
|
||||||
@@ -111,6 +117,7 @@ export const openIDFormFields = {
|
|||||||
placeholder: "openid,profile,email",
|
placeholder: "openid,profile,email",
|
||||||
type: "text",
|
type: "text",
|
||||||
hasError: (s: string, editMode: boolean) => "",
|
hasError: (s: string, editMode: boolean) => "",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
redirect_uri: {
|
redirect_uri: {
|
||||||
required: false,
|
required: false,
|
||||||
@@ -119,6 +126,7 @@ export const openIDFormFields = {
|
|||||||
placeholder: "https://console-endpoint-url/oauth_callback",
|
placeholder: "https://console-endpoint-url/oauth_callback",
|
||||||
type: "text",
|
type: "text",
|
||||||
hasError: (s: string, editMode: boolean) => "",
|
hasError: (s: string, editMode: boolean) => "",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
role_policy: {
|
role_policy: {
|
||||||
required: false,
|
required: false,
|
||||||
@@ -127,6 +135,7 @@ export const openIDFormFields = {
|
|||||||
placeholder: "readonly",
|
placeholder: "readonly",
|
||||||
type: "text",
|
type: "text",
|
||||||
hasError: (s: string, editMode: boolean) => "",
|
hasError: (s: string, editMode: boolean) => "",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
claim_userinfo: {
|
claim_userinfo: {
|
||||||
required: false,
|
required: false,
|
||||||
@@ -135,6 +144,7 @@ export const openIDFormFields = {
|
|||||||
placeholder: "Claim User Info",
|
placeholder: "Claim User Info",
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
hasError: (s: string, editMode: boolean) => "",
|
hasError: (s: string, editMode: boolean) => "",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
redirect_uri_dynamic: {
|
redirect_uri_dynamic: {
|
||||||
required: false,
|
required: false,
|
||||||
@@ -143,6 +153,7 @@ export const openIDFormFields = {
|
|||||||
placeholder: "Redirect URI Dynamic",
|
placeholder: "Redirect URI Dynamic",
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
hasError: (s: string, editMode: boolean) => "",
|
hasError: (s: string, editMode: boolean) => "",
|
||||||
|
editOnly: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,6 @@ import { RedirectRule } from "api/consoleApi";
|
|||||||
import { redirectRules } from "./login.utils";
|
import { redirectRules } from "./login.utils";
|
||||||
import { setHelpName } from "../../systemSlice";
|
import { setHelpName } from "../../systemSlice";
|
||||||
|
|
||||||
export interface LoginStrategyPayload {
|
|
||||||
accessKey: string;
|
|
||||||
secretKey: string;
|
|
||||||
sts?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTargetPath = () => {
|
export const getTargetPath = () => {
|
||||||
let targetPath = "/browser";
|
let targetPath = "/browser";
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ func getIDPConfiguration(ctx context.Context, idpType, name string, client Minio
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &models.IdpServerConfiguration{
|
return &models.IdpServerConfiguration{
|
||||||
Name: config.Name,
|
Name: config.Name,
|
||||||
Type: config.Type,
|
Type: config.Type,
|
||||||
|
|||||||
Reference in New Issue
Block a user