-
Notifications
You must be signed in to change notification settings - Fork 9
reuse ldap connection #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,7 @@ import ( | |
| "net/url" | ||
| "strconv" | ||
| "strings" | ||
| "sync" | ||
| "time" | ||
|
|
||
| "github.com/go-ldap/ldap/v3" | ||
|
|
@@ -71,6 +72,9 @@ type LDAPIdentifierBackend struct { | |
|
|
||
| timeout int | ||
| limiter *rate.Limiter | ||
|
|
||
| mutex sync.Mutex | ||
| conn *ldap.Conn | ||
| } | ||
|
|
||
| type ldapAttributeMapping map[string]string | ||
|
|
@@ -115,7 +119,7 @@ func newLdapUser(entryID string, mapping ldapAttributeMapping, entry *ldap.Entry | |
| for n, mapped := range mapping { | ||
| // LDAP attribute descriptors / short names are case insensitive. See | ||
| // https://tools.ietf.org/html/rfc4512#page-4. | ||
| if strings.ToLower(attribute.Name) == strings.ToLower(mapped) { | ||
| if strings.EqualFold(attribute.Name, mapped) { | ||
| // Check if we need conversion. | ||
| switch mapping[fmt.Sprintf("%s_type", n)] { | ||
| case AttributeValueTypeBinary: | ||
|
|
@@ -370,9 +374,8 @@ func (b *LDAPIdentifierBackend) Logon(ctx context.Context, audience, username, p | |
|
|
||
| l, err := b.connect(ctx) | ||
| if err != nil { | ||
| return false, nil, nil, nil, fmt.Errorf("ldap identifier backend logon connect error: %v", err) | ||
| return false, nil, nil, nil, fmt.Errorf("ldap identifier backend logon global connect error: %v", err) | ||
| } | ||
| defer l.Close() | ||
|
|
||
| // Search for the given username. | ||
| entry, err := b.searchUsername(l, username, b.attributeMapping.attributes()) | ||
|
|
@@ -387,8 +390,15 @@ func (b *LDAPIdentifierBackend) Logon(ctx context.Context, audience, username, p | |
| return false, nil, nil, nil, fmt.Errorf("ldap identifier backend logon search returned wrong user") | ||
| } | ||
|
|
||
| // Bind as the user to verify the password. | ||
| err = l.Bind(entry.DN, password) | ||
| // Use a temporary connection for the user Bind to verify the password. | ||
| ul, err := b.createConnection(ctx, entry.DN, password) | ||
| if err != nil { | ||
| return false, nil, nil, nil, fmt.Errorf("ldap identifier backend logon user connect error: %v", err) | ||
| } | ||
| // Always close the temporary connection | ||
| defer ul.Close() | ||
|
|
||
| err = ul.Bind(entry.DN, password) | ||
| switch { | ||
| case ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials): | ||
| return false, nil, nil, nil, nil | ||
|
|
@@ -431,7 +441,6 @@ func (b *LDAPIdentifierBackend) ResolveUserByUsername(ctx context.Context, usern | |
| if err != nil { | ||
| return nil, fmt.Errorf("ldap identifier backend resolve connect error: %v", err) | ||
| } | ||
| defer l.Close() | ||
|
|
||
| // Search for the given username. | ||
| entry, err := b.searchUsername(l, username, b.attributeMapping.attributes()) | ||
|
|
@@ -464,7 +473,6 @@ func (b *LDAPIdentifierBackend) GetUser(ctx context.Context, entryID string, ses | |
| if err != nil { | ||
| return nil, fmt.Errorf("ldap identifier backend get user connect error: %v", err) | ||
| } | ||
| defer l.Close() | ||
|
|
||
| entry, err := b.getUser(l, entryID, b.attributeMapping.attributes()) | ||
| if err != nil { | ||
|
|
@@ -517,7 +525,7 @@ func (b *LDAPIdentifierBackend) Name() string { | |
| return ldapIdentifierBackendName | ||
| } | ||
|
|
||
| func (b *LDAPIdentifierBackend) connect(parentCtx context.Context) (*ldap.Conn, error) { | ||
| func (b *LDAPIdentifierBackend) createConnection(parentCtx context.Context, bindDN, bindPassword string) (*ldap.Conn, error) { | ||
| // A timeout for waiting for a limiter slot. The timeout also includes the | ||
| // time to connect to the LDAP server which as a consequence means that both | ||
| // getting a free slot and establishing the connection are one timeout. | ||
|
|
@@ -550,9 +558,8 @@ func (b *LDAPIdentifierBackend) connect(parentCtx context.Context) (*ldap.Conn, | |
|
|
||
| l.Start() | ||
|
|
||
| // Bind with general user (which is preferably read only). | ||
| if b.bindDN != "" { | ||
| err = l.Bind(b.bindDN, b.bindPassword) | ||
| if bindDN != "" { | ||
| err = l.Bind(bindDN, bindPassword) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
@@ -561,6 +568,20 @@ func (b *LDAPIdentifierBackend) connect(parentCtx context.Context) (*ldap.Conn, | |
| return l, nil | ||
| } | ||
|
|
||
| // connect establishes a global connection that is used for all requests except the user Bind to check the password in the Logon call. | ||
longsleep marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| func (b *LDAPIdentifierBackend) connect(parentCtx context.Context) (*ldap.Conn, error) { | ||
| b.mutex.Lock() | ||
| defer b.mutex.Unlock() | ||
|
|
||
| if b.conn != nil && !b.conn.IsClosing() { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not really know if the connection actually still works and might result in error and thus logon failure when getting used. Does the ldap connection do anything (like in the background) to ensure that does not happen? Normally that would be the job of the pool before giving the connection to the caller.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, the connection closes itself only when it cannot read a response. We could port the reconnect wrapper from https://github.com/cs3org/reva/blob/edge/pkg/utils/ldap/reconnect.go
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this needs to be solved before this can be merged. One way or another the connection needs to be "checked" if it is still usable (or some retry logic). |
||
| return b.conn, nil | ||
| } | ||
| var err error | ||
| b.conn, err = b.createConnection(parentCtx, b.bindDN, b.bindPassword) | ||
|
|
||
| return b.conn, err | ||
| } | ||
|
|
||
| func (b *LDAPIdentifierBackend) searchUsername(l *ldap.Conn, username string, attributes []string) (*ldap.Entry, error) { | ||
| base, filter := b.baseAndSearchFilterFromUsername(username) | ||
| // Search for the given username. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.