0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2025-03-18 02:22:53 -05:00

feat(ldap): allow to customize user filter (#2927)

feat(ldap): allow to customize user filter (#2927)

Signed-off-by: Vladimir Ermakov <vooon341@gmail.com>
This commit is contained in:
Vladimir Ermakov 2025-01-31 16:32:07 +01:00 committed by GitHub
parent 05823cd74f
commit 4fcd1079f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 57 additions and 18 deletions

View file

@ -19,6 +19,7 @@
"startTLS": false,
"baseDN":"ou=Users,dc=example,dc=org",
"userAttribute": "uid",
"userFilter": "(!(nsaccountlock=TRUE))",
"userGroupAttribute": "memberOf",
"skipVerify": true,
"subtreeSearch": true
@ -69,4 +70,4 @@
"output": "/tmp/zot.log",
"audit": "/tmp/zot-audit.log"
}
}
}

View file

@ -272,7 +272,8 @@ func (amw *AuthnMiddleware) tryAuthnHandlers(ctlr *Controller) mux.MiddlewareFun
BindDN: ldapConfig.BindDN(),
BindPassword: ldapConfig.BindPassword(),
UserGroupAttribute: ldapConfig.UserGroupAttribute, // from config
UserFilter: fmt.Sprintf("(%s=%%s)", ldapConfig.UserAttribute),
UserAttribute: ldapConfig.UserAttribute,
UserFilter: ldapConfig.UserFilter,
InsecureSkipVerify: ldapConfig.SkipVerify,
ServerName: ldapConfig.Address,
Log: ctlr.Log,

View file

@ -175,6 +175,7 @@ type LDAPConfig struct {
UserGroupAttribute string
BaseDN string
UserAttribute string
UserFilter string
CACert string
}

View file

@ -90,6 +90,7 @@ var (
LDAPBaseDN = "ou=" + username //nolint: gochecknoglobals
LDAPBindDN = "cn=reader," + LDAPBaseDN //nolint: gochecknoglobals
LDAPBindPassword = "ldappass" //nolint: gochecknoglobals
LDAPUserAttr = "uid" //nolint: gochecknoglobals
)
func TestNew(t *testing.T) {
@ -2974,6 +2975,13 @@ func (l *testLDAPServer) Search(boundDN string, req vldap.SearchRequest,
}, nil
}
if req.Filter == "(&(uid=locked-user)((!(nsaccountlock=TRUE))))" {
return vldap.ServerSearchResult{
Entries: []*vldap.Entry{},
ResultCode: vldap.LDAPResultSuccess,
}, nil
}
check := fmt.Sprintf("(uid=%s)", username)
if check == req.Filter {
@ -3769,13 +3777,14 @@ func TestLDAPClient(t *testing.T) {
// bad user credentials with anonymous authentication
lClient = &api.LDAPClient{
Host: LDAPAddress,
Port: ldapPort,
BindDN: LDAPBindDN,
BindPassword: LDAPBindPassword,
Base: LDAPBaseDN,
UserFilter: "(uid=%s)",
SkipTLS: true,
Host: LDAPAddress,
Port: ldapPort,
BindDN: LDAPBindDN,
BindPassword: LDAPBindPassword,
Base: LDAPBaseDN,
UserAttribute: LDAPUserAttr,
UserFilter: "",
SkipTLS: true,
}
_, _, _, err = lClient.Authenticate("fail-user-bind", "")
@ -3783,17 +3792,33 @@ func TestLDAPClient(t *testing.T) {
// bad user credentials with anonymous authentication
lClient = &api.LDAPClient{
Host: LDAPAddress,
Port: ldapPort,
BindDN: LDAPBindDN,
BindPassword: LDAPBindPassword,
Base: LDAPBaseDN,
UserFilter: "(uid=%s)",
SkipTLS: true,
Host: LDAPAddress,
Port: ldapPort,
BindDN: LDAPBindDN,
BindPassword: LDAPBindPassword,
Base: LDAPBaseDN,
UserAttribute: LDAPUserAttr,
UserFilter: "",
SkipTLS: true,
}
_, _, _, err = lClient.Authenticate("fail-user-bind", "pass")
So(err, ShouldNotBeNil)
// user filtered by additional filter (disabled account in FreeIPA)
lClient = &api.LDAPClient{
Host: LDAPAddress,
Port: ldapPort,
BindDN: LDAPBindDN,
BindPassword: LDAPBindPassword,
Base: LDAPBaseDN,
UserAttribute: LDAPUserAttr,
UserFilter: "(!(nsaccountlock=TRUE))",
SkipTLS: true,
}
_, _, _, err = lClient.Authenticate("locked-user", "pass")
So(err, ShouldNotBeNil)
})
}

View file

@ -29,7 +29,8 @@ type LDAPClient struct {
UserGroupAttribute string // e.g. "memberOf"
Host string
ServerName string
UserFilter string // e.g. "(uid=%s)"
UserFilter string // e.g. "(!(nsaccountlock=TRUE))"
UserAttribute string // e.g. "uid"
Conn *ldap.Conn
ClientCertificates []tls.Certificate // Adding client certificates
ClientCAs *x509.CertPool
@ -187,7 +188,7 @@ func (lc *LDAPClient) Authenticate(username, password string) (bool, map[string]
searchRequest := ldap.NewSearchRequest(
lc.Base,
searchScope, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf(lc.UserFilter, username),
lc.userFilter(username),
attributes,
nil,
)
@ -242,3 +243,13 @@ func (lc *LDAPClient) Authenticate(username, password string) (bool, map[string]
return true, user, userGroups, nil
}
func (lc *LDAPClient) userFilter(username string) string {
filter := fmt.Sprintf("(%s=%s)", lc.UserAttribute, ldap.EscapeFilter(username))
if lc.UserFilter != "" {
filter = fmt.Sprintf("(&(%s)(%s))", filter, lc.UserFilter)
}
return filter
}