77 * and limitations under the License.
88 */
99
10- package keyfactor
10+ package kfbackend
1111
1212import (
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"
@@ -27,7 +25,9 @@ import (
2725 "github.com/hashicorp/vault/sdk/logical"
2826)
2927
30- //var config map[string]string
28+ const (
29+ operationPrefixKeyfactor string = "keyfactor"
30+ )
3131
3232// Factory configures and returns backend
3333func Factory (ctx context.Context , conf * logical.BackendConfig ) (logical.Backend , error ) {
@@ -42,7 +42,7 @@ func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend,
4242// // Store certificates by serial number
4343type keyfactorBackend struct {
4444 * framework.Backend
45- lock sync.RWMutex
45+ configLock sync.RWMutex
4646 cachedConfig * keyfactorConfig
4747 client * keyfactorClient
4848}
@@ -68,19 +68,31 @@ func backend() *keyfactorBackend {
6868 pathCA (& b ),
6969 pathCerts (& b ),
7070 ),
71- Secrets : []* framework.Secret {},
72- BackendType : logical .TypeLogical ,
73- Invalidate : b .invalidate ,
71+ Secrets : []* framework.Secret {},
72+ BackendType : logical .TypeLogical ,
73+ Invalidate : b .invalidate ,
74+ InitializeFunc : b .Initialize ,
7475 }
7576 return & b
7677}
7778
7879// reset clears any client configuration for a new
7980// backend to be configured
8081func (b * keyfactorBackend ) reset () {
81- b .lock .Lock ()
82- defer b .lock .Unlock ()
82+ b .configLock .RLock ()
83+ defer b .configLock .RUnlock ()
84+ b .cachedConfig = nil
8385 b .client = nil
86+
87+ }
88+
89+ func (b * keyfactorBackend ) Initialize (ctx context.Context , req * logical.InitializationRequest ) error {
90+ b .configLock .RLock ()
91+ defer b .configLock .RUnlock ()
92+ if req == nil {
93+ return fmt .Errorf ("initialization request is nil" )
94+ }
95+ return nil
8496}
8597
8698// invalidate clears an existing client configuration in
@@ -94,63 +106,73 @@ func (b *keyfactorBackend) invalidate(ctx context.Context, key string) {
94106// getClient locks the backend as it configures and creates a
95107// a new client for the target API
96108func (b * keyfactorBackend ) getClient (ctx context.Context , s logical.Storage ) (* keyfactorClient , error ) {
97- b .lock .RLock ()
98- unlockFunc := b .lock .RUnlock
99- defer func () { unlockFunc () }()
109+ b .configLock .RLock ()
110+ defer b .configLock .RUnlock ()
100111
101112 if b .client != nil {
102113 return b .client , nil
103114 }
104115
105- b .lock .RUnlock ()
106- b .lock .Lock ()
107- unlockFunc = b .lock .Unlock
116+ // get configuration
117+ config , err := b .fetchConfig (ctx , s )
118+ if err != nil {
119+ return nil , err
120+ }
121+ if config == nil {
122+ return nil , errors .New ("configuration is empty" )
123+ }
108124
109- return nil , fmt .Errorf ("need to return client" )
125+ b .client , err = newClient (config , b )
126+ if err != nil {
127+ return nil , err
128+ }
129+ return b .client , nil
110130}
111131
112132// Handle interface with Keyfactor API to enroll a certificate with given content
113- 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 )
133+ func (b * keyfactorBackend ) submitCSR (ctx context.Context , req * logical.Request , csr string , caName string , templateName string , metaDataJson string ) ([]string , string , error ) {
134+ config , err := b .fetchConfig (ctx , req .Storage )
115135 if err != nil {
116136 return nil , "" , err
117137 }
118138 if config == nil {
119139 return nil , "" , errors .New ("configuration is empty" )
120140 }
121141
122- ca := config .CertAuthority
123- template := config .CertTemplate
124-
125- creds := config .Username + ":" + config .Password
126- encCreds := b64 .StdEncoding .EncodeToString ([]byte (creds ))
127-
128142 location , _ := time .LoadLocation ("UTC" )
129143 t := time .Now ().In (location )
130144 time := t .Format ("2006-01-02T15:04:05" )
131145
132- // This is only needed when running as a vault extension
146+ // get client
147+ client , err := b .getClient (ctx , req .Storage )
148+ if err != nil {
149+ return nil , "" , fmt .Errorf ("error getting client: %w" , err )
150+ }
151+
133152 b .Logger ().Debug ("Closing idle connections" )
134- http .DefaultClient .CloseIdleConnections ()
153+ client .httpClient .CloseIdleConnections ()
154+
155+ // build request parameter structure
135156
136- // Build request
137- url := config .KeyfactorUrl + "/KeyfactorAPI/Enrollment/CSR"
157+ url := config .KeyfactorUrl + "/" + config .CommandAPIPath + "/Enrollment/CSR"
138158 b .Logger ().Debug ("url: " + url )
139- bodyContent := "{\" CSR\" : \" " + csr + "\" ,\" CertificateAuthority\" :\" " + ca + "\" ,\" IncludeChain\" : true, \" Metadata\" : {} , \" Timestamp\" : \" " + time + "\" ,\" Template\" : \" " + template + "\" ,\" SANs\" : {}}"
159+ bodyContent := "{\" CSR\" : \" " + csr + "\" ,\" CertificateAuthority\" :\" " + caName + "\" ,\" IncludeChain\" : true, \" Metadata\" : " + metaDataJson + " , \" Timestamp\" : \" " + time + "\" ,\" Template\" : \" " + templateName + "\" ,\" SANs\" : {}}"
140160 payload := strings .NewReader (bodyContent )
141161 b .Logger ().Debug ("body: " + bodyContent )
142162 httpReq , err := http .NewRequest ("POST" , url , payload )
163+
143164 if err != nil {
144165 b .Logger ().Info ("Error forming request: {{err}}" , err )
145166 }
167+
146168 httpReq .Header .Add ("x-keyfactor-requested-with" , "APIClient" )
147169 httpReq .Header .Add ("content-type" , "application/json" )
148- httpReq .Header .Add ("authorization" , "Basic " + encCreds )
149170 httpReq .Header .Add ("x-certificateformat" , "PEM" )
150171
151172 // Send request and check status
173+
152174 b .Logger ().Debug ("About to connect to " + config .KeyfactorUrl + "for csr submission" )
153- res , err := http . DefaultClient .Do (httpReq )
175+ res , err := client . httpClient .Do (httpReq )
154176 if err != nil {
155177 b .Logger ().Info ("CSR Enrollment failed: {{err}}" , err .Error ())
156178 return nil , "" , err
@@ -166,7 +188,7 @@ func (b *keyfactorBackend) submitCSR(ctx context.Context, req *logical.Request,
166188 // Read response and return certificate and key
167189
168190 defer res .Body .Close ()
169- body , err := ioutil .ReadAll (res .Body )
191+ body , err := io .ReadAll (res .Body )
170192 if err != nil {
171193 b .Logger ().Error ("Error reading response: {{err}}" , err )
172194 return nil , "" , err
@@ -233,3 +255,15 @@ func (b *keyfactorBackend) submitCSR(ctx context.Context, req *logical.Request,
233255const keyfactorHelp = `
234256The Keyfactor backend is a pki service that issues and manages certificates.
235257`
258+
259+ func (b * keyfactorBackend ) isValidJSON (str string ) bool {
260+ var js json.RawMessage
261+ err := json .Unmarshal ([]byte (str ), & js )
262+ if err != nil {
263+ b .Logger ().Debug (err .Error ())
264+ return false
265+ } else {
266+ b .Logger ().Debug ("the metadata was able to be parsed as valid JSON" )
267+ return true
268+ }
269+ }
0 commit comments