blob: 883e4f635b5d2670455e6d5d0f269b6457b52a8c [file] [log] [blame]
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001
2<!DOCTYPE html>
3<html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6 <style>
7 body {
8 background: black;
9 color: rgb(80, 80, 80);
10 }
11 body, pre, #legend span {
12 font-family: Menlo, monospace;
13 font-weight: bold;
14 }
15 #topbar {
16 background: black;
17 position: fixed;
18 top: 0; left: 0; right: 0;
19 height: 42px;
20 border-bottom: 1px solid rgb(80, 80, 80);
21 }
22 #content {
23 margin-top: 50px;
24 }
25 #nav, #legend {
26 float: left;
27 margin-left: 10px;
28 }
29 #legend {
30 margin-top: 12px;
31 }
32 #nav {
33 margin-top: 10px;
34 }
35 #legend span {
36 margin: 0 5px;
37 }
38 .cov0 { color: rgb(192, 0, 0) }
39.cov1 { color: rgb(128, 128, 128) }
40.cov2 { color: rgb(116, 140, 131) }
41.cov3 { color: rgb(104, 152, 134) }
42.cov4 { color: rgb(92, 164, 137) }
43.cov5 { color: rgb(80, 176, 140) }
44.cov6 { color: rgb(68, 188, 143) }
45.cov7 { color: rgb(56, 200, 146) }
46.cov8 { color: rgb(44, 212, 149) }
47.cov9 { color: rgb(32, 224, 152) }
48.cov10 { color: rgb(20, 236, 155) }
49
50 </style>
51 </head>
52 <body>
53 <div id="topbar">
54 <div id="nav">
55 <select id="files">
56
Kiran Kaminenic660d1b2018-09-20 10:43:28 -070057 <option value="file0">sms/auth/auth.go (79.8%)</option>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -070058
Kiran Kamineni7597c152018-04-19 21:27:01 -070059 <option value="file1">sms/backend/backend.go (80.0%)</option>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -070060
Kiran Kaminenic660d1b2018-09-20 10:43:28 -070061 <option value="file2">sms/backend/vault.go (68.6%)</option>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -070062
Kiran Kamineni7597c152018-04-19 21:27:01 -070063 <option value="file3">sms/config/config.go (78.6%)</option>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -070064
Kiran Kaminenic660d1b2018-09-20 10:43:28 -070065 <option value="file4">sms/handler/handler.go (62.0%)</option>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -070066
Kiran Kaminenic660d1b2018-09-20 10:43:28 -070067 <option value="file5">sms/log/logger.go (78.1%)</option>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -070068
Kiran Kamineni7597c152018-04-19 21:27:01 -070069 <option value="file6">sms/sms.go (77.8%)</option>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -070070
71 </select>
72 </div>
73 <div id="legend">
74 <span>not tracked</span>
75
76 <span class="cov0">no coverage</span>
77 <span class="cov1">low coverage</span>
78 <span class="cov2">*</span>
79 <span class="cov3">*</span>
80 <span class="cov4">*</span>
81 <span class="cov5">*</span>
82 <span class="cov6">*</span>
83 <span class="cov7">*</span>
84 <span class="cov8">*</span>
85 <span class="cov9">*</span>
86 <span class="cov10">high coverage</span>
87
88 </div>
89 </div>
90 <div id="content">
91
92 <pre class="file" id="file0" style="display: none">/*
93 * Copyright 2018 Intel Corporation, Inc
94 *
95 * Licensed under the Apache License, Version 2.0 (the "License");
96 * you may not use this file except in compliance with the License.
97 * You may obtain a copy of the License at
98 *
99 * http://www.apache.org/licenses/LICENSE-2.0
100 *
101 * Unless required by applicable law or agreed to in writing, software
102 * distributed under the License is distributed on an "AS IS" BASIS,
103 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
104 * See the License for the specific language governing permissions and
105 * limitations under the License.
106 */
107
108package auth
109
110import (
111 "bytes"
Kiran Kamineni7597c152018-04-19 21:27:01 -0700112 "crypto"
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700113 "crypto/tls"
114 "crypto/x509"
115 "encoding/base64"
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700116 "encoding/pem"
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700117 "golang.org/x/crypto/openpgp"
118 "golang.org/x/crypto/openpgp/packet"
119 "io/ioutil"
120
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700121 smsconfig "sms/config"
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700122 smslogger "sms/log"
123)
124
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700125// GetTLSConfig initializes a tlsConfig using the CA's certificate
126// This config is then used to enable the server for mutual TLS
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700127func GetTLSConfig(caCertFile string, certFile string, keyFile string) (*tls.Config, error) <span class="cov8" title="3">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700128
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700129 // Initialize tlsConfig once
Kiran Kamineni7597c152018-04-19 21:27:01 -0700130 caCert, err := ioutil.ReadFile(caCertFile)
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700131
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700132 if smslogger.CheckError(err, "Read CA Cert file") != nil </span><span class="cov1" title="1">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700133 return nil, err
134 }</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700135
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700136 <span class="cov5" title="2">caCertPool := x509.NewCertPool()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700137 caCertPool.AppendCertsFromPEM(caCert)
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700138
Kiran Kamineni7597c152018-04-19 21:27:01 -0700139 tlsConfig := &amp;tls.Config{
140 // Change to RequireAndVerify once we have mandatory certs
141 ClientAuth: tls.VerifyClientCertIfGiven,
142 ClientCAs: caCertPool,
143 MinVersion: tls.VersionTLS12,
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700144 }
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700145
146 certPEMBlk, err := readPEMBlock(certFile)
147 if smslogger.CheckError(err, "Read Cert File") != nil </span><span class="cov0" title="0">{
148 return nil, err
149 }</span>
150
151 <span class="cov5" title="2">keyPEMBlk, err := readPEMBlock(keyFile)
152 if smslogger.CheckError(err, "Read Key File") != nil </span><span class="cov0" title="0">{
153 return nil, err
154 }</span>
155
156 <span class="cov5" title="2">tlsConfig.Certificates = make([]tls.Certificate, 1)
157 tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlk, keyPEMBlk)
158 if smslogger.CheckError(err, "Load x509 cert and key") != nil </span><span class="cov0" title="0">{
159 return nil, err
160 }</span>
161
162 <span class="cov5" title="2">tlsConfig.BuildNameToCertificate()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700163 return tlsConfig, nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700164}
165
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700166func readPEMBlock(filename string) ([]byte, error) <span class="cov10" title="4">{
167
168 pemData, err := ioutil.ReadFile(filename)
169
170 if smslogger.CheckError(err, "Read PEM File") != nil </span><span class="cov0" title="0">{
171 return nil, err
172 }</span>
173
174 <span class="cov10" title="4">pemBlock, rest := pem.Decode(pemData)
175 if len(rest) &gt; 0 </span><span class="cov1" title="1">{
176 smslogger.WriteWarn("Pemfile has extra data")
177 }</span>
178
179 <span class="cov10" title="4">if x509.IsEncryptedPEMBlock(pemBlock) </span><span class="cov1" title="1">{
180 pByte, err := base64.StdEncoding.DecodeString(smsconfig.SMSConfig.Password)
181 if smslogger.CheckError(err, "Decode PEM Password") != nil </span><span class="cov0" title="0">{
182 return nil, err
183 }</span>
184
185 <span class="cov1" title="1">pemData, err = x509.DecryptPEMBlock(pemBlock, pByte)
186 if smslogger.CheckError(err, "Decrypt PEM Data") != nil </span><span class="cov0" title="0">{
187 return nil, err
188 }</span>
189 <span class="cov1" title="1">var newPEMBlock pem.Block
190 newPEMBlock.Type = pemBlock.Type
191 newPEMBlock.Bytes = pemData
192 // Converting back to PEM from DER data you get from
193 // DecryptPEMBlock
194 pemData = pem.EncodeToMemory(&amp;newPEMBlock)</span>
195 }
196
197 <span class="cov10" title="4">return pemData, nil</span>
198}
199
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700200// GeneratePGPKeyPair produces a PGP key pair and returns
201// two things:
202// A base64 encoded form of the public part of the entity
203// A base64 encoded form of the private key
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700204func GeneratePGPKeyPair() (string, string, error) <span class="cov8" title="3">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700205
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700206 var entity *openpgp.Entity
Kiran Kamineni7597c152018-04-19 21:27:01 -0700207 config := &amp;packet.Config{
208 DefaultHash: crypto.SHA256,
209 }
210
211 entity, err := openpgp.NewEntity("aaf.sms.init", "PGP Key for unsealing", "", config)
212 if smslogger.CheckError(err, "Create Entity") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700213 return "", "", err
214 }</span>
215
216 // Sign the identity in the entity
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700217 <span class="cov8" title="3">for _, id := range entity.Identities </span><span class="cov8" title="3">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700218 err = id.SelfSignature.SignUserId(id.UserId.Id, entity.PrimaryKey, entity.PrivateKey, nil)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700219 if smslogger.CheckError(err, "Sign Entity") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700220 return "", "", err
221 }</span>
222 }
223
224 // Sign the subkey in the entity
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700225 <span class="cov8" title="3">for _, subkey := range entity.Subkeys </span><span class="cov8" title="3">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700226 err := subkey.Sig.SignKey(subkey.PublicKey, entity.PrivateKey, nil)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700227 if smslogger.CheckError(err, "Sign Subkey") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700228 return "", "", err
229 }</span>
230 }
231
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700232 <span class="cov8" title="3">buffer := new(bytes.Buffer)
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700233 entity.Serialize(buffer)
234 pbkey := base64.StdEncoding.EncodeToString(buffer.Bytes())
235
236 buffer.Reset()
237 entity.SerializePrivate(buffer, nil)
238 prkey := base64.StdEncoding.EncodeToString(buffer.Bytes())
239
240 return pbkey, prkey, nil</span>
241}
242
Kiran Kamineni7597c152018-04-19 21:27:01 -0700243// EncryptPGPString takes data and a public key and encrypts using that
244// public key
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700245func EncryptPGPString(data string, pbKey string) (string, error) <span class="cov5" title="2">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700246
247 pbKeyBytes, err := base64.StdEncoding.DecodeString(pbKey)
248 if smslogger.CheckError(err, "Decoding Base64 Public Key") != nil </span><span class="cov0" title="0">{
249 return "", err
250 }</span>
251
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700252 <span class="cov5" title="2">dataBytes := []byte(data)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700253
254 pbEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(pbKeyBytes)))
255 if smslogger.CheckError(err, "Reading entity from PGP key") != nil </span><span class="cov0" title="0">{
256 return "", err
257 }</span>
258
259 // encrypt string
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700260 <span class="cov5" title="2">buf := new(bytes.Buffer)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700261 out, err := openpgp.Encrypt(buf, []*openpgp.Entity{pbEntity}, nil, nil, nil)
262 if smslogger.CheckError(err, "Creating Encryption Pipe") != nil </span><span class="cov0" title="0">{
263 return "", err
264 }</span>
265
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700266 <span class="cov5" title="2">_, err = out.Write(dataBytes)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700267 if smslogger.CheckError(err, "Writing to Encryption Pipe") != nil </span><span class="cov0" title="0">{
268 return "", err
269 }</span>
270
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700271 <span class="cov5" title="2">err = out.Close()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700272 if smslogger.CheckError(err, "Closing Encryption Pipe") != nil </span><span class="cov0" title="0">{
273 return "", err
274 }</span>
275
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700276 <span class="cov5" title="2">crp := base64.StdEncoding.EncodeToString(buf.Bytes())
Kiran Kamineni7597c152018-04-19 21:27:01 -0700277 return crp, nil</span>
278}
279
280// DecryptPGPString decrypts a PGP encoded input string and returns
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700281// a base64 representation of the decoded string
Kiran Kamineni7597c152018-04-19 21:27:01 -0700282func DecryptPGPString(data string, prKey string) (string, error) <span class="cov1" title="1">{
283
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700284 // Convert private key to bytes from base64
285 prKeyBytes, err := base64.StdEncoding.DecodeString(prKey)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700286 if smslogger.CheckError(err, "Decoding Base64 Private Key") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700287 return "", err
288 }</span>
289
Kiran Kamineni7597c152018-04-19 21:27:01 -0700290 <span class="cov1" title="1">dataBytes, err := base64.StdEncoding.DecodeString(data)
291 if smslogger.CheckError(err, "Decoding base64 data") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700292 return "", err
293 }</span>
294
Kiran Kamineni7597c152018-04-19 21:27:01 -0700295 <span class="cov1" title="1">prEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(prKeyBytes)))
296 if smslogger.CheckError(err, "Read Entity") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700297 return "", err
298 }</span>
299
Kiran Kamineni7597c152018-04-19 21:27:01 -0700300 <span class="cov1" title="1">prEntityList := &amp;openpgp.EntityList{prEntity}
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700301 message, err := openpgp.ReadMessage(bytes.NewBuffer(dataBytes), prEntityList, nil, nil)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700302 if smslogger.CheckError(err, "Decrypting Message") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700303 return "", err
304 }</span>
305
Kiran Kamineni7597c152018-04-19 21:27:01 -0700306 <span class="cov1" title="1">var retBuf bytes.Buffer
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700307 retBuf.ReadFrom(message.UnverifiedBody)
308
309 return retBuf.String(), nil</span>
310}
Kiran Kamineni7597c152018-04-19 21:27:01 -0700311
312// ReadFromFile reads a file and loads the PGP key into
313// a string
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700314func ReadFromFile(fileName string) (string, error) <span class="cov1" title="1">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700315
316 data, err := ioutil.ReadFile(fileName)
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700317 if smslogger.CheckError(err, "Read from file") != nil </span><span class="cov1" title="1">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700318 return "", err
319 }</span>
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700320 <span class="cov0" title="0">return string(data), nil</span>
Kiran Kamineni7597c152018-04-19 21:27:01 -0700321}
322
323// WriteToFile writes a PGP key into a file.
324// It will truncate the file if it exists
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700325func WriteToFile(data string, fileName string) error <span class="cov5" title="2">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700326
327 err := ioutil.WriteFile(fileName, []byte(data), 0600)
328 if smslogger.CheckError(err, "Write to file") != nil </span><span class="cov0" title="0">{
329 return err
330 }</span>
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700331 <span class="cov5" title="2">return nil</span>
Kiran Kamineni7597c152018-04-19 21:27:01 -0700332}
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700333</pre>
334
335 <pre class="file" id="file1" style="display: none">/*
336 * Copyright 2018 Intel Corporation, Inc
337 *
338 * Licensed under the Apache License, Version 2.0 (the "License");
339 * you may not use this file except in compliance with the License.
340 * You may obtain a copy of the License at
341 *
342 * http://www.apache.org/licenses/LICENSE-2.0
343 *
344 * Unless required by applicable law or agreed to in writing, software
345 * distributed under the License is distributed on an "AS IS" BASIS,
346 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
347 * See the License for the specific language governing permissions and
348 * limitations under the License.
349 */
350
351package backend
352
353import (
354 smsconfig "sms/config"
355 smslogger "sms/log"
356)
357
358// SecretDomain is where Secrets are stored.
359// A single domain can have any number of secrets
360type SecretDomain struct {
361 UUID string `json:"uuid"`
362 Name string `json:"name"`
363}
364
365// Secret is the struct that defines the structure of a secret
366// It consists of a name and map containing key value pairs
367type Secret struct {
368 Name string `json:"name"`
369 Values map[string]interface{} `json:"values"`
370}
371
372// SecretBackend interface that will be implemented for various secret backends
373type SecretBackend interface {
374 Init() error
375 GetStatus() (bool, error)
376 Unseal(shard string) error
Kiran Kamineni7597c152018-04-19 21:27:01 -0700377 RegisterQuorum(pgpkey string) (string, error)
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700378
379 GetSecret(dom string, sec string) (Secret, error)
380 ListSecret(dom string) ([]string, error)
381
382 CreateSecretDomain(name string) (SecretDomain, error)
383 CreateSecret(dom string, sec Secret) error
384
385 DeleteSecretDomain(name string) error
386 DeleteSecret(dom string, name string) error
387}
388
389// InitSecretBackend returns an interface implementation
Kiran Kamineni7597c152018-04-19 21:27:01 -0700390func InitSecretBackend() (SecretBackend, error) <span class="cov8" title="1">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700391 backendImpl := &amp;Vault{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700392 vaultAddress: smsconfig.SMSConfig.BackendAddress,
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700393 vaultToken: smsconfig.SMSConfig.VaultToken,
394 }
395
396 err := backendImpl.Init()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700397 if smslogger.CheckError(err, "InitSecretBackend") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700398 return nil, err
399 }</span>
400
Kiran Kamineni7597c152018-04-19 21:27:01 -0700401 <span class="cov8" title="1">return backendImpl, nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700402}
403
404// LoginBackend Interface that will be implemented for various login backends
405type LoginBackend interface {
406}
407</pre>
408
409 <pre class="file" id="file2" style="display: none">/*
410 * Copyright 2018 Intel Corporation, Inc
411 *
412 * Licensed under the Apache License, Version 2.0 (the "License");
413 * you may not use this file except in compliance with the License.
414 * You may obtain a copy of the License at
415 *
416 * http://www.apache.org/licenses/LICENSE-2.0
417 *
418 * Unless required by applicable law or agreed to in writing, software
419 * distributed under the License is distributed on an "AS IS" BASIS,
420 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
421 * See the License for the specific language governing permissions and
422 * limitations under the License.
423 */
424
425package backend
426
427import (
428 uuid "github.com/hashicorp/go-uuid"
429 vaultapi "github.com/hashicorp/vault/api"
430 smsauth "sms/auth"
431 smslogger "sms/log"
432
433 "errors"
434 "fmt"
435 "strings"
436 "sync"
437 "time"
438)
439
440// Vault is the main Struct used in Backend to initialize the struct
441type Vault struct {
442 sync.Mutex
Kiran Kamineni7597c152018-04-19 21:27:01 -0700443 initRoleDone bool
444 policyName string
445 roleID string
446 secretID string
447 vaultAddress string
448 vaultClient *vaultapi.Client
449 vaultMountPrefix string
450 internalDomain string
451 internalDomainMounted bool
452 vaultTempTokenTTL time.Time
453 vaultToken string
454 shards []string
455 prkey string
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700456}
457
Kiran Kamineni7597c152018-04-19 21:27:01 -0700458// initVaultClient will create the initial
459// Vault strcuture and populate it with the
460// right values and it will also create
461// a vault client
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700462func (v *Vault) initVaultClient() error <span class="cov7" title="11">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700463
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700464 vaultCFG := vaultapi.DefaultConfig()
465 vaultCFG.Address = v.vaultAddress
466 client, err := vaultapi.NewClient(vaultCFG)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700467 if smslogger.CheckError(err, "Create new vault client") != nil </span><span class="cov0" title="0">{
468 return err
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700469 }</span>
470
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700471 <span class="cov7" title="11">v.initRoleDone = false
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700472 v.policyName = "smsvaultpolicy"
473 v.vaultClient = client
Kiran Kamineni7597c152018-04-19 21:27:01 -0700474 v.vaultMountPrefix = "sms"
475 v.internalDomain = "smsinternaldomain"
476 v.internalDomainMounted = false
477 v.prkey = ""
478 return nil</span>
479}
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700480
Kiran Kamineni7597c152018-04-19 21:27:01 -0700481// Init will initialize the vault connection
482// It will also initialize vault if it is not
483// already initialized.
484// The initial policy will also be created
485func (v *Vault) Init() error <span class="cov1" title="1">{
486
487 v.initVaultClient()
488 // Initialize vault if it is not already
489 // Returns immediately if it is initialized
490 v.initializeVault()
491
492 err := v.initRole()
493 if smslogger.CheckError(err, "InitRole First Attempt") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700494 smslogger.WriteInfo("InitRole will try again later")
495 }</span>
496
Kiran Kamineni7597c152018-04-19 21:27:01 -0700497 <span class="cov1" title="1">return nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700498}
499
500// GetStatus returns the current seal status of vault
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700501func (v *Vault) GetStatus() (bool, error) <span class="cov2" title="2">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700502
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700503 sys := v.vaultClient.Sys()
504 sealStatus, err := sys.SealStatus()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700505 if smslogger.CheckError(err, "Getting Status") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700506 return false, errors.New("Error getting status")
507 }</span>
508
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700509 <span class="cov2" title="2">return sealStatus.Sealed, nil</span>
Kiran Kamineni7597c152018-04-19 21:27:01 -0700510}
511
512// RegisterQuorum registers the PGP public key for a quorum client
513// We will return a shard to the client that is registering
514func (v *Vault) RegisterQuorum(pgpkey string) (string, error) <span class="cov0" title="0">{
515
516 v.Lock()
517 defer v.Unlock()
518
519 if v.shards == nil </span><span class="cov0" title="0">{
520 smslogger.WriteError("Invalid operation in RegisterQuorum")
521 return "", errors.New("Invalid operation")
522 }</span>
523 // Pop the slice
524 <span class="cov0" title="0">var sh string
525 sh, v.shards = v.shards[len(v.shards)-1], v.shards[:len(v.shards)-1]
526 if len(v.shards) == 0 </span><span class="cov0" title="0">{
527 v.shards = nil
528 }</span>
529
530 // Decrypt with SMS pgp Key
531 <span class="cov0" title="0">sh, _ = smsauth.DecryptPGPString(sh, v.prkey)
532 // Encrypt with Quorum client pgp key
533 sh, _ = smsauth.EncryptPGPString(sh, pgpkey)
534
535 return sh, nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700536}
537
538// Unseal is a passthrough API that allows any
539// unseal or initialization processes for the backend
540func (v *Vault) Unseal(shard string) error <span class="cov0" title="0">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700541
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700542 sys := v.vaultClient.Sys()
543 _, err := sys.Unseal(shard)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700544 if smslogger.CheckError(err, "Unseal Operation") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700545 return errors.New("Unable to execute unseal operation with specified shard")
546 }</span>
547
548 <span class="cov0" title="0">return nil</span>
549}
550
551// GetSecret returns a secret mounted on a particular domain name
552// The secret itself is referenced via its name which translates to
553// a mount path in vault
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700554func (v *Vault) GetSecret(dom string, name string) (Secret, error) <span class="cov2" title="2">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700555
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700556 err := v.checkToken()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700557 if smslogger.CheckError(err, "Tocken Check") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700558 return Secret{}, errors.New("Token check failed")
559 }</span>
560
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700561 <span class="cov2" title="2">dom = strings.TrimSpace(dom)
562 dom = v.vaultMountPrefix + "/" + dom
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700563
564 sec, err := v.vaultClient.Logical().Read(dom + "/" + name)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700565 if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700566 return Secret{}, errors.New("Unable to read Secret at provided path")
567 }</span>
568
569 // sec and err are nil in the case where a path does not exist
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700570 <span class="cov2" title="2">if sec == nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700571 smslogger.WriteWarn("Vault read was empty. Invalid Path")
572 return Secret{}, errors.New("Secret not found at the provided path")
573 }</span>
574
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700575 <span class="cov2" title="2">return Secret{Name: name, Values: sec.Data}, nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700576}
577
578// ListSecret returns a list of secret names on a particular domain
579// The values of the secret are not returned
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700580func (v *Vault) ListSecret(dom string) ([]string, error) <span class="cov2" title="2">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700581
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700582 err := v.checkToken()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700583 if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700584 return nil, errors.New("Token check failed")
585 }</span>
586
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700587 <span class="cov2" title="2">dom = strings.TrimSpace(dom)
588 dom = v.vaultMountPrefix + "/" + dom
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700589
590 sec, err := v.vaultClient.Logical().List(dom)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700591 if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700592 return nil, errors.New("Unable to read Secret at provided path")
593 }</span>
594
595 // sec and err are nil in the case where a path does not exist
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700596 <span class="cov2" title="2">if sec == nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700597 smslogger.WriteWarn("Vaultclient returned empty data")
598 return nil, errors.New("Secret not found at the provided path")
599 }</span>
600
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700601 <span class="cov2" title="2">val, ok := sec.Data["keys"].([]interface{})
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700602 if !ok </span><span class="cov0" title="0">{
603 smslogger.WriteError("Secret not found at the provided path")
604 return nil, errors.New("Secret not found at the provided path")
605 }</span>
606
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700607 <span class="cov2" title="2">retval := make([]string, len(val))
608 for i, v := range val </span><span class="cov2" title="2">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700609 retval[i] = fmt.Sprint(v)
610 }</span>
611
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700612 <span class="cov2" title="2">return retval, nil</span>
Kiran Kamineni7597c152018-04-19 21:27:01 -0700613}
614
615// Mounts the internal Domain if its not already mounted
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700616func (v *Vault) mountInternalDomain(name string) error <span class="cov5" title="7">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700617
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700618 if v.internalDomainMounted </span><span class="cov0" title="0">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700619 return nil
620 }</span>
621
622 <span class="cov5" title="7">name = strings.TrimSpace(name)
623 mountPath := v.vaultMountPrefix + "/" + name
624 mountInput := &amp;vaultapi.MountInput{
625 Type: "kv",
626 Description: "Mount point for domain: " + name,
627 Local: false,
628 SealWrap: false,
629 Config: vaultapi.MountConfigInput{},
630 }
631
632 err := v.vaultClient.Sys().Mount(mountPath, mountInput)
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700633 if smslogger.CheckError(err, "Mount internal Domain") != nil </span><span class="cov0" title="0">{
634 if strings.Contains(err.Error(), "existing mount") </span><span class="cov0" title="0">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700635 // It is already mounted
636 v.internalDomainMounted = true
637 return nil
638 }</span>
639 // Ran into some other error mounting it.
640 <span class="cov0" title="0">return errors.New("Unable to mount internal Domain")</span>
641 }
642
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700643 <span class="cov5" title="7">v.internalDomainMounted = true
Kiran Kamineni7597c152018-04-19 21:27:01 -0700644 return nil</span>
645}
646
647// Stores the UUID created for secretdomain in vault
648// under v.vaultMountPrefix / smsinternal domain
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700649func (v *Vault) storeUUID(uuid string, name string) error <span class="cov5" title="7">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700650
651 // Check if token is still valid
652 err := v.checkToken()
653 if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
654 return errors.New("Token Check failed")
655 }</span>
656
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700657 <span class="cov5" title="7">err = v.mountInternalDomain(v.internalDomain)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700658 if smslogger.CheckError(err, "Mount Internal Domain") != nil </span><span class="cov0" title="0">{
659 return err
660 }</span>
661
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700662 <span class="cov5" title="7">secret := Secret{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700663 Name: name,
664 Values: map[string]interface{}{
665 "uuid": uuid,
666 },
667 }
668
669 err = v.CreateSecret(v.internalDomain, secret)
670 if smslogger.CheckError(err, "Write UUID to domain") != nil </span><span class="cov0" title="0">{
671 return err
672 }</span>
673
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700674 <span class="cov5" title="7">return nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700675}
676
677// CreateSecretDomain mounts the kv backend on a path with the given name
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700678func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span class="cov5" title="7">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700679
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700680 // Check if token is still valid
681 err := v.checkToken()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700682 if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700683 return SecretDomain{}, errors.New("Token Check failed")
684 }</span>
685
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700686 <span class="cov5" title="7">name = strings.TrimSpace(name)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700687 mountPath := v.vaultMountPrefix + "/" + name
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700688 mountInput := &amp;vaultapi.MountInput{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700689 Type: "kv",
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700690 Description: "Mount point for domain: " + name,
691 Local: false,
692 SealWrap: false,
693 Config: vaultapi.MountConfigInput{},
694 }
695
696 err = v.vaultClient.Sys().Mount(mountPath, mountInput)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700697 if smslogger.CheckError(err, "Create Domain") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700698 return SecretDomain{}, errors.New("Unable to create Secret Domain")
699 }</span>
700
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700701 <span class="cov5" title="7">uuid, _ := uuid.GenerateUUID()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700702 err = v.storeUUID(uuid, name)
703 if smslogger.CheckError(err, "Store UUID") != nil </span><span class="cov0" title="0">{
704 // Mount was successful at this point.
705 // Rollback the mount operation since we could not
706 // store the UUID for the mount.
707 v.vaultClient.Sys().Unmount(mountPath)
708 return SecretDomain{}, errors.New("Unable to store Secret Domain UUID. Retry")
709 }</span>
710
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700711 <span class="cov5" title="7">return SecretDomain{uuid, name}, nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700712}
713
714// CreateSecret creates a secret mounted on a particular domain name
715// The secret itself is mounted on a path specified by name
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700716func (v *Vault) CreateSecret(dom string, sec Secret) error <span class="cov7" title="12">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700717
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700718 err := v.checkToken()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700719 if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700720 return errors.New("Token check failed")
721 }</span>
722
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700723 <span class="cov7" title="12">dom = strings.TrimSpace(dom)
724 dom = v.vaultMountPrefix + "/" + dom
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700725
726 // Vault return is empty on successful write
727 // TODO: Check if values is not empty
728 _, err = v.vaultClient.Logical().Write(dom+"/"+sec.Name, sec.Values)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700729 if smslogger.CheckError(err, "Create Secret") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700730 return errors.New("Unable to create Secret at provided path")
731 }</span>
732
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700733 <span class="cov7" title="12">return nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700734}
735
736// DeleteSecretDomain deletes a secret domain which translates to
737// an unmount operation on the given path in Vault
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700738func (v *Vault) DeleteSecretDomain(dom string) error <span class="cov2" title="2">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700739
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700740 err := v.checkToken()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700741 if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700742 return errors.New("Token Check Failed")
743 }</span>
744
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700745 <span class="cov2" title="2">dom = strings.TrimSpace(dom)
746 mountPath := v.vaultMountPrefix + "/" + dom
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700747
748 err = v.vaultClient.Sys().Unmount(mountPath)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700749 if smslogger.CheckError(err, "Delete Domain") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700750 return errors.New("Unable to delete domain specified")
751 }</span>
752
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700753 <span class="cov2" title="2">return nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700754}
755
756// DeleteSecret deletes a secret mounted on the path provided
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700757func (v *Vault) DeleteSecret(dom string, name string) error <span class="cov2" title="2">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700758
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700759 err := v.checkToken()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700760 if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700761 return errors.New("Token check failed")
762 }</span>
763
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700764 <span class="cov2" title="2">dom = strings.TrimSpace(dom)
765 dom = v.vaultMountPrefix + "/" + dom
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700766
767 // Vault return is empty on successful delete
768 _, err = v.vaultClient.Logical().Delete(dom + "/" + name)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700769 if smslogger.CheckError(err, "Delete Secret") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700770 return errors.New("Unable to delete Secret at provided path")
771 }</span>
772
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700773 <span class="cov2" title="2">return nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700774}
775
Kiran Kamineni7597c152018-04-19 21:27:01 -0700776// initRole is called only once during SMS bring up
777// It initially creates a role and secret id associated with
778// that role. Later restarts will use the existing role-id
779// and secret-id stored on disk
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700780func (v *Vault) initRole() error <span class="cov10" title="36">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700781
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700782 if v.initRoleDone </span><span class="cov9" title="28">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700783 return nil
784 }</span>
785
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700786 // Use the root token once here
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700787 <span class="cov6" title="8">v.vaultClient.SetToken(v.vaultToken)
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700788 defer v.vaultClient.ClearToken()
789
Kiran Kamineni7597c152018-04-19 21:27:01 -0700790 // Check if roleID and secretID has already been created
791 rID, error := smsauth.ReadFromFile("auth/role")
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700792 if error != nil </span><span class="cov6" title="8">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700793 smslogger.WriteWarn("Unable to find RoleID. Generating...")
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700794 }</span> else<span class="cov0" title="0"> {
Kiran Kamineni7597c152018-04-19 21:27:01 -0700795 sID, error := smsauth.ReadFromFile("auth/secret")
796 if error != nil </span><span class="cov0" title="0">{
797 smslogger.WriteWarn("Unable to find secretID. Generating...")
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700798 }</span> else<span class="cov0" title="0"> {
Kiran Kamineni7597c152018-04-19 21:27:01 -0700799 v.roleID = rID
800 v.secretID = sID
801 v.initRoleDone = true
802 return nil
803 }</span>
804 }
805
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700806 <span class="cov6" title="8">rules := `path "sms/*" { capabilities = ["create", "read", "update", "delete", "list"] }
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700807 path "sys/mounts/sms*" { capabilities = ["update","delete","create"] }`
808 err := v.vaultClient.Sys().PutPolicy(v.policyName, rules)
Kiran Kamineni7597c152018-04-19 21:27:01 -0700809 if smslogger.CheckError(err, "Creating Policy") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700810 return errors.New("Unable to create policy for approle creation")
811 }</span>
812
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700813 //Check if applrole is mounted
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700814 <span class="cov6" title="8">authMounts, err := v.vaultClient.Sys().ListAuth()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700815 if smslogger.CheckError(err, "Mount Auth Backend") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700816 return errors.New("Unable to get mounted auth backends")
817 }</span>
818
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700819 <span class="cov6" title="8">approleMounted := false
820 for k, v := range authMounts </span><span class="cov6" title="8">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700821 if v.Type == "approle" &amp;&amp; k == "approle/" </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700822 approleMounted = true
823 break</span>
824 }
825 }
826
827 // Mount approle in case its not already mounted
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700828 <span class="cov6" title="8">if !approleMounted </span><span class="cov6" title="8">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700829 v.vaultClient.Sys().EnableAuth("approle", "approle", "")
830 }</span>
831
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700832 <span class="cov6" title="8">rName := v.vaultMountPrefix + "-role"
Kiran Kamineni7597c152018-04-19 21:27:01 -0700833 data := map[string]interface{}{
834 "token_ttl": "60m",
835 "policies": [2]string{"default", v.policyName},
836 }
837
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700838 // Create a role-id
Kiran Kamineni7597c152018-04-19 21:27:01 -0700839 v.vaultClient.Logical().Write("auth/approle/role/"+rName, data)
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700840 sec, err := v.vaultClient.Logical().Read("auth/approle/role/" + rName + "/role-id")
Kiran Kamineni7597c152018-04-19 21:27:01 -0700841 if smslogger.CheckError(err, "Create RoleID") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700842 return errors.New("Unable to create role ID for approle")
843 }</span>
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700844 <span class="cov6" title="8">v.roleID = sec.Data["role_id"].(string)
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700845
846 // Create a secret-id to go with it
847 sec, err = v.vaultClient.Logical().Write("auth/approle/role/"+rName+"/secret-id",
848 map[string]interface{}{})
Kiran Kamineni7597c152018-04-19 21:27:01 -0700849 if smslogger.CheckError(err, "Create SecretID") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700850 return errors.New("Unable to create secret ID for role")
851 }</span>
852
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700853 <span class="cov6" title="8">v.secretID = sec.Data["secret_id"].(string)
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700854 v.initRoleDone = true
Kiran Kamineni7597c152018-04-19 21:27:01 -0700855 /*
856 * Revoke the Root token.
857 * If a new Root Token is needed, it will need to be created
858 * using the unseal shards.
859 */
860 err = v.vaultClient.Auth().Token().RevokeSelf(v.vaultToken)
861 if smslogger.CheckError(err, "Revoke Root Token") != nil </span><span class="cov0" title="0">{
862 smslogger.WriteWarn("Unable to Revoke Token")
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700863 }</span> else<span class="cov6" title="8"> {
Kiran Kamineni7597c152018-04-19 21:27:01 -0700864 // Revoked successfully and clear it
865 v.vaultToken = ""
866 }</span>
867
868 // Store the role-id and secret-id
869 // We will need this if SMS restarts
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700870 <span class="cov6" title="8">smsauth.WriteToFile(v.roleID, "auth/role")
Kiran Kamineni7597c152018-04-19 21:27:01 -0700871 smsauth.WriteToFile(v.secretID, "auth/secret")
872
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700873 return nil</span>
874}
875
876// Function checkToken() gets called multiple times to create
877// temporary tokens
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700878func (v *Vault) checkToken() error <span class="cov9" title="34">{
Kiran Kamineni7597c152018-04-19 21:27:01 -0700879
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700880 v.Lock()
881 defer v.Unlock()
882
883 // Init Role if it is not yet done
884 // Role needs to be created before token can be created
Kiran Kamineni7597c152018-04-19 21:27:01 -0700885 err := v.initRole()
886 if err != nil </span><span class="cov0" title="0">{
887 smslogger.WriteError(err.Error())
888 return errors.New("Unable to initRole in checkToken")
889 }</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700890
891 // Return immediately if token still has life
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700892 <span class="cov9" title="34">if v.vaultClient.Token() != "" &amp;&amp;
893 time.Since(v.vaultTempTokenTTL) &lt; time.Minute*50 </span><span class="cov9" title="27">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700894 return nil
895 }</span>
896
897 // Create a temporary token using our roleID and secretID
Kiran Kamineni7597c152018-04-19 21:27:01 -0700898 <span class="cov5" title="7">out, err := v.vaultClient.Logical().Write("auth/approle/login",
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700899 map[string]interface{}{"role_id": v.roleID, "secret_id": v.secretID})
Kiran Kamineni7597c152018-04-19 21:27:01 -0700900 if smslogger.CheckError(err, "Create Temp Token") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700901 return errors.New("Unable to create Temporary Token for Role")
902 }</span>
903
Kiran Kamineni7597c152018-04-19 21:27:01 -0700904 <span class="cov5" title="7">tok, err := out.TokenID()
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700905
906 v.vaultTempTokenTTL = time.Now()
907 v.vaultClient.SetToken(tok)
908 return nil</span>
909}
910
911// vaultInit() is used to initialize the vault in cases where it is not
912// initialized. This happens once during intial bring up.
Kiran Kamineni7597c152018-04-19 21:27:01 -0700913func (v *Vault) initializeVault() error <span class="cov2" title="2">{
914
915 // Check for vault init status and don't exit till it is initialized
916 for </span><span class="cov2" title="2">{
917 init, err := v.vaultClient.Sys().InitStatus()
918 if smslogger.CheckError(err, "Get Vault Init Status") != nil </span><span class="cov0" title="0">{
919 smslogger.WriteInfo("Trying again in 10s...")
920 time.Sleep(time.Second * 10)
921 continue</span>
922 }
923 // Did not get any error
924 <span class="cov2" title="2">if init == true </span><span class="cov1" title="1">{
925 smslogger.WriteInfo("Vault is already Initialized")
926 return nil
927 }</span>
928
929 // init status is false
930 // break out of loop and finish initialization
931 <span class="cov1" title="1">smslogger.WriteInfo("Vault is not initialized. Initializing...")
932 break</span>
933 }
934
935 // Hardcoded this to 3. We should make this configurable
936 // in the future
937 <span class="cov1" title="1">initReq := &amp;vaultapi.InitRequest{
938 SecretShares: 3,
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700939 SecretThreshold: 3,
940 }
941
942 pbkey, prkey, err := smsauth.GeneratePGPKeyPair()
Kiran Kamineni7597c152018-04-19 21:27:01 -0700943
944 if smslogger.CheckError(err, "Generating PGP Keys") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700945 smslogger.WriteError("Error Generating PGP Keys. Vault Init will not use encryption!")
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700946 }</span> else<span class="cov1" title="1"> {
Kiran Kamineni7597c152018-04-19 21:27:01 -0700947 initReq.PGPKeys = []string{pbkey, pbkey, pbkey}
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700948 initReq.RootTokenPGPKey = pbkey
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700949 }</span>
950
Kiran Kamineni7597c152018-04-19 21:27:01 -0700951 <span class="cov1" title="1">resp, err := v.vaultClient.Sys().Init(initReq)
952 if smslogger.CheckError(err, "Initialize Vault") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700953 return errors.New("FATAL: Unable to initialize Vault")
954 }</span>
955
Kiran Kamineni7597c152018-04-19 21:27:01 -0700956 <span class="cov1" title="1">if resp != nil </span><span class="cov1" title="1">{
957 v.prkey = prkey
958 v.shards = resp.KeysB64
959 v.vaultToken, _ = smsauth.DecryptPGPString(resp.RootToken, prkey)
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700960 return nil
961 }</span>
962
963 <span class="cov0" title="0">return errors.New("FATAL: Init response was empty")</span>
964}
965</pre>
966
967 <pre class="file" id="file3" style="display: none">/*
968 * Copyright 2018 Intel Corporation, Inc
969 *
970 * Licensed under the Apache License, Version 2.0 (the "License");
971 * you may not use this file except in compliance with the License.
972 * You may obtain a copy of the License at
973 *
974 * http://www.apache.org/licenses/LICENSE-2.0
975 *
976 * Unless required by applicable law or agreed to in writing, software
977 * distributed under the License is distributed on an "AS IS" BASIS,
978 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
979 * See the License for the specific language governing permissions and
980 * limitations under the License.
981 */
982
983package config
984
985import (
986 "encoding/json"
987 "os"
Kiran Kamineni7597c152018-04-19 21:27:01 -0700988 smslogger "sms/log"
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700989)
990
991// SMSConfiguration loads up all the values that are used to configure
992// backend implementations
993// TODO: Review these and see if they can be created/discovered dynamically
994type SMSConfiguration struct {
995 CAFile string `json:"cafile"`
996 ServerCert string `json:"servercert"`
997 ServerKey string `json:"serverkey"`
Kiran Kaminenic660d1b2018-09-20 10:43:28 -0700998 Password string `json:"password"`
Kiran Kamineni937a0cd2018-03-23 14:14:10 -0700999
Kiran Kamineni7597c152018-04-19 21:27:01 -07001000 BackendAddress string `json:"smsdbaddress"`
1001 VaultToken string `json:"vaulttoken"`
1002 DisableTLS bool `json:"disable_tls"`
1003 BackendAddressEnvVariable string `json:"smsdburlenv"`
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001004}
1005
1006// SMSConfig is the structure that stores the configuration
1007var SMSConfig *SMSConfiguration
1008
1009// ReadConfigFile reads the specified smsConfig file to setup some env variables
1010func ReadConfigFile(file string) (*SMSConfiguration, error) <span class="cov10" title="3">{
1011 if SMSConfig == nil </span><span class="cov10" title="3">{
1012 f, err := os.Open(file)
1013 if err != nil </span><span class="cov1" title="1">{
1014 return nil, err
1015 }</span>
1016 <span class="cov6" title="2">defer f.Close()
1017
Kiran Kamineni7597c152018-04-19 21:27:01 -07001018 // Default behaviour is to enable TLS
1019 SMSConfig = &amp;SMSConfiguration{DisableTLS: false}
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001020 decoder := json.NewDecoder(f)
1021 err = decoder.Decode(SMSConfig)
1022 if err != nil </span><span class="cov0" title="0">{
1023 return nil, err
1024 }</span>
Kiran Kamineni7597c152018-04-19 21:27:01 -07001025
1026 <span class="cov6" title="2">if SMSConfig.BackendAddress == "" &amp;&amp; SMSConfig.BackendAddressEnvVariable != "" </span><span class="cov0" title="0">{
1027 // Get the value from ENV variable
1028 smslogger.WriteInfo("Using Environment Variable: " + SMSConfig.BackendAddressEnvVariable)
1029 SMSConfig.BackendAddress = os.Getenv(SMSConfig.BackendAddressEnvVariable)
1030 }</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001031 }
1032
1033 <span class="cov6" title="2">return SMSConfig, nil</span>
1034}
1035</pre>
1036
1037 <pre class="file" id="file4" style="display: none">/*
1038 * Copyright 2018 Intel Corporation, Inc
1039 *
1040 * Licensed under the Apache License, Version 2.0 (the "License");
1041 * you may not use this file except in compliance with the License.
1042 * You may obtain a copy of the License at
1043 *
1044 * http://www.apache.org/licenses/LICENSE-2.0
1045 *
1046 * Unless required by applicable law or agreed to in writing, software
1047 * distributed under the License is distributed on an "AS IS" BASIS,
1048 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1049 * See the License for the specific language governing permissions and
1050 * limitations under the License.
1051 */
1052
1053package handler
1054
1055import (
1056 "encoding/json"
1057 "github.com/gorilla/mux"
1058 "net/http"
1059
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001060 uuid "github.com/hashicorp/go-uuid"
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001061 smsbackend "sms/backend"
1062 smslogger "sms/log"
1063)
1064
1065// handler stores two interface implementations that implement
1066// the backend functionality
1067type handler struct {
1068 secretBackend smsbackend.SecretBackend
1069 loginBackend smsbackend.LoginBackend
1070}
1071
1072// createSecretDomainHandler creates a secret domain with a name provided
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001073func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001074 var d smsbackend.SecretDomain
1075
1076 err := json.NewDecoder(r.Body).Decode(&amp;d)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001077 if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001078 http.Error(w, err.Error(), http.StatusBadRequest)
1079 return
1080 }</span>
1081
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001082 <span class="cov6" title="2">dom, err := h.secretBackend.CreateSecretDomain(d.Name)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001083 if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001084 http.Error(w, err.Error(), http.StatusInternalServerError)
1085 return
1086 }</span>
1087
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001088 <span class="cov6" title="2">w.Header().Set("Content-Type", "application/json")
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001089 w.WriteHeader(http.StatusCreated)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001090 err = json.NewEncoder(w).Encode(dom)
1091 if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
1092 http.Error(w, err.Error(), http.StatusInternalServerError)
1093 return
1094 }</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001095}
1096
1097// deleteSecretDomainHandler deletes a secret domain with the name provided
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001098func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001099 vars := mux.Vars(r)
1100 domName := vars["domName"]
1101
1102 err := h.secretBackend.DeleteSecretDomain(domName)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001103 if smslogger.CheckError(err, "DeleteSecretDomainHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001104 http.Error(w, err.Error(), http.StatusInternalServerError)
1105 return
1106 }</span>
1107
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001108 <span class="cov6" title="2">w.WriteHeader(http.StatusNoContent)</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001109}
1110
1111// createSecretHandler handles creation of secrets on a given domain name
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001112func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001113 // Get domain name from URL
1114 vars := mux.Vars(r)
1115 domName := vars["domName"]
1116
1117 // Get secrets to be stored from body
1118 var b smsbackend.Secret
1119 err := json.NewDecoder(r.Body).Decode(&amp;b)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001120 if smslogger.CheckError(err, "CreateSecretHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001121 http.Error(w, err.Error(), http.StatusBadRequest)
1122 return
1123 }</span>
1124
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001125 <span class="cov6" title="2">err = h.secretBackend.CreateSecret(domName, b)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001126 if smslogger.CheckError(err, "CreateSecretHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001127 http.Error(w, err.Error(), http.StatusInternalServerError)
1128 return
1129 }</span>
1130
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001131 <span class="cov6" title="2">w.WriteHeader(http.StatusCreated)</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001132}
1133
1134// getSecretHandler handles reading a secret by given domain name and secret name
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001135func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001136 vars := mux.Vars(r)
1137 domName := vars["domName"]
1138 secName := vars["secretName"]
1139
1140 sec, err := h.secretBackend.GetSecret(domName, secName)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001141 if smslogger.CheckError(err, "GetSecretHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001142 http.Error(w, err.Error(), http.StatusInternalServerError)
1143 return
1144 }</span>
1145
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001146 <span class="cov6" title="2">w.Header().Set("Content-Type", "application/json")
Kiran Kamineni7597c152018-04-19 21:27:01 -07001147 err = json.NewEncoder(w).Encode(sec)
1148 if smslogger.CheckError(err, "GetSecretHandler") != nil </span><span class="cov0" title="0">{
1149 http.Error(w, err.Error(), http.StatusInternalServerError)
1150 return
1151 }</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001152}
1153
1154// listSecretHandler handles listing all secrets under a particular domain name
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001155func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001156 vars := mux.Vars(r)
1157 domName := vars["domName"]
1158
1159 secList, err := h.secretBackend.ListSecret(domName)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001160 if smslogger.CheckError(err, "ListSecretHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001161 http.Error(w, err.Error(), http.StatusInternalServerError)
1162 return
1163 }</span>
1164
1165 // Creating an anonymous struct to store the returned list of data
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001166 <span class="cov6" title="2">var retStruct = struct {
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001167 SecretNames []string `json:"secretnames"`
1168 }{
1169 secList,
1170 }
1171
Kiran Kamineni7597c152018-04-19 21:27:01 -07001172 w.Header().Set("Content-Type", "application/json")
1173 err = json.NewEncoder(w).Encode(retStruct)
1174 if smslogger.CheckError(err, "ListSecretHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001175 http.Error(w, err.Error(), http.StatusInternalServerError)
1176 return
1177 }</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001178}
1179
1180// deleteSecretHandler handles deleting a secret by given domain name and secret name
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001181func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001182 vars := mux.Vars(r)
1183 domName := vars["domName"]
1184 secName := vars["secretName"]
1185
1186 err := h.secretBackend.DeleteSecret(domName, secName)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001187 if smslogger.CheckError(err, "DeleteSecretHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001188 http.Error(w, err.Error(), http.StatusInternalServerError)
1189 return
1190 }</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001191
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001192 <span class="cov6" title="2">w.WriteHeader(http.StatusNoContent)</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001193}
1194
1195// statusHandler returns information related to SMS and SMS backend services
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001196func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) <span class="cov10" title="3">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001197 s, err := h.secretBackend.GetStatus()
Kiran Kamineni7597c152018-04-19 21:27:01 -07001198 if smslogger.CheckError(err, "StatusHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001199 http.Error(w, err.Error(), http.StatusInternalServerError)
1200 return
1201 }</span>
1202
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001203 <span class="cov10" title="3">status := struct {
Kiran Kamineni7597c152018-04-19 21:27:01 -07001204 Seal bool `json:"sealstatus"`
1205 }{
1206 s,
1207 }
1208
1209 w.Header().Set("Content-Type", "application/json")
1210 err = json.NewEncoder(w).Encode(status)
1211 if smslogger.CheckError(err, "StatusHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001212 http.Error(w, err.Error(), http.StatusInternalServerError)
1213 return
1214 }</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001215}
1216
1217// loginHandler handles login via password and username
1218func (h handler) loginHandler(w http.ResponseWriter, r *http.Request) {<span class="cov0" title="0">
1219
1220}</span>
1221
1222// unsealHandler is a pass through that sends requests from quorum client
1223// to the backend.
1224func (h handler) unsealHandler(w http.ResponseWriter, r *http.Request) <span class="cov0" title="0">{
1225 // Get shards to be used for unseal
1226 type unsealStruct struct {
1227 UnsealShard string `json:"unsealshard"`
1228 }
1229
1230 var inp unsealStruct
1231 decoder := json.NewDecoder(r.Body)
1232 decoder.DisallowUnknownFields()
1233 err := decoder.Decode(&amp;inp)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001234 if smslogger.CheckError(err, "UnsealHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001235 http.Error(w, "Bad input JSON", http.StatusBadRequest)
1236 return
1237 }</span>
1238
1239 <span class="cov0" title="0">err = h.secretBackend.Unseal(inp.UnsealShard)
Kiran Kamineni7597c152018-04-19 21:27:01 -07001240 if smslogger.CheckError(err, "UnsealHandler") != nil </span><span class="cov0" title="0">{
1241 http.Error(w, err.Error(), http.StatusInternalServerError)
1242 return
1243 }</span>
1244}
1245
1246// registerHandler allows the quorum clients to register with SMS
1247// with their PGP public keys that are then used by sms for backend
1248// initialization
1249func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) <span class="cov1" title="1">{
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001250
Kiran Kamineni7597c152018-04-19 21:27:01 -07001251 // Get shards to be used for unseal
1252 type registerStruct struct {
1253 PGPKey string `json:"pgpkey"`
1254 QuorumID string `json:"quorumid"`
1255 }
1256
1257 var inp registerStruct
1258 decoder := json.NewDecoder(r.Body)
1259 decoder.DisallowUnknownFields()
1260 err := decoder.Decode(&amp;inp)
1261 if smslogger.CheckError(err, "RegisterHandler") != nil </span><span class="cov0" title="0">{
1262 http.Error(w, "Bad input JSON", http.StatusBadRequest)
1263 return
1264 }</span>
1265
1266 <span class="cov1" title="1">sh, err := h.secretBackend.RegisterQuorum(inp.PGPKey)
1267 if smslogger.CheckError(err, "RegisterHandler") != nil </span><span class="cov0" title="0">{
1268 http.Error(w, err.Error(), http.StatusInternalServerError)
1269 return
1270 }</span>
1271
1272 // Creating a struct for return data
1273 <span class="cov1" title="1">shStruct := struct {
1274 Shard string `json:"shard"`
1275 }{
1276 sh,
1277 }
1278
1279 w.Header().Set("Content-Type", "application/json")
1280 err = json.NewEncoder(w).Encode(shStruct)
1281 if smslogger.CheckError(err, "RegisterHandler") != nil </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001282 http.Error(w, err.Error(), http.StatusInternalServerError)
1283 return
1284 }</span>
1285}
1286
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001287// healthCheckHandler runs a few commands on the backend and returns
1288// OK or not depending on the status of the backend
1289func (h handler) healthCheckHandler(w http.ResponseWriter, r *http.Request) <span class="cov1" title="1">{
1290
1291 sealed, err := h.secretBackend.GetStatus()
1292 if smslogger.CheckError(err, "HealthCheck") != nil </span><span class="cov0" title="0">{
1293 http.Error(w, err.Error(), http.StatusInternalServerError)
1294 return
1295 }</span>
1296
1297 // backend is sealed
1298 <span class="cov1" title="1">if sealed == true </span><span class="cov0" title="0">{
1299 http.Error(w, "Secret Backend is not ready for operations", http.StatusInternalServerError)
1300 return
1301 }</span>
1302
1303 // backend is not sealed
1304 <span class="cov1" title="1">dname, _ := uuid.GenerateUUID()
1305 dom, err := h.secretBackend.CreateSecretDomain(dname)
1306 if smslogger.CheckError(err, "HealthCheck Create Domain") != nil </span><span class="cov0" title="0">{
1307 http.Error(w, err.Error(), http.StatusInternalServerError)
1308 return
1309 }</span>
1310
1311 <span class="cov1" title="1">err = h.secretBackend.DeleteSecretDomain(dom.UUID)
1312 if smslogger.CheckError(err, "HealthCheck Delete Domain") != nil </span><span class="cov0" title="0">{
1313 http.Error(w, err.Error(), http.StatusInternalServerError)
1314 return
1315 }</span>
1316
1317 <span class="cov1" title="1">w.WriteHeader(http.StatusOK)</span>
1318}
1319
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001320// CreateRouter returns an http.Handler for the registered URLs
1321// Takes an interface implementation as input
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001322func CreateRouter(b smsbackend.SecretBackend) http.Handler <span class="cov6" title="2">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001323 h := handler{secretBackend: b}
1324
1325 // Create a new mux to handle URL endpoints
1326 router := mux.NewRouter()
1327
1328 router.HandleFunc("/v1/sms/login", h.loginHandler).Methods("POST")
1329
1330 // Initialization APIs which will be used by quorum client
1331 // to unseal and to provide root token to sms service
Kiran Kamineni7597c152018-04-19 21:27:01 -07001332 router.HandleFunc("/v1/sms/quorum/status", h.statusHandler).Methods("GET")
1333 router.HandleFunc("/v1/sms/quorum/unseal", h.unsealHandler).Methods("POST")
1334 router.HandleFunc("/v1/sms/quorum/register", h.registerHandler).Methods("POST")
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001335
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001336 router.HandleFunc("/v1/sms/healthcheck", h.healthCheckHandler).Methods("GET")
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001337 router.HandleFunc("/v1/sms/domain", h.createSecretDomainHandler).Methods("POST")
1338 router.HandleFunc("/v1/sms/domain/{domName}", h.deleteSecretDomainHandler).Methods("DELETE")
1339
1340 router.HandleFunc("/v1/sms/domain/{domName}/secret", h.createSecretHandler).Methods("POST")
1341 router.HandleFunc("/v1/sms/domain/{domName}/secret", h.listSecretHandler).Methods("GET")
1342 router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.getSecretHandler).Methods("GET")
1343 router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.deleteSecretHandler).Methods("DELETE")
1344
1345 return router
1346}</span>
1347</pre>
1348
1349 <pre class="file" id="file5" style="display: none">/*
1350 * Copyright 2018 Intel Corporation, Inc
1351 *
1352 * Licensed under the Apache License, Version 2.0 (the "License");
1353 * you may not use this file except in compliance with the License.
1354 * You may obtain a copy of the License at
1355 *
1356 * http://www.apache.org/licenses/LICENSE-2.0
1357 *
1358 * Unless required by applicable law or agreed to in writing, software
1359 * distributed under the License is distributed on an "AS IS" BASIS,
1360 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1361 * See the License for the specific language governing permissions and
1362 * limitations under the License.
1363 */
1364
1365package log
1366
1367import (
Kiran Kamineni7597c152018-04-19 21:27:01 -07001368 "fmt"
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001369 "log"
1370 "os"
1371)
1372
Kiran Kamineni7597c152018-04-19 21:27:01 -07001373var errL, warnL, infoL *log.Logger
1374var stdErr, stdWarn, stdInfo *log.Logger
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001375
1376// Init will be called by sms.go before any other packages use it
Kiran Kamineni7597c152018-04-19 21:27:01 -07001377func Init(filePath string) <span class="cov1" title="1">{
1378
1379 stdErr = log.New(os.Stderr, "ERROR: ", log.Lshortfile|log.LstdFlags)
1380 stdWarn = log.New(os.Stdout, "WARNING: ", log.Lshortfile|log.LstdFlags)
1381 stdInfo = log.New(os.Stdout, "INFO: ", log.Lshortfile|log.LstdFlags)
1382
1383 if filePath == "" </span><span class="cov0" title="0">{
1384 // We will just to std streams
1385 return
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001386 }</span>
Kiran Kamineni7597c152018-04-19 21:27:01 -07001387
1388 <span class="cov1" title="1">f, err := os.Create(filePath)
1389 if err != nil </span><span class="cov0" title="0">{
1390 stdErr.Println("Unable to create log file: " + err.Error())
1391 return
1392 }</span>
1393
1394 <span class="cov1" title="1">errL = log.New(f, "ERROR: ", log.Lshortfile|log.LstdFlags)
1395 warnL = log.New(f, "WARNING: ", log.Lshortfile|log.LstdFlags)
1396 infoL = log.New(f, "INFO: ", log.Lshortfile|log.LstdFlags)</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001397}
1398
1399// WriteError writes output to the writer we have
Kiran Kamineni7597c152018-04-19 21:27:01 -07001400// defined during its creation with ERROR prefix
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001401func WriteError(msg string) <span class="cov0" title="0">{
Kiran Kamineni7597c152018-04-19 21:27:01 -07001402 if errL != nil </span><span class="cov0" title="0">{
1403 errL.Output(2, fmt.Sprintln(msg))
1404 }</span>
1405 <span class="cov0" title="0">if stdErr != nil </span><span class="cov0" title="0">{
1406 stdErr.Output(2, fmt.Sprintln(msg))
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001407 }</span>
1408}
1409
1410// WriteWarn writes output to the writer we have
Kiran Kamineni7597c152018-04-19 21:27:01 -07001411// defined during its creation with WARNING prefix
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001412func WriteWarn(msg string) <span class="cov2" title="2">{
1413 if warnL != nil </span><span class="cov2" title="2">{
Kiran Kamineni7597c152018-04-19 21:27:01 -07001414 warnL.Output(2, fmt.Sprintln(msg))
1415 }</span>
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001416 <span class="cov2" title="2">if stdWarn != nil </span><span class="cov2" title="2">{
Kiran Kamineni7597c152018-04-19 21:27:01 -07001417 stdWarn.Output(2, fmt.Sprintln(msg))
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001418 }</span>
1419}
1420
1421// WriteInfo writes output to the writer we have
Kiran Kamineni7597c152018-04-19 21:27:01 -07001422// defined during its creation with INFO prefix
1423func WriteInfo(msg string) <span class="cov1" title="1">{
1424 if infoL != nil </span><span class="cov1" title="1">{
1425 infoL.Output(2, fmt.Sprintln(msg))
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001426 }</span>
Kiran Kamineni7597c152018-04-19 21:27:01 -07001427 <span class="cov1" title="1">if stdInfo != nil </span><span class="cov1" title="1">{
1428 stdInfo.Output(2, fmt.Sprintln(msg))
1429 }</span>
1430}
1431
1432//CheckError is a helper function to reduce
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001433//repetition of error checking blocks of code
1434func CheckError(err error, topic string) error <span class="cov10" title="55">{
Kiran Kamineni7597c152018-04-19 21:27:01 -07001435 if err != nil </span><span class="cov1" title="1">{
1436 msg := topic + ": " + err.Error()
1437 if errL != nil </span><span class="cov1" title="1">{
1438 errL.Output(2, fmt.Sprintln(msg))
1439 }</span>
1440 <span class="cov1" title="1">if stdErr != nil </span><span class="cov1" title="1">{
1441 stdErr.Output(2, fmt.Sprintln(msg))
1442 }</span>
1443 <span class="cov1" title="1">return err</span>
1444 }
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001445 <span class="cov9" title="54">return nil</span>
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001446}
1447</pre>
1448
1449 <pre class="file" id="file6" style="display: none">/*
1450 * Copyright 2018 Intel Corporation, Inc
1451 *
1452 * Licensed under the Apache License, Version 2.0 (the "License");
1453 * you may not use this file except in compliance with the License.
1454 * You may obtain a copy of the License at
1455 *
1456 * http://www.apache.org/licenses/LICENSE-2.0
1457 *
1458 * Unless required by applicable law or agreed to in writing, software
1459 * distributed under the License is distributed on an "AS IS" BASIS,
1460 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1461 * See the License for the specific language governing permissions and
1462 * limitations under the License.
1463 */
1464
1465package main
1466
1467import (
1468 "context"
1469 "log"
1470 "net/http"
1471 "os"
1472 "os/signal"
1473
1474 smsauth "sms/auth"
1475 smsbackend "sms/backend"
1476 smsconfig "sms/config"
1477 smshandler "sms/handler"
1478 smslogger "sms/log"
1479)
1480
1481func main() <span class="cov8" title="1">{
1482 // Initialize logger
1483 smslogger.Init("sms.log")
1484
1485 // Read Configuration File
1486 smsConf, err := smsconfig.ReadConfigFile("smsconfig.json")
1487 if err != nil </span><span class="cov0" title="0">{
1488 log.Fatal(err)
1489 }</span>
1490
1491 <span class="cov8" title="1">backendImpl, err := smsbackend.InitSecretBackend()
1492 if err != nil </span><span class="cov0" title="0">{
1493 log.Fatal(err)
1494 }</span>
1495
1496 <span class="cov8" title="1">httpRouter := smshandler.CreateRouter(backendImpl)
1497
Kiran Kamineni7597c152018-04-19 21:27:01 -07001498 httpServer := &amp;http.Server{
1499 Handler: httpRouter,
1500 Addr: ":10443",
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001501 }
1502
1503 // Listener for SIGINT so that it returns cleanly
1504 connectionsClose := make(chan struct{})
1505 go func() </span><span class="cov8" title="1">{
1506 c := make(chan os.Signal, 1)
1507 signal.Notify(c, os.Interrupt)
1508 &lt;-c
1509 httpServer.Shutdown(context.Background())
1510 close(connectionsClose)
1511 }</span>()
1512
Kiran Kamineni7597c152018-04-19 21:27:01 -07001513 // Start in TLS mode by default
1514 <span class="cov8" title="1">if smsConf.DisableTLS == true </span><span class="cov0" title="0">{
1515 smslogger.WriteWarn("TLS is Disabled")
1516 err = httpServer.ListenAndServe()
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001517 }</span> else<span class="cov8" title="1"> {
1518 // Populate TLSConfig with the certificates and privatekey
1519 // information
1520 tlsConfig, err := smsauth.GetTLSConfig(smsConf.CAFile, smsConf.ServerCert, smsConf.ServerKey)
1521 if smslogger.CheckError(err, "Get TLS Configuration") != nil </span><span class="cov0" title="0">{
Kiran Kamineni7597c152018-04-19 21:27:01 -07001522 log.Fatal(err)
1523 }</span>
1524
1525 <span class="cov8" title="1">httpServer.TLSConfig = tlsConfig
Kiran Kaminenic660d1b2018-09-20 10:43:28 -07001526 // empty strings because tlsconfig already has this information
1527 err = httpServer.ListenAndServeTLS("", "")</span>
Kiran Kamineni7597c152018-04-19 21:27:01 -07001528 }
1529
1530 <span class="cov8" title="1">if err != nil &amp;&amp; err != http.ErrServerClosed </span><span class="cov0" title="0">{
Kiran Kamineni937a0cd2018-03-23 14:14:10 -07001531 log.Fatal(err)
1532 }</span>
1533
1534 <span class="cov8" title="1">&lt;-connectionsClose</span>
1535}
1536</pre>
1537
1538 </div>
1539 </body>
1540 <script>
1541 (function() {
1542 var files = document.getElementById('files');
1543 var visible;
1544 files.addEventListener('change', onChange, false);
1545 function select(part) {
1546 if (visible)
1547 visible.style.display = 'none';
1548 visible = document.getElementById(part);
1549 if (!visible)
1550 return;
1551 files.value = part;
1552 visible.style.display = 'block';
1553 location.hash = part;
1554 }
1555 function onChange() {
1556 select(files.value);
1557 window.scrollTo(0, 0);
1558 }
1559 if (location.hash != "") {
1560 select(location.hash.substr(1));
1561 }
1562 if (!visible) {
1563 select("file0");
1564 }
1565 })();
1566 </script>
1567</html>