You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "fmt"
  7. "math/rand"
  8. "strings"
  9. "testing"
  10. "code.gitea.io/gitea/modules/setting"
  11. "code.gitea.io/gitea/modules/util"
  12. "github.com/stretchr/testify/assert"
  13. )
  14. func TestUserIsPublicMember(t *testing.T) {
  15. assert.NoError(t, PrepareTestDatabase())
  16. tt := []struct {
  17. uid int64
  18. orgid int64
  19. expected bool
  20. }{
  21. {2, 3, true},
  22. {4, 3, false},
  23. {5, 6, true},
  24. {5, 7, false},
  25. }
  26. for _, v := range tt {
  27. t.Run(fmt.Sprintf("UserId%dIsPublicMemberOf%d", v.uid, v.orgid), func(t *testing.T) {
  28. testUserIsPublicMember(t, v.uid, v.orgid, v.expected)
  29. })
  30. }
  31. }
  32. func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) {
  33. user, err := GetUserByID(uid)
  34. assert.NoError(t, err)
  35. assert.Equal(t, expected, user.IsPublicMember(orgID))
  36. }
  37. func TestIsUserOrgOwner(t *testing.T) {
  38. assert.NoError(t, PrepareTestDatabase())
  39. tt := []struct {
  40. uid int64
  41. orgid int64
  42. expected bool
  43. }{
  44. {2, 3, true},
  45. {4, 3, false},
  46. {5, 6, true},
  47. {5, 7, true},
  48. }
  49. for _, v := range tt {
  50. t.Run(fmt.Sprintf("UserId%dIsOrgOwnerOf%d", v.uid, v.orgid), func(t *testing.T) {
  51. testIsUserOrgOwner(t, v.uid, v.orgid, v.expected)
  52. })
  53. }
  54. }
  55. func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {
  56. user, err := GetUserByID(uid)
  57. assert.NoError(t, err)
  58. assert.Equal(t, expected, user.IsUserOrgOwner(orgID))
  59. }
  60. func TestGetUserEmailsByNames(t *testing.T) {
  61. assert.NoError(t, PrepareTestDatabase())
  62. // ignore none active user email
  63. assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user9"}))
  64. assert.Equal(t, []string{"user8@example.com", "user5@example.com"}, GetUserEmailsByNames([]string{"user8", "user5"}))
  65. assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user7"}))
  66. }
  67. func TestCanCreateOrganization(t *testing.T) {
  68. assert.NoError(t, PrepareTestDatabase())
  69. admin := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
  70. assert.True(t, admin.CanCreateOrganization())
  71. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  72. assert.True(t, user.CanCreateOrganization())
  73. // Disable user create organization permission.
  74. user.AllowCreateOrganization = false
  75. assert.False(t, user.CanCreateOrganization())
  76. setting.Admin.DisableRegularOrgCreation = true
  77. user.AllowCreateOrganization = true
  78. assert.True(t, admin.CanCreateOrganization())
  79. assert.False(t, user.CanCreateOrganization())
  80. }
  81. func TestSearchUsers(t *testing.T) {
  82. assert.NoError(t, PrepareTestDatabase())
  83. testSuccess := func(opts *SearchUserOptions, expectedUserOrOrgIDs []int64) {
  84. users, _, err := SearchUsers(opts)
  85. assert.NoError(t, err)
  86. if assert.Len(t, users, len(expectedUserOrOrgIDs)) {
  87. for i, expectedID := range expectedUserOrOrgIDs {
  88. assert.EqualValues(t, expectedID, users[i].ID)
  89. }
  90. }
  91. }
  92. // test orgs
  93. testOrgSuccess := func(opts *SearchUserOptions, expectedOrgIDs []int64) {
  94. opts.Type = UserTypeOrganization
  95. testSuccess(opts, expectedOrgIDs)
  96. }
  97. testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 1, PageSize: 2}},
  98. []int64{3, 6})
  99. testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 2, PageSize: 2}},
  100. []int64{7, 17})
  101. testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 3, PageSize: 2}},
  102. []int64{19, 25})
  103. testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 4, PageSize: 2}},
  104. []int64{26})
  105. testOrgSuccess(&SearchUserOptions{ListOptions: ListOptions{Page: 5, PageSize: 2}},
  106. []int64{})
  107. // test users
  108. testUserSuccess := func(opts *SearchUserOptions, expectedUserIDs []int64) {
  109. opts.Type = UserTypeIndividual
  110. testSuccess(opts, expectedUserIDs)
  111. }
  112. testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 1}},
  113. []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30})
  114. testUserSuccess(&SearchUserOptions{ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse},
  115. []int64{9})
  116. testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
  117. []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 28, 29, 30})
  118. testUserSuccess(&SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
  119. []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
  120. // order by name asc default
  121. testUserSuccess(&SearchUserOptions{Keyword: "user1", ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
  122. []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
  123. }
  124. func TestDeleteUser(t *testing.T) {
  125. test := func(userID int64) {
  126. assert.NoError(t, PrepareTestDatabase())
  127. user := AssertExistsAndLoadBean(t, &User{ID: userID}).(*User)
  128. ownedRepos := make([]*Repository, 0, 10)
  129. assert.NoError(t, x.Find(&ownedRepos, &Repository{OwnerID: userID}))
  130. if len(ownedRepos) > 0 {
  131. err := DeleteUser(user)
  132. assert.Error(t, err)
  133. assert.True(t, IsErrUserOwnRepos(err))
  134. return
  135. }
  136. orgUsers := make([]*OrgUser, 0, 10)
  137. assert.NoError(t, x.Find(&orgUsers, &OrgUser{UID: userID}))
  138. for _, orgUser := range orgUsers {
  139. if err := RemoveOrgUser(orgUser.OrgID, orgUser.UID); err != nil {
  140. assert.True(t, IsErrLastOrgOwner(err))
  141. return
  142. }
  143. }
  144. assert.NoError(t, DeleteUser(user))
  145. AssertNotExistsBean(t, &User{ID: userID})
  146. CheckConsistencyFor(t, &User{}, &Repository{})
  147. }
  148. test(2)
  149. test(4)
  150. test(8)
  151. test(11)
  152. org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
  153. assert.Error(t, DeleteUser(org))
  154. }
  155. func TestEmailNotificationPreferences(t *testing.T) {
  156. assert.NoError(t, PrepareTestDatabase())
  157. for _, test := range []struct {
  158. expected string
  159. userID int64
  160. }{
  161. {EmailNotificationsEnabled, 1},
  162. {EmailNotificationsEnabled, 2},
  163. {EmailNotificationsOnMention, 3},
  164. {EmailNotificationsOnMention, 4},
  165. {EmailNotificationsEnabled, 5},
  166. {EmailNotificationsEnabled, 6},
  167. {EmailNotificationsDisabled, 7},
  168. {EmailNotificationsEnabled, 8},
  169. {EmailNotificationsOnMention, 9},
  170. } {
  171. user := AssertExistsAndLoadBean(t, &User{ID: test.userID}).(*User)
  172. assert.Equal(t, test.expected, user.EmailNotifications())
  173. // Try all possible settings
  174. assert.NoError(t, user.SetEmailNotifications(EmailNotificationsEnabled))
  175. assert.Equal(t, EmailNotificationsEnabled, user.EmailNotifications())
  176. assert.NoError(t, user.SetEmailNotifications(EmailNotificationsOnMention))
  177. assert.Equal(t, EmailNotificationsOnMention, user.EmailNotifications())
  178. assert.NoError(t, user.SetEmailNotifications(EmailNotificationsDisabled))
  179. assert.Equal(t, EmailNotificationsDisabled, user.EmailNotifications())
  180. }
  181. }
  182. func TestHashPasswordDeterministic(t *testing.T) {
  183. b := make([]byte, 16)
  184. u := &User{}
  185. algos := []string{"argon2", "pbkdf2", "scrypt", "bcrypt"}
  186. for j := 0; j < len(algos); j++ {
  187. u.PasswdHashAlgo = algos[j]
  188. for i := 0; i < 50; i++ {
  189. // generate a random password
  190. rand.Read(b)
  191. pass := string(b)
  192. // save the current password in the user - hash it and store the result
  193. u.SetPassword(pass)
  194. r1 := u.Passwd
  195. // run again
  196. u.SetPassword(pass)
  197. r2 := u.Passwd
  198. assert.NotEqual(t, r1, r2)
  199. assert.True(t, u.ValidatePassword(pass))
  200. }
  201. }
  202. }
  203. func BenchmarkHashPassword(b *testing.B) {
  204. // BenchmarkHashPassword ensures that it takes a reasonable amount of time
  205. // to hash a password - in order to protect from brute-force attacks.
  206. pass := "password1337"
  207. u := &User{Passwd: pass}
  208. b.ResetTimer()
  209. for i := 0; i < b.N; i++ {
  210. u.SetPassword(pass)
  211. }
  212. }
  213. func TestGetOrgRepositoryIDs(t *testing.T) {
  214. assert.NoError(t, PrepareTestDatabase())
  215. user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  216. user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
  217. user5 := AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
  218. accessibleRepos, err := user2.GetOrgRepositoryIDs()
  219. assert.NoError(t, err)
  220. // User 2's team has access to private repos 3, 5, repo 32 is a public repo of the organization
  221. assert.Equal(t, []int64{3, 5, 23, 24, 32}, accessibleRepos)
  222. accessibleRepos, err = user4.GetOrgRepositoryIDs()
  223. assert.NoError(t, err)
  224. // User 4's team has access to private repo 3, repo 32 is a public repo of the organization
  225. assert.Equal(t, []int64{3, 32}, accessibleRepos)
  226. accessibleRepos, err = user5.GetOrgRepositoryIDs()
  227. assert.NoError(t, err)
  228. // User 5's team has no access to any repo
  229. assert.Len(t, accessibleRepos, 0)
  230. }
  231. func TestNewGitSig(t *testing.T) {
  232. users := make([]*User, 0, 20)
  233. sess := x.NewSession()
  234. defer sess.Close()
  235. sess.Find(&users)
  236. for _, user := range users {
  237. sig := user.NewGitSig()
  238. assert.NotContains(t, sig.Name, "<")
  239. assert.NotContains(t, sig.Name, ">")
  240. assert.NotContains(t, sig.Name, "\n")
  241. assert.NotEqual(t, len(strings.TrimSpace(sig.Name)), 0)
  242. }
  243. }
  244. func TestDisplayName(t *testing.T) {
  245. users := make([]*User, 0, 20)
  246. sess := x.NewSession()
  247. defer sess.Close()
  248. sess.Find(&users)
  249. for _, user := range users {
  250. displayName := user.DisplayName()
  251. assert.Equal(t, strings.TrimSpace(displayName), displayName)
  252. if len(strings.TrimSpace(user.FullName)) == 0 {
  253. assert.Equal(t, user.Name, displayName)
  254. }
  255. assert.NotEqual(t, len(strings.TrimSpace(displayName)), 0)
  256. }
  257. }
  258. func TestCreateUser(t *testing.T) {
  259. user := &User{
  260. Name: "GiteaBot",
  261. Email: "GiteaBot@gitea.io",
  262. Passwd: ";p['////..-++']",
  263. IsAdmin: false,
  264. Theme: setting.UI.DefaultTheme,
  265. MustChangePassword: false,
  266. }
  267. assert.NoError(t, CreateUser(user))
  268. assert.NoError(t, DeleteUser(user))
  269. }
  270. func TestCreateUserInvalidEmail(t *testing.T) {
  271. user := &User{
  272. Name: "GiteaBot",
  273. Email: "GiteaBot@gitea.io\r\n",
  274. Passwd: ";p['////..-++']",
  275. IsAdmin: false,
  276. Theme: setting.UI.DefaultTheme,
  277. MustChangePassword: false,
  278. }
  279. err := CreateUser(user)
  280. assert.Error(t, err)
  281. assert.True(t, IsErrEmailInvalid(err))
  282. }
  283. func TestCreateUser_Issue5882(t *testing.T) {
  284. // Init settings
  285. _ = setting.Admin
  286. passwd := ".//.;1;;//.,-=_"
  287. tt := []struct {
  288. user *User
  289. disableOrgCreation bool
  290. }{
  291. {&User{Name: "GiteaBot", Email: "GiteaBot@gitea.io", Passwd: passwd, MustChangePassword: false}, false},
  292. {&User{Name: "GiteaBot2", Email: "GiteaBot2@gitea.io", Passwd: passwd, MustChangePassword: false}, true},
  293. }
  294. setting.Service.DefaultAllowCreateOrganization = true
  295. for _, v := range tt {
  296. setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation
  297. assert.NoError(t, CreateUser(v.user))
  298. u, err := GetUserByEmail(v.user.Email)
  299. assert.NoError(t, err)
  300. assert.Equal(t, !u.AllowCreateOrganization, v.disableOrgCreation)
  301. assert.NoError(t, DeleteUser(v.user))
  302. }
  303. }
  304. func TestGetUserIDsByNames(t *testing.T) {
  305. // ignore non existing
  306. IDs, err := GetUserIDsByNames([]string{"user1", "user2", "none_existing_user"}, true)
  307. assert.NoError(t, err)
  308. assert.Equal(t, []int64{1, 2}, IDs)
  309. // ignore non existing
  310. IDs, err = GetUserIDsByNames([]string{"user1", "do_not_exist"}, false)
  311. assert.Error(t, err)
  312. assert.Equal(t, []int64(nil), IDs)
  313. }
  314. func TestGetMaileableUsersByIDs(t *testing.T) {
  315. results, err := GetMaileableUsersByIDs([]int64{1, 4}, false)
  316. assert.NoError(t, err)
  317. assert.Equal(t, 1, len(results))
  318. if len(results) > 1 {
  319. assert.Equal(t, results[0].ID, 1)
  320. }
  321. results, err = GetMaileableUsersByIDs([]int64{1, 4}, true)
  322. assert.NoError(t, err)
  323. assert.Equal(t, 2, len(results))
  324. if len(results) > 2 {
  325. assert.Equal(t, results[0].ID, 1)
  326. assert.Equal(t, results[1].ID, 4)
  327. }
  328. }
  329. func TestAddLdapSSHPublicKeys(t *testing.T) {
  330. assert.NoError(t, PrepareTestDatabase())
  331. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  332. s := &LoginSource{ID: 1}
  333. testCases := []struct {
  334. keyString string
  335. number int
  336. keyContents []string
  337. }{
  338. {
  339. keyString: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
  340. number: 1,
  341. keyContents: []string{
  342. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=",
  343. },
  344. },
  345. {
  346. keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment
  347. ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`,
  348. number: 2,
  349. keyContents: []string{
  350. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=",
  351. "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=",
  352. },
  353. },
  354. {
  355. keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment
  356. # comment asmdna,ndp
  357. ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`,
  358. number: 2,
  359. keyContents: []string{
  360. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=",
  361. "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=",
  362. },
  363. },
  364. {
  365. keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment
  366. 382488320jasdj1lasmva/vasodifipi4193-fksma.cm
  367. ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`,
  368. number: 2,
  369. keyContents: []string{
  370. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=",
  371. "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=",
  372. },
  373. },
  374. }
  375. for i, kase := range testCases {
  376. s.ID = int64(i) + 20
  377. addLdapSSHPublicKeys(user, s, []string{kase.keyString})
  378. keys, err := ListPublicLdapSSHKeys(user.ID, s.ID)
  379. assert.NoError(t, err)
  380. if err != nil {
  381. continue
  382. }
  383. assert.Equal(t, kase.number, len(keys))
  384. for _, key := range keys {
  385. assert.Contains(t, kase.keyContents, key.Content)
  386. }
  387. for _, key := range keys {
  388. DeletePublicKey(user, key.ID)
  389. }
  390. }
  391. }