Browse Source

webdav: remove the username path prefix

so we have the same URIs for all protocols

Fixes #293
Nicola Murino 4 years ago
parent
commit
ce731020a7
2 changed files with 11 additions and 88 deletions
  1. 4 18
      webdavd/server.go
  2. 7 70
      webdavd/webdavd_test.go

+ 4 - 18
webdavd/server.go

@@ -27,7 +27,6 @@ import (
 
 var (
 	err401        = errors.New("Unauthorized")
-	err403        = errors.New("Forbidden")
 	xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
 	xRealIP       = http.CanonicalHeaderKey("X-Real-IP")
 )
@@ -105,11 +104,11 @@ func (s *webDavServer) verifyTLSConnection(state tls.ConnectionState) error {
 	return nil
 }
 
-// returns true if a response was sent
-func (s *webDavServer) checkRequestMethod(ctx context.Context, r *http.Request, connection *Connection, prefix string) bool {
+// returns true if we have to handle a HEAD response, for a directory, ourself
+func (s *webDavServer) checkRequestMethod(ctx context.Context, r *http.Request, connection *Connection) bool {
 	// see RFC4918, section 9.4
 	if r.Method == http.MethodGet || r.Method == http.MethodHead {
-		p := strings.TrimPrefix(path.Clean(r.URL.Path), prefix)
+		p := path.Clean(r.URL.Path)
 		info, err := connection.Stat(ctx, p)
 		if err == nil && info.IsDir() {
 			if r.Method == http.MethodHead {
@@ -154,11 +153,6 @@ func (s *webDavServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if path.Clean(r.URL.Path) == "/" && (r.Method == http.MethodGet || r.Method == "PROPFIND" || r.Method == http.MethodOptions) {
-		http.Redirect(w, r, path.Join("/", user.Username), http.StatusMovedPermanently)
-		return
-	}
-
 	connectionID, err := s.validateUser(&user, r)
 	if err != nil {
 		updateLoginMetrics(&user, ipAddr, err)
@@ -187,8 +181,7 @@ func (s *webDavServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 
 	dataprovider.UpdateLastLogin(user) //nolint:errcheck
 
-	prefix := path.Join("/", user.Username)
-	if s.checkRequestMethod(ctx, r, connection, prefix) {
+	if s.checkRequestMethod(ctx, r, connection) {
 		w.Header().Set("Content-Type", "text/xml; charset=utf-8")
 		w.WriteHeader(http.StatusMultiStatus)
 		w.Write([]byte("")) //nolint:errcheck
@@ -196,7 +189,6 @@ func (s *webDavServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	}
 
 	handler := webdav.Handler{
-		Prefix:     prefix,
 		FileSystem: connection,
 		LockSystem: lockSystem,
 		Logger:     writeLog,
@@ -257,12 +249,6 @@ func (s *webDavServer) validateUser(user *dataprovider.User, r *http.Request) (s
 	connID := xid.New().String()
 	connectionID := fmt.Sprintf("%v_%v", common.ProtocolWebDAV, connID)
 
-	uriSegments := strings.Split(path.Clean(r.URL.Path), "/")
-	if len(uriSegments) < 2 || uriSegments[1] != user.Username {
-		logger.Debug(logSender, connectionID, "URI %#v not allowed for user %#v", r.URL.Path, user.Username)
-		return connID, err403
-	}
-
 	if !filepath.IsAbs(user.HomeDir) {
 		logger.Warn(logSender, connectionID, "user %#v has an invalid home dir: %#v. Home dir must be an absolute path, login not allowed",
 			user.Username, user.HomeDir)

+ 7 - 70
webdavd/webdavd_test.go

@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"crypto/rand"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -472,7 +471,7 @@ func TestPropPatch(t *testing.T) {
 		assert.NoError(t, err)
 		httpClient := httpclient.GetHTTPClient()
 		propatchBody := `<?xml version="1.0" encoding="utf-8" ?><D:propertyupdate xmlns:D="DAV:" xmlns:Z="urn:schemas-microsoft-com:"><D:set><D:prop><Z:Win32CreationTime>Wed, 04 Nov 2020 13:25:51 GMT</Z:Win32CreationTime><Z:Win32LastAccessTime>Sat, 05 Dec 2020 21:16:12 GMT</Z:Win32LastAccessTime><Z:Win32LastModifiedTime>Wed, 04 Nov 2020 13:25:51 GMT</Z:Win32LastModifiedTime><Z:Win32FileAttributes>00000000</Z:Win32FileAttributes></D:prop></D:set></D:propertyupdate>`
-		req, err := http.NewRequest("PROPPATCH", fmt.Sprintf("http://%v/%v/%v", webDavServerAddr, user.Username, testFileName), bytes.NewReader([]byte(propatchBody)))
+		req, err := http.NewRequest("PROPPATCH", fmt.Sprintf("http://%v/%v", webDavServerAddr, testFileName), bytes.NewReader([]byte(propatchBody)))
 		assert.NoError(t, err)
 		req.SetBasicAuth(u.Username, u.Password)
 		resp, err := httpClient.Do(req)
@@ -554,68 +553,6 @@ func TestDefender(t *testing.T) {
 	assert.NoError(t, err)
 }
 
-func TestLoginInvalidURL(t *testing.T) {
-	u := getTestUser()
-	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
-	assert.NoError(t, err)
-	u1 := getTestUser()
-	u1.Username = user.Username + "1"
-	user1, _, err := httpdtest.AddUser(u1, http.StatusCreated)
-	assert.NoError(t, err)
-	rootPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, user.Username+"1")
-	client := gowebdav.NewClient(rootPath, user.Username, defaultPassword)
-	client.SetTimeout(5 * time.Second)
-	assert.Error(t, checkBasicFunc(client))
-	_, err = httpdtest.RemoveUser(user, http.StatusOK)
-	assert.NoError(t, err)
-	_, err = httpdtest.RemoveUser(user1, http.StatusOK)
-	assert.NoError(t, err)
-}
-
-func TestRootRedirect(t *testing.T) {
-	errRedirect := errors.New("redirect error")
-	u := getTestUser()
-	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
-	assert.NoError(t, err)
-	client := getWebDavClient(user)
-	assert.NoError(t, checkBasicFunc(client))
-	rootPath := fmt.Sprintf("http://%v/", webDavServerAddr)
-	httpClient := httpclient.GetHTTPClient()
-	httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
-		return errRedirect
-	}
-	req, err := http.NewRequest(http.MethodOptions, rootPath, nil)
-	assert.NoError(t, err)
-	req.SetBasicAuth(u.Username, u.Password)
-	resp, err := httpClient.Do(req)
-	if assert.Error(t, err) {
-		assert.Contains(t, err.Error(), errRedirect.Error())
-	}
-	err = resp.Body.Close()
-	assert.NoError(t, err)
-	req, err = http.NewRequest(http.MethodGet, rootPath, nil)
-	assert.NoError(t, err)
-	req.SetBasicAuth(u.Username, u.Password)
-	resp, err = httpClient.Do(req)
-	if assert.Error(t, err) {
-		assert.Contains(t, err.Error(), errRedirect.Error())
-	}
-	err = resp.Body.Close()
-	assert.NoError(t, err)
-	req, err = http.NewRequest("PROPFIND", rootPath, nil)
-	assert.NoError(t, err)
-	req.SetBasicAuth(u.Username, u.Password)
-	resp, err = httpClient.Do(req)
-	if assert.Error(t, err) {
-		assert.Contains(t, err.Error(), errRedirect.Error())
-	}
-	err = resp.Body.Close()
-	assert.NoError(t, err)
-
-	_, err = httpdtest.RemoveUser(user, http.StatusOK)
-	assert.NoError(t, err)
-}
-
 func TestLoginExternalAuth(t *testing.T) {
 	if runtime.GOOS == osWindows {
 		t.Skip("this test is not available on Windows")
@@ -1275,7 +1212,7 @@ func TestBytesRangeRequests(t *testing.T) {
 		client := getWebDavClient(user)
 		err = uploadFile(testFilePath, testFileName, int64(len(fileContent)), client)
 		assert.NoError(t, err)
-		remotePath := fmt.Sprintf("http://%v/%v/%v", webDavServerAddr, user.Username, testFileName)
+		remotePath := fmt.Sprintf("http://%v/%v", webDavServerAddr, testFileName)
 		req, err := http.NewRequest(http.MethodGet, remotePath, nil)
 		if assert.NoError(t, err) {
 			httpClient := httpclient.GetHTTPClient()
@@ -1318,7 +1255,7 @@ func TestHEAD(t *testing.T) {
 	u := getTestUser()
 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 	assert.NoError(t, err)
-	rootPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, user.Username)
+	rootPath := fmt.Sprintf("http://%v", webDavServerAddr)
 	httpClient := httpclient.GetHTTPClient()
 	req, err := http.NewRequest(http.MethodHead, rootPath, nil)
 	if assert.NoError(t, err) {
@@ -1343,7 +1280,7 @@ func TestGETAsPROPFIND(t *testing.T) {
 	u.Permissions[subDir1] = []string{dataprovider.PermUpload, dataprovider.PermCreateDirs}
 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 	assert.NoError(t, err)
-	rootPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, user.Username)
+	rootPath := fmt.Sprintf("http://%v/", webDavServerAddr)
 	httpClient := httpclient.GetHTTPClient()
 	req, err := http.NewRequest(http.MethodGet, rootPath, nil)
 	if assert.NoError(t, err) {
@@ -1357,7 +1294,7 @@ func TestGETAsPROPFIND(t *testing.T) {
 	client := getWebDavClient(user)
 	err = client.MkdirAll(path.Join(subDir1, "sub", "sub1"), os.ModePerm)
 	assert.NoError(t, err)
-	subPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, path.Join(user.Username, subDir1))
+	subPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, subDir1)
 	req, err = http.NewRequest(http.MethodGet, subPath, nil)
 	if assert.NoError(t, err) {
 		req.SetBasicAuth(u.Username, u.Password)
@@ -1370,7 +1307,7 @@ func TestGETAsPROPFIND(t *testing.T) {
 		}
 	}
 	// we cannot stat the sub at all
-	subPath1 := fmt.Sprintf("http://%v/%v", webDavServerAddr, path.Join(user.Username, subDir1, "sub"))
+	subPath1 := fmt.Sprintf("http://%v/%v", webDavServerAddr, path.Join(subDir1, "sub"))
 	req, err = http.NewRequest(http.MethodGet, subPath1, nil)
 	if assert.NoError(t, err) {
 		req.SetBasicAuth(u.Username, u.Password)
@@ -1622,7 +1559,7 @@ func downloadFile(remoteSourcePath string, localDestPath string, expectedSize in
 }
 
 func getWebDavClient(user dataprovider.User) *gowebdav.Client {
-	rootPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, user.Username)
+	rootPath := fmt.Sprintf("http://%v/", webDavServerAddr)
 	pwd := defaultPassword
 	if len(user.Password) > 0 {
 		pwd = user.Password