Remove expired certs and key, use them from oom.
[aaf/sms.git] / docs / coverage.html
1
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                                 
57                                 <option value="file0">sms/auth/auth.go (79.8%)</option>
58                                 
59                                 <option value="file1">sms/backend/backend.go (80.0%)</option>
60                                 
61                                 <option value="file2">sms/backend/vault.go (68.6%)</option>
62                                 
63                                 <option value="file3">sms/config/config.go (78.6%)</option>
64                                 
65                                 <option value="file4">sms/handler/handler.go (62.0%)</option>
66                                 
67                                 <option value="file5">sms/log/logger.go (78.1%)</option>
68                                 
69                                 <option value="file6">sms/sms.go (77.8%)</option>
70                                 
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
108 package auth
109
110 import (
111         "bytes"
112         "crypto"
113         "crypto/tls"
114         "crypto/x509"
115         "encoding/base64"
116         "encoding/pem"
117         "golang.org/x/crypto/openpgp"
118         "golang.org/x/crypto/openpgp/packet"
119         "io/ioutil"
120
121         smsconfig "sms/config"
122         smslogger "sms/log"
123 )
124
125 // GetTLSConfig initializes a tlsConfig using the CA's certificate
126 // This config is then used to enable the server for mutual TLS
127 func GetTLSConfig(caCertFile string, certFile string, keyFile string) (*tls.Config, error) <span class="cov8" title="3">{
128
129         // Initialize tlsConfig once
130         caCert, err := ioutil.ReadFile(caCertFile)
131
132         if smslogger.CheckError(err, "Read CA Cert file") != nil </span><span class="cov1" title="1">{
133                 return nil, err
134         }</span>
135
136         <span class="cov5" title="2">caCertPool := x509.NewCertPool()
137         caCertPool.AppendCertsFromPEM(caCert)
138
139         tlsConfig := &amp;tls.Config{
140                 // Change to RequireAndVerify once we have mandatory certs
141                 ClientAuth: tls.VerifyClientCertIfGiven,
142                 ClientCAs:  caCertPool,
143                 MinVersion: tls.VersionTLS12,
144         }
145
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()
163         return tlsConfig, nil</span>
164 }
165
166 func 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
200 // 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
204 func GeneratePGPKeyPair() (string, string, error) <span class="cov8" title="3">{
205
206         var entity *openpgp.Entity
207         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">{
213                 return "", "", err
214         }</span>
215
216         // Sign the identity in the entity
217         <span class="cov8" title="3">for _, id := range entity.Identities </span><span class="cov8" title="3">{
218                 err = id.SelfSignature.SignUserId(id.UserId.Id, entity.PrimaryKey, entity.PrivateKey, nil)
219                 if smslogger.CheckError(err, "Sign Entity") != nil </span><span class="cov0" title="0">{
220                         return "", "", err
221                 }</span>
222         }
223
224         // Sign the subkey in the entity
225         <span class="cov8" title="3">for _, subkey := range entity.Subkeys </span><span class="cov8" title="3">{
226                 err := subkey.Sig.SignKey(subkey.PublicKey, entity.PrivateKey, nil)
227                 if smslogger.CheckError(err, "Sign Subkey") != nil </span><span class="cov0" title="0">{
228                         return "", "", err
229                 }</span>
230         }
231
232         <span class="cov8" title="3">buffer := new(bytes.Buffer)
233         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
243 // EncryptPGPString takes data and a public key and encrypts using that
244 // public key
245 func EncryptPGPString(data string, pbKey string) (string, error) <span class="cov5" title="2">{
246
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
252         <span class="cov5" title="2">dataBytes := []byte(data)
253
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
260         <span class="cov5" title="2">buf := new(bytes.Buffer)
261         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
266         <span class="cov5" title="2">_, err = out.Write(dataBytes)
267         if smslogger.CheckError(err, "Writing to Encryption Pipe") != nil </span><span class="cov0" title="0">{
268                 return "", err
269         }</span>
270
271         <span class="cov5" title="2">err = out.Close()
272         if smslogger.CheckError(err, "Closing Encryption Pipe") != nil </span><span class="cov0" title="0">{
273                 return "", err
274         }</span>
275
276         <span class="cov5" title="2">crp := base64.StdEncoding.EncodeToString(buf.Bytes())
277         return crp, nil</span>
278 }
279
280 // DecryptPGPString decrypts a PGP encoded input string and returns
281 // a base64 representation of the decoded string
282 func DecryptPGPString(data string, prKey string) (string, error) <span class="cov1" title="1">{
283
284         // Convert private key to bytes from base64
285         prKeyBytes, err := base64.StdEncoding.DecodeString(prKey)
286         if smslogger.CheckError(err, "Decoding Base64 Private Key") != nil </span><span class="cov0" title="0">{
287                 return "", err
288         }</span>
289
290         <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">{
292                 return "", err
293         }</span>
294
295         <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">{
297                 return "", err
298         }</span>
299
300         <span class="cov1" title="1">prEntityList := &amp;openpgp.EntityList{prEntity}
301         message, err := openpgp.ReadMessage(bytes.NewBuffer(dataBytes), prEntityList, nil, nil)
302         if smslogger.CheckError(err, "Decrypting Message") != nil </span><span class="cov0" title="0">{
303                 return "", err
304         }</span>
305
306         <span class="cov1" title="1">var retBuf bytes.Buffer
307         retBuf.ReadFrom(message.UnverifiedBody)
308
309         return retBuf.String(), nil</span>
310 }
311
312 // ReadFromFile reads a file and loads the PGP key into
313 // a string
314 func ReadFromFile(fileName string) (string, error) <span class="cov1" title="1">{
315
316         data, err := ioutil.ReadFile(fileName)
317         if smslogger.CheckError(err, "Read from file") != nil </span><span class="cov1" title="1">{
318                 return "", err
319         }</span>
320         <span class="cov0" title="0">return string(data), nil</span>
321 }
322
323 // WriteToFile writes a PGP key into a file.
324 // It will truncate the file if it exists
325 func WriteToFile(data string, fileName string) error <span class="cov5" title="2">{
326
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>
331         <span class="cov5" title="2">return nil</span>
332 }
333 </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
351 package backend
352
353 import (
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
360 type 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
367 type 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
373 type SecretBackend interface {
374         Init() error
375         GetStatus() (bool, error)
376         Unseal(shard string) error
377         RegisterQuorum(pgpkey string) (string, error)
378
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
390 func InitSecretBackend() (SecretBackend, error) <span class="cov8" title="1">{
391         backendImpl := &amp;Vault{
392                 vaultAddress: smsconfig.SMSConfig.BackendAddress,
393                 vaultToken:   smsconfig.SMSConfig.VaultToken,
394         }
395
396         err := backendImpl.Init()
397         if smslogger.CheckError(err, "InitSecretBackend") != nil </span><span class="cov0" title="0">{
398                 return nil, err
399         }</span>
400
401         <span class="cov8" title="1">return backendImpl, nil</span>
402 }
403
404 // LoginBackend Interface that will be implemented for various login backends
405 type 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
425 package backend
426
427 import (
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
441 type Vault struct {
442         sync.Mutex
443         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
456 }
457
458 // 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
462 func (v *Vault) initVaultClient() error <span class="cov7" title="11">{
463
464         vaultCFG := vaultapi.DefaultConfig()
465         vaultCFG.Address = v.vaultAddress
466         client, err := vaultapi.NewClient(vaultCFG)
467         if smslogger.CheckError(err, "Create new vault client") != nil </span><span class="cov0" title="0">{
468                 return err
469         }</span>
470
471         <span class="cov7" title="11">v.initRoleDone = false
472         v.policyName = "smsvaultpolicy"
473         v.vaultClient = client
474         v.vaultMountPrefix = "sms"
475         v.internalDomain = "smsinternaldomain"
476         v.internalDomainMounted = false
477         v.prkey = ""
478         return nil</span>
479 }
480
481 // 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
485 func (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">{
494                 smslogger.WriteInfo("InitRole will try again later")
495         }</span>
496
497         <span class="cov1" title="1">return nil</span>
498 }
499
500 // GetStatus returns the current seal status of vault
501 func (v *Vault) GetStatus() (bool, error) <span class="cov2" title="2">{
502
503         sys := v.vaultClient.Sys()
504         sealStatus, err := sys.SealStatus()
505         if smslogger.CheckError(err, "Getting Status") != nil </span><span class="cov0" title="0">{
506                 return false, errors.New("Error getting status")
507         }</span>
508
509         <span class="cov2" title="2">return sealStatus.Sealed, nil</span>
510 }
511
512 // RegisterQuorum registers the PGP public key for a quorum client
513 // We will return a shard to the client that is registering
514 func (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>
536 }
537
538 // Unseal is a passthrough API that allows any
539 // unseal or initialization processes for the backend
540 func (v *Vault) Unseal(shard string) error <span class="cov0" title="0">{
541
542         sys := v.vaultClient.Sys()
543         _, err := sys.Unseal(shard)
544         if smslogger.CheckError(err, "Unseal Operation") != nil </span><span class="cov0" title="0">{
545                 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
554 func (v *Vault) GetSecret(dom string, name string) (Secret, error) <span class="cov2" title="2">{
555
556         err := v.checkToken()
557         if smslogger.CheckError(err, "Tocken Check") != nil </span><span class="cov0" title="0">{
558                 return Secret{}, errors.New("Token check failed")
559         }</span>
560
561         <span class="cov2" title="2">dom = strings.TrimSpace(dom)
562         dom = v.vaultMountPrefix + "/" + dom
563
564         sec, err := v.vaultClient.Logical().Read(dom + "/" + name)
565         if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{
566                 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
570         <span class="cov2" title="2">if sec == nil </span><span class="cov0" title="0">{
571                 smslogger.WriteWarn("Vault read was empty. Invalid Path")
572                 return Secret{}, errors.New("Secret not found at the provided path")
573         }</span>
574
575         <span class="cov2" title="2">return Secret{Name: name, Values: sec.Data}, nil</span>
576 }
577
578 // ListSecret returns a list of secret names on a particular domain
579 // The values of the secret are not returned
580 func (v *Vault) ListSecret(dom string) ([]string, error) <span class="cov2" title="2">{
581
582         err := v.checkToken()
583         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
584                 return nil, errors.New("Token check failed")
585         }</span>
586
587         <span class="cov2" title="2">dom = strings.TrimSpace(dom)
588         dom = v.vaultMountPrefix + "/" + dom
589
590         sec, err := v.vaultClient.Logical().List(dom)
591         if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{
592                 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
596         <span class="cov2" title="2">if sec == nil </span><span class="cov0" title="0">{
597                 smslogger.WriteWarn("Vaultclient returned empty data")
598                 return nil, errors.New("Secret not found at the provided path")
599         }</span>
600
601         <span class="cov2" title="2">val, ok := sec.Data["keys"].([]interface{})
602         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
607         <span class="cov2" title="2">retval := make([]string, len(val))
608         for i, v := range val </span><span class="cov2" title="2">{
609                 retval[i] = fmt.Sprint(v)
610         }</span>
611
612         <span class="cov2" title="2">return retval, nil</span>
613 }
614
615 // Mounts the internal Domain if its not already mounted
616 func (v *Vault) mountInternalDomain(name string) error <span class="cov5" title="7">{
617
618         if v.internalDomainMounted </span><span class="cov0" title="0">{
619                 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)
633         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">{
635                         // 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
643         <span class="cov5" title="7">v.internalDomainMounted = true
644         return nil</span>
645 }
646
647 // Stores the UUID created for secretdomain in vault
648 // under v.vaultMountPrefix / smsinternal domain
649 func (v *Vault) storeUUID(uuid string, name string) error <span class="cov5" title="7">{
650
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
657         <span class="cov5" title="7">err = v.mountInternalDomain(v.internalDomain)
658         if smslogger.CheckError(err, "Mount Internal Domain") != nil </span><span class="cov0" title="0">{
659                 return err
660         }</span>
661
662         <span class="cov5" title="7">secret := Secret{
663                 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
674         <span class="cov5" title="7">return nil</span>
675 }
676
677 // CreateSecretDomain mounts the kv backend on a path with the given name
678 func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span class="cov5" title="7">{
679
680         // Check if token is still valid
681         err := v.checkToken()
682         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
683                 return SecretDomain{}, errors.New("Token Check failed")
684         }</span>
685
686         <span class="cov5" title="7">name = strings.TrimSpace(name)
687         mountPath := v.vaultMountPrefix + "/" + name
688         mountInput := &amp;vaultapi.MountInput{
689                 Type:        "kv",
690                 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)
697         if smslogger.CheckError(err, "Create Domain") != nil </span><span class="cov0" title="0">{
698                 return SecretDomain{}, errors.New("Unable to create Secret Domain")
699         }</span>
700
701         <span class="cov5" title="7">uuid, _ := uuid.GenerateUUID()
702         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
711         <span class="cov5" title="7">return SecretDomain{uuid, name}, nil</span>
712 }
713
714 // CreateSecret creates a secret mounted on a particular domain name
715 // The secret itself is mounted on a path specified by name
716 func (v *Vault) CreateSecret(dom string, sec Secret) error <span class="cov7" title="12">{
717
718         err := v.checkToken()
719         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
720                 return errors.New("Token check failed")
721         }</span>
722
723         <span class="cov7" title="12">dom = strings.TrimSpace(dom)
724         dom = v.vaultMountPrefix + "/" + dom
725
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)
729         if smslogger.CheckError(err, "Create Secret") != nil </span><span class="cov0" title="0">{
730                 return errors.New("Unable to create Secret at provided path")
731         }</span>
732
733         <span class="cov7" title="12">return nil</span>
734 }
735
736 // DeleteSecretDomain deletes a secret domain which translates to
737 // an unmount operation on the given path in Vault
738 func (v *Vault) DeleteSecretDomain(dom string) error <span class="cov2" title="2">{
739
740         err := v.checkToken()
741         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
742                 return errors.New("Token Check Failed")
743         }</span>
744
745         <span class="cov2" title="2">dom = strings.TrimSpace(dom)
746         mountPath := v.vaultMountPrefix + "/" + dom
747
748         err = v.vaultClient.Sys().Unmount(mountPath)
749         if smslogger.CheckError(err, "Delete Domain") != nil </span><span class="cov0" title="0">{
750                 return errors.New("Unable to delete domain specified")
751         }</span>
752
753         <span class="cov2" title="2">return nil</span>
754 }
755
756 // DeleteSecret deletes a secret mounted on the path provided
757 func (v *Vault) DeleteSecret(dom string, name string) error <span class="cov2" title="2">{
758
759         err := v.checkToken()
760         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
761                 return errors.New("Token check failed")
762         }</span>
763
764         <span class="cov2" title="2">dom = strings.TrimSpace(dom)
765         dom = v.vaultMountPrefix + "/" + dom
766
767         // Vault return is empty on successful delete
768         _, err = v.vaultClient.Logical().Delete(dom + "/" + name)
769         if smslogger.CheckError(err, "Delete Secret") != nil </span><span class="cov0" title="0">{
770                 return errors.New("Unable to delete Secret at provided path")
771         }</span>
772
773         <span class="cov2" title="2">return nil</span>
774 }
775
776 // 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
780 func (v *Vault) initRole() error <span class="cov10" title="36">{
781
782         if v.initRoleDone </span><span class="cov9" title="28">{
783                 return nil
784         }</span>
785
786         // Use the root token once here
787         <span class="cov6" title="8">v.vaultClient.SetToken(v.vaultToken)
788         defer v.vaultClient.ClearToken()
789
790         // Check if roleID and secretID has already been created
791         rID, error := smsauth.ReadFromFile("auth/role")
792         if error != nil </span><span class="cov6" title="8">{
793                 smslogger.WriteWarn("Unable to find RoleID. Generating...")
794         }</span> else<span class="cov0" title="0"> {
795                 sID, error := smsauth.ReadFromFile("auth/secret")
796                 if error != nil </span><span class="cov0" title="0">{
797                         smslogger.WriteWarn("Unable to find secretID. Generating...")
798                 }</span> else<span class="cov0" title="0"> {
799                         v.roleID = rID
800                         v.secretID = sID
801                         v.initRoleDone = true
802                         return nil
803                 }</span>
804         }
805
806         <span class="cov6" title="8">rules := `path "sms/*" { capabilities = ["create", "read", "update", "delete", "list"] }
807                         path "sys/mounts/sms*" { capabilities = ["update","delete","create"] }`
808         err := v.vaultClient.Sys().PutPolicy(v.policyName, rules)
809         if smslogger.CheckError(err, "Creating Policy") != nil </span><span class="cov0" title="0">{
810                 return errors.New("Unable to create policy for approle creation")
811         }</span>
812
813         //Check if applrole is mounted
814         <span class="cov6" title="8">authMounts, err := v.vaultClient.Sys().ListAuth()
815         if smslogger.CheckError(err, "Mount Auth Backend") != nil </span><span class="cov0" title="0">{
816                 return errors.New("Unable to get mounted auth backends")
817         }</span>
818
819         <span class="cov6" title="8">approleMounted := false
820         for k, v := range authMounts </span><span class="cov6" title="8">{
821                 if v.Type == "approle" &amp;&amp; k == "approle/" </span><span class="cov0" title="0">{
822                         approleMounted = true
823                         break</span>
824                 }
825         }
826
827         // Mount approle in case its not already mounted
828         <span class="cov6" title="8">if !approleMounted </span><span class="cov6" title="8">{
829                 v.vaultClient.Sys().EnableAuth("approle", "approle", "")
830         }</span>
831
832         <span class="cov6" title="8">rName := v.vaultMountPrefix + "-role"
833         data := map[string]interface{}{
834                 "token_ttl": "60m",
835                 "policies":  [2]string{"default", v.policyName},
836         }
837
838         // Create a role-id
839         v.vaultClient.Logical().Write("auth/approle/role/"+rName, data)
840         sec, err := v.vaultClient.Logical().Read("auth/approle/role/" + rName + "/role-id")
841         if smslogger.CheckError(err, "Create RoleID") != nil </span><span class="cov0" title="0">{
842                 return errors.New("Unable to create role ID for approle")
843         }</span>
844         <span class="cov6" title="8">v.roleID = sec.Data["role_id"].(string)
845
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{}{})
849         if smslogger.CheckError(err, "Create SecretID") != nil </span><span class="cov0" title="0">{
850                 return errors.New("Unable to create secret ID for role")
851         }</span>
852
853         <span class="cov6" title="8">v.secretID = sec.Data["secret_id"].(string)
854         v.initRoleDone = true
855         /*
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")
863         }</span> else<span class="cov6" title="8"> {
864                 // 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
870         <span class="cov6" title="8">smsauth.WriteToFile(v.roleID, "auth/role")
871         smsauth.WriteToFile(v.secretID, "auth/secret")
872
873         return nil</span>
874 }
875
876 // Function checkToken() gets called multiple times to create
877 // temporary tokens
878 func (v *Vault) checkToken() error <span class="cov9" title="34">{
879
880         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
885         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>
890
891         // Return immediately if token still has life
892         <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">{
894                 return nil
895         }</span>
896
897         // Create a temporary token using our roleID and secretID
898         <span class="cov5" title="7">out, err := v.vaultClient.Logical().Write("auth/approle/login",
899                 map[string]interface{}{"role_id": v.roleID, "secret_id": v.secretID})
900         if smslogger.CheckError(err, "Create Temp Token") != nil </span><span class="cov0" title="0">{
901                 return errors.New("Unable to create Temporary Token for Role")
902         }</span>
903
904         <span class="cov5" title="7">tok, err := out.TokenID()
905
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.
913 func (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,
939                 SecretThreshold: 3,
940         }
941
942         pbkey, prkey, err := smsauth.GeneratePGPKeyPair()
943
944         if smslogger.CheckError(err, "Generating PGP Keys") != nil </span><span class="cov0" title="0">{
945                 smslogger.WriteError("Error Generating PGP Keys. Vault Init will not use encryption!")
946         }</span> else<span class="cov1" title="1"> {
947                 initReq.PGPKeys = []string{pbkey, pbkey, pbkey}
948                 initReq.RootTokenPGPKey = pbkey
949         }</span>
950
951         <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">{
953                 return errors.New("FATAL: Unable to initialize Vault")
954         }</span>
955
956         <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)
960                 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
983 package config
984
985 import (
986         "encoding/json"
987         "os"
988         smslogger "sms/log"
989 )
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
994 type SMSConfiguration struct {
995         CAFile     string `json:"cafile"`
996         ServerCert string `json:"servercert"`
997         ServerKey  string `json:"serverkey"`
998         Password   string `json:"password"`
999
1000         BackendAddress            string `json:"smsdbaddress"`
1001         VaultToken                string `json:"vaulttoken"`
1002         DisableTLS                bool   `json:"disable_tls"`
1003         BackendAddressEnvVariable string `json:"smsdburlenv"`
1004 }
1005
1006 // SMSConfig is the structure that stores the configuration
1007 var SMSConfig *SMSConfiguration
1008
1009 // ReadConfigFile reads the specified smsConfig file to setup some env variables
1010 func 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
1018                 // Default behaviour is to enable TLS
1019                 SMSConfig = &amp;SMSConfiguration{DisableTLS: false}
1020                 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>
1025
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>
1031         }
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
1053 package handler
1054
1055 import (
1056         "encoding/json"
1057         "github.com/gorilla/mux"
1058         "net/http"
1059
1060         uuid "github.com/hashicorp/go-uuid"
1061         smsbackend "sms/backend"
1062         smslogger "sms/log"
1063 )
1064
1065 // handler stores two interface implementations that implement
1066 // the backend functionality
1067 type handler struct {
1068         secretBackend smsbackend.SecretBackend
1069         loginBackend  smsbackend.LoginBackend
1070 }
1071
1072 // createSecretDomainHandler creates a secret domain with a name provided
1073 func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
1074         var d smsbackend.SecretDomain
1075
1076         err := json.NewDecoder(r.Body).Decode(&amp;d)
1077         if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
1078                 http.Error(w, err.Error(), http.StatusBadRequest)
1079                 return
1080         }</span>
1081
1082         <span class="cov6" title="2">dom, err := h.secretBackend.CreateSecretDomain(d.Name)
1083         if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
1084                 http.Error(w, err.Error(), http.StatusInternalServerError)
1085                 return
1086         }</span>
1087
1088         <span class="cov6" title="2">w.Header().Set("Content-Type", "application/json")
1089         w.WriteHeader(http.StatusCreated)
1090         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>
1095 }
1096
1097 // deleteSecretDomainHandler deletes a secret domain with the name provided
1098 func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
1099         vars := mux.Vars(r)
1100         domName := vars["domName"]
1101
1102         err := h.secretBackend.DeleteSecretDomain(domName)
1103         if smslogger.CheckError(err, "DeleteSecretDomainHandler") != nil </span><span class="cov0" title="0">{
1104                 http.Error(w, err.Error(), http.StatusInternalServerError)
1105                 return
1106         }</span>
1107
1108         <span class="cov6" title="2">w.WriteHeader(http.StatusNoContent)</span>
1109 }
1110
1111 // createSecretHandler handles creation of secrets on a given domain name
1112 func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
1113         // 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)
1120         if smslogger.CheckError(err, "CreateSecretHandler") != nil </span><span class="cov0" title="0">{
1121                 http.Error(w, err.Error(), http.StatusBadRequest)
1122                 return
1123         }</span>
1124
1125         <span class="cov6" title="2">err = h.secretBackend.CreateSecret(domName, b)
1126         if smslogger.CheckError(err, "CreateSecretHandler") != nil </span><span class="cov0" title="0">{
1127                 http.Error(w, err.Error(), http.StatusInternalServerError)
1128                 return
1129         }</span>
1130
1131         <span class="cov6" title="2">w.WriteHeader(http.StatusCreated)</span>
1132 }
1133
1134 // getSecretHandler handles reading a secret by given domain name and secret name
1135 func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
1136         vars := mux.Vars(r)
1137         domName := vars["domName"]
1138         secName := vars["secretName"]
1139
1140         sec, err := h.secretBackend.GetSecret(domName, secName)
1141         if smslogger.CheckError(err, "GetSecretHandler") != nil </span><span class="cov0" title="0">{
1142                 http.Error(w, err.Error(), http.StatusInternalServerError)
1143                 return
1144         }</span>
1145
1146         <span class="cov6" title="2">w.Header().Set("Content-Type", "application/json")
1147         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>
1152 }
1153
1154 // listSecretHandler handles listing all secrets under a particular domain name
1155 func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
1156         vars := mux.Vars(r)
1157         domName := vars["domName"]
1158
1159         secList, err := h.secretBackend.ListSecret(domName)
1160         if smslogger.CheckError(err, "ListSecretHandler") != nil </span><span class="cov0" title="0">{
1161                 http.Error(w, err.Error(), http.StatusInternalServerError)
1162                 return
1163         }</span>
1164
1165         // Creating an anonymous struct to store the returned list of data
1166         <span class="cov6" title="2">var retStruct = struct {
1167                 SecretNames []string `json:"secretnames"`
1168         }{
1169                 secList,
1170         }
1171
1172         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">{
1175                 http.Error(w, err.Error(), http.StatusInternalServerError)
1176                 return
1177         }</span>
1178 }
1179
1180 // deleteSecretHandler handles deleting a secret by given domain name and secret name
1181 func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="2">{
1182         vars := mux.Vars(r)
1183         domName := vars["domName"]
1184         secName := vars["secretName"]
1185
1186         err := h.secretBackend.DeleteSecret(domName, secName)
1187         if smslogger.CheckError(err, "DeleteSecretHandler") != nil </span><span class="cov0" title="0">{
1188                 http.Error(w, err.Error(), http.StatusInternalServerError)
1189                 return
1190         }</span>
1191
1192         <span class="cov6" title="2">w.WriteHeader(http.StatusNoContent)</span>
1193 }
1194
1195 // statusHandler returns information related to SMS and SMS backend services
1196 func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) <span class="cov10" title="3">{
1197         s, err := h.secretBackend.GetStatus()
1198         if smslogger.CheckError(err, "StatusHandler") != nil </span><span class="cov0" title="0">{
1199                 http.Error(w, err.Error(), http.StatusInternalServerError)
1200                 return
1201         }</span>
1202
1203         <span class="cov10" title="3">status := struct {
1204                 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">{
1212                 http.Error(w, err.Error(), http.StatusInternalServerError)
1213                 return
1214         }</span>
1215 }
1216
1217 // loginHandler handles login via password and username
1218 func (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.
1224 func (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)
1234         if smslogger.CheckError(err, "UnsealHandler") != nil </span><span class="cov0" title="0">{
1235                 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)
1240         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
1249 func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) <span class="cov1" title="1">{
1250
1251         // 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">{
1282                 http.Error(w, err.Error(), http.StatusInternalServerError)
1283                 return
1284         }</span>
1285 }
1286
1287 // healthCheckHandler runs a few commands on the backend and returns
1288 // OK or not depending on the status of the backend
1289 func (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
1320 // CreateRouter returns an http.Handler for the registered URLs
1321 // Takes an interface implementation as input
1322 func CreateRouter(b smsbackend.SecretBackend) http.Handler <span class="cov6" title="2">{
1323         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
1332         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")
1335
1336         router.HandleFunc("/v1/sms/healthcheck", h.healthCheckHandler).Methods("GET")
1337         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
1365 package log
1366
1367 import (
1368         "fmt"
1369         "log"
1370         "os"
1371 )
1372
1373 var errL, warnL, infoL *log.Logger
1374 var stdErr, stdWarn, stdInfo *log.Logger
1375
1376 // Init will be called by sms.go before any other packages use it
1377 func 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
1386         }</span>
1387
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>
1397 }
1398
1399 // WriteError writes output to the writer we have
1400 // defined during its creation with ERROR prefix
1401 func WriteError(msg string) <span class="cov0" title="0">{
1402         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))
1407         }</span>
1408 }
1409
1410 // WriteWarn writes output to the writer we have
1411 // defined during its creation with WARNING prefix
1412 func WriteWarn(msg string) <span class="cov2" title="2">{
1413         if warnL != nil </span><span class="cov2" title="2">{
1414                 warnL.Output(2, fmt.Sprintln(msg))
1415         }</span>
1416         <span class="cov2" title="2">if stdWarn != nil </span><span class="cov2" title="2">{
1417                 stdWarn.Output(2, fmt.Sprintln(msg))
1418         }</span>
1419 }
1420
1421 // WriteInfo writes output to the writer we have
1422 // defined during its creation with INFO prefix
1423 func 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))
1426         }</span>
1427         <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
1433 //repetition of error checking blocks of code
1434 func CheckError(err error, topic string) error <span class="cov10" title="55">{
1435         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         }
1445         <span class="cov9" title="54">return nil</span>
1446 }
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
1465 package main
1466
1467 import (
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
1481 func 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
1498         httpServer := &amp;http.Server{
1499                 Handler: httpRouter,
1500                 Addr:    ":10443",
1501         }
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
1513         // 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()
1517         }</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">{
1522                         log.Fatal(err)
1523                 }</span>
1524
1525                 <span class="cov8" title="1">httpServer.TLSConfig = tlsConfig
1526                 // empty strings because tlsconfig already has this information
1527                 err = httpServer.ListenAndServeTLS("", "")</span>
1528         }
1529
1530         <span class="cov8" title="1">if err != nil &amp;&amp; err != http.ErrServerClosed </span><span class="cov0" title="0">{
1531                 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>