github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/api/accessor/accessor_test.go (about)

     1  package accessor_test
     2  
     3  import (
     4  	. "github.com/onsi/ginkgo"
     5  	. "github.com/onsi/ginkgo/extensions/table"
     6  	. "github.com/onsi/gomega"
     7  
     8  	"github.com/pf-qiu/concourse/v6/atc"
     9  	"github.com/pf-qiu/concourse/v6/atc/api/accessor"
    10  	"github.com/pf-qiu/concourse/v6/atc/db"
    11  	"github.com/pf-qiu/concourse/v6/atc/db/dbfakes"
    12  )
    13  
    14  var _ = Describe("Accessor", func() {
    15  	var (
    16  		verification accessor.Verification
    17  		requiredRole string
    18  		teams        []db.Team
    19  		access       accessor.Access
    20  
    21  		fakeTeam1 *dbfakes.FakeTeam
    22  		fakeTeam2 *dbfakes.FakeTeam
    23  		fakeTeam3 *dbfakes.FakeTeam
    24  	)
    25  
    26  	BeforeEach(func() {
    27  		fakeTeam1 = new(dbfakes.FakeTeam)
    28  		fakeTeam1.NameReturns("some-team-1")
    29  		fakeTeam2 = new(dbfakes.FakeTeam)
    30  		fakeTeam2.NameReturns("some-team-2")
    31  		fakeTeam3 = new(dbfakes.FakeTeam)
    32  		fakeTeam3.NameReturns("some-team-3")
    33  
    34  		verification = accessor.Verification{}
    35  
    36  		teams = []db.Team{fakeTeam1, fakeTeam2, fakeTeam3}
    37  	})
    38  
    39  	JustBeforeEach(func() {
    40  		access = accessor.NewAccessor(verification, requiredRole, "sub", []string{"system"}, teams)
    41  	})
    42  
    43  	Describe("HasToken", func() {
    44  		var result bool
    45  
    46  		JustBeforeEach(func() {
    47  			result = access.HasToken()
    48  		})
    49  
    50  		Context("when verification does not have a token", func() {
    51  			BeforeEach(func() {
    52  				verification.HasToken = false
    53  			})
    54  
    55  			It("returns false", func() {
    56  				Expect(result).To(BeFalse())
    57  			})
    58  		})
    59  
    60  		Context("when verification has a token", func() {
    61  			BeforeEach(func() {
    62  				verification.HasToken = true
    63  			})
    64  
    65  			It("returns true", func() {
    66  				Expect(result).To(BeTrue())
    67  			})
    68  		})
    69  	})
    70  
    71  	Describe("IsAuthenticated", func() {
    72  		var result bool
    73  
    74  		JustBeforeEach(func() {
    75  			result = access.IsAuthenticated()
    76  		})
    77  
    78  		Context("when verification does not have a token", func() {
    79  			BeforeEach(func() {
    80  				verification.HasToken = false
    81  			})
    82  
    83  			It("returns false", func() {
    84  				Expect(result).To(BeFalse())
    85  			})
    86  		})
    87  
    88  		Context("when verification has a token", func() {
    89  			BeforeEach(func() {
    90  				verification.HasToken = true
    91  			})
    92  
    93  			Context("when verification token is not valid", func() {
    94  				BeforeEach(func() {
    95  					verification.IsTokenValid = false
    96  				})
    97  
    98  				It("returns false", func() {
    99  					Expect(result).To(BeFalse())
   100  				})
   101  			})
   102  
   103  			Context("when verification token is valid", func() {
   104  				BeforeEach(func() {
   105  					verification.IsTokenValid = true
   106  				})
   107  
   108  				It("returns true", func() {
   109  					Expect(result).To(BeTrue())
   110  				})
   111  			})
   112  		})
   113  	})
   114  
   115  	Describe("IsAuthorized", func() {
   116  		var result bool
   117  
   118  		JustBeforeEach(func() {
   119  			result = access.IsAuthorized("some-team")
   120  		})
   121  
   122  		Context("when the user has no token", func() {
   123  			BeforeEach(func() {
   124  				verification.HasToken = false
   125  			})
   126  
   127  			It("returns false", func() {
   128  				Expect(result).To(BeFalse())
   129  			})
   130  		})
   131  
   132  		Context("when the user has invalid token", func() {
   133  			BeforeEach(func() {
   134  				verification.HasToken = true
   135  				verification.IsTokenValid = false
   136  			})
   137  
   138  			It("returns false", func() {
   139  				Expect(result).To(BeFalse())
   140  			})
   141  		})
   142  
   143  		Context("when the user has valid token", func() {
   144  			BeforeEach(func() {
   145  				verification.HasToken = true
   146  				verification.IsTokenValid = true
   147  				verification.RawClaims = map[string]interface{}{
   148  					"federated_claims": map[string]interface{}{
   149  						"connector_id": "some-connector",
   150  						"user_id":      "some-user-id",
   151  					},
   152  				}
   153  			})
   154  
   155  			Context("when the user is part of any admin team", func() {
   156  				BeforeEach(func() {
   157  					fakeTeam1.NameReturns("not-some-team")
   158  					fakeTeam1.AdminReturns(true)
   159  					fakeTeam1.AuthReturns(atc.TeamAuth{
   160  						"owner": map[string][]string{
   161  							"users": {"some-connector:some-user-id"},
   162  						},
   163  					})
   164  				})
   165  
   166  				It("returns true", func() {
   167  					Expect(result).To(BeTrue())
   168  				})
   169  			})
   170  		})
   171  	})
   172  
   173  	DescribeTable("IsAuthorized for users",
   174  		func(requiredRole string, actualRole string, expected bool) {
   175  
   176  			verification.HasToken = true
   177  			verification.IsTokenValid = true
   178  			verification.RawClaims = map[string]interface{}{
   179  				"federated_claims": map[string]interface{}{
   180  					"connector_id": "some-connector",
   181  					"user_id":      "some-user-id",
   182  				},
   183  			}
   184  
   185  			fakeTeam1.NameReturns("some-team")
   186  			fakeTeam1.AdminReturns(true)
   187  			fakeTeam1.AuthReturns(atc.TeamAuth{
   188  				actualRole: map[string][]string{
   189  					"users": {"some-connector:some-user-id"},
   190  				},
   191  			})
   192  
   193  			access = accessor.NewAccessor(verification, requiredRole, "sub", []string{"system"}, teams)
   194  			result := access.IsAuthorized("some-team")
   195  			Expect(expected).Should(Equal(result))
   196  		},
   197  
   198  		Entry("viewer attempting viewer action", "viewer", "viewer", true),
   199  		Entry("pipeline-operator attempting viewer action", "viewer", "pipeline-operator", true),
   200  		Entry("member attempting viewer action", "viewer", "member", true),
   201  		Entry("owner attempting viewer action", "viewer", "owner", true),
   202  
   203  		Entry("viewer attempting pipeline-operator action", "pipeline-operator", "viewer", false),
   204  		Entry("pipeline-operator attempting pipeline-operator action", "pipeline-operator", "pipeline-operator", true),
   205  		Entry("member attempting pipeline-operator action", "pipeline-operator", "member", true),
   206  		Entry("owner attempting pipeline-operator action", "pipeline-operator", "owner", true),
   207  
   208  		Entry("viewer attempting member action", "member", "viewer", false),
   209  		Entry("pipeline-operator attempting member action", "member", "pipeline-operator", false),
   210  		Entry("member attempting member action", "member", "member", true),
   211  		Entry("owner attempting member action", "member", "owner", true),
   212  
   213  		Entry("viewer attempting owner action", "owner", "viewer", false),
   214  		Entry("pipeline-operator attempting owner action", "owner", "pipeline-operator", false),
   215  		Entry("member attempting owner action", "owner", "member", false),
   216  		Entry("owner attempting owner action", "owner", "owner", true),
   217  	)
   218  
   219  	DescribeTable("IsAuthorized for groups",
   220  		func(requiredRole string, actualRole string, expected bool) {
   221  
   222  			verification.HasToken = true
   223  			verification.IsTokenValid = true
   224  
   225  			verification.RawClaims = map[string]interface{}{
   226  				"groups": []interface{}{"some-group"},
   227  				"federated_claims": map[string]interface{}{
   228  					"connector_id": "some-connector",
   229  				},
   230  			}
   231  
   232  			fakeTeam1.NameReturns("some-team")
   233  			fakeTeam1.AdminReturns(true)
   234  			fakeTeam1.AuthReturns(atc.TeamAuth{
   235  				actualRole: map[string][]string{
   236  					"groups": {"some-connector:some-group"},
   237  				},
   238  			})
   239  
   240  			access = accessor.NewAccessor(verification, requiredRole, "sub", []string{"system"}, teams)
   241  			result := access.IsAuthorized("some-team")
   242  			Expect(expected).Should(Equal(result))
   243  		},
   244  
   245  		Entry("viewer attempting viewer action", "viewer", "viewer", true),
   246  		Entry("pipeline-operator attempting viewer action", "viewer", "pipeline-operator", true),
   247  		Entry("member attempting viewer action", "viewer", "member", true),
   248  		Entry("owner attempting viewer action", "viewer", "owner", true),
   249  
   250  		Entry("viewer attempting pipeline-operator action", "pipeline-operator", "viewer", false),
   251  		Entry("pipeline-operator attempting pipeline-operator action", "pipeline-operator", "pipeline-operator", true),
   252  		Entry("member attempting pipeline-operator action", "pipeline-operator", "member", true),
   253  		Entry("owner attempting pipeline-operator action", "pipeline-operator", "owner", true),
   254  
   255  		Entry("viewer attempting member action", "member", "viewer", false),
   256  		Entry("pipeline-operator attempting member action", "member", "pipeline-operator", false),
   257  		Entry("member attempting member action", "member", "member", true),
   258  		Entry("owner attempting member action", "member", "owner", true),
   259  
   260  		Entry("viewer attempting owner action", "owner", "viewer", false),
   261  		Entry("pipeline-operator attempting owner action", "owner", "pipeline-operator", false),
   262  		Entry("member attempting owner action", "owner", "member", false),
   263  		Entry("owner attempting owner action", "owner", "owner", true),
   264  	)
   265  
   266  	Describe("TeamNames", func() {
   267  		var result []string
   268  
   269  		JustBeforeEach(func() {
   270  			result = access.TeamNames()
   271  		})
   272  
   273  		Context("when the user has no token", func() {
   274  			BeforeEach(func() {
   275  				verification.HasToken = false
   276  			})
   277  
   278  			It("returns nothing", func() {
   279  				Expect(result).To(BeEmpty())
   280  			})
   281  		})
   282  
   283  		Context("when the user has invalid token", func() {
   284  			BeforeEach(func() {
   285  				verification.HasToken = true
   286  				verification.IsTokenValid = false
   287  			})
   288  
   289  			It("returns nothing", func() {
   290  				Expect(result).To(BeEmpty())
   291  			})
   292  		})
   293  
   294  		Context("when the user has valid token", func() {
   295  			BeforeEach(func() {
   296  				verification.HasToken = true
   297  				verification.IsTokenValid = true
   298  				verification.RawClaims = map[string]interface{}{
   299  					"federated_claims": map[string]interface{}{
   300  						"connector_id": "some-connector",
   301  						"user_id":      "some-user-id",
   302  					},
   303  				}
   304  			})
   305  
   306  			Context("when the user is part of any admin team", func() {
   307  				BeforeEach(func() {
   308  					fakeTeam1.AdminReturns(true)
   309  					fakeTeam1.AuthReturns(atc.TeamAuth{
   310  						"owner": map[string][]string{
   311  							"users": {"some-connector:some-user-id"},
   312  						},
   313  					})
   314  				})
   315  
   316  				It("returns all teams", func() {
   317  					Expect(result).To(ConsistOf(
   318  						"some-team-1",
   319  						"some-team-2",
   320  						"some-team-3",
   321  					))
   322  				})
   323  			})
   324  
   325  			Context("the team has the user configured", func() {
   326  
   327  				BeforeEach(func() {
   328  					fakeTeam1.AuthReturns(atc.TeamAuth{
   329  						"owner": map[string][]string{
   330  							"users": {"some-connector:some-user-id"},
   331  						},
   332  					})
   333  					fakeTeam2.AuthReturns(atc.TeamAuth{
   334  						"member": map[string][]string{
   335  							"users": {"some-connector:some-user-id"},
   336  						},
   337  					})
   338  					fakeTeam3.AuthReturns(atc.TeamAuth{
   339  						"viewer": map[string][]string{
   340  							"users": {"some-connector:some-user-id"},
   341  						},
   342  					})
   343  				})
   344  
   345  				Context("when the action requires a 'viewer' role", func() {
   346  					BeforeEach(func() {
   347  						requiredRole = "viewer"
   348  					})
   349  
   350  					It("returns all teams", func() {
   351  						Expect(result).To(ConsistOf(
   352  							"some-team-1",
   353  							"some-team-2",
   354  							"some-team-3",
   355  						))
   356  					})
   357  				})
   358  
   359  				Context("when the action requires a 'member' role", func() {
   360  					BeforeEach(func() {
   361  						requiredRole = "member"
   362  					})
   363  
   364  					It("returns all teams", func() {
   365  						Expect(result).To(ConsistOf(
   366  							"some-team-1",
   367  							"some-team-2",
   368  						))
   369  					})
   370  				})
   371  
   372  				Context("when the action requires an 'owner' role", func() {
   373  					BeforeEach(func() {
   374  						requiredRole = "owner"
   375  					})
   376  
   377  					It("returns all teams", func() {
   378  						Expect(result).To(ConsistOf(
   379  							"some-team-1",
   380  						))
   381  					})
   382  				})
   383  			})
   384  		})
   385  	})
   386  
   387  	Describe("IsAdmin", func() {
   388  		var result bool
   389  
   390  		JustBeforeEach(func() {
   391  			result = access.IsAdmin()
   392  		})
   393  
   394  		Context("when the user has no token", func() {
   395  			BeforeEach(func() {
   396  				verification.HasToken = false
   397  			})
   398  
   399  			It("returns false", func() {
   400  				Expect(result).To(BeFalse())
   401  			})
   402  		})
   403  
   404  		Context("when the user has invalid token", func() {
   405  			BeforeEach(func() {
   406  				verification.HasToken = true
   407  				verification.IsTokenValid = false
   408  			})
   409  
   410  			It("returns false", func() {
   411  				Expect(result).To(BeFalse())
   412  			})
   413  		})
   414  
   415  		Context("when the user has valid token", func() {
   416  			BeforeEach(func() {
   417  				verification.HasToken = true
   418  				verification.IsTokenValid = true
   419  				verification.RawClaims = map[string]interface{}{
   420  					"federated_claims": map[string]interface{}{
   421  						"connector_id": "some-connector",
   422  						"user_id":      "some-user-id",
   423  					},
   424  				}
   425  			})
   426  
   427  			Context("when the user is a not on an admin team", func() {
   428  				BeforeEach(func() {
   429  					fakeTeam1.AuthReturns(atc.TeamAuth{
   430  						"viewer": map[string][]string{
   431  							"users": {"some-connector:some-user-id"},
   432  						},
   433  					})
   434  					fakeTeam2.AuthReturns(atc.TeamAuth{
   435  						"member": map[string][]string{
   436  							"users": {"some-connector:some-user-id"},
   437  						},
   438  					})
   439  					fakeTeam3.AuthReturns(atc.TeamAuth{
   440  						"owner": map[string][]string{
   441  							"users": {"some-connector:some-user-id"},
   442  						},
   443  					})
   444  				})
   445  
   446  				It("returns false", func() {
   447  					Expect(result).To(BeFalse())
   448  				})
   449  			})
   450  
   451  			Context("when the user is a 'viewer' on an admin team", func() {
   452  				BeforeEach(func() {
   453  					fakeTeam1.AdminReturns(true)
   454  					fakeTeam1.AuthReturns(atc.TeamAuth{
   455  						"viewer": map[string][]string{
   456  							"users": {"some-connector:some-user-id"},
   457  						},
   458  					})
   459  				})
   460  
   461  				It("returns false", func() {
   462  					Expect(result).To(BeFalse())
   463  				})
   464  			})
   465  
   466  			Context("when the user is a 'member' on an admin team", func() {
   467  				BeforeEach(func() {
   468  					fakeTeam1.AdminReturns(true)
   469  					fakeTeam1.AuthReturns(atc.TeamAuth{
   470  						"member": map[string][]string{
   471  							"users": {"some-connector:some-user-id"},
   472  						},
   473  					})
   474  				})
   475  
   476  				It("returns false", func() {
   477  					Expect(result).To(BeFalse())
   478  				})
   479  			})
   480  
   481  			Context("when the user is a 'owner' on an admin team", func() {
   482  				BeforeEach(func() {
   483  					fakeTeam1.AdminReturns(true)
   484  					fakeTeam1.AuthReturns(atc.TeamAuth{
   485  						"owner": map[string][]string{
   486  							"users": []string{"some-connector:some-user-id"},
   487  						},
   488  					})
   489  				})
   490  
   491  				It("returns true", func() {
   492  					Expect(result).To(BeTrue())
   493  				})
   494  			})
   495  		})
   496  	})
   497  
   498  	Describe("IsSystem", func() {
   499  		var result bool
   500  
   501  		JustBeforeEach(func() {
   502  			result = access.IsSystem()
   503  		})
   504  
   505  		Context("when the user has no token", func() {
   506  			BeforeEach(func() {
   507  				verification.HasToken = false
   508  			})
   509  
   510  			It("returns false", func() {
   511  				Expect(result).To(BeFalse())
   512  			})
   513  		})
   514  
   515  		Context("when the user has invalid token", func() {
   516  			BeforeEach(func() {
   517  				verification.HasToken = true
   518  				verification.IsTokenValid = false
   519  			})
   520  
   521  			It("returns false", func() {
   522  				Expect(result).To(BeFalse())
   523  			})
   524  		})
   525  
   526  		Context("when the token does not have the system sub", func() {
   527  			BeforeEach(func() {
   528  				verification.HasToken = true
   529  				verification.IsTokenValid = true
   530  				verification.RawClaims = map[string]interface{}{
   531  					"sub": "not-system",
   532  				}
   533  			})
   534  
   535  			It("returns false", func() {
   536  				Expect(result).To(BeFalse())
   537  			})
   538  		})
   539  
   540  		Context("when the token does have the system sub", func() {
   541  			BeforeEach(func() {
   542  				verification.HasToken = true
   543  				verification.IsTokenValid = true
   544  				verification.RawClaims = map[string]interface{}{
   545  					"sub": "system",
   546  				}
   547  			})
   548  
   549  			It("returns true", func() {
   550  				Expect(result).To(BeTrue())
   551  			})
   552  		})
   553  	})
   554  
   555  	Describe("Claims", func() {
   556  		var result accessor.Claims
   557  
   558  		JustBeforeEach(func() {
   559  			result = access.Claims()
   560  		})
   561  
   562  		Context("when the user has no token", func() {
   563  			BeforeEach(func() {
   564  				verification.HasToken = false
   565  			})
   566  
   567  			It("returns empty", func() {
   568  				Expect(result).To(Equal(accessor.Claims{}))
   569  			})
   570  		})
   571  
   572  		Context("when the user has invalid token", func() {
   573  			BeforeEach(func() {
   574  				verification.HasToken = true
   575  				verification.IsTokenValid = false
   576  			})
   577  
   578  			It("returns empty", func() {
   579  				Expect(result).To(Equal(accessor.Claims{}))
   580  			})
   581  		})
   582  
   583  		Context("when the token has a preferred user_name", func() {
   584  			BeforeEach(func() {
   585  				verification.HasToken = true
   586  				verification.IsTokenValid = true
   587  				verification.RawClaims = map[string]interface{}{
   588  					"sub":                "some-sub",
   589  					"name":               "some-name",
   590  					"preferred_username": "some-user-name",
   591  					"email":              "some-email",
   592  					"federated_claims": map[string]interface{}{
   593  						"user_id":      "some-id",
   594  						"connector_id": "some-connector",
   595  					},
   596  				}
   597  			})
   598  
   599  			It("returns the result", func() {
   600  				Expect(result).To(Equal(accessor.Claims{
   601  					Sub:               "some-sub",
   602  					UserName:          "some-name",
   603  					Email:             "some-email",
   604  					UserID:            "some-id",
   605  					PreferredUsername: "some-user-name",
   606  					Connector:         "some-connector",
   607  				}))
   608  			})
   609  		})
   610  	})
   611  
   612  	Describe("TeamRoles", func() {
   613  		var result map[string][]string
   614  
   615  		JustBeforeEach(func() {
   616  			result = access.TeamRoles()
   617  		})
   618  
   619  		Context("when the user has no token", func() {
   620  			BeforeEach(func() {
   621  				verification.HasToken = false
   622  			})
   623  
   624  			It("returns empty", func() {
   625  				Expect(result).To(Equal(map[string][]string{}))
   626  			})
   627  		})
   628  
   629  		Context("when the user has invalid token", func() {
   630  			BeforeEach(func() {
   631  				verification.HasToken = true
   632  				verification.IsTokenValid = false
   633  			})
   634  
   635  			It("returns empty", func() {
   636  				Expect(result).To(Equal(map[string][]string{}))
   637  			})
   638  		})
   639  
   640  		Context("when the token has claims", func() {
   641  			BeforeEach(func() {
   642  				verification.HasToken = true
   643  				verification.IsTokenValid = true
   644  				verification.RawClaims = map[string]interface{}{
   645  					"sub":                "some-sub",
   646  					"name":               "some-name",
   647  					"preferred_username": "some-user-name",
   648  					"email":              "some-email",
   649  					"federated_claims": map[string]interface{}{
   650  						"connector_id": "some-connector",
   651  						"user_id":      "some-user-id",
   652  					},
   653  					"groups": []interface{}{"some-group"},
   654  				}
   655  			})
   656  
   657  			Context("when the user is not part of any teams", func() {
   658  				It("returns empty", func() {
   659  					Expect(result).To(Equal(map[string][]string{}))
   660  				})
   661  			})
   662  
   663  			Context("when the user is granted a role from their user id", func() {
   664  				BeforeEach(func() {
   665  					fakeTeam1.AuthReturns(atc.TeamAuth{
   666  						"owner": map[string][]string{
   667  							"users": {"some-connector:some-user-id"},
   668  						},
   669  					})
   670  					fakeTeam2.AuthReturns(atc.TeamAuth{
   671  						"member": map[string][]string{
   672  							"users": {"some-connector:some-user-id"},
   673  						},
   674  					})
   675  					fakeTeam3.AuthReturns(atc.TeamAuth{
   676  						"viewer": map[string][]string{
   677  							"users": {"some-connector:some-user-id"},
   678  						},
   679  					})
   680  				})
   681  
   682  				It("returns result with teams", func() {
   683  					Expect(result["some-team-1"]).To(ContainElement("owner"))
   684  					Expect(result["some-team-2"]).To(ContainElement("member"))
   685  					Expect(result["some-team-3"]).To(ContainElement("viewer"))
   686  				})
   687  			})
   688  
   689  			Context("when the user is granted a role from their user name", func() {
   690  				BeforeEach(func() {
   691  					fakeTeam1.AuthReturns(atc.TeamAuth{
   692  						"owner": map[string][]string{
   693  							"users": {"some-connector:some-user-name"},
   694  						},
   695  					})
   696  					fakeTeam2.AuthReturns(atc.TeamAuth{
   697  						"member": map[string][]string{
   698  							"users": {"some-connector:some-user-name"},
   699  						},
   700  					})
   701  					fakeTeam3.AuthReturns(atc.TeamAuth{
   702  						"viewer": map[string][]string{
   703  							"users": {"some-connector:some-user-name"},
   704  						},
   705  					})
   706  				})
   707  
   708  				It("returns result with teams", func() {
   709  					Expect(result["some-team-1"]).To(ContainElement("owner"))
   710  					Expect(result["some-team-2"]).To(ContainElement("member"))
   711  					Expect(result["some-team-3"]).To(ContainElement("viewer"))
   712  				})
   713  			})
   714  
   715  			Context("when the user is granted a role from a group", func() {
   716  				BeforeEach(func() {
   717  					fakeTeam1.AuthReturns(atc.TeamAuth{
   718  						"owner": map[string][]string{
   719  							"groups": {"some-connector:some-group"},
   720  						},
   721  					})
   722  					fakeTeam2.AuthReturns(atc.TeamAuth{
   723  						"member": map[string][]string{
   724  							"groups": {"some-connector:some-group"},
   725  						},
   726  					})
   727  					fakeTeam3.AuthReturns(atc.TeamAuth{
   728  						"viewer": map[string][]string{
   729  							"groups": {"some-connector:some-group"},
   730  						},
   731  					})
   732  				})
   733  
   734  				It("returns result with teams", func() {
   735  					Expect(result["some-team-1"]).To(ContainElement("owner"))
   736  					Expect(result["some-team-2"]).To(ContainElement("member"))
   737  					Expect(result["some-team-3"]).To(ContainElement("viewer"))
   738  				})
   739  			})
   740  
   741  			Context("when the user is granted multiple roles on the same team", func() {
   742  				BeforeEach(func() {
   743  					fakeTeam1.AuthReturns(atc.TeamAuth{
   744  						"owner": map[string][]string{
   745  							"users": {"some-connector:some-user-id"},
   746  						},
   747  						"member": map[string][]string{
   748  							"groups": {"some-connector:some-group"},
   749  						},
   750  					})
   751  				})
   752  
   753  				It("adds both roles", func() {
   754  					Expect(result["some-team-1"]).To(ContainElement("owner"))
   755  					Expect(result["some-team-1"]).To(ContainElement("member"))
   756  				})
   757  			})
   758  
   759  			Context("when the user is granted the same role multiple times", func() {
   760  				BeforeEach(func() {
   761  					fakeTeam1.AuthReturns(atc.TeamAuth{
   762  						"owner": map[string][]string{
   763  							"users":  {"some-connector:some-user-id"},
   764  							"groups": {"some-connector:some-group"},
   765  						},
   766  					})
   767  				})
   768  
   769  				It("only adds the role once", func() {
   770  					Expect(result["some-team-1"]).To(ContainElement("owner"))
   771  				})
   772  			})
   773  		})
   774  	})
   775  })