1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
13 "git.arvados.org/arvados.git/lib/boot"
14 "git.arvados.org/arvados.git/lib/config"
15 "git.arvados.org/arvados.git/sdk/go/arvados"
16 "git.arvados.org/arvados.git/sdk/go/arvadostest"
17 "git.arvados.org/arvados.git/sdk/go/ctxlog"
18 check "gopkg.in/check.v1"
21 var _ = check.Suite(&FederationSuite{})
23 var origAPIHost, origAPIToken string
25 type FederationSuite struct {
26 testClusters map[string]*boot.TestCluster
27 oidcprovider *arvadostest.OIDCProvider
30 func (s *FederationSuite) SetUpSuite(c *check.C) {
31 origAPIHost = os.Getenv("ARVADOS_API_HOST")
32 origAPIToken = os.Getenv("ARVADOS_API_TOKEN")
36 s.oidcprovider = arvadostest.NewOIDCProvider(c)
37 s.oidcprovider.AuthEmail = "user@example.com"
38 s.oidcprovider.AuthEmailVerified = true
39 s.oidcprovider.AuthName = "Example User"
40 s.oidcprovider.ValidClientID = "clientid"
41 s.oidcprovider.ValidClientSecret = "clientsecret"
43 s.testClusters = map[string]*boot.TestCluster{
47 hostport := map[string]string{}
48 for id := range s.testClusters {
49 hostport[id] = func() string {
50 // TODO: Instead of expecting random ports on
51 // 127.0.0.11, 22 to be race-safe, try
52 // different 127.x.y.z until finding one that
54 ln, err := net.Listen("tcp", ":0")
55 c.Assert(err, check.IsNil)
57 _, port, err := net.SplitHostPort(ln.Addr().String())
58 c.Assert(err, check.IsNil)
59 return "127.0.0." + id[3:] + ":" + port
62 for id := range s.testClusters {
67 ExternalURL: https://` + hostport[id] + `
74 Host: ` + hostport["z1111"] + `
82 Host: ` + hostport["z2222"] + `
95 Issuer: ` + s.oidcprovider.Issuer.URL + `
96 ClientID: ` + s.oidcprovider.ValidClientID + `
97 ClientSecret: ` + s.oidcprovider.ValidClientSecret + `
99 EmailVerifiedClaim: email_verified
108 loader := config.NewLoader(bytes.NewBufferString(yaml), ctxlog.TestLogger(c))
110 loader.SkipLegacy = true
111 loader.SkipAPICalls = true
112 cfg, err := loader.Load()
113 c.Assert(err, check.IsNil)
114 tc := boot.NewTestCluster(
115 filepath.Join(cwd, "..", ".."),
116 id, cfg, "127.0.0."+id[3:], c.Log)
117 tc.Super.NoWorkbench1 = true
118 tc.Super.NoWorkbench2 = true
120 s.testClusters[id] = tc
122 for _, tc := range s.testClusters {
124 c.Assert(ok, check.Equals, true)
127 // Activate user, make it admin.
128 conn1 := s.testClusters["z1111"].Conn()
129 rootctx1, _, _ := s.testClusters["z1111"].RootClients()
130 userctx1, _, _, _ := s.testClusters["z1111"].UserClients(rootctx1, c, conn1, s.oidcprovider.AuthEmail, true)
131 user1, err := conn1.UserGetCurrent(userctx1, arvados.GetOptions{})
132 c.Assert(err, check.IsNil)
133 c.Assert(user1.IsAdmin, check.Equals, false)
134 user1, err = conn1.UserUpdate(rootctx1, arvados.UpdateOptions{
136 Attrs: map[string]interface{}{
140 c.Assert(err, check.IsNil)
141 c.Assert(user1.IsAdmin, check.Equals, true)
144 func (s *FederationSuite) TearDownSuite(c *check.C) {
145 for _, c := range s.testClusters {
148 _ = os.Setenv("ARVADOS_API_HOST", origAPIHost)
149 _ = os.Setenv("ARVADOS_API_TOKEN", origAPIToken)
152 func (s *FederationSuite) TestGroupSyncingOnFederatedCluster(c *check.C) {
153 // Get admin user's V2 token
154 conn1 := s.testClusters["z1111"].Conn()
155 rootctx1, _, _ := s.testClusters["z1111"].RootClients()
156 userctx1, _, _, _ := s.testClusters["z1111"].UserClients(rootctx1, c, conn1, s.oidcprovider.AuthEmail, true)
157 user1Auth, err := conn1.APIClientAuthorizationCurrent(userctx1, arvados.GetOptions{})
158 c.Check(err, check.IsNil)
159 userV2Token := user1Auth.TokenV2()
161 // Get federated admin clients on z2222 to set up environment
162 conn2 := s.testClusters["z2222"].Conn()
163 userctx2, userac2, _ := s.testClusters["z2222"].ClientsWithToken(userV2Token)
164 user2, err := conn2.UserGetCurrent(userctx2, arvados.GetOptions{})
165 c.Check(err, check.IsNil)
166 c.Check(user2.IsAdmin, check.Equals, true)
168 // Set up environment for sync-groups using admin user credentials on z2222
169 err = os.Setenv("ARVADOS_API_HOST", userac2.APIHost)
170 c.Assert(err, check.IsNil)
171 err = os.Setenv("ARVADOS_API_TOKEN", userac2.AuthToken)
172 c.Assert(err, check.IsNil)
174 // Check that no parent group is created
175 gl := arvados.GroupList{}
176 params := arvados.ResourceListParams{
177 Filters: []arvados.Filter{{
180 Operand: s.testClusters["z2222"].ClusterID + "-tpzed-000000000000000",
184 Operand: "Externally synchronized groups",
187 err = userac2.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
188 c.Assert(err, check.IsNil)
189 c.Assert(gl.ItemsAvailable, check.Equals, 0)
191 // Set up config, confirm that the parent group was created
192 os.Args = []string{"cmd", "somefile.csv"}
193 config, err := GetConfig()
194 c.Assert(err, check.IsNil)
195 userac2.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
196 c.Assert(gl.ItemsAvailable, check.Equals, 1)
198 // Run the tool with custom config
200 {"TestGroup1", user2.Email},
202 tmpfile, err := MakeTempCSVFile(data)
203 c.Assert(err, check.IsNil)
204 defer os.Remove(tmpfile.Name()) // clean up
205 config.Path = tmpfile.Name()
206 err = doMain(&config)
207 c.Assert(err, check.IsNil)
208 // Check the group was created correctly, and has the user as a member
209 groupUUID, err := RemoteGroupExists(&config, "TestGroup1")
210 c.Assert(err, check.IsNil)
211 c.Assert(groupUUID, check.Not(check.Equals), "")
212 c.Assert(GroupMembershipExists(config.Client, user2.UUID, groupUUID, "can_write"), check.Equals, true)