/
auth.go
141 lines (119 loc) · 3.88 KB
/
auth.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
129
130
131
132
133
134
135
136
137
138
139
140
141
package sitewise
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"math/rand"
"net/http"
"net/url"
"path"
"strconv"
"time"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/iot-sitewise-datasource/pkg/models"
)
type EdgeAuthenticator struct {
Settings models.AWSSiteWiseDataSourceSetting
}
type AuthRequest struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
AuthMechanism string `json:"authMechanism,omitempty"`
}
func (a *EdgeAuthenticator) Authenticate() (models.AuthInfo, error) {
reqBodyJson, err := json.Marshal(
&AuthRequest{
Username: a.Settings.EdgeAuthUser,
Password: a.Settings.EdgeAuthPass,
AuthMechanism: a.Settings.EdgeAuthMode,
})
if err != nil {
return models.AuthInfo{}, err
}
pool, _ := x509.SystemCertPool()
if pool == nil {
pool = x509.NewCertPool()
}
if a.Settings.Cert == "" {
return models.AuthInfo{}, fmt.Errorf("certificate cannot be null")
}
block, _ := pem.Decode([]byte(a.Settings.Cert))
if block == nil || block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
return models.AuthInfo{}, fmt.Errorf("decode certificate failed: %s", a.Settings.Cert)
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return models.AuthInfo{}, err
}
pool.AddCert(cert)
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true, //Not actually skipping, check the cert in VerifyPeerCertificate
RootCAs: pool,
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
// If this is the first handshake on a connection, process and
// (optionally) verify the server's certificates.
certs := make([]*x509.Certificate, len(rawCerts))
for i, asn1Data := range rawCerts {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
return fmt.Errorf("tls: failed to parse certificate from server: " + err.Error())
}
certs[i] = cert
}
// see: https://github.com/golang/go/issues/21971
opts := x509.VerifyOptions{
Roots: pool,
CurrentTime: time.Now(),
DNSName: "", // <- skip hostname verification
Intermediates: x509.NewCertPool(),
}
for i, cert := range certs {
if i == 0 {
continue
}
opts.Intermediates.AddCert(cert)
}
_, err := certs[0].Verify(opts)
return err
},
},
}
client := &http.Client{Transport: tr, Timeout: time.Second * 5}
u, err := url.Parse(a.Settings.AWSDatasourceSettings.Endpoint)
if err != nil {
log.DefaultLogger.Error("error parsing edge endpoint url.", "endpoint url:", a.Settings.AWSDatasourceSettings.Endpoint)
return models.AuthInfo{}, fmt.Errorf("cannot parse edge endpoint url. url: %v", a.Settings.AWSDatasourceSettings.Endpoint)
}
u.Path = path.Join(u.Path, "authenticate")
authEndpoint := u.String()
resp, err := client.Post(authEndpoint, "application/json", bytes.NewBuffer(reqBodyJson))
if err != nil {
return models.AuthInfo{}, err
}
if resp.StatusCode != 200 {
log.DefaultLogger.Error("edge auth response not ok:", "response code:", strconv.Itoa(resp.StatusCode))
return models.AuthInfo{}, fmt.Errorf("request not ok. returned code: %v", resp.StatusCode)
}
log.DefaultLogger.Debug("edge auth response ok.")
authInfo := models.AuthInfo{}
err = json.NewDecoder(resp.Body).Decode(&authInfo)
return authInfo, err
}
type DummyAuthenticator struct {
Settings models.AWSSiteWiseDataSourceSetting
}
func (a *DummyAuthenticator) Authenticate() (models.AuthInfo, error) {
if rand.Float64() > .8 {
return models.AuthInfo{}, fmt.Errorf("dummy auth failed (1/5) chance of that")
}
return models.AuthInfo{
AccessKeyId: a.Settings.AccessKey,
SecretAccessKey: a.Settings.SecretKey,
SessionToken: "",
SessionExpiryTime: time.Now().Add(20 * time.Second),
}, nil
}