Merge pull request #147 from clems4ever/userdn-ldap-filter
Add {dn} as an available matcher in LDAP groups filterpull/149/head
commit
4b51ae30cc
|
@ -33,8 +33,9 @@ ldap:
|
||||||
|
|
||||||
# The groups filter used for retrieving groups of a given user.
|
# The groups filter used for retrieving groups of a given user.
|
||||||
# {0} is a matcher replaced by username.
|
# {0} is a matcher replaced by username.
|
||||||
# 'member=cn={0},<additional_users_dn>,<base_dn>' by default.
|
# {dn} is a matcher replaced by user DN.
|
||||||
groups_filter: (&(member=cn={0},ou=users,dc=example,dc=com)(objectclass=groupOfNames))
|
# 'member={dn}' by default.
|
||||||
|
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||||
|
|
||||||
# The attribute holding the name of the group
|
# The attribute holding the name of the group
|
||||||
group_name_attribute: cn
|
group_name_attribute: cn
|
||||||
|
|
|
@ -33,8 +33,9 @@ ldap:
|
||||||
|
|
||||||
# The groups filter used for retrieving groups of a given user.
|
# The groups filter used for retrieving groups of a given user.
|
||||||
# {0} is a matcher replaced by username.
|
# {0} is a matcher replaced by username.
|
||||||
# 'member=cn={0},<additional_users_dn>,<base_dn>' by default.
|
# {dn} is a matcher replaced by user DN.
|
||||||
groups_filter: (&(member=cn={0},ou=users,dc=example,dc=com)(objectclass=groupOfNames))
|
# 'member={dn}' by default.
|
||||||
|
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||||
|
|
||||||
# The attribute holding the name of the group
|
# The attribute holding the name of the group
|
||||||
group_name_attribute: cn
|
group_name_attribute: cn
|
||||||
|
|
|
@ -29,10 +29,7 @@ function ensure_key_existence(config: object, path: string): void {
|
||||||
|
|
||||||
function adaptLdapConfiguration(userConfig: UserLdapConfiguration): LdapConfiguration {
|
function adaptLdapConfiguration(userConfig: UserLdapConfiguration): LdapConfiguration {
|
||||||
const DEFAULT_USERS_FILTER = "cn={0}";
|
const DEFAULT_USERS_FILTER = "cn={0}";
|
||||||
const DEFAULT_GROUPS_FILTER =
|
const DEFAULT_GROUPS_FILTER = "member={dn}";
|
||||||
userConfig.additional_users_dn
|
|
||||||
? Util.format("member=cn={0},%s,%s", userConfig.additional_groups_dn, userConfig.base_dn)
|
|
||||||
: Util.format("member=cn={0},%s", userConfig.base_dn);
|
|
||||||
const DEFAULT_GROUP_NAME_ATTRIBUTE = "cn";
|
const DEFAULT_GROUP_NAME_ATTRIBUTE = "cn";
|
||||||
const DEFAULT_MAIL_ATTRIBUTE = "mail";
|
const DEFAULT_MAIL_ATTRIBUTE = "mail";
|
||||||
|
|
||||||
|
|
|
@ -47,18 +47,34 @@ export class Client implements IClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createGroupsFilter(userGroupsFilter: string, username: string): BluebirdPromise<string> {
|
||||||
|
if (userGroupsFilter.indexOf("{0}") > 0) {
|
||||||
|
return BluebirdPromise.resolve(userGroupsFilter.replace("{0}", username));
|
||||||
|
}
|
||||||
|
else if (userGroupsFilter.indexOf("{dn}") > 0) {
|
||||||
|
return this.searchUserDn(username)
|
||||||
|
.then(function (userDN: string) {
|
||||||
|
return BluebirdPromise.resolve(userGroupsFilter.replace("{dn}", userDN));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return BluebirdPromise.resolve(userGroupsFilter);
|
||||||
|
}
|
||||||
|
|
||||||
searchGroups(username: string): BluebirdPromise<string[]> {
|
searchGroups(username: string): BluebirdPromise<string[]> {
|
||||||
const that = this;
|
const that = this;
|
||||||
const filter = that.options.groups_filter.replace("{0}", username);
|
return this.createGroupsFilter(this.options.groups_filter, username)
|
||||||
|
.then(function (groupsFilter: string) {
|
||||||
|
that.logger.debug("Computed groups filter is %s", groupsFilter);
|
||||||
const query = {
|
const query = {
|
||||||
scope: "sub",
|
scope: "sub",
|
||||||
attributes: [that.options.group_name_attribute],
|
attributes: [that.options.group_name_attribute],
|
||||||
filter: filter
|
filter: groupsFilter
|
||||||
};
|
};
|
||||||
return this.ldapClient.searchAsync(that.options.groups_dn, query)
|
return that.ldapClient.searchAsync(that.options.groups_dn, query);
|
||||||
|
})
|
||||||
.then(function (docs: { cn: string }[]) {
|
.then(function (docs: { cn: string }[]) {
|
||||||
const groups = docs.map((doc: any) => { return doc.cn; });
|
const groups = docs.map((doc: any) => { return doc.cn; });
|
||||||
that.logger.debug("LDAP: groups of user %s are %s", username, groups);
|
that.logger.debug("LDAP: groups of user %s are [%s]", username, groups.join(","));
|
||||||
return BluebirdPromise.resolve(groups);
|
return BluebirdPromise.resolve(groups);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -66,6 +82,7 @@ export class Client implements IClient {
|
||||||
searchUserDn(username: string): BluebirdPromise<string> {
|
searchUserDn(username: string): BluebirdPromise<string> {
|
||||||
const that = this;
|
const that = this;
|
||||||
const filter = this.options.users_filter.replace("{0}", username);
|
const filter = this.options.users_filter.replace("{0}", username);
|
||||||
|
this.logger.debug("Computed users filter is %s", filter);
|
||||||
const query = {
|
const query = {
|
||||||
scope: "sub",
|
scope: "sub",
|
||||||
sizeLimit: 1,
|
sizeLimit: 1,
|
||||||
|
|
|
@ -45,7 +45,7 @@ function verify_filter(req: express.Request, res: express.Response): BluebirdPro
|
||||||
|
|
||||||
const isAllowed = accessController.isAccessAllowed(domain, path, username, groups);
|
const isAllowed = accessController.isAccessAllowed(domain, path, username, groups);
|
||||||
if (!isAllowed) return BluebirdPromise.reject(
|
if (!isAllowed) return BluebirdPromise.reject(
|
||||||
new exceptions.DomainAccessDenied(Util.format("User '%s' does not have access to '%'",
|
new exceptions.DomainAccessDenied(Util.format("User '%s' does not have access to '%s'",
|
||||||
username, domain)));
|
username, domain)));
|
||||||
|
|
||||||
if (authenticationMethod == "two_factor" && !authSession.second_factor)
|
if (authenticationMethod == "two_factor" && !authSession.second_factor)
|
||||||
|
|
|
@ -56,7 +56,7 @@ describe("test ldap configuration adaptation", function () {
|
||||||
users_dn: "dc=example,dc=com",
|
users_dn: "dc=example,dc=com",
|
||||||
users_filter: "cn={0}",
|
users_filter: "cn={0}",
|
||||||
groups_dn: "dc=example,dc=com",
|
groups_dn: "dc=example,dc=com",
|
||||||
groups_filter: "member=cn={0},dc=example,dc=com",
|
groups_filter: "member={dn}",
|
||||||
group_name_attribute: "cn",
|
group_name_attribute: "cn",
|
||||||
mail_attribute: "mail",
|
mail_attribute: "mail",
|
||||||
user: "admin",
|
user: "admin",
|
||||||
|
|
|
@ -31,9 +31,9 @@ describe("test authelia ldap client", function () {
|
||||||
const ldapClient = new LdapClientStub();
|
const ldapClient = new LdapClientStub();
|
||||||
|
|
||||||
factory.createStub.returns(ldapClient);
|
factory.createStub.returns(ldapClient);
|
||||||
ldapClient.searchAsyncStub.returns(BluebirdPromise.resolve([
|
ldapClient.searchAsyncStub.returns(BluebirdPromise.resolve([{
|
||||||
"group1"
|
cn: "group1"
|
||||||
]));
|
}]));
|
||||||
const client = new Client(ADMIN_USER_DN, ADMIN_PASSWORD, options, factory, Dovehash, Winston);
|
const client = new Client(ADMIN_USER_DN, ADMIN_PASSWORD, options, factory, Dovehash, Winston);
|
||||||
|
|
||||||
return client.searchGroups("user1")
|
return client.searchGroups("user1")
|
||||||
|
@ -42,4 +42,49 @@ describe("test authelia ldap client", function () {
|
||||||
"member=cn=user1,ou=users,dc=example,dc=com");
|
"member=cn=user1,ou=users,dc=example,dc=com");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should replace {dn} by user DN when searching for groups in LDAP", function () {
|
||||||
|
const USER_DN = "cn=user1,ou=users,dc=example,dc=com";
|
||||||
|
const options: LdapConfiguration = {
|
||||||
|
url: "ldap://ldap",
|
||||||
|
users_dn: "ou=users,dc=example,dc=com",
|
||||||
|
users_filter: "cn={0}",
|
||||||
|
groups_dn: "ou=groups,dc=example,dc=com",
|
||||||
|
groups_filter: "member={dn}",
|
||||||
|
group_name_attribute: "cn",
|
||||||
|
mail_attribute: "mail",
|
||||||
|
user: "cn=admin,dc=example,dc=com",
|
||||||
|
password: "password"
|
||||||
|
};
|
||||||
|
const factory = new LdapClientFactoryStub();
|
||||||
|
const ldapClient = new LdapClientStub();
|
||||||
|
|
||||||
|
factory.createStub.returns(ldapClient);
|
||||||
|
|
||||||
|
// Retrieve user DN
|
||||||
|
ldapClient.searchAsyncStub.withArgs("ou=users,dc=example,dc=com", {
|
||||||
|
scope: "sub",
|
||||||
|
sizeLimit: 1,
|
||||||
|
attributes: ["dn"],
|
||||||
|
filter: "cn=user1"
|
||||||
|
}).returns(BluebirdPromise.resolve([{
|
||||||
|
dn: USER_DN
|
||||||
|
}]));
|
||||||
|
|
||||||
|
// Retrieve groups
|
||||||
|
ldapClient.searchAsyncStub.withArgs("ou=groups,dc=example,dc=com", {
|
||||||
|
scope: "sub",
|
||||||
|
attributes: ["cn"],
|
||||||
|
filter: "member=" + USER_DN
|
||||||
|
}).returns(BluebirdPromise.resolve([{
|
||||||
|
cn: "group1"
|
||||||
|
}]));
|
||||||
|
|
||||||
|
const client = new Client(ADMIN_USER_DN, ADMIN_PASSWORD, options, factory, Dovehash, Winston);
|
||||||
|
|
||||||
|
return client.searchGroups("user1")
|
||||||
|
.then(function (groups: string[]) {
|
||||||
|
Assert.deepEqual(groups, ["group1"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
Loading…
Reference in New Issue