forked from masterzen/winrm
/
auth_win11.go
128 lines (106 loc) · 3.38 KB
/
auth_win11.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package winrm
import (
"crypto/tls"
"fmt"
"io"
"net"
"net/http"
"strings"
"time"
"github.com/siemens-cdc/winrm/soap"
)
// ClientAuthRequestWin11 ClientAuthRequestWin11
type ClientAuthRequestWin11 struct {
transport http.RoundTripper
dial func(network, addr string) (net.Conn, error)
}
// Transport Transport
func (c *ClientAuthRequestWin11) Transport(endpoint *Endpoint, minVersion uint16, maxVersion uint16, cipherSuites []uint16) error {
cert, err := tls.X509KeyPair(endpoint.Cert, endpoint.Key)
if err != nil {
return err
}
dial := (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial
if c.dial != nil {
dial = c.dial
}
//nolint:gosec
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
Renegotiation: tls.RenegotiateOnceAsClient,
InsecureSkipVerify: endpoint.Insecure,
Certificates: []tls.Certificate{cert},
MaxVersion: maxVersion,
MinVersion: minVersion,
ClientAuth: tls.RequireAndVerifyClientCert,
//0xc02b, 0xc02f, 0xc02c, 0xc030, 0xcca9, 0xcca8, 0xc009, 0xc013, 0xc00a, 0xc014, 0x009c, 0x009d, 0x002f, 0x0035, 0xc012, 0x000a, 0x1301, 0x1302, 0x1303
CipherSuites: cipherSuites,
},
Dial: dial,
ResponseHeaderTimeout: endpoint.Timeout,
}
if endpoint.CACert != nil && len(endpoint.CACert) > 0 {
certPool, err := readCACerts(endpoint.CACert)
if err != nil {
return err
}
transport.TLSClientConfig.RootCAs = certPool
}
c.transport = transport
return nil
}
// parseWin11 func reads the response body and return it as a string
func parseWin11(response *http.Response) (string, error) {
// if we received the content we expected
if strings.Contains(response.Header.Get("Content-Type"), "application/soap+xml") {
body, err := io.ReadAll(response.Body)
defer func() {
// defer can modify the returned value before
// it is actually passed to the calling statement
if errClose := response.Body.Close(); errClose != nil && err == nil {
err = errClose
}
}()
if err != nil {
return "", fmt.Errorf("error while reading request body %w", err)
}
return string(body), nil
}
return "", fmt.Errorf("invalid content type")
}
// Post Post
func (c ClientAuthRequestWin11) Post(client *Client, request *soap.SoapMessage) (string, error) {
httpClient := &http.Client{Transport: c.transport}
req, err := http.NewRequest("POST", client.url, strings.NewReader(request.String()))
if err != nil {
return "", fmt.Errorf("impossible to create Http request %w", err)
}
req.Header.Set("Content-Type", soapXML+";charset=UTF-8")
req.Header.Set("Authorization", "http://schemas.dmtf.org/wbem/wsman/1/wsman/secprofile/https/mutual")
resp, err := httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("unknown error %w", err)
}
body, err := parseWin11(resp)
if err != nil {
return "", fmt.Errorf("Http response error: %d - %w", resp.StatusCode, err)
}
// if we have different 200 Http status code
// we must replace the error
defer func() {
if resp.StatusCode != 200 {
body, err = "", fmt.Errorf("Http error %d: %s", resp.StatusCode, body)
}
}()
return body, err
}
// NewClientAuthRequestWithDialWin11 NewClientAuthRequestWithDialWin11
func NewClientAuthRequestWithDialWin11(dial func(network, addr string) (net.Conn, error)) *ClientAuthRequestWin11 {
return &ClientAuthRequestWin11{
dial: dial,
}
}