From c642531a1ef5e8391f3588080d85513f1401b542 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 4 Sep 2018 14:04:13 +0100 Subject: [PATCH] webdav: add --webdav-bearer-token-command - fixes #2380 This can be used with oidc-agent to get a bearer token --- backend/webdav/webdav.go | 66 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go index 6517d06fe..23ec0709b 100644 --- a/backend/webdav/webdav.go +++ b/backend/webdav/webdav.go @@ -15,6 +15,7 @@ import ( "io" "net/http" "net/url" + "os/exec" "path" "strings" "time" @@ -80,17 +81,22 @@ func init() { }, { Name: "bearer_token", Help: "Bearer token instead of user/pass (eg a Macaroon)", + }, { + Name: "bearer_token_command", + Help: "Command to run to get a bearer token", + Advanced: true, }}, }) } // Options defines the configuration for this backend type Options struct { - URL string `config:"url"` - Vendor string `config:"vendor"` - User string `config:"user"` - Pass string `config:"pass"` - BearerToken string `config:"bearer_token"` + URL string `config:"url"` + Vendor string `config:"vendor"` + User string `config:"user"` + Pass string `config:"pass"` + BearerToken string `config:"bearer_token"` + BearerTokenCommand string `config:"bearer_token_command"` } // Fs represents a remote webdav @@ -330,7 +336,12 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) { if opt.User != "" || opt.Pass != "" { f.srv.SetUserPass(opt.User, opt.Pass) } else if opt.BearerToken != "" { - f.srv.SetHeader("Authorization", "BEARER "+opt.BearerToken) + f.setBearerToken(opt.BearerToken) + } else if f.opt.BearerTokenCommand != "" { + err = f.fetchAndSetBearerToken() + if err != nil { + return nil, err + } } f.srv.SetErrorHandler(errorHandler) err = f.setQuirks(opt.Vendor) @@ -360,6 +371,49 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) { return f, nil } +// sets the BearerToken up +func (f *Fs) setBearerToken(token string) { + f.opt.BearerToken = token + f.srv.SetHeader("Authorization", "BEARER "+token) +} + +// fetch the bearer token using the command +func (f *Fs) fetchBearerToken(cmd string) (string, error) { + var ( + args = strings.Split(cmd, " ") + stdout bytes.Buffer + stderr bytes.Buffer + c = exec.Command(args[0], args[1:]...) + ) + c.Stdout = &stdout + c.Stderr = &stderr + var ( + err = c.Run() + stdoutString = strings.TrimSpace(stdout.String()) + stderrString = strings.TrimSpace(stderr.String()) + ) + if err != nil { + if stderrString == "" { + stderrString = stdoutString + } + return "", errors.Wrapf(err, "failed to get bearer token using %q: %s", f.opt.BearerTokenCommand, stderrString) + } + return stdoutString, nil +} + +// fetch the bearer token and set it if successful +func (f *Fs) fetchAndSetBearerToken() error { + if f.opt.BearerTokenCommand == "" { + return nil + } + token, err := f.fetchBearerToken(f.opt.BearerTokenCommand) + if err != nil { + return err + } + f.setBearerToken(token) + return nil +} + // setQuirks adjusts the Fs for the vendor passed in func (f *Fs) setQuirks(vendor string) error { switch vendor {