16981: Removes config loader code to fix import cycle.
[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         "bytes"
9         "net"
10         "os"
11         "path/filepath"
12
13         "git.arvados.org/arvados.git/lib/config"
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"
18 )
19
20 var _ = check.Suite(&FederationSuite{})
21
22 var origAPIHost, origAPIToken string
23
24 type FederationSuite struct {
25         testClusters map[string]*arvadostest.TestCluster
26         oidcprovider *arvadostest.OIDCProvider
27 }
28
29 func (s *FederationSuite) SetUpSuite(c *check.C) {
30         origAPIHost = os.Getenv("ARVADOS_API_HOST")
31         origAPIToken = os.Getenv("ARVADOS_API_TOKEN")
32
33         cwd, _ := os.Getwd()
34
35         s.oidcprovider = arvadostest.NewOIDCProvider(c)
36         s.oidcprovider.AuthEmail = "user@example.com"
37         s.oidcprovider.AuthEmailVerified = true
38         s.oidcprovider.AuthName = "Example User"
39         s.oidcprovider.ValidClientID = "clientid"
40         s.oidcprovider.ValidClientSecret = "clientsecret"
41
42         s.testClusters = map[string]*arvadostest.TestCluster{
43                 "z1111": nil,
44                 "z2222": nil,
45         }
46         hostport := map[string]string{}
47         for id := range s.testClusters {
48                 hostport[id] = func() string {
49                         // TODO: Instead of expecting random ports on
50                         // 127.0.0.11, 22 to be race-safe, try
51                         // different 127.x.y.z until finding one that
52                         // isn't in use.
53                         ln, err := net.Listen("tcp", ":0")
54                         c.Assert(err, check.IsNil)
55                         ln.Close()
56                         _, port, err := net.SplitHostPort(ln.Addr().String())
57                         c.Assert(err, check.IsNil)
58                         return "127.0.0." + id[3:] + ":" + port
59                 }()
60         }
61         for id := range s.testClusters {
62                 yaml := `Clusters:
63   ` + id + `:
64     Services:
65       Controller:
66         ExternalURL: https://` + hostport[id] + `
67     TLS:
68       Insecure: true
69     SystemLogs:
70       Format: text
71     RemoteClusters:
72       z1111:
73         Host: ` + hostport["z1111"] + `
74         Scheme: https
75         Insecure: true
76         Proxy: true
77         ActivateUsers: true
78 `
79                 if id != "z2222" {
80                         yaml += `      z2222:
81         Host: ` + hostport["z2222"] + `
82         Scheme: https
83         Insecure: true
84         Proxy: true
85         ActivateUsers: true
86 `
87                 }
88                 if id == "z1111" {
89                         yaml += `
90     Login:
91       LoginCluster: z1111
92       OpenIDConnect:
93         Enable: true
94         Issuer: ` + s.oidcprovider.Issuer.URL + `
95         ClientID: ` + s.oidcprovider.ValidClientID + `
96         ClientSecret: ` + s.oidcprovider.ValidClientSecret + `
97         EmailClaim: email
98         EmailVerifiedClaim: email_verified
99 `
100                 } else {
101                         yaml += `
102     Login:
103       LoginCluster: z1111
104 `
105                 }
106
107                 loader := config.NewLoader(bytes.NewBufferString(yaml), ctxlog.TestLogger(c))
108                 loader.Path = "-"
109                 loader.SkipLegacy = true
110                 loader.SkipAPICalls = true
111                 cfg, err := loader.Load()
112                 c.Assert(err, check.IsNil)
113                 tc := arvadostest.NewTestCluster(
114                         filepath.Join(cwd, "..", ".."),
115                         id, cfg, "127.0.0."+id[3:], c.Log)
116                 s.testClusters[id] = tc
117                 s.testClusters[id].Start()
118         }
119         for _, tc := range s.testClusters {
120                 ok := tc.WaitReady()
121                 c.Assert(ok, check.Equals, true)
122         }
123
124         // Activate user, make it admin.
125         conn1 := s.testClusters["z1111"].Conn()
126         rootctx1, _, _ := s.testClusters["z1111"].RootClients()
127         userctx1, _, _, _ := s.testClusters["z1111"].UserClients(rootctx1, c, conn1, s.oidcprovider.AuthEmail, true)
128         user1, err := conn1.UserGetCurrent(userctx1, arvados.GetOptions{})
129         c.Assert(err, check.IsNil)
130         c.Assert(user1.IsAdmin, check.Equals, false)
131         user1, err = conn1.UserUpdate(rootctx1, arvados.UpdateOptions{
132                 UUID: user1.UUID,
133                 Attrs: map[string]interface{}{
134                         "is_admin": true,
135                 },
136         })
137         c.Assert(err, check.IsNil)
138         c.Assert(user1.IsAdmin, check.Equals, true)
139 }
140
141 func (s *FederationSuite) TearDownSuite(c *check.C) {
142         for _, c := range s.testClusters {
143                 c.Super.Stop()
144         }
145         _ = os.Setenv("ARVADOS_API_HOST", origAPIHost)
146         _ = os.Setenv("ARVADOS_API_TOKEN", origAPIToken)
147 }
148
149 func (s *FederationSuite) TestGroupSyncingOnFederatedCluster(c *check.C) {
150         // Get admin user's V2 token
151         conn1 := s.testClusters["z1111"].Conn()
152         rootctx1, _, _ := s.testClusters["z1111"].RootClients()
153         userctx1, _, _, _ := s.testClusters["z1111"].UserClients(rootctx1, c, conn1, s.oidcprovider.AuthEmail, true)
154         user1Auth, err := conn1.APIClientAuthorizationCurrent(userctx1, arvados.GetOptions{})
155         c.Check(err, check.IsNil)
156         userV2Token := user1Auth.TokenV2()
157
158         // Get federated admin clients on z2222 to set up environment
159         conn2 := s.testClusters["z2222"].Conn()
160         userctx2, userac2, _ := s.testClusters["z2222"].ClientsWithToken(userV2Token)
161         user2, err := conn2.UserGetCurrent(userctx2, arvados.GetOptions{})
162         c.Check(err, check.IsNil)
163         c.Check(user2.IsAdmin, check.Equals, true)
164
165         // Set up environment for sync-groups using admin user credentials on z2222
166         err = os.Setenv("ARVADOS_API_HOST", userac2.APIHost)
167         c.Assert(err, check.IsNil)
168         err = os.Setenv("ARVADOS_API_TOKEN", userac2.AuthToken)
169         c.Assert(err, check.IsNil)
170
171         // Check that no parent group is created
172         gl := arvados.GroupList{}
173         params := arvados.ResourceListParams{
174                 Filters: []arvados.Filter{{
175                         Attr:     "owner_uuid",
176                         Operator: "=",
177                         Operand:  s.testClusters["z2222"].ClusterID + "-tpzed-000000000000000",
178                 }, {
179                         Attr:     "name",
180                         Operator: "=",
181                         Operand:  "Externally synchronized groups",
182                 }},
183         }
184         err = userac2.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
185         c.Assert(err, check.IsNil)
186         c.Assert(gl.ItemsAvailable, check.Equals, 0)
187
188         // Set up config, confirm that the parent group was created
189         os.Args = []string{"cmd", "somefile.csv"}
190         config, err := GetConfig()
191         c.Assert(err, check.IsNil)
192         userac2.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
193         c.Assert(gl.ItemsAvailable, check.Equals, 1)
194
195         // Run the tool with custom config
196         data := [][]string{
197                 {"TestGroup1", user2.Email},
198         }
199         tmpfile, err := MakeTempCSVFile(data)
200         c.Assert(err, check.IsNil)
201         defer os.Remove(tmpfile.Name()) // clean up
202         config.Path = tmpfile.Name()
203         err = doMain(&config)
204         c.Assert(err, check.IsNil)
205         // Check the group was created correctly, and has the user as a member
206         groupUUID, err := RemoteGroupExists(&config, "TestGroup1")
207         c.Assert(err, check.IsNil)
208         c.Assert(groupUUID, check.Not(check.Equals), "")
209         c.Assert(GroupMembershipExists(config.Client, user2.UUID, groupUUID, "can_write"), check.Equals, true)
210 }