Skip to content

Commit 0f7f116

Browse files
Updated to use Go Client, added CA and Template parameters to issue path
1 parent 1414e43 commit 0f7f116

12 files changed

+639
-634
lines changed

backend.go

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,14 @@
77
* and limitations under the License.
88
*/
99

10-
package keyfactor
10+
package kfbackend
1111

1212
import (
1313
"context"
14-
b64 "encoding/base64"
1514
"encoding/json"
1615
"errors"
1716
"fmt"
1817
"io"
19-
"io/ioutil"
2018
"net/http"
2119
"strings"
2220
"sync"
@@ -42,7 +40,7 @@ func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend,
4240
// // Store certificates by serial number
4341
type keyfactorBackend struct {
4442
*framework.Backend
45-
lock sync.RWMutex
43+
configLock sync.RWMutex
4644
cachedConfig *keyfactorConfig
4745
client *keyfactorClient
4846
}
@@ -78,9 +76,11 @@ func backend() *keyfactorBackend {
7876
// reset clears any client configuration for a new
7977
// backend to be configured
8078
func (b *keyfactorBackend) reset() {
81-
b.lock.Lock()
82-
defer b.lock.Unlock()
79+
b.configLock.RLock()
80+
defer b.configLock.RUnlock()
81+
b.cachedConfig = nil
8382
b.client = nil
83+
8484
}
8585

8686
// invalidate clears an existing client configuration in
@@ -94,63 +94,73 @@ func (b *keyfactorBackend) invalidate(ctx context.Context, key string) {
9494
// getClient locks the backend as it configures and creates a
9595
// a new client for the target API
9696
func (b *keyfactorBackend) getClient(ctx context.Context, s logical.Storage) (*keyfactorClient, error) {
97-
b.lock.RLock()
98-
unlockFunc := b.lock.RUnlock
99-
defer func() { unlockFunc() }()
97+
b.configLock.RLock()
98+
defer b.configLock.RUnlock()
10099

101100
if b.client != nil {
102101
return b.client, nil
103102
}
104103

105-
b.lock.RUnlock()
106-
b.lock.Lock()
107-
unlockFunc = b.lock.Unlock
104+
// get configuration
105+
config, err := b.fetchConfig(ctx, s)
106+
if err != nil {
107+
return nil, err
108+
}
109+
if config == nil {
110+
return nil, errors.New("configuration is empty")
111+
}
108112

109-
return nil, fmt.Errorf("need to return client")
113+
b.client, err = newClient(config)
114+
if err != nil {
115+
return nil, err
116+
}
117+
return b.client, nil
110118
}
111119

112120
// Handle interface with Keyfactor API to enroll a certificate with given content
113121
func (b *keyfactorBackend) submitCSR(ctx context.Context, req *logical.Request, csr string, caName string, templateName string) ([]string, string, error) {
114-
config, err := b.config(ctx, req.Storage)
122+
config, err := b.fetchConfig(ctx, req.Storage)
115123
if err != nil {
116124
return nil, "", err
117125
}
118126
if config == nil {
119127
return nil, "", errors.New("configuration is empty")
120128
}
121129

122-
ca := config.CertAuthority
123-
template := config.CertTemplate
124-
125-
creds := config.Username + ":" + config.Password
126-
encCreds := b64.StdEncoding.EncodeToString([]byte(creds))
127-
128130
location, _ := time.LoadLocation("UTC")
129131
t := time.Now().In(location)
130132
time := t.Format("2006-01-02T15:04:05")
131133

132-
// This is only needed when running as a vault extension
134+
// get client
135+
client, err := b.getClient(ctx, req.Storage)
136+
if err != nil {
137+
return nil, "", fmt.Errorf("error getting client: %w", err)
138+
}
139+
133140
b.Logger().Debug("Closing idle connections")
134-
http.DefaultClient.CloseIdleConnections()
141+
b.client.httpClient.CloseIdleConnections()
142+
143+
// build request parameter structure
135144

136-
// Build request
137145
url := config.KeyfactorUrl + "/KeyfactorAPI/Enrollment/CSR"
138146
b.Logger().Debug("url: " + url)
139-
bodyContent := "{\"CSR\": \"" + csr + "\",\"CertificateAuthority\":\"" + ca + "\",\"IncludeChain\": true, \"Metadata\": {}, \"Timestamp\": \"" + time + "\",\"Template\": \"" + template + "\",\"SANs\": {}}"
147+
bodyContent := "{\"CSR\": \"" + csr + "\",\"CertificateAuthority\":\"" + caName + "\",\"IncludeChain\": true, \"Metadata\": {}, \"Timestamp\": \"" + time + "\",\"Template\": \"" + templateName + "\",\"SANs\": {}}"
140148
payload := strings.NewReader(bodyContent)
141149
b.Logger().Debug("body: " + bodyContent)
142150
httpReq, err := http.NewRequest("POST", url, payload)
151+
143152
if err != nil {
144153
b.Logger().Info("Error forming request: {{err}}", err)
145154
}
155+
146156
httpReq.Header.Add("x-keyfactor-requested-with", "APIClient")
147157
httpReq.Header.Add("content-type", "application/json")
148-
httpReq.Header.Add("authorization", "Basic "+encCreds)
149158
httpReq.Header.Add("x-certificateformat", "PEM")
150159

151160
// Send request and check status
161+
152162
b.Logger().Debug("About to connect to " + config.KeyfactorUrl + "for csr submission")
153-
res, err := http.DefaultClient.Do(httpReq)
163+
res, err := client.httpClient.Do(httpReq)
154164
if err != nil {
155165
b.Logger().Info("CSR Enrollment failed: {{err}}", err.Error())
156166
return nil, "", err
@@ -166,7 +176,7 @@ func (b *keyfactorBackend) submitCSR(ctx context.Context, req *logical.Request,
166176
// Read response and return certificate and key
167177

168178
defer res.Body.Close()
169-
body, err := ioutil.ReadAll(res.Body)
179+
body, err := io.ReadAll(res.Body)
170180
if err != nil {
171181
b.Logger().Error("Error reading response: {{err}}", err)
172182
return nil, "", err

cert_util.go

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* and limitations under the License.
88
*/
99

10-
package keyfactor
10+
package kfbackend
1111

1212
import (
1313
"bytes"
@@ -18,12 +18,11 @@ import (
1818
"crypto/x509/pkix"
1919
"encoding/asn1"
2020
"encoding/base64"
21-
b64 "encoding/base64"
2221
"encoding/json"
2322
"encoding/pem"
2423
"errors"
2524
"fmt"
26-
"io/ioutil"
25+
"io"
2726
"net"
2827
"net/http"
2928
"net/url"
@@ -37,7 +36,7 @@ import (
3736
// fetch the CA info from keyfactor
3837
func fetchCAInfo(ctx context.Context, req *logical.Request, b *keyfactorBackend) (response *logical.Response, retErr error) {
3938
// first we see if we have previously retreived the CA or chain
40-
config, err := b.config(ctx, req.Storage)
39+
config, err := b.fetchConfig(ctx, req.Storage)
4140
if err != nil {
4241
return nil, err
4342
}
@@ -151,12 +150,12 @@ func fetchCaChainInfo(ctx context.Context, req *logical.Request, b *keyfactorBac
151150
}
152151

153152
func getCAId(ctx context.Context, req *logical.Request, b *keyfactorBackend) (string, error) {
154-
config, err := b.config(ctx, req.Storage)
153+
config, err := b.fetchConfig(ctx, req.Storage)
155154
if err != nil {
156155
return "", err
157156
}
158157
if config == nil {
159-
return "", errors.New("unable to load configuration.")
158+
return "", errors.New("unable to load configuration")
160159
}
161160

162161
if config.CertAuthority == "" {
@@ -168,12 +167,16 @@ func getCAId(ctx context.Context, req *logical.Request, b *keyfactorBackend) (st
168167

169168
// This is only needed when running as a vault extension
170169
b.Logger().Debug("Closing idle connections")
171-
http.DefaultClient.CloseIdleConnections()
170+
client, err := b.getClient(ctx, req.Storage)
171+
if err != nil {
172+
b.Logger().Error("unable to create the http client")
173+
}
174+
client.httpClient.CloseIdleConnections()
172175

173176
ca_name = url.QueryEscape(ca_name)
174177

175-
creds := config.Username + ":" + config.Password
176-
encCreds := b64.StdEncoding.EncodeToString([]byte(creds))
178+
//creds := config.Username + ":" + config.Password
179+
//encCreds := b64.StdEncoding.EncodeToString([]byte(creds))
177180

178181
// Build request
179182

@@ -183,21 +186,21 @@ func getCAId(ctx context.Context, req *logical.Request, b *keyfactorBackend) (st
183186
if err != nil {
184187
b.Logger().Info("Error forming request: {{err}}", err)
185188
}
186-
httpReq.Header.Add("x-keyfactor-requested-with", "APIClient")
189+
//httpReq.Header.Add("x-keyfactor-requested-with", "APIClient")
187190
httpReq.Header.Add("x-keyfactor-api-version", "1")
188-
httpReq.Header.Add("authorization", "Basic "+encCreds)
191+
//httpReq.Header.Add("authorization", "Basic "+encCreds)
189192

190193
// Send request and check status
191194
b.Logger().Debug("About to connect to " + config.KeyfactorUrl + "for ca retrieval")
192-
res, err := http.DefaultClient.Do(httpReq)
195+
res, err := client.httpClient.Do(httpReq)
193196
if err != nil {
194197
b.Logger().Info("failed getting CA: {{err}}", err)
195198
return "", err
196199
}
197200
if res.StatusCode != 200 {
198201
b.Logger().Error("request failed: server returned" + fmt.Sprint(res.StatusCode))
199202
defer res.Body.Close()
200-
body, err := ioutil.ReadAll(res.Body)
203+
body, err := io.ReadAll(res.Body)
201204
if err != nil {
202205
b.Logger().Info("Error reading response: {{err}}", err)
203206
return "", err
@@ -246,22 +249,25 @@ func (b *keyfactorBackend) generateCSR(cn string, ip_sans []string, dns_sans []s
246249
}
247250

248251
func fetchCertFromKeyfactor(ctx context.Context, req *logical.Request, b *keyfactorBackend, kfCertId string, includeChain bool) (string, error) {
249-
config, err := b.config(ctx, req.Storage)
252+
config, err := b.fetchConfig(ctx, req.Storage)
250253
if err != nil {
251254
return "", err
252255
}
253256
if config == nil {
254257
return "", errors.New("unable to load configuration")
255258
}
256-
creds := config.Username + ":" + config.Password
257-
encCreds := b64.StdEncoding.EncodeToString([]byte(creds))
258-
//location, _ := time.LoadLocation("UTC")
259-
//t := time.Now().In(location)
260-
//time := t.Format("2006-01-02T15:04:05")
259+
// creds := config.Username + ":" + config.Password
260+
// encCreds := b64.StdEncoding.EncodeToString([]byte(creds))
261261

262+
// get the client
263+
client, err := b.getClient(ctx, req.Storage)
264+
if err != nil {
265+
b.Logger().Error("unable to create the http client")
266+
}
262267
// This is only needed when running as a vault extension
263268
b.Logger().Debug("Closing idle connections")
264-
http.DefaultClient.CloseIdleConnections()
269+
client.httpClient.CloseIdleConnections()
270+
265271
include := "false"
266272
if includeChain {
267273
include = "true"
@@ -279,12 +285,11 @@ func fetchCertFromKeyfactor(ctx context.Context, req *logical.Request, b *keyfac
279285
}
280286
httpReq.Header.Add("x-keyfactor-requested-with", "APIClient")
281287
httpReq.Header.Add("content-type", "application/json")
282-
httpReq.Header.Add("authorization", "Basic "+encCreds)
283288
httpReq.Header.Add("x-certificateformat", "PEM")
284289

285290
// Send request and check status
286291
b.Logger().Debug("About to connect to " + config.KeyfactorUrl + "for cert retrieval")
287-
res, err := http.DefaultClient.Do(httpReq)
292+
res, err := client.httpClient.Do(httpReq)
288293
if err != nil {
289294
b.Logger().Info("failed getting cert: {{err}}", err)
290295
return "", err
@@ -298,7 +303,7 @@ func fetchCertFromKeyfactor(ctx context.Context, req *logical.Request, b *keyfac
298303
// Read response and return certificate and key
299304
defer res.Body.Close()
300305

301-
body, err := ioutil.ReadAll(res.Body)
306+
body, err := io.ReadAll(res.Body)
302307
if err != nil {
303308
b.Logger().Info("Error reading response: {{err}}", err)
304309
return "", err
@@ -339,7 +344,7 @@ func fetchCertBySerial(ctx context.Context, req *logical.Request, prefix, serial
339344
return nil, errutil.InternalError{Err: fmt.Sprintf("error fetching certificate %s: %s", serial, err)}
340345
}
341346
if certEntry != nil {
342-
if certEntry.Value == nil || len(certEntry.Value) == 0 {
347+
if len(certEntry.Value) == 0 {
343348
return nil, errutil.InternalError{Err: fmt.Sprintf("returned certificate bytes for serial %s were empty", serial)}
344349
}
345350
return certEntry, nil
@@ -358,7 +363,7 @@ func fetchCertBySerial(ctx context.Context, req *logical.Request, prefix, serial
358363
if certEntry == nil {
359364
return nil, nil
360365
}
361-
if certEntry.Value == nil || len(certEntry.Value) == 0 {
366+
if len(certEntry.Value) == 0 {
362367
return nil, errutil.InternalError{Err: fmt.Sprintf("returned certificate bytes for serial %s were empty", serial)}
363368
}
364369

0 commit comments

Comments
 (0)