Skip to content

Commit

Permalink
Controls redirect via r.Header.Set(XInhibitRedirect, "1")
Browse files Browse the repository at this point in the history
  • Loading branch information
chripo committed Feb 8, 2023
1 parent 96c2ca7 commit e3d49a5
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 8 deletions.
19 changes: 13 additions & 6 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ type negoAuth struct {
}

// nullAuth initializes the whole authentication flow
type nullAuth struct{}
type nullAuth struct {
isFirstRound bool
}

// NewAutoAuth creates an auto Authenticator factory
func NewAutoAuth(login string, secret string) Authorizer {
fmap := make([]authfactory, 0)
az := &authorizer{fmap, sync.Mutex{}, &nullAuth{}}
az := &authorizer{fmap, sync.Mutex{}, &nullAuth{true}}

az.AddAuthenticator("basic", func(rq *http.Request, rs *http.Response, method, path string) (auth Authenticator, err error) {
return &BasicAuth{login, secret}, nil
Expand All @@ -78,7 +80,7 @@ func NewAutoAuth(login string, secret string) Authorizer {
// NewEmptyAuth creates an empty Authenticator factory
func NewEmptyAuth() Authorizer {
fmap := make([]authfactory, 0)
az := &authorizer{fmap, sync.Mutex{}, &nullAuth{}}
az := &authorizer{fmap, sync.Mutex{}, &nullAuth{true}}
return az
}

Expand Down Expand Up @@ -151,7 +153,7 @@ func (a *authorizer) factory(rq *http.Request, rs *http.Response, method, path s
auth = &negoAuth{auths, a.setDefaultAuthenticator}
}
} else {
auth = &nullAuth{}
auth = &nullAuth{false}
}

a.setDefaultAuthenticator(auth)
Expand Down Expand Up @@ -273,12 +275,17 @@ func (n *negoAuth) String() string {

// Authorize the current request
func (n *nullAuth) Authorize(c *http.Client, rq *http.Request, method string, path string) error {
if n.isFirstRound {
rq.Header.Set(XInhibitRedirect, "1")
}
return nil
}

// Verify checks for authentication issues and may trigger a re-authentication
func (n *nullAuth) Verify(rq *http.Request, rs *http.Response, method string, path string) (reauth bool, err error) {
if "" == strings.ToLower(rs.Header.Get("Www-Authenticate")) {
// TODO handle redirects if any
if "" == rs.Header.Get("Www-Authenticate") {
n.isFirstRound = false
return false, nil
}
return true, AlgoChangedErr
Expand All @@ -292,7 +299,7 @@ func (n *nullAuth) Close() error {
// Clone creates a copy of itself
func (n *nullAuth) Clone() Authenticator {
// no copy due to read only access
return n
return &nullAuth{n.isFirstRound}
}

// String toString
Expand Down
51 changes: 50 additions & 1 deletion auth_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package gowebdav

import "testing"
import (
"bytes"
"net/http"
"strings"
"testing"
)

func TestEmptyAuth(t *testing.T) {
auth := NewEmptyAuth()
Expand All @@ -11,3 +16,47 @@ func TestEmptyAuth(t *testing.T) {
t.Fatalf("got nil want error")
}
}

func TestRedirectAuthWIP(t *testing.T) {
hasPassedAuthServer := false
authHandler := func(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if user, passwd, ok := r.BasicAuth(); ok {
if user == "user" && passwd == "password" {
hasPassedAuthServer = true
w.WriteHeader(200)
return
}
}
w.Header().Set("Www-Authenticate", `Basic realm="x"`)
w.WriteHeader(401)
}
}

psrv, _, _ := newAuthSrv(t, authHandler)
defer psrv.Close()

dataHandler := func(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
hasAuth := strings.Contains(r.Header.Get("Authorization"), "Basic dXNlcjpwYXNzd29yZA==")

if hasPassedAuthServer && hasAuth {
h.ServeHTTP(w, r)
return
}
w.Header().Set("Www-Authenticate", `Basic realm="x"`)
http.Redirect(w, r, psrv.URL+"/", 302)
}
}

srv, _, _ := newAuthSrv(t, dataHandler)
defer srv.Close()
cli := NewClient(srv.URL, "user", "password")
data, err := cli.Read("/hello.txt")
if err != nil {
t.Logf("WIP got error=%v; want nil", err)
}
if bytes.Compare(data, []byte("hello gowebdav\n")) != 0 {
t.Logf("WIP got data=%v; want=hello gowebdav", data)
}
}
16 changes: 15 additions & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gowebdav
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"io"
"net/http"
Expand All @@ -13,6 +14,8 @@ import (
"time"
)

const XInhibitRedirect = "X-Gowebdav-Inhibit-Redirect"

// Client defines our structure
type Client struct {
root string
Expand All @@ -29,7 +32,18 @@ func NewClient(uri, user, pw string) *Client {

// NewAuthClient creates a new client instance with a custom Authorizer
func NewAuthClient(uri string, auth Authorizer) *Client {
return &Client{FixSlash(uri), make(http.Header), nil, &http.Client{}, auth}
c := &http.Client{
CheckRedirect: func(rq *http.Request, via []*http.Request) error {
if len(via) >= 10 {
return errors.New("stopped after 10 redirects")
}
if via[0].Header.Get(XInhibitRedirect) != "" {
return http.ErrUseLastResponse
}
return nil
},
}
return &Client{FixSlash(uri), make(http.Header), nil, c, auth}
}

// SetHeader lets us set arbitrary headers for a given client
Expand Down

0 comments on commit e3d49a5

Please sign in to comment.