diff --git a/client.go b/client.go index bc22091..4e04558 100644 --- a/client.go +++ b/client.go @@ -28,6 +28,7 @@ import ( "io/ioutil" "log" "net/http" + "net/url" "strings" "time" @@ -118,7 +119,7 @@ func (c *challenge) authorize(method, uri string) (string, error) { sl = append(sl, fmt.Sprintf("nc=%08x", c.NonceCount)) sl = append(sl, fmt.Sprintf(`cnonce="%s"`, c.Cnonce)) } - return fmt.Sprintf("Digest %s", strings.Join(sl, ", ")), nil + return fmt.Sprintf("Digest %s", strings.Join(sl, ",")), nil } // origin https://code.google.com/p/mlab-ns2/source/browse/gae/ns/digest/digest.go#90 @@ -161,7 +162,8 @@ func (c *challenge) parseChallenge(input string) error { // Client is a thin wrapper around http.Client. type Client struct { http.Client - target, username, password string + target, targetPath string + username, password string useDigest, Debug, OptimizeEnum bool challenge *challenge } @@ -173,12 +175,17 @@ type Client struct { // username or password are empty, we will not try to authenticate. // If useDigest is true, we will try to use digest auth instead of // basic auth. -func NewClient(target, username, password string, useDigest bool) *Client { +func NewClient(target, username, password string, useDigest bool) (*Client, error) { + u, err := url.Parse(target) + if err != nil { + return nil, fmt.Errorf("failed to parse target as url %v", err) + } res := &Client{ - target: target, - username: username, - password: password, - useDigest: useDigest, + target: target, + targetPath: u.Path, + username: username, + password: password, + useDigest: useDigest, } res.Timeout = 10 * time.Second res.Transport = &http.Transport{ @@ -188,16 +195,16 @@ func NewClient(target, username, password string, useDigest bool) *Client { res.challenge = &challenge{Username: res.username, Password: res.password} resp, err := res.PostForm(res.target, nil) if err != nil { - log.Fatalf("Unable to perform digest auth with %s: %v", res.target, err) + return nil, fmt.Errorf("Unable to perform digest auth with %s: %v", res.target, err) } if resp.StatusCode != 401 { - log.Fatalf("No digest auth at %s", res.target) + return nil, fmt.Errorf("No digest auth at %s", res.target) } if err := res.challenge.parseChallenge(resp.Header.Get("WWW-Authenticate")); err != nil { - log.Fatalf("Failed to parse auth header %v", err) + return nil, fmt.Errorf("Failed to parse auth header %v", err) } } - return res + return res, nil } // Endpoint returns the endpoint that the Client will try to ocmmunicate with. @@ -214,7 +221,7 @@ func (c *Client) Post(msg *soap.Message) (response *soap.Message, err error) { } if c.username != "" && c.password != "" { if c.useDigest { - auth, err := c.challenge.authorize("POST", c.target) + auth, err := c.challenge.authorize("POST", c.targetPath) if err != nil { return nil, fmt.Errorf("Failed digest auth %v", err) } @@ -232,11 +239,13 @@ func (c *Client) Post(msg *soap.Message) (response *soap.Message, err error) { return nil, err } if c.useDigest && res.StatusCode == 401 { - log.Printf("Digest reauthorizing") + if c.Debug { + log.Printf("Digest reauthorizing") + } if err := c.challenge.parseChallenge(res.Header.Get("WWW-Authenticate")); err != nil { return nil, err } - auth, err := c.challenge.authorize("POST", c.target) + auth, err := c.challenge.authorize("POST", c.targetPath) if err != nil { return nil, fmt.Errorf("Failed digest auth %v", err) } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ecfc22f --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module github.com/VictorLowther/wsman + +go 1.16 + +require ( + github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230 + github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 + github.com/satori/go.uuid v1.2.0 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..58aadfd --- /dev/null +++ b/go.sum @@ -0,0 +1,13 @@ +github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230 h1:t95Grn2mOPfb3+kPDWsNnj4dlNcxnvuR72IjY8eYjfQ= +github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230/go.mod h1:t2EzW1qybnPDQ3LR/GgeF0GOzHUXT5IVMLP2gkW1cmc= +github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 h1:a0MBqYm44o0NcthLKCljZHe1mxlN6oahCQHHThnSwB4= +github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22/go.mod h1:/B7V22rcz4860iDqstGvia/2+IYWXf3/JdQCVd/1D2A= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/wscli/main.go b/wscli/main.go index 30dbf0b..0b241a7 100644 --- a/wscli/main.go +++ b/wscli/main.go @@ -107,7 +107,11 @@ func main() { fmt.Printf("%v", flag.Args()) os.Exit(argError) } - client := wsman.NewClient(Endpoint, Username, Password, useDigest) + client, err := wsman.NewClient(Endpoint, Username, Password, useDigest) + if err != nil { + log.Println(err.Error()) + os.Exit(argError) + } client.Debug = debug client.OptimizeEnum = optimizeEnum client.Timeout = (time.Duration(timeout) * time.Second)