mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 04:27:29 +00:00
added user controller and modified auth method page
This commit is contained in:
@@ -148,6 +148,43 @@ export const updateAuthProvider = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update auth provider of the current user to [authProvider]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const updateAuthProviders = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
authProviders
|
||||||
|
} = req.body;
|
||||||
|
|
||||||
|
if (
|
||||||
|
req.user?.authProvider === AuthProvider.OKTA_SAML
|
||||||
|
|| req.user?.authProvider === AuthProvider.AZURE_SAML
|
||||||
|
|| req.user?.authProvider === AuthProvider.JUMPCLOUD_SAML
|
||||||
|
) {
|
||||||
|
return res.status(400).send({
|
||||||
|
message: "Failed to update user authentication method because SAML SSO is enforced"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await User.findByIdAndUpdate(
|
||||||
|
req.user._id.toString(),
|
||||||
|
{
|
||||||
|
authProviders
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
user
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return organizations that the current user is part of.
|
* Return organizations that the current user is part of.
|
||||||
* @param req
|
* @param req
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export interface IUser extends Document {
|
|||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
authId?: string;
|
authId?: string;
|
||||||
authProvider?: AuthProvider;
|
authProvider?: AuthProvider;
|
||||||
|
authProviders?: AuthProvider[];
|
||||||
email: string;
|
email: string;
|
||||||
firstName?: string;
|
firstName?: string;
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
|
|||||||
@@ -57,6 +57,24 @@ router.patch(
|
|||||||
usersController.updateAuthProvider
|
usersController.updateAuthProvider
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.put(
|
||||||
|
"/me/auth-providers",
|
||||||
|
requireAuth({
|
||||||
|
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY],
|
||||||
|
}),
|
||||||
|
body("authProviders").exists().isArray({
|
||||||
|
min: 1,
|
||||||
|
}).custom((authProviders: AuthProvider[]) => {
|
||||||
|
return authProviders.every(provider => [
|
||||||
|
AuthProvider.EMAIL,
|
||||||
|
AuthProvider.GOOGLE,
|
||||||
|
AuthProvider.GITHUB
|
||||||
|
].includes(provider))
|
||||||
|
}),
|
||||||
|
validateRequest,
|
||||||
|
usersController.updateAuthProviders,
|
||||||
|
);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/me/organizations",
|
"/me/organizations",
|
||||||
requireAuth({
|
requireAuth({
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type Props = {
|
|||||||
position?: "item-aligned" | "popper";
|
position?: "item-aligned" | "popper";
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
icon?: IconProp;
|
icon?: IconProp;
|
||||||
|
isMulti?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SelectProps = Omit<SelectPrimitive.SelectProps, "disabled"> & Props;
|
export type SelectProps = Omit<SelectPrimitive.SelectProps, "disabled"> & Props;
|
||||||
|
|||||||
@@ -15,5 +15,6 @@ export {
|
|||||||
useRegisterUserAction,
|
useRegisterUserAction,
|
||||||
useRevokeMySessions,
|
useRevokeMySessions,
|
||||||
useUpdateOrgUserRole,
|
useUpdateOrgUserRole,
|
||||||
useUpdateUserAuthProvider
|
useUpdateUserAuthProvider,
|
||||||
|
useUpdateUserAuthProviders,
|
||||||
} from "./queries";
|
} from "./queries";
|
||||||
|
|||||||
@@ -80,6 +80,28 @@ export const useUpdateUserAuthProvider = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const useUpdateUserAuthProviders = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async ({
|
||||||
|
authProviders
|
||||||
|
}: {
|
||||||
|
authProviders: string[];
|
||||||
|
}) => {
|
||||||
|
const { data: { user } } = await apiRequest.put("/api/v2/users/me/auth-providers", {
|
||||||
|
authProviders
|
||||||
|
});
|
||||||
|
|
||||||
|
return user;
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(userKeys.getUser);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const useGetUserAction = (action: string) =>
|
export const useGetUserAction = (action: string) =>
|
||||||
useQuery({
|
useQuery({
|
||||||
queryKey: userKeys.userAction,
|
queryKey: userKeys.userAction,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export type User = {
|
|||||||
firstName?: string;
|
firstName?: string;
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
authProvider?: AuthProvider;
|
authProvider?: AuthProvider;
|
||||||
|
authProviders?: AuthProvider[];
|
||||||
encryptionVersion?: number;
|
encryptionVersion?: number;
|
||||||
protectedKey?: string;
|
protectedKey?: string;
|
||||||
protectedKeyIV?: string;
|
protectedKeyIV?: string;
|
||||||
|
|||||||
+41
-46
@@ -1,17 +1,16 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { yupResolver } from "@hookform/resolvers/yup";
|
import { yupResolver } from "@hookform/resolvers/yup";
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
|
|
||||||
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
FormControl,
|
Checkbox
|
||||||
Select,
|
} from "@app/components/v2";
|
||||||
SelectItem} from "@app/components/v2";
|
|
||||||
import { useUser } from "@app/context";
|
import { useUser } from "@app/context";
|
||||||
import {
|
import {
|
||||||
useUpdateUserAuthProvider
|
useUpdateUserAuthProviders
|
||||||
} from "@app/hooks/api";
|
} from "@app/hooks/api";
|
||||||
|
|
||||||
const authMethods = [
|
const authMethods = [
|
||||||
@@ -24,7 +23,7 @@ const authMethods = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const schema = yup.object({
|
const schema = yup.object({
|
||||||
authMethod: yup.string().required("Auth method is required")
|
authMethods: yup.array().required("Auth method is required")
|
||||||
});
|
});
|
||||||
|
|
||||||
export type FormData = yup.InferType<typeof schema>;
|
export type FormData = yup.InferType<typeof schema>;
|
||||||
@@ -32,35 +31,38 @@ export type FormData = yup.InferType<typeof schema>;
|
|||||||
export const AuthMethodSection = () => {
|
export const AuthMethodSection = () => {
|
||||||
const { createNotification } = useNotificationContext();
|
const { createNotification } = useNotificationContext();
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
const { mutateAsync, isLoading } = useUpdateUserAuthProvider();
|
const { mutateAsync, isLoading } = useUpdateUserAuthProviders();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
reset,
|
reset,
|
||||||
control,
|
handleSubmit,
|
||||||
handleSubmit
|
setValue,
|
||||||
|
watch,
|
||||||
} = useForm<FormData>({
|
} = useForm<FormData>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
authMethod: user?.authProvider ?? "email"
|
authMethods: [user?.authProvider ?? "email"]
|
||||||
},
|
},
|
||||||
resolver: yupResolver(schema)
|
resolver: yupResolver(schema)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const selectedAuthMethods = watch("authMethods");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user) {
|
if (user) {
|
||||||
reset({
|
reset({
|
||||||
authMethod: user?.authProvider ?? "email"
|
authMethods: [user?.authProvider ?? "email"]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
const onFormSubmit = async ({
|
const onFormSubmit = async ({
|
||||||
authMethod
|
authMethods
|
||||||
}: FormData) => {
|
}: FormData) => {
|
||||||
try {
|
try {
|
||||||
if (
|
if (
|
||||||
authMethod === "okta-saml"
|
authMethods.includes("okta-saml")
|
||||||
|| authMethod === "azure-saml"
|
|| authMethods.includes("azure-saml")
|
||||||
|| authMethod === "jumpcloud-saml"
|
|| authMethods.includes("jumpcloud-saml")
|
||||||
) {
|
) {
|
||||||
createNotification({
|
createNotification({
|
||||||
text: "SAML authentication can only be configured in your organization settings",
|
text: "SAML authentication can only be configured in your organization settings",
|
||||||
@@ -71,7 +73,7 @@ export const AuthMethodSection = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
authProvider: authMethod
|
authProviders: authMethods
|
||||||
});
|
});
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
@@ -96,36 +98,29 @@ export const AuthMethodSection = () => {
|
|||||||
Authentication Method
|
Authentication Method
|
||||||
</h2>
|
</h2>
|
||||||
<div className="max-w-md mb-4">
|
<div className="max-w-md mb-4">
|
||||||
<Controller
|
{
|
||||||
control={control}
|
authMethods.map(authMethod => (
|
||||||
name="authMethod"
|
<Checkbox
|
||||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
className="data-[state=checked]:bg-primary"
|
||||||
<FormControl
|
id={`auth-method-id-${authMethod.label}`}
|
||||||
className="mb-0"
|
key={`auth-method-${authMethod.label}`}
|
||||||
errorText={error?.message}
|
isChecked={selectedAuthMethods.includes(authMethod.value)}
|
||||||
isError={Boolean(error)}
|
onCheckedChange={(checked) => {
|
||||||
>
|
if (checked) {
|
||||||
<Select
|
setValue("authMethods", [
|
||||||
defaultValue={field.value}
|
...selectedAuthMethods,
|
||||||
{...field}
|
authMethod.value
|
||||||
onValueChange={(e) => onChange(e)}
|
])
|
||||||
className="w-full bg-mineshaft-800 border border-mineshaft-600"
|
} else {
|
||||||
>
|
setValue("authMethods", selectedAuthMethods.filter(auth => auth !== authMethod.value))
|
||||||
{authMethods.map((authMethod) => {
|
}
|
||||||
return (
|
}}>
|
||||||
<SelectItem
|
{authMethod.label}
|
||||||
value={authMethod.value}
|
</Checkbox>
|
||||||
key={`auth-method-${authMethod.value}`}
|
))
|
||||||
>
|
}
|
||||||
{authMethod.label}
|
|
||||||
</SelectItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
colorSchema="secondary"
|
colorSchema="secondary"
|
||||||
@@ -136,4 +131,4 @@ export const AuthMethodSection = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user