mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Refactor: Move login out of models (#16199)
`models` does far too much. In particular it handles all `UserSignin`. It shouldn't be responsible for calling LDAP, SMTP or PAM for signing in. Therefore we should move this code out of `models`. This code has to depend on `models` - therefore it belongs in `services`. There is a package in `services` called `auth` and clearly this functionality belongs in there. Plan: - [x] Change `auth.Auth` to `auth.Method` - as they represent methods of authentication. - [x] Move `models.UserSignIn` into `auth` - [x] Move `models.ExternalUserLogin` - [x] Move most of the `LoginVia*` methods to `auth` or subpackages - [x] Move Resynchronize functionality to `auth` - Involved some restructuring of `models/ssh_key.go` to reduce the size of this massive file and simplify its files. - [x] Move the rest of the LDAP functionality in to the ldap subpackage - [x] Re-factor the login sources to express an interfaces `auth.Source`? - I've done this through some smaller interfaces Authenticator and Synchronizable - which would allow us to extend things in future - [x] Now LDAP is out of models - need to think about modules/auth/ldap and I think all of that functionality might just be moveable - [x] Similarly a lot Oauth2 functionality need not be in models too and should be moved to services/auth/source/oauth2 - [x] modules/auth/oauth2/oauth2.go uses xorm... This is naughty - probably need to move this into models. - [x] models/oauth2.go - mostly should be in modules/auth/oauth2 or services/auth/source/oauth2 - [x] More simplifications of login_source.go may need to be done - Allow wiring in of notify registration - *this can now easily be done - but I think we should do it in another PR* - see #16178 - More refactors...? - OpenID should probably become an auth Method but I think that can be left for another PR - Methods should also probably be cleaned up - again another PR I think. - SSPI still needs more refactors.* Rename auth.Auth auth.Method * Restructure ssh_key.go - move functions from models/user.go that relate to ssh_key to ssh_key - split ssh_key.go to try create clearer function domains for allow for future refactors here. Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
		
							
								
								
									
										184
									
								
								services/auth/source/ldap/source_sync.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								services/auth/source/ldap/source_sync.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| // Copyright 2021 The Gitea Authors. All rights reserved. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package ldap | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| ) | ||||
|  | ||||
| // Sync causes this ldap source to synchronize its users with the db | ||||
| func (source *Source) Sync(ctx context.Context, updateExisting bool) error { | ||||
| 	log.Trace("Doing: SyncExternalUsers[%s]", source.loginSource.Name) | ||||
|  | ||||
| 	var existingUsers []int64 | ||||
| 	isAttributeSSHPublicKeySet := len(strings.TrimSpace(source.AttributeSSHPublicKey)) > 0 | ||||
| 	var sshKeysNeedUpdate bool | ||||
|  | ||||
| 	// Find all users with this login type - FIXME: Should this be an iterator? | ||||
| 	users, err := models.GetUsersBySource(source.loginSource) | ||||
| 	if err != nil { | ||||
| 		log.Error("SyncExternalUsers: %v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	select { | ||||
| 	case <-ctx.Done(): | ||||
| 		log.Warn("SyncExternalUsers: Cancelled before update of %s", source.loginSource.Name) | ||||
| 		return models.ErrCancelledf("Before update of %s", source.loginSource.Name) | ||||
| 	default: | ||||
| 	} | ||||
|  | ||||
| 	sr, err := source.SearchEntries() | ||||
| 	if err != nil { | ||||
| 		log.Error("SyncExternalUsers LDAP source failure [%s], skipped", source.loginSource.Name) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if len(sr) == 0 { | ||||
| 		if !source.AllowDeactivateAll { | ||||
| 			log.Error("LDAP search found no entries but did not report an error. Refusing to deactivate all users") | ||||
| 			return nil | ||||
| 		} | ||||
| 		log.Warn("LDAP search found no entries but did not report an error. All users will be deactivated as per settings") | ||||
| 	} | ||||
|  | ||||
| 	for _, su := range sr { | ||||
| 		select { | ||||
| 		case <-ctx.Done(): | ||||
| 			log.Warn("SyncExternalUsers: Cancelled at update of %s before completed update of users", source.loginSource.Name) | ||||
| 			// Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed | ||||
| 			if sshKeysNeedUpdate { | ||||
| 				err = models.RewriteAllPublicKeys() | ||||
| 				if err != nil { | ||||
| 					log.Error("RewriteAllPublicKeys: %v", err) | ||||
| 				} | ||||
| 			} | ||||
| 			return models.ErrCancelledf("During update of %s before completed update of users", source.loginSource.Name) | ||||
| 		default: | ||||
| 		} | ||||
| 		if len(su.Username) == 0 { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if len(su.Mail) == 0 { | ||||
| 			su.Mail = fmt.Sprintf("%s@localhost", su.Username) | ||||
| 		} | ||||
|  | ||||
| 		var usr *models.User | ||||
| 		// Search for existing user | ||||
| 		for _, du := range users { | ||||
| 			if du.LowerName == strings.ToLower(su.Username) { | ||||
| 				usr = du | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		fullName := composeFullName(su.Name, su.Surname, su.Username) | ||||
| 		// If no existing user found, create one | ||||
| 		if usr == nil { | ||||
| 			log.Trace("SyncExternalUsers[%s]: Creating user %s", source.loginSource.Name, su.Username) | ||||
|  | ||||
| 			usr = &models.User{ | ||||
| 				LowerName:    strings.ToLower(su.Username), | ||||
| 				Name:         su.Username, | ||||
| 				FullName:     fullName, | ||||
| 				LoginType:    source.loginSource.Type, | ||||
| 				LoginSource:  source.loginSource.ID, | ||||
| 				LoginName:    su.Username, | ||||
| 				Email:        su.Mail, | ||||
| 				IsAdmin:      su.IsAdmin, | ||||
| 				IsRestricted: su.IsRestricted, | ||||
| 				IsActive:     true, | ||||
| 			} | ||||
|  | ||||
| 			err = models.CreateUser(usr) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", source.loginSource.Name, su.Username, err) | ||||
| 			} else if isAttributeSSHPublicKeySet { | ||||
| 				log.Trace("SyncExternalUsers[%s]: Adding LDAP Public SSH Keys for user %s", source.loginSource.Name, usr.Name) | ||||
| 				if models.AddPublicKeysBySource(usr, source.loginSource, su.SSHPublicKey) { | ||||
| 					sshKeysNeedUpdate = true | ||||
| 				} | ||||
| 			} | ||||
| 		} else if updateExisting { | ||||
| 			existingUsers = append(existingUsers, usr.ID) | ||||
|  | ||||
| 			// Synchronize SSH Public Key if that attribute is set | ||||
| 			if isAttributeSSHPublicKeySet && models.SynchronizePublicKeys(usr, source.loginSource, su.SSHPublicKey) { | ||||
| 				sshKeysNeedUpdate = true | ||||
| 			} | ||||
|  | ||||
| 			// Check if user data has changed | ||||
| 			if (len(source.AdminFilter) > 0 && usr.IsAdmin != su.IsAdmin) || | ||||
| 				(len(source.RestrictedFilter) > 0 && usr.IsRestricted != su.IsRestricted) || | ||||
| 				!strings.EqualFold(usr.Email, su.Mail) || | ||||
| 				usr.FullName != fullName || | ||||
| 				!usr.IsActive { | ||||
|  | ||||
| 				log.Trace("SyncExternalUsers[%s]: Updating user %s", source.loginSource.Name, usr.Name) | ||||
|  | ||||
| 				usr.FullName = fullName | ||||
| 				usr.Email = su.Mail | ||||
| 				// Change existing admin flag only if AdminFilter option is set | ||||
| 				if len(source.AdminFilter) > 0 { | ||||
| 					usr.IsAdmin = su.IsAdmin | ||||
| 				} | ||||
| 				// Change existing restricted flag only if RestrictedFilter option is set | ||||
| 				if !usr.IsAdmin && len(source.RestrictedFilter) > 0 { | ||||
| 					usr.IsRestricted = su.IsRestricted | ||||
| 				} | ||||
| 				usr.IsActive = true | ||||
|  | ||||
| 				err = models.UpdateUserCols(usr, "full_name", "email", "is_admin", "is_restricted", "is_active") | ||||
| 				if err != nil { | ||||
| 					log.Error("SyncExternalUsers[%s]: Error updating user %s: %v", source.loginSource.Name, usr.Name, err) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed | ||||
| 	if sshKeysNeedUpdate { | ||||
| 		err = models.RewriteAllPublicKeys() | ||||
| 		if err != nil { | ||||
| 			log.Error("RewriteAllPublicKeys: %v", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	select { | ||||
| 	case <-ctx.Done(): | ||||
| 		log.Warn("SyncExternalUsers: Cancelled during update of %s before delete users", source.loginSource.Name) | ||||
| 		return models.ErrCancelledf("During update of %s before delete users", source.loginSource.Name) | ||||
| 	default: | ||||
| 	} | ||||
|  | ||||
| 	// Deactivate users not present in LDAP | ||||
| 	if updateExisting { | ||||
| 		for _, usr := range users { | ||||
| 			found := false | ||||
| 			for _, uid := range existingUsers { | ||||
| 				if usr.ID == uid { | ||||
| 					found = true | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			if !found { | ||||
| 				log.Trace("SyncExternalUsers[%s]: Deactivating user %s", source.loginSource.Name, usr.Name) | ||||
|  | ||||
| 				usr.IsActive = false | ||||
| 				err = models.UpdateUserCols(usr, "is_active") | ||||
| 				if err != nil { | ||||
| 					log.Error("SyncExternalUsers[%s]: Error deactivating user %s: %v", source.loginSource.Name, usr.Name, err) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user