mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
fix(ldap): preserve the directory-provided bind DN (#1486)
This commit is contained in:
1 parent
4897024324
commit
378be3405a
2 files changed
+37
-8
No files matched your search
@@ -141,12 +141,15 @@ export function createLdapLogin(ctx: PluginContext, store: ProviderStore) {
|
||||
config.displayNameAttribute || "cn",
|
||||
"mail",
|
||||
"email",
|
||||
"distinguishedName",
|
||||
],
|
||||
);
|
||||
if (entries.length === 0) throw await refuse("user not found");
|
||||
|
||||
const userEntry = entries[0];
|
||||
const userDN = userEntry.dn.toString();
|
||||
// AD supplies its DN as an attribute; avoid re-serializing it through ldapjs.
|
||||
const userDN =
|
||||
firstValue(userEntry, "distinguishedName") || userEntry.dn.toString();
|
||||
const uid =
|
||||
firstValue(userEntry, config.usernameAttribute || "uid") || username;
|
||||
const displayName =
|
||||
|
||||
@@ -11,7 +11,9 @@ const directory = vi.hoisted(() => ({
|
||||
binds: [] as string[],
|
||||
}));
|
||||
|
||||
vi.mock("ldapjs", () => {
|
||||
vi.mock("ldapjs", async () => {
|
||||
const { default: ldap } =
|
||||
await vi.importActual<typeof import("ldapjs")>("ldapjs");
|
||||
function createClient() {
|
||||
return {
|
||||
bind: (dn: string, password: string, cb: (err?: Error) => void) => {
|
||||
@@ -25,7 +27,7 @@ vi.mock("ldapjs", () => {
|
||||
},
|
||||
search: (
|
||||
base: string,
|
||||
options: { filter: string },
|
||||
options: { filter: string; attributes: string[] },
|
||||
cb: (err: Error | null, res: unknown) => void,
|
||||
) => {
|
||||
const listeners: Record<string, (value?: unknown) => void> = {};
|
||||
@@ -49,11 +51,13 @@ vi.mock("ldapjs", () => {
|
||||
const user = match ? directory.users[match[1]] : undefined;
|
||||
if (user) {
|
||||
listeners.searchEntry?.({
|
||||
dn: { toString: () => user.dn },
|
||||
attributes: Object.entries(user.attrs).map(([type, value]) => ({
|
||||
type,
|
||||
values: [value],
|
||||
})),
|
||||
dn: ldap.parseDN(user.dn),
|
||||
attributes: Object.entries(user.attrs)
|
||||
.filter(([type]) => options.attributes.includes(type))
|
||||
.map(([type, value]) => ({
|
||||
type,
|
||||
values: [value],
|
||||
})),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -121,6 +125,28 @@ function verify(
|
||||
}
|
||||
|
||||
describe("LDAP sign-in", () => {
|
||||
it.each([
|
||||
"CN=Bob,OU=Первый Департамент,DC=example,DC=com",
|
||||
String.raw`CN=Bob\, Builder,OU=Первый Департамент,DC=example,DC=com`,
|
||||
String.raw`CN=Bob\5cBuilder,OU=People,DC=example,DC=com`,
|
||||
])(
|
||||
"binds with the directory's original distinguishedName: %s",
|
||||
async (dn) => {
|
||||
const { s, id } = await withDirectory();
|
||||
directory.users.bob.dn = dn;
|
||||
directory.users.bob.attrs.distinguishedName = dn;
|
||||
const identity = await verify(s, String(id), {
|
||||
username: "bob",
|
||||
password: "hunter2",
|
||||
});
|
||||
expect(identity).toMatchObject({ subject: "bob" });
|
||||
expect(directory.binds).toEqual(["cn=service", dn]);
|
||||
await expect(
|
||||
verify(s, String(id), { username: "bob", password: "wrong" }),
|
||||
).rejects.toMatchObject({ status: 401 });
|
||||
},
|
||||
);
|
||||
|
||||
it("binds as the service, then as the user, and returns the identity", async () => {
|
||||
const { s, id } = await withDirectory();
|
||||
directory.adminDns = ["uid=bob,ou=people"];
|
||||
|
||||
Reference in new issue
Block a user