From 8bb0a6f425f994addc2822a21e0dca60e8c5251a Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 27 Dec 2018 17:28:48 +0000 Subject: Synchronize SSH keys on login with LDAP + Fix SQLite deadlock on ldap ssh key deletion (#5557) * Synchronize SSH keys on login with LDAP * BUG: Fix hang on sqlite during LDAP key deletion --- models/login_source.go | 15 ++++++++++++++- models/ssh_key.go | 12 ++++++++---- models/user.go | 14 ++++++++------ modules/auth/ldap/ldap.go | 16 +++++++++------- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/models/login_source.go b/models/login_source.go index 2c0b4fb5f9..25c7aa3120 100644 --- a/models/login_source.go +++ b/models/login_source.go @@ -393,7 +393,13 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR return nil, ErrUserNotExist{0, login, 0} } + var isAttributeSSHPublicKeySet = len(strings.TrimSpace(source.LDAP().AttributeSSHPublicKey)) > 0 + if !autoRegister { + if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) { + RewriteAllPublicKeys() + } + return user, nil } @@ -421,7 +427,14 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR IsActive: true, IsAdmin: sr.IsAdmin, } - return user, CreateUser(user) + + err := CreateUser(user) + + if err == nil && isAttributeSSHPublicKeySet && addLdapSSHPublicKeys(user, source, sr.SSHPublicKey) { + RewriteAllPublicKeys() + } + + return user, err } // _________ __________________________ diff --git a/models/ssh_key.go b/models/ssh_key.go index 0f8e5225bb..27c5bf0808 100644 --- a/models/ssh_key.go +++ b/models/ssh_key.go @@ -451,11 +451,9 @@ func GetPublicKeyByID(keyID int64) (*PublicKey, error) { return key, nil } -// SearchPublicKeyByContent searches content as prefix (leak e-mail part) -// and returns public key found. -func SearchPublicKeyByContent(content string) (*PublicKey, error) { +func searchPublicKeyByContentWithEngine(e Engine, content string) (*PublicKey, error) { key := new(PublicKey) - has, err := x. + has, err := e. Where("content like ?", content+"%"). Get(key) if err != nil { @@ -466,6 +464,12 @@ func SearchPublicKeyByContent(content string) (*PublicKey, error) { return key, nil } +// SearchPublicKeyByContent searches content as prefix (leak e-mail part) +// and returns public key found. +func SearchPublicKeyByContent(content string) (*PublicKey, error) { + return searchPublicKeyByContentWithEngine(x, content) +} + // SearchPublicKey returns a list of public keys matching the provided arguments. func SearchPublicKey(uid int64, fingerprint string) ([]*PublicKey, error) { keys := make([]*PublicKey, 0, 5) diff --git a/models/user.go b/models/user.go index a30e0d8e52..3a47346e34 100644 --- a/models/user.go +++ b/models/user.go @@ -1402,7 +1402,7 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) { // Delete keys marked for deletion var sshKeysNeedUpdate bool for _, KeyToDelete := range keys { - key, err := SearchPublicKeyByContent(KeyToDelete) + key, err := searchPublicKeyByContentWithEngine(sess, KeyToDelete) if err != nil { log.Error(4, "SearchPublicKeyByContent: %v", err) continue @@ -1421,7 +1421,8 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) { return sshKeysNeedUpdate, nil } -func addLdapSSHPublicKeys(s *LoginSource, usr *User, SSHPublicKeys []string) bool { +// addLdapSSHPublicKeys add a users public keys. Returns true if there are changes. +func addLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []string) bool { var sshKeysNeedUpdate bool for _, sshKey := range SSHPublicKeys { _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(sshKey)) @@ -1440,7 +1441,8 @@ func addLdapSSHPublicKeys(s *LoginSource, usr *User, SSHPublicKeys []string) boo return sshKeysNeedUpdate } -func synchronizeLdapSSHPublicKeys(s *LoginSource, SSHPublicKeys []string, usr *User) bool { +// synchronizeLdapSSHPublicKeys updates a users public keys. Returns true if there are changes. +func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []string) bool { var sshKeysNeedUpdate bool log.Trace("synchronizeLdapSSHPublicKeys[%s]: Handling LDAP Public SSH Key synchronization for user %s", s.Name, usr.Name) @@ -1479,7 +1481,7 @@ func synchronizeLdapSSHPublicKeys(s *LoginSource, SSHPublicKeys []string, usr *U newLdapSSHKeys = append(newLdapSSHKeys, LDAPPublicSSHKey) } } - if addLdapSSHPublicKeys(s, usr, newLdapSSHKeys) { + if addLdapSSHPublicKeys(usr, s, newLdapSSHKeys) { sshKeysNeedUpdate = true } @@ -1581,7 +1583,7 @@ func SyncExternalUsers() { log.Error(4, "SyncExternalUsers[%s]: Error creating user %s: %v", s.Name, su.Username, err) } else if isAttributeSSHPublicKeySet { log.Trace("SyncExternalUsers[%s]: Adding LDAP Public SSH Keys for user %s", s.Name, usr.Name) - if addLdapSSHPublicKeys(s, usr, su.SSHPublicKey) { + if addLdapSSHPublicKeys(usr, s, su.SSHPublicKey) { sshKeysNeedUpdate = true } } @@ -1589,7 +1591,7 @@ func SyncExternalUsers() { existingUsers = append(existingUsers, usr.ID) // Synchronize SSH Public Key if that attribute is set - if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(s, su.SSHPublicKey, usr) { + if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(usr, s, su.SSHPublicKey) { sshKeysNeedUpdate = true } diff --git a/modules/auth/ldap/ldap.go b/modules/auth/ldap/ldap.go index f4c55d0bd6..c33dbea11b 100644 --- a/modules/auth/ldap/ldap.go +++ b/modules/auth/ldap/ldap.go @@ -247,10 +247,10 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul return nil } - log.Trace("Fetching attributes '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, userFilter, userDN) + log.Trace("Fetching attributes '%v', '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey, userFilter, userDN) search := ldap.NewSearchRequest( userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter, - []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}, + []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, ls.AttributeSSHPublicKey}, nil) sr, err := l.Search(search) @@ -271,6 +271,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName) surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname) mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail) + sshPublicKey := sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey) isAdmin := checkAdmin(l, ls, userDN) if !directBind && ls.AttributesInBind { @@ -282,11 +283,12 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul } return &SearchResult{ - Username: username, - Name: firstname, - Surname: surname, - Mail: mail, - IsAdmin: isAdmin, + Username: username, + Name: firstname, + Surname: surname, + Mail: mail, + SSHPublicKey: sshPublicKey, + IsAdmin: isAdmin, } } -- cgit v1.2.3