Closed sasjafor closed 7 months ago
Hi, @sasjafor
Could you provide your confs and debug logs
?
When using the options
BindDN
andBindPassword
in combination withAllowedGroups
then theAllowedGroups
are checked using the user credentials instead of the bind credentials.Is this intentional behaviour?
Please check Operations Mode docs. All subsequent LDAP
operations will be performed based on the Operation Mode
defined in confs. You can also check this mode by checking ldapAuth
's logs.
You can also check this example. I think you need to set searchFilter option to perform what you need.
Hello @wiltonsr,
I checked the source code and I saw that the method ServeHTTP
first calls LdapCheckUser
and then LdapCheckUserAuthorized
.
LdapCheckUser
performs a bind on the LDAP connection with the credentials of the user trying to sign in.
Then there is no further bind until LdapCheckUserAuthorized
is called, where the group membership is checked, while still bound using the user credentials instead of the BindDN
and BindPassword
. This is not mentioned in the docs as far as I could see.
The example you provided does not use AllowedGroups
and as such does not apply to my use case.
Here is my config:
http:
middlewares:
my-ldapAuth:
plugin:
ldapAuth:
Enabled: true
LogLevel: "DEBUG"
Url: "ldap://mydomain.example"
Port: 389
BaseDN: "dc=company,dc=local"
Attribute: "uid"
BindDN: "cn=read,dc=company,dc=local"
BindPassword: "<censored>"
AllowedGroups:
- "cn=root,ou=groups,dc=company,dc=local"
SearchFilter: (\{\{.Attribute\}\}=\{\{.Username\}\})
And the debug log:
traefik | time="2024-03-20T10:08:47Z" level=info msg="Configuration loaded from flags."
traefik | INFO: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: Starting my-ldapAuth@file Middleware...
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: Enabled => 'true'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: LogLevel => 'DEBUG'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: URL => 'ldap://mydomain.example'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: Port => '389'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: CacheTimeout => '300'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: CacheCookieName => 'ldapAuth_session_token'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: CacheCookiePath => ''
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: CacheCookieSecure => 'false'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: CacheKey => 'super-secret-key'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: StartTLS => 'false'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: InsecureSkipVerify => 'false'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: MinVersionTLS => 'tls.VersionTLS12'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: MaxVersionTLS => 'tls.VersionTLS13'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: CertificateAuthority => ''
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: Attribute => 'uid'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: SearchFilter => '(\{\{.Attribute\}\}=\{\{.Username\}\})'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: BaseDN => 'dc=company,dc=local'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: BindDN => 'cn=read,dc=company,dc=local'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: BindPassword => '<censored>'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: ForwardUsername => 'true'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: ForwardUsernameHeader => 'Username'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: ForwardAuthorization => 'false'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: ForwardExtraLdapHeaders => 'false'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: WWWAuthenticateHeader => 'true'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: WWWAuthenticateHeaderRealm => ''
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: EnableNestedGroupFilter => 'false'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: AllowedGroups => '[cn=root,ou=groups,dc=company,dc=local]'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: AllowedUsers => '[]'
traefik | DEBUG: ldapAuth: 2024/03/20 10:08:47 restricted.go:51: Username => ''
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: Session details: &{ map[] 0xc00166e140 true {0xc002b8b040 {0xc002df56c0 0xc0020c12a8 406}} ldapAuth_session_token}
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:52: No session found! Trying to authenticate in LDAP
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: Connect Address: 'ldap://mydomain.example:389'
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: Running in Search Mode
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: Performing User BindDN Search
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: Search Filter: '(uid=testuser)'
traefik | INFO: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: Authenticating User: cn=Test User,ou=users,dc=company,dc=local
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: Group Filter: '(|(member=cn=Test User,ou=users,dc=company,dc=local)(uniqueMember=cn=Test User,ou=users,dc=company,dc=local)(memberUid=testuser))'
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: Searching Group: 'cn=root,ou=groups,dc=company,dc=local' with User: 'cn=Test User,ou=users,dc=company,dc=local'
traefik | INFO: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: LDAP Result Code 32 "No Such Object":
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: User: 'testuser' not found in Group: 'cn=root,ou=groups,dc=company,dc=local'
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:52: [LDAP Result Code 32 "No Such Object":
traefik | User 'testuser' does not match any allowed users nor allowed groups.]
traefik | ERROR: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: LDAP Result Code 32 "No Such Object":
traefik | User 'testuser' does not match any allowed users nor allowed groups.
LdapCheckUser
performs a bind on the LDAP connection with the credentials of the user trying to sign in.
This only happens if your searchFilter
is empty.
Otherwise, the function SearchMode
will be called
And the bind
will be made authenticated
or anonymous
based on bindDN
and bindPassword
options.
The example you provided does not use AllowedGroups and as such does not apply to my use case.
There is an example using AllowedGroups
. But your confs looks OK and you are running in SearchMode
traefik | DEBUG: ldapAuth: 2024/03/20 10:09:24 restricted.go:51: Running in Search Mode
Could you provide a ldapsearch
in your "cn=root,ou=groups,dc=company,dc=local"
group?
An example using ldap.forumsys.com
will be
ldapsearch -x \
-b "ou=mathematicians,dc=example,dc=com" \
-H ldap://ldap.forumsys.com \
-D "uid=tesla,dc=example,dc=com" \
-w password
In this case we got
# extended LDIF
#
# LDAPv3
# base <ou=mathematicians,dc=example,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# mathematicians, example.com
dn: ou=mathematicians,dc=example,dc=com
uniqueMember: uid=euclid,dc=example,dc=com
uniqueMember: uid=riemann,dc=example,dc=com
uniqueMember: uid=euler,dc=example,dc=com
uniqueMember: uid=gauss,dc=example,dc=com
uniqueMember: uid=test,dc=example,dc=com
ou: mathematicians
cn: Mathematicians
objectClass: groupOfUniqueNames
objectClass: top
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
That matches with the Group Filter
with the attribute uniqueMember
Yes, SearchMode
is called, but later in LdapCheckUser
a bind is performed again also using the user credentials:
https://github.com/wiltonsr/ldapAuth/blob/5de938dfa1b7d8c5746e8a11cdc4f2f33155b27b/ldapauth.go#L274
I added
conn.Bind(la.config.BindDN, la.config.BindPassword)
before LdapCheckUserAuthorized
is called and that fixed my problem.
Yes,
SearchMode
is called, but later inLdapCheckUser
a bind is performed again also using the user credentials:
You are right, thanks for pointing that out.
EDIT: I will work on this in this branch. I would like to ping you to test the fix as soon as possible.
I tested and now it works as expected. Thanks for the quick fix!
When using the options
BindDN
andBindPassword
in combination withAllowedGroups
then theAllowedGroups
are checked using the user credentials instead of the bind credentials.Is this intentional behaviour?
For me this creates an issue since the individual users cannot access group membership information. Only the bind user has access to those parts of the directory.
If it's unintentional, consider this a bug report. If it's intentional, then a feature request for a toggle to choose the behaviour.