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/sdk/go/arvados"
15 "git.arvados.org/arvados.git/sdk/go/arvadostest"
16 "git.arvados.org/arvados.git/sdk/go/ctxlog"
17 check "gopkg.in/check.v1"
20 var _ = check.Suite(&FederationSuite{})
22 var origAPIHost, origAPIToken string
24 type FederationSuite struct {
25 super *boot.Supervisor
26 oidcprovider *arvadostest.OIDCProvider
29 func (s *FederationSuite) SetUpSuite(c *check.C) {
30 origAPIHost = os.Getenv("ARVADOS_API_HOST")
31 origAPIToken = os.Getenv("ARVADOS_API_TOKEN")
33 s.oidcprovider = arvadostest.NewOIDCProvider(c)
34 s.oidcprovider.AuthEmail = "user@example.com"
35 s.oidcprovider.AuthEmailVerified = true
36 s.oidcprovider.AuthName = "Example User"
37 s.oidcprovider.ValidClientID = "clientid"
38 s.oidcprovider.ValidClientSecret = "clientsecret"
40 hostport := map[string]string{}
41 for _, id := range []string{"z1111", "z2222"} {
42 hostport[id] = func() string {
43 // TODO: Instead of expecting random ports on
44 // 127.0.0.11, 22 to be race-safe, try
45 // different 127.x.y.z until finding one that
47 ln, err := net.Listen("tcp", ":0")
48 c.Assert(err, check.IsNil)
50 _, port, err := net.SplitHostPort(ln.Addr().String())
51 c.Assert(err, check.IsNil)
52 return "127.0.0." + id[3:] + ":" + port
56 for id := range hostport {
61 ExternalURL: https://` + hostport[id] + `
68 Host: ` + hostport["z1111"] + `
76 Host: ` + hostport["z2222"] + `
89 Issuer: ` + s.oidcprovider.Issuer.URL + `
90 ClientID: ` + s.oidcprovider.ValidClientID + `
91 ClientSecret: ` + s.oidcprovider.ValidClientSecret + `
93 EmailVerifiedClaim: email_verified
102 s.super = &boot.Supervisor{
105 Stderr: ctxlog.LogWriter(c.Log),
108 OwnTemporaryDatabase: true,
111 // Give up if startup takes longer than 3m
112 timeout := time.AfterFunc(3*time.Minute, s.super.Stop)
114 s.super.Start(context.Background())
115 ok := s.super.WaitReady()
116 c.Assert(ok, check.Equals, true)
118 // Activate user, make it admin.
119 conn1 := s.super.Conn("z1111")
120 rootctx1, _, _ := s.super.RootClients("z1111")
121 userctx1, _, _, _ := s.super.UserClients("z1111", rootctx1, c, conn1, s.oidcprovider.AuthEmail, true)
122 user1, err := conn1.UserGetCurrent(userctx1, arvados.GetOptions{})
123 c.Assert(err, check.IsNil)
124 c.Assert(user1.IsAdmin, check.Equals, false)
125 user1, err = conn1.UserUpdate(rootctx1, arvados.UpdateOptions{
127 Attrs: map[string]interface{}{
131 c.Assert(err, check.IsNil)
132 c.Assert(user1.IsAdmin, check.Equals, true)
135 func (s *FederationSuite) TearDownSuite(c *check.C) {
137 _ = os.Setenv("ARVADOS_API_HOST", origAPIHost)
138 _ = os.Setenv("ARVADOS_API_TOKEN", origAPIToken)
141 func (s *FederationSuite) TestGroupSyncingOnFederatedCluster(c *check.C) {
142 // Get admin user's V2 token
143 conn1 := s.super.Conn("z1111")
144 rootctx1, _, _ := s.super.RootClients("z1111")
145 userctx1, _, _, _ := s.super.UserClients("z1111", rootctx1, c, conn1, s.oidcprovider.AuthEmail, true)
146 user1Auth, err := conn1.APIClientAuthorizationCurrent(userctx1, arvados.GetOptions{})
147 c.Check(err, check.IsNil)
148 userV2Token := user1Auth.TokenV2()
150 // Get federated admin clients on z2222 to set up environment
151 conn2 := s.super.Conn("z2222")
152 userctx2, userac2, _ := s.super.ClientsWithToken("z2222", userV2Token)
153 user2, err := conn2.UserGetCurrent(userctx2, arvados.GetOptions{})
154 c.Check(err, check.IsNil)
155 c.Check(user2.IsAdmin, check.Equals, true)
157 // Set up environment for sync-groups using admin user credentials on z2222
158 err = os.Setenv("ARVADOS_API_HOST", userac2.APIHost)
159 c.Assert(err, check.IsNil)
160 err = os.Setenv("ARVADOS_API_TOKEN", userac2.AuthToken)
161 c.Assert(err, check.IsNil)
163 // Check that no parent group is created
164 gl := arvados.GroupList{}
165 params := arvados.ResourceListParams{
166 Filters: []arvados.Filter{{
169 Operand: s.super.Cluster("z2222").ClusterID + "-tpzed-000000000000000",
173 Operand: "Externally synchronized groups",
176 err = userac2.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
177 c.Assert(err, check.IsNil)
178 c.Assert(gl.ItemsAvailable, check.Equals, 0)
180 // Set up config, confirm that the parent group was created
181 os.Args = []string{"cmd", "somefile.csv"}
182 config, err := GetConfig()
183 c.Assert(err, check.IsNil)
184 userac2.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
185 c.Assert(gl.ItemsAvailable, check.Equals, 1)
187 // Run the tool with custom config
189 {"TestGroup1", user2.Email},
191 tmpfile, err := MakeTempCSVFile(data)
192 c.Assert(err, check.IsNil)
193 defer os.Remove(tmpfile.Name()) // clean up
194 config.Path = tmpfile.Name()
195 err = doMain(&config)
196 c.Assert(err, check.IsNil)
197 // Check the group was created correctly, and has the user as a member
198 groupUUID, err := RemoteGroupExists(&config, "TestGroup1")
199 c.Assert(err, check.IsNil)
200 c.Assert(groupUUID, check.Not(check.Equals), "")
201 c.Assert(GroupMembershipExists(config.Client, user2.UUID, groupUUID, "can_write"), check.Equals, true)