16981: Adds federation test on sync-groups.
[arvados.git] / tools / sync-groups / federation_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package main
6
7 import (
8         "net"
9         "os"
10         "path/filepath"
11
12         "git.arvados.org/arvados.git/sdk/go/arvados"
13         "git.arvados.org/arvados.git/sdk/go/arvadostest"
14         check "gopkg.in/check.v1"
15 )
16
17 var _ = check.Suite(&FederationSuite{})
18
19 var origAPIHost, origAPIToken string
20
21 type FederationSuite struct {
22         testClusters map[string]*arvadostest.TestCluster
23         oidcprovider *arvadostest.OIDCProvider
24 }
25
26 func (s *FederationSuite) SetUpSuite(c *check.C) {
27         origAPIHost = os.Getenv("ARVADOS_API_HOST")
28         origAPIToken = os.Getenv("ARVADOS_API_TOKEN")
29
30         cwd, _ := os.Getwd()
31
32         s.oidcprovider = arvadostest.NewOIDCProvider(c)
33         s.oidcprovider.AuthEmail = "user@example.com"
34         s.oidcprovider.AuthEmailVerified = true
35         s.oidcprovider.AuthName = "Example User"
36         s.oidcprovider.ValidClientID = "clientid"
37         s.oidcprovider.ValidClientSecret = "clientsecret"
38
39         s.testClusters = map[string]*arvadostest.TestCluster{
40                 "z1111": nil,
41                 "z2222": nil,
42         }
43         hostport := map[string]string{}
44         for id := range s.testClusters {
45                 hostport[id] = func() string {
46                         // TODO: Instead of expecting random ports on
47                         // 127.0.0.11, 22 to be race-safe, try
48                         // different 127.x.y.z until finding one that
49                         // isn't in use.
50                         ln, err := net.Listen("tcp", ":0")
51                         c.Assert(err, check.IsNil)
52                         ln.Close()
53                         _, port, err := net.SplitHostPort(ln.Addr().String())
54                         c.Assert(err, check.IsNil)
55                         return "127.0.0." + id[3:] + ":" + port
56                 }()
57         }
58         for id := range s.testClusters {
59                 yaml := `Clusters:
60   ` + id + `:
61     Services:
62       Controller:
63         ExternalURL: https://` + hostport[id] + `
64     TLS:
65       Insecure: true
66     SystemLogs:
67       Format: text
68     RemoteClusters:
69       z1111:
70         Host: ` + hostport["z1111"] + `
71         Scheme: https
72         Insecure: true
73         Proxy: true
74         ActivateUsers: true
75 `
76                 if id != "z2222" {
77                         yaml += `      z2222:
78         Host: ` + hostport["z2222"] + `
79         Scheme: https
80         Insecure: true
81         Proxy: true
82         ActivateUsers: true
83 `
84                 }
85                 if id == "z1111" {
86                         yaml += `
87     Login:
88       LoginCluster: z1111
89       OpenIDConnect:
90         Enable: true
91         Issuer: ` + s.oidcprovider.Issuer.URL + `
92         ClientID: ` + s.oidcprovider.ValidClientID + `
93         ClientSecret: ` + s.oidcprovider.ValidClientSecret + `
94         EmailClaim: email
95         EmailVerifiedClaim: email_verified
96 `
97                 } else {
98                         yaml += `
99     Login:
100       LoginCluster: z1111
101 `
102                 }
103
104                 tc, err := arvadostest.NewTestCluster(
105                         filepath.Join(cwd, "..", ".."),
106                         id, yaml, "127.0.0."+id[3:], c.Log)
107                 c.Assert(err, check.IsNil)
108                 s.testClusters[id] = tc
109                 s.testClusters[id].Start()
110         }
111         for _, tc := range s.testClusters {
112                 ok := tc.WaitReady()
113                 c.Assert(ok, check.Equals, true)
114         }
115
116         // Activate user, make it admin.
117         conn1 := s.testClusters["z1111"].Conn()
118         rootctx1, _, _ := s.testClusters["z1111"].RootClients()
119         userctx1, _, _, _ := s.testClusters["z1111"].UserClients(rootctx1, c, conn1, s.oidcprovider.AuthEmail, true)
120         user1, err := conn1.UserGetCurrent(userctx1, arvados.GetOptions{})
121         c.Assert(err, check.IsNil)
122         c.Assert(user1.IsAdmin, check.Equals, false)
123         user1, err = conn1.UserUpdate(rootctx1, arvados.UpdateOptions{
124                 UUID: user1.UUID,
125                 Attrs: map[string]interface{}{
126                         "is_admin": true,
127                 },
128         })
129         c.Assert(err, check.IsNil)
130         c.Assert(user1.IsAdmin, check.Equals, true)
131 }
132
133 func (s *FederationSuite) TearDownSuite(c *check.C) {
134         for _, c := range s.testClusters {
135                 c.Super.Stop()
136         }
137         _ = os.Setenv("ARVADOS_API_HOST", origAPIHost)
138         _ = os.Setenv("ARVADOS_API_TOKEN", origAPIToken)
139 }
140
141 func (s *FederationSuite) TestGroupSyncingOnFederatedCluster(c *check.C) {
142         // Get admin user's V2 token
143         conn1 := s.testClusters["z1111"].Conn()
144         rootctx1, _, _ := s.testClusters["z1111"].RootClients()
145         userctx1, _, _, _ := s.testClusters["z1111"].UserClients(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()
149
150         // Get federated admin clients on z2222 to set up environment
151         conn2 := s.testClusters["z2222"].Conn()
152         userctx2, userac2, _ := s.testClusters["z2222"].ClientsWithToken(userV2Token)
153         user2, err := conn2.UserGetCurrent(userctx2, arvados.GetOptions{})
154         c.Check(err, check.IsNil)
155         c.Check(user2.IsAdmin, check.Equals, true)
156
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)
162
163         // Check that no parent group is created
164         gl := arvados.GroupList{}
165         params := arvados.ResourceListParams{
166                 Filters: []arvados.Filter{{
167                         Attr:     "owner_uuid",
168                         Operator: "=",
169                         Operand:  s.testClusters["z2222"].ClusterID + "-tpzed-000000000000000",
170                 }, {
171                         Attr:     "name",
172                         Operator: "=",
173                         Operand:  "Externally synchronized groups",
174                 }},
175         }
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)
179
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)
186
187         // Run the tool with custom config
188         data := [][]string{
189                 {"TestGroup1", user2.Email},
190         }
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)
202 }