mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	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:
		| @@ -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 | ||||||
| } | } | ||||||
|  |  | ||||||
| //   _________   __________________________ | //   _________   __________________________ | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
| @@ -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 | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 { | ||||||
| @@ -282,11 +283,12 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return &SearchResult{ | 	return &SearchResult{ | ||||||
| 		Username: username, | 		Username:     username, | ||||||
| 		Name:     firstname, | 		Name:         firstname, | ||||||
| 		Surname:  surname, | 		Surname:      surname, | ||||||
| 		Mail:     mail, | 		Mail:         mail, | ||||||
| 		IsAdmin:  isAdmin, | 		SSHPublicKey: sshPublicKey, | ||||||
|  | 		IsAdmin:      isAdmin, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user