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
This commit is contained in:
zeripath 2018-12-27 17:28:48 +00:00 committed by techknowlogick
parent 2058c362a8
commit 8bb0a6f425
4 changed files with 39 additions and 18 deletions

View file

@ -393,7 +393,13 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR
return nil, ErrUserNotExist{0, login, 0} return nil, ErrUserNotExist{0, login, 0}
} }
var isAttributeSSHPublicKeySet = len(strings.TrimSpace(source.LDAP().AttributeSSHPublicKey)) > 0
if !autoRegister { if !autoRegister {
if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) {
RewriteAllPublicKeys()
}
return user, nil return user, nil
} }
@ -421,7 +427,14 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR
IsActive: true, IsActive: true,
IsAdmin: sr.IsAdmin, IsAdmin: sr.IsAdmin,
} }
return user, CreateUser(user)
err := CreateUser(user)
if err == nil && isAttributeSSHPublicKeySet && addLdapSSHPublicKeys(user, source, sr.SSHPublicKey) {
RewriteAllPublicKeys()
}
return user, err
} }
// _________ __________________________ // _________ __________________________

View file

@ -451,11 +451,9 @@ func GetPublicKeyByID(keyID int64) (*PublicKey, error) {
return key, nil return key, nil
} }
// SearchPublicKeyByContent searches content as prefix (leak e-mail part) func searchPublicKeyByContentWithEngine(e Engine, content string) (*PublicKey, error) {
// and returns public key found.
func SearchPublicKeyByContent(content string) (*PublicKey, error) {
key := new(PublicKey) key := new(PublicKey)
has, err := x. has, err := e.
Where("content like ?", content+"%"). Where("content like ?", content+"%").
Get(key) Get(key)
if err != nil { if err != nil {
@ -466,6 +464,12 @@ func SearchPublicKeyByContent(content string) (*PublicKey, error) {
return key, nil 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. // SearchPublicKey returns a list of public keys matching the provided arguments.
func SearchPublicKey(uid int64, fingerprint string) ([]*PublicKey, error) { func SearchPublicKey(uid int64, fingerprint string) ([]*PublicKey, error) {
keys := make([]*PublicKey, 0, 5) keys := make([]*PublicKey, 0, 5)

View file

@ -1402,7 +1402,7 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) {
// Delete keys marked for deletion // Delete keys marked for deletion
var sshKeysNeedUpdate bool var sshKeysNeedUpdate bool
for _, KeyToDelete := range keys { for _, KeyToDelete := range keys {
key, err := SearchPublicKeyByContent(KeyToDelete) key, err := searchPublicKeyByContentWithEngine(sess, KeyToDelete)
if err != nil { if err != nil {
log.Error(4, "SearchPublicKeyByContent: %v", err) log.Error(4, "SearchPublicKeyByContent: %v", err)
continue continue
@ -1421,7 +1421,8 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) {
return sshKeysNeedUpdate, nil 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 var sshKeysNeedUpdate bool
for _, sshKey := range SSHPublicKeys { for _, sshKey := range SSHPublicKeys {
_, _, _, _, err := ssh.ParseAuthorizedKey([]byte(sshKey)) _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(sshKey))
@ -1440,7 +1441,8 @@ func addLdapSSHPublicKeys(s *LoginSource, usr *User, SSHPublicKeys []string) boo
return sshKeysNeedUpdate 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 var sshKeysNeedUpdate bool
log.Trace("synchronizeLdapSSHPublicKeys[%s]: Handling LDAP Public SSH Key synchronization for user %s", s.Name, usr.Name) 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) newLdapSSHKeys = append(newLdapSSHKeys, LDAPPublicSSHKey)
} }
} }
if addLdapSSHPublicKeys(s, usr, newLdapSSHKeys) { if addLdapSSHPublicKeys(usr, s, newLdapSSHKeys) {
sshKeysNeedUpdate = true sshKeysNeedUpdate = true
} }
@ -1581,7 +1583,7 @@ func SyncExternalUsers() {
log.Error(4, "SyncExternalUsers[%s]: Error creating user %s: %v", s.Name, su.Username, err) log.Error(4, "SyncExternalUsers[%s]: Error creating user %s: %v", s.Name, su.Username, err)
} else if isAttributeSSHPublicKeySet { } else if isAttributeSSHPublicKeySet {
log.Trace("SyncExternalUsers[%s]: Adding LDAP Public SSH Keys for user %s", s.Name, usr.Name) 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 sshKeysNeedUpdate = true
} }
} }
@ -1589,7 +1591,7 @@ func SyncExternalUsers() {
existingUsers = append(existingUsers, usr.ID) existingUsers = append(existingUsers, usr.ID)
// Synchronize SSH Public Key if that attribute is set // 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 sshKeysNeedUpdate = true
} }

View file

@ -247,10 +247,10 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
return nil 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( search := ldap.NewSearchRequest(
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter, 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) nil)
sr, err := l.Search(search) 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) firstname := sr.Entries[0].GetAttributeValue(ls.AttributeName)
surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname) surname := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail) mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
sshPublicKey := sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey)
isAdmin := checkAdmin(l, ls, userDN) isAdmin := checkAdmin(l, ls, userDN)
if !directBind && ls.AttributesInBind { if !directBind && ls.AttributesInBind {
@ -286,6 +287,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
Name: firstname, Name: firstname,
Surname: surname, Surname: surname,
Mail: mail, Mail: mail,
SSHPublicKey: sshPublicKey,
IsAdmin: isAdmin, IsAdmin: isAdmin,
} }
} }