13111: Test webdav with http basic authentication.
[arvados.git] / services / keep-web / cadaver_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         "fmt"
10         "io"
11         "io/ioutil"
12         "net/url"
13         "os"
14         "os/exec"
15         "path/filepath"
16         "strings"
17         "time"
18
19         "git.curoverse.com/arvados.git/sdk/go/arvados"
20         "git.curoverse.com/arvados.git/sdk/go/arvadostest"
21         check "gopkg.in/check.v1"
22 )
23
24 func (s *IntegrationSuite) TestCadaverHTTPAuth(c *check.C) {
25         s.testCadaver(c, arvadostest.ActiveToken, func(newUUID string) (string, string, string) {
26                 r := "/c=" + arvadostest.FooAndBarFilesInDirUUID + "/"
27                 w := "/c=" + newUUID + "/"
28                 pdh := "/c=" + strings.Replace(arvadostest.FooAndBarFilesInDirPDH, "+", "-", -1) + "/"
29                 return r, w, pdh
30         })
31 }
32
33 func (s *IntegrationSuite) TestCadaverPathAuth(c *check.C) {
34         s.testCadaver(c, "", func(newUUID string) (string, string, string) {
35                 r := "/c=" + arvadostest.FooAndBarFilesInDirUUID + "/t=" + arvadostest.ActiveToken + "/"
36                 w := "/c=" + newUUID + "/t=" + arvadostest.ActiveToken + "/"
37                 pdh := "/c=" + strings.Replace(arvadostest.FooAndBarFilesInDirPDH, "+", "-", -1) + "/t=" + arvadostest.ActiveToken + "/"
38                 return r, w, pdh
39         })
40 }
41
42 func (s *IntegrationSuite) testCadaver(c *check.C, password string, pathFunc func(string) (string, string, string)) {
43         testdata := []byte("the human tragedy consists in the necessity of living with the consequences of actions performed under the pressure of compulsions we do not understand")
44
45         tempdir, err := ioutil.TempDir("", "keep-web-test-")
46         c.Assert(err, check.IsNil)
47         defer os.RemoveAll(tempdir)
48
49         localfile, err := ioutil.TempFile(tempdir, "localfile")
50         c.Assert(err, check.IsNil)
51         localfile.Write(testdata)
52
53         emptyfile, err := ioutil.TempFile(tempdir, "emptyfile")
54         c.Assert(err, check.IsNil)
55
56         checkfile, err := ioutil.TempFile(tempdir, "checkfile")
57         c.Assert(err, check.IsNil)
58
59         var newCollection arvados.Collection
60         arv := arvados.NewClientFromEnv()
61         arv.AuthToken = arvadostest.ActiveToken
62         err = arv.RequestAndDecode(&newCollection, "POST", "/arvados/v1/collections", bytes.NewBufferString(url.Values{"collection": {"{}"}}.Encode()), nil)
63         c.Assert(err, check.IsNil)
64
65         readPath, writePath, pdhPath := pathFunc(newCollection.UUID)
66
67         matchToday := time.Now().Format("Jan +2")
68
69         type testcase struct {
70                 path  string
71                 cmd   string
72                 match string
73                 data  []byte
74         }
75         for _, trial := range []testcase{
76                 {
77                         path:  readPath,
78                         cmd:   "ls\n",
79                         match: `(?ms).*dir1 *0 .*`,
80                 },
81                 {
82                         path:  readPath,
83                         cmd:   "ls dir1\n",
84                         match: `(?ms).*bar *3.*foo *3 .*`,
85                 },
86                 {
87                         path:  readPath + "_/dir1",
88                         cmd:   "ls\n",
89                         match: `(?ms).*bar *3.*foo *3 .*`,
90                 },
91                 {
92                         path:  readPath + "dir1/",
93                         cmd:   "ls\n",
94                         match: `(?ms).*bar *3.*foo +3 +Feb +\d+ +2014.*`,
95                 },
96                 {
97                         path:  writePath,
98                         cmd:   "get emptyfile '" + checkfile.Name() + "'\n",
99                         match: `(?ms).*Not Found.*`,
100                 },
101                 {
102                         path:  writePath,
103                         cmd:   "put '" + emptyfile.Name() + "' emptyfile\n",
104                         match: `(?ms).*Uploading .* succeeded.*`,
105                 },
106                 {
107                         path:  writePath,
108                         cmd:   "get emptyfile '" + checkfile.Name() + "'\n",
109                         match: `(?ms).*Downloading .* succeeded.*`,
110                         data:  []byte{},
111                 },
112                 {
113                         path:  writePath,
114                         cmd:   "put '" + localfile.Name() + "' testfile\n",
115                         match: `(?ms).*Uploading .* succeeded.*`,
116                 },
117                 {
118                         path:  writePath,
119                         cmd:   "get testfile '" + checkfile.Name() + "'\n",
120                         match: `(?ms).*succeeded.*`,
121                         data:  testdata,
122                 },
123                 {
124                         path:  writePath,
125                         cmd:   "move testfile newdir0/\n",
126                         match: `(?ms).*Moving .* succeeded.*`,
127                 },
128                 {
129                         path:  writePath,
130                         cmd:   "move testfile newdir0/\n",
131                         match: `(?ms).*Moving .* failed.*`,
132                 },
133                 {
134                         path:  writePath,
135                         cmd:   "ls\n",
136                         match: `(?ms).*newdir0.* 0 +` + matchToday + ` \d+:\d+\n.*`,
137                 },
138                 {
139                         path:  writePath,
140                         cmd:   "move newdir0/testfile emptyfile/bogus/\n",
141                         match: `(?ms).*Moving .* failed.*`,
142                 },
143                 {
144                         path:  writePath,
145                         cmd:   "mkcol newdir1\n",
146                         match: `(?ms).*Creating .* succeeded.*`,
147                 },
148                 {
149                         path:  writePath,
150                         cmd:   "move newdir0/testfile newdir1/\n",
151                         match: `(?ms).*Moving .* succeeded.*`,
152                 },
153                 {
154                         path:  writePath,
155                         cmd:   "move newdir1 newdir1/\n",
156                         match: `(?ms).*Moving .* failed.*`,
157                 },
158                 {
159                         path:  writePath,
160                         cmd:   "get newdir1/testfile '" + checkfile.Name() + "'\n",
161                         match: `(?ms).*succeeded.*`,
162                         data:  testdata,
163                 },
164                 {
165                         path:  writePath,
166                         cmd:   "put '" + localfile.Name() + "' newdir1/testfile1\n",
167                         match: `(?ms).*Uploading .* succeeded.*`,
168                 },
169                 {
170                         path:  writePath,
171                         cmd:   "mkcol newdir2\n",
172                         match: `(?ms).*Creating .* succeeded.*`,
173                 },
174                 {
175                         path:  writePath,
176                         cmd:   "put '" + localfile.Name() + "' newdir2/testfile2\n",
177                         match: `(?ms).*Uploading .* succeeded.*`,
178                 },
179                 {
180                         path:  writePath,
181                         cmd:   "copy newdir2/testfile2 testfile3\n",
182                         match: `(?ms).*succeeded.*`,
183                 },
184                 {
185                         path:  writePath,
186                         cmd:   "get testfile3 '" + checkfile.Name() + "'\n",
187                         match: `(?ms).*succeeded.*`,
188                         data:  testdata,
189                 },
190                 {
191                         path:  writePath,
192                         cmd:   "get newdir2/testfile2 '" + checkfile.Name() + "'\n",
193                         match: `(?ms).*succeeded.*`,
194                         data:  testdata,
195                 },
196                 {
197                         path:  writePath,
198                         cmd:   "rmcol newdir2\n",
199                         match: `(?ms).*Deleting collection .* succeeded.*`,
200                 },
201                 {
202                         path:  writePath,
203                         cmd:   "get newdir2/testfile2 '" + checkfile.Name() + "'\n",
204                         match: `(?ms).*Downloading .* failed.*`,
205                 },
206                 {
207                         path:  "/c=" + arvadostest.UserAgreementCollection + "/t=" + arv.AuthToken + "/",
208                         cmd:   "put '" + localfile.Name() + "' foo\n",
209                         match: `(?ms).*Uploading .* failed:.*403 Forbidden.*`,
210                 },
211                 {
212                         path:  pdhPath,
213                         cmd:   "put '" + localfile.Name() + "' foo\n",
214                         match: `(?ms).*Uploading .* failed:.*405 Method Not Allowed.*`,
215                 },
216                 {
217                         path:  pdhPath,
218                         cmd:   "move foo bar\n",
219                         match: `(?ms).*Moving .* failed:.*405 Method Not Allowed.*`,
220                 },
221                 {
222                         path:  pdhPath,
223                         cmd:   "copy foo bar\n",
224                         match: `(?ms).*Copying .* failed:.*405 Method Not Allowed.*`,
225                 },
226                 {
227                         path:  pdhPath,
228                         cmd:   "delete foo\n",
229                         match: `(?ms).*Deleting .* failed:.*405 Method Not Allowed.*`,
230                 },
231         } {
232                 c.Logf("%s %+v", "http://"+s.testServer.Addr, trial)
233
234                 os.Remove(checkfile.Name())
235
236                 cmd := exec.Command("cadaver", "http://"+s.testServer.Addr+trial.path)
237                 if password != "" {
238                         // cadaver won't try username/password
239                         // authentication unless the server responds
240                         // 401 to an unauthenticated request, which it
241                         // only does in AttachmentOnlyHost,
242                         // TrustAllContent, and per-collection vhost
243                         // cases.
244                         s.testServer.Config.AttachmentOnlyHost = s.testServer.Addr
245
246                         cmd.Env = append(os.Environ(), "HOME="+tempdir)
247                         f, err := os.OpenFile(filepath.Join(tempdir, ".netrc"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
248                         c.Assert(err, check.IsNil)
249                         _, err = fmt.Fprintf(f, "default login none password %s\n", password)
250                         c.Assert(err, check.IsNil)
251                         c.Assert(f.Close(), check.IsNil)
252                 }
253                 cmd.Stdin = bytes.NewBufferString(trial.cmd)
254                 stdout, err := cmd.StdoutPipe()
255                 c.Assert(err, check.Equals, nil)
256                 cmd.Stderr = cmd.Stdout
257                 go cmd.Start()
258
259                 var buf bytes.Buffer
260                 _, err = io.Copy(&buf, stdout)
261                 c.Check(err, check.Equals, nil)
262                 err = cmd.Wait()
263                 c.Check(err, check.Equals, nil)
264                 c.Check(buf.String(), check.Matches, trial.match)
265
266                 if trial.data == nil {
267                         continue
268                 }
269                 checkfile, err = os.Open(checkfile.Name())
270                 c.Assert(err, check.IsNil)
271                 checkfile.Seek(0, os.SEEK_SET)
272                 got, err := ioutil.ReadAll(checkfile)
273                 c.Check(got, check.DeepEquals, trial.data)
274                 c.Check(err, check.IsNil)
275         }
276 }