feat(ldap): Adding support for LDAP authentication (#554)

This commit is contained in:
WolverinDEV
2024-08-24 16:15:33 +02:00
committed by GitHub
parent 4924f76394
commit 4186a768b3
17 changed files with 573 additions and 128 deletions

View File

@@ -11,7 +11,14 @@ import {
} from "@mantine/core";
import Link from "next/link";
import { Dispatch, SetStateAction } from "react";
import { TbAt, TbMail, TbShare, TbSocial, TbSquare } from "react-icons/tb";
import {
TbAt,
TbMail,
TbShare,
TbSocial,
TbSquare,
TbBinaryTree,
} from "react-icons/tb";
import { FormattedMessage } from "react-intl";
const categories = [
@@ -20,6 +27,7 @@ const categories = [
{ name: "Share", icon: <TbShare /> },
{ name: "SMTP", icon: <TbAt /> },
{ name: "OAuth", icon: <TbSocial /> },
{ name: "LDAP", icon: <TbBinaryTree /> },
];
const useStyles = createStyles((theme) => ({

View File

@@ -1,4 +1,4 @@
import { ActionIcon, Box, Group, Skeleton, Table } from "@mantine/core";
import { ActionIcon, Badge, Box, Group, Skeleton, Table } from "@mantine/core";
import { useModals } from "@mantine/modals";
import { TbCheck, TbEdit, TbTrash } from "react-icons/tb";
import User from "../../../types/user.type";
@@ -40,21 +40,28 @@ const ManageUserTable = ({
? skeletonRows
: users.map((user) => (
<tr key={user.id}>
<td>{user.username}</td>
<td>
{user.username}{" "}
{user.isLdap ? (
<Badge style={{ marginLeft: "1em" }}>LDAP</Badge>
) : null}
</td>
<td>{user.email}</td>
<td>{user.isAdmin && <TbCheck />}</td>
<td>
<Group position="right">
<ActionIcon
variant="light"
color="primary"
size="sm"
onClick={() =>
showUpdateUserModal(modals, user, getUsers)
}
>
<TbEdit />
</ActionIcon>
{user.isLdap ? null : (
<ActionIcon
variant="light"
color="primary"
size="sm"
onClick={() =>
showUpdateUserModal(modals, user, getUsers)
}
>
<TbEdit />
</ActionIcon>
)}
<ActionIcon
variant="light"
color="red"

View File

@@ -570,6 +570,21 @@ export default {
"admin.config.oauth.oidc-client-secret.description":
"Client secret of the OpenID Connect OAuth app",
"admin.config.category.ldap": "LDAP",
"admin.config.ldap.enabled": "Enabled LDAP",
"admin.config.ldap.enabled.description": "Use LDAP authentication for user login",
"admin.config.ldap.url": "Server URL",
"admin.config.ldap.url.description": "URL of the LDAP server",
"admin.config.ldap.bind-dn": "Bind DN",
"admin.config.ldap.bind-dn.description": "Default user which will be used to execute the user search",
"admin.config.ldap.bind-password": "Bind password",
"admin.config.ldap.bind-password.description": "Password for the user search user",
"admin.config.ldap.search-base": "User base",
"admin.config.ldap.search-base.description": "Base location, where the user search will be performed",
"admin.config.ldap.search-query": "User query",
"admin.config.ldap.search-query.description": "The user query will be used to search the 'User base' for the LDAP user. %username% can be used as the placeholder for the user given input.",
"admin.config.ldap.admin-groups": "Admin group",
// 404
"404.description": "Oops this page doesn't exist.",
"404.button.home": "Bring me back home",

View File

@@ -157,6 +157,7 @@ const Account = () => {
<Stack>
<TextInput
label={t("account.card.info.username")}
disabled={user?.isLdap}
{...accountForm.getInputProps("username")}
/>
<TextInput
@@ -171,45 +172,47 @@ const Account = () => {
</Stack>
</form>
</Paper>
<Paper withBorder p="xl" mt="lg">
<Title order={5} mb="xs">
<FormattedMessage id="account.card.password.title" />
</Title>
<form
onSubmit={passwordForm.onSubmit((values) =>
authService
.updatePassword(values.oldPassword, values.password)
.then(async () => {
refreshUser();
toast.success(t("account.notify.password.success"));
passwordForm.reset();
})
.catch(toast.axiosError),
)}
>
<Stack>
{user?.hasPassword ? (
<PasswordInput
label={t("account.card.password.old")}
{...passwordForm.getInputProps("oldPassword")}
/>
) : (
<Text size="sm" color="dimmed">
<FormattedMessage id="account.card.password.noPasswordSet" />
</Text>
{user?.isLdap ? null : (
<Paper withBorder p="xl" mt="lg">
<Title order={5} mb="xs">
<FormattedMessage id="account.card.password.title" />
</Title>
<form
onSubmit={passwordForm.onSubmit((values) =>
authService
.updatePassword(values.oldPassword, values.password)
.then(async () => {
refreshUser();
toast.success(t("account.notify.password.success"));
passwordForm.reset();
})
.catch(toast.axiosError),
)}
<PasswordInput
label={t("account.card.password.new")}
{...passwordForm.getInputProps("password")}
/>
<Group position="right">
<Button type="submit">
<FormattedMessage id="common.button.save" />
</Button>
</Group>
</Stack>
</form>
</Paper>
>
<Stack>
{user?.hasPassword ? (
<PasswordInput
label={t("account.card.password.old")}
{...passwordForm.getInputProps("oldPassword")}
/>
) : (
<Text size="sm" color="dimmed">
<FormattedMessage id="account.card.password.noPasswordSet" />
</Text>
)}
<PasswordInput
label={t("account.card.password.new")}
{...passwordForm.getInputProps("password")}
/>
<Group position="right">
<Button type="submit">
<FormattedMessage id="common.button.save" />
</Button>
</Group>
</Stack>
</form>
</Paper>
)}
{oauth.length > 0 && (
<Paper withBorder p="xl" mt="lg">
<Title order={5} mb="xs">

View File

@@ -3,6 +3,7 @@ type User = {
username: string;
email: string;
isAdmin: boolean;
isLdap: boolean;
totpVerified: boolean;
hasPassword: boolean;
};