-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgo_api_client.go
156 lines (145 loc) · 4.48 KB
/
go_api_client.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package cephapi
import (
"context"
"crypto/tls"
"net/http"
"net/url"
"strings"
"time"
"golang.org/x/oauth2"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/credentials/oauth"
"google.golang.org/grpc/metadata"
)
const defaultOAuthClientID = "ceph-api"
const defaultUrl = "localhost:9969"
type ClientConfig struct {
// GrpcUrl - Default value: "localhost:9969"
GrpcUrl string
// HttpUrl - Default value: "localhost:9969"
HttpUrl string
// OAuthClientID - vault oauth2 client id. Default value: "vault"
OAuthClientID string
// TLSSkipVerify set true if vault using self-issued certificates.
TLSSkipVerify bool
Secure bool
Login string
Password string
}
type Client struct {
httpURL string
oauthClientID string
httpClient *http.Client
ts oauth2.TokenSource
grpcConn *grpc.ClientConn
}
func (c *Client) Conn() *grpc.ClientConn {
return c.grpcConn
}
func (c *Client) Close() error {
err := c.grpcConn.Close()
if err != nil {
return err
}
tok, err := c.ts.Token()
if err != nil {
return err
}
_, err = c.httpClient.PostForm(c.httpURL+"/v1/auth/revoke", url.Values{
"client_id": []string{c.oauthClientID},
"token": []string{tok.RefreshToken},
"token_type_hint": []string{"refresh_token"},
})
return err
}
// New returns authenticated vault client. Revokes all tokens on ctx cancel or on Client.Close() method.
func New(ctx context.Context, conf ClientConfig) (*Client, error) {
c := &Client{
httpURL: defaultUrl,
oauthClientID: defaultOAuthClientID,
}
if conf.HttpUrl != "" {
c.httpURL = conf.HttpUrl
}
if conf.OAuthClientID != "" {
c.oauthClientID = conf.OAuthClientID
}
grpcUrl := c.httpURL
if conf.GrpcUrl != "" {
grpcUrl = conf.GrpcUrl
}
if strings.HasPrefix(grpcUrl, "http") {
grpcUrl = strings.TrimPrefix(grpcUrl, "https://")
grpcUrl = strings.TrimPrefix(grpcUrl, "http://")
}
if !strings.HasPrefix(c.httpURL, "http") {
if conf.Secure {
c.httpURL = "https://" + c.httpURL
} else {
c.httpURL = "http://" + c.httpURL
}
}
ac := oauth2.Config{
ClientID: c.oauthClientID,
Endpoint: oauth2.Endpoint{
TokenURL: c.httpURL + "/api/oauth/token",
},
}
c.httpClient = http.DefaultClient
if conf.Secure && conf.TLSSkipVerify {
customTransport := http.DefaultTransport.(*http.Transport)
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint: gosec
c.httpClient = &http.Client{Transport: customTransport}
}
oauthCtx := context.WithValue(ctx, oauth2.HTTPClient, c.httpClient)
token, err := ac.PasswordCredentialsToken(oauthCtx, conf.Login, conf.Password)
if err != nil {
return nil, err
}
c.ts = ac.TokenSource(ctx, token)
if !conf.Secure {
c.grpcConn, err = grpc.DialContext(ctx, grpcUrl,
grpc.WithTransportCredentials(insecure.NewCredentials()), //nolint: gosec
grpc.WithConnectParams(grpc.ConnectParams{MinConnectTimeout: time.Second, Backoff: backoff.DefaultConfig}),
grpc.WithBlock(),
grpc.WithChainUnaryInterceptor(func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
t, err := ac.PasswordCredentialsToken(oauthCtx, conf.Login, conf.Password)
if err != nil {
return err
}
md := metadata.Pairs(
"Authorization", "Bearer "+t.AccessToken,
)
return invoker(metadata.NewOutgoingContext(ctx, md), method, req, reply, cc, opts...)
}),
grpc.WithChainStreamInterceptor(func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
t, err := ac.PasswordCredentialsToken(oauthCtx, conf.Login, conf.Password)
if err != nil {
return nil, err
}
md := metadata.Pairs(
"Authorization", "Bearer "+t.AccessToken,
)
return streamer(metadata.NewOutgoingContext(ctx, md), desc, cc, method, opts...)
}),
)
} else {
c.grpcConn, err = grpc.DialContext(ctx, grpcUrl,
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: conf.TLSSkipVerify})), //nolint: gosec
grpc.WithConnectParams(grpc.ConnectParams{MinConnectTimeout: time.Second, Backoff: backoff.DefaultConfig}),
grpc.WithBlock(),
grpc.WithPerRPCCredentials(&oauth.TokenSource{TokenSource: c.ts}),
)
}
if err != nil {
return nil, err
}
go func() {
<-oauthCtx.Done()
_ = c.Close()
}()
return c, nil
}