gitea源码

source_sync.go 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package ldap
  4. import (
  5. "context"
  6. "strings"
  7. asymkey_model "code.gitea.io/gitea/models/asymkey"
  8. "code.gitea.io/gitea/models/db"
  9. "code.gitea.io/gitea/models/organization"
  10. user_model "code.gitea.io/gitea/models/user"
  11. auth_module "code.gitea.io/gitea/modules/auth"
  12. "code.gitea.io/gitea/modules/container"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/optional"
  15. asymkey_service "code.gitea.io/gitea/services/asymkey"
  16. source_service "code.gitea.io/gitea/services/auth/source"
  17. user_service "code.gitea.io/gitea/services/user"
  18. )
  19. // Sync causes this ldap source to synchronize its users with the db
  20. func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
  21. log.Trace("Doing: SyncExternalUsers[%s]", source.AuthSource.Name)
  22. isAttributeSSHPublicKeySet := strings.TrimSpace(source.AttributeSSHPublicKey) != ""
  23. var sshKeysNeedUpdate bool
  24. // Find all users with this login type - FIXME: Should this be an iterator?
  25. users, err := user_model.GetUsersBySource(ctx, source.AuthSource)
  26. if err != nil {
  27. log.Error("SyncExternalUsers: %v", err)
  28. return err
  29. }
  30. select {
  31. case <-ctx.Done():
  32. log.Warn("SyncExternalUsers: Cancelled before update of %s", source.AuthSource.Name)
  33. return db.ErrCancelledf("Before update of %s", source.AuthSource.Name)
  34. default:
  35. }
  36. usernameUsers := make(map[string]*user_model.User, len(users))
  37. mailUsers := make(map[string]*user_model.User, len(users))
  38. keepActiveUsers := make(container.Set[int64])
  39. for _, u := range users {
  40. usernameUsers[u.LowerName] = u
  41. mailUsers[strings.ToLower(u.Email)] = u
  42. }
  43. sr, err := source.SearchEntries()
  44. if err != nil {
  45. log.Error("SyncExternalUsers LDAP source failure [%s], skipped", source.AuthSource.Name)
  46. return nil
  47. }
  48. if len(sr) == 0 {
  49. if !source.AllowDeactivateAll {
  50. log.Error("LDAP search found no entries but did not report an error. Refusing to deactivate all users")
  51. return nil
  52. }
  53. log.Warn("LDAP search found no entries but did not report an error. All users will be deactivated as per settings")
  54. }
  55. orgCache := make(map[string]*organization.Organization)
  56. teamCache := make(map[string]*organization.Team)
  57. groupTeamMapping, err := auth_module.UnmarshalGroupTeamMapping(source.GroupTeamMap)
  58. if err != nil {
  59. return err
  60. }
  61. for _, su := range sr {
  62. select {
  63. case <-ctx.Done():
  64. log.Warn("SyncExternalUsers: Cancelled at update of %s before completed update of users", source.AuthSource.Name)
  65. // Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed
  66. if sshKeysNeedUpdate {
  67. err = asymkey_service.RewriteAllPublicKeys(ctx)
  68. if err != nil {
  69. log.Error("RewriteAllPublicKeys: %v", err)
  70. }
  71. }
  72. return db.ErrCancelledf("During update of %s before completed update of users", source.AuthSource.Name)
  73. default:
  74. }
  75. if su.Username == "" && su.Mail == "" {
  76. continue
  77. }
  78. var usr *user_model.User
  79. if su.Username != "" {
  80. usr = usernameUsers[su.LowerName]
  81. }
  82. if usr == nil && su.Mail != "" {
  83. usr = mailUsers[strings.ToLower(su.Mail)]
  84. }
  85. if usr != nil {
  86. keepActiveUsers.Add(usr.ID)
  87. } else if su.Username == "" {
  88. // we cannot create the user if su.Username is empty
  89. continue
  90. }
  91. if su.Mail == "" {
  92. su.Mail = su.Username + "@localhost.local"
  93. }
  94. fullName := composeFullName(su.Name, su.Surname, su.Username)
  95. // If no existing user found, create one
  96. if usr == nil {
  97. log.Trace("SyncExternalUsers[%s]: Creating user %s", source.AuthSource.Name, su.Username)
  98. usr = &user_model.User{
  99. LowerName: su.LowerName,
  100. Name: su.Username,
  101. FullName: fullName,
  102. LoginType: source.AuthSource.Type,
  103. LoginSource: source.AuthSource.ID,
  104. LoginName: su.Username,
  105. Email: su.Mail,
  106. IsAdmin: su.IsAdmin,
  107. }
  108. overwriteDefault := &user_model.CreateUserOverwriteOptions{
  109. IsRestricted: optional.Some(su.IsRestricted),
  110. IsActive: optional.Some(true),
  111. }
  112. err = user_model.CreateUser(ctx, usr, &user_model.Meta{}, overwriteDefault)
  113. if err != nil {
  114. log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", source.AuthSource.Name, su.Username, err)
  115. }
  116. if err == nil && isAttributeSSHPublicKeySet {
  117. log.Trace("SyncExternalUsers[%s]: Adding LDAP Public SSH Keys for user %s", source.AuthSource.Name, usr.Name)
  118. if asymkey_model.AddPublicKeysBySource(ctx, usr, source.AuthSource, su.SSHPublicKey) {
  119. sshKeysNeedUpdate = true
  120. }
  121. }
  122. if err == nil && source.AttributeAvatar != "" {
  123. _ = user_service.UploadAvatar(ctx, usr, su.Avatar)
  124. }
  125. } else if updateExisting {
  126. // Synchronize SSH Public Key if that attribute is set
  127. if isAttributeSSHPublicKeySet && asymkey_model.SynchronizePublicKeys(ctx, usr, source.AuthSource, su.SSHPublicKey) {
  128. sshKeysNeedUpdate = true
  129. }
  130. // Check if user data has changed
  131. if (source.AdminFilter != "" && usr.IsAdmin != su.IsAdmin) ||
  132. (source.RestrictedFilter != "" && usr.IsRestricted != su.IsRestricted) ||
  133. !strings.EqualFold(usr.Email, su.Mail) ||
  134. usr.FullName != fullName ||
  135. !usr.IsActive {
  136. log.Trace("SyncExternalUsers[%s]: Updating user %s", source.AuthSource.Name, usr.Name)
  137. opts := &user_service.UpdateOptions{
  138. FullName: optional.Some(fullName),
  139. IsActive: optional.Some(true),
  140. }
  141. if source.AdminFilter != "" {
  142. opts.IsAdmin = user_service.UpdateOptionFieldFromSync(su.IsAdmin)
  143. }
  144. // Change existing restricted flag only if RestrictedFilter option is set
  145. if !su.IsAdmin && source.RestrictedFilter != "" {
  146. opts.IsRestricted = optional.Some(su.IsRestricted)
  147. }
  148. if err := user_service.UpdateUser(ctx, usr, opts); err != nil {
  149. log.Error("SyncExternalUsers[%s]: Error updating user %s: %v", source.AuthSource.Name, usr.Name, err)
  150. }
  151. if err := user_service.ReplacePrimaryEmailAddress(ctx, usr, su.Mail); err != nil {
  152. log.Error("SyncExternalUsers[%s]: Error updating user %s primary email %s: %v", source.AuthSource.Name, usr.Name, su.Mail, err)
  153. }
  154. }
  155. if source.AttributeAvatar != "" {
  156. if len(su.Avatar) > 0 && usr.IsUploadAvatarChanged(su.Avatar) {
  157. log.Trace("SyncExternalUsers[%s]: Uploading new avatar for %s", source.AuthSource.Name, usr.Name)
  158. _ = user_service.UploadAvatar(ctx, usr, su.Avatar)
  159. }
  160. }
  161. }
  162. // Synchronize LDAP groups with organization and team memberships
  163. if source.GroupsEnabled && (source.GroupTeamMap != "" || source.GroupTeamMapRemoval) {
  164. if err := source_service.SyncGroupsToTeamsCached(ctx, usr, su.Groups, groupTeamMapping, source.GroupTeamMapRemoval, orgCache, teamCache); err != nil {
  165. log.Error("SyncGroupsToTeamsCached: %v", err)
  166. }
  167. }
  168. }
  169. // Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed
  170. if sshKeysNeedUpdate {
  171. err = asymkey_service.RewriteAllPublicKeys(ctx)
  172. if err != nil {
  173. log.Error("RewriteAllPublicKeys: %v", err)
  174. }
  175. }
  176. select {
  177. case <-ctx.Done():
  178. log.Warn("SyncExternalUsers: Cancelled during update of %s before delete users", source.AuthSource.Name)
  179. return db.ErrCancelledf("During update of %s before delete users", source.AuthSource.Name)
  180. default:
  181. }
  182. // Deactivate users not present in LDAP
  183. if updateExisting {
  184. for _, usr := range users {
  185. if keepActiveUsers.Contains(usr.ID) {
  186. continue
  187. }
  188. log.Trace("SyncExternalUsers[%s]: Deactivating user %s", source.AuthSource.Name, usr.Name)
  189. opts := &user_service.UpdateOptions{
  190. IsActive: optional.Some(false),
  191. }
  192. if err := user_service.UpdateUser(ctx, usr, opts); err != nil {
  193. log.Error("SyncExternalUsers[%s]: Error deactivating user %s: %v", source.AuthSource.Name, usr.Name, err)
  194. }
  195. }
  196. }
  197. return nil
  198. }