Adding a docs folder under sms repo
[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 (76.1%)</option>
58                                 
59                                 <option value="file1">sms/backend/backend.go (80.0%)</option>
60                                 
61                                 <option value="file2">sms/backend/vault.go (72.5%)</option>
62                                 
63                                 <option value="file3">sms/config/config.go (78.6%)</option>
64                                 
65                                 <option value="file4">sms/handler/handler.go (63.0%)</option>
66                                 
67                                 <option value="file5">sms/log/logger.go (65.6%)</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         "golang.org/x/crypto/openpgp"
117         "golang.org/x/crypto/openpgp/packet"
118         "io/ioutil"
119
120         smslogger "sms/log"
121 )
122
123 // GetTLSConfig initializes a tlsConfig using the CA's certificate
124 // This config is then used to enable the server for mutual TLS
125 func GetTLSConfig(caCertFile string) (*tls.Config, error) <span class="cov10" title="3">{
126
127         // Initialize tlsConfig once
128         caCert, err := ioutil.ReadFile(caCertFile)
129
130         if err != nil </span><span class="cov1" title="1">{
131                 return nil, err
132         }</span>
133
134         <span class="cov6" title="2">caCertPool := x509.NewCertPool()
135         caCertPool.AppendCertsFromPEM(caCert)
136
137         tlsConfig := &amp;tls.Config{
138                 // Change to RequireAndVerify once we have mandatory certs
139                 ClientAuth: tls.VerifyClientCertIfGiven,
140                 ClientCAs:  caCertPool,
141                 MinVersion: tls.VersionTLS12,
142         }
143         tlsConfig.BuildNameToCertificate()
144         return tlsConfig, nil</span>
145 }
146
147 // GeneratePGPKeyPair produces a PGP key pair and returns
148 // two things:
149 // A base64 encoded form of the public part of the entity
150 // A base64 encoded form of the private key
151 func GeneratePGPKeyPair() (string, string, error) <span class="cov10" title="3">{
152
153         var entity *openpgp.Entity
154         config := &amp;packet.Config{
155                 DefaultHash: crypto.SHA256,
156         }
157
158         entity, err := openpgp.NewEntity("aaf.sms.init", "PGP Key for unsealing", "", config)
159         if smslogger.CheckError(err, "Create Entity") != nil </span><span class="cov0" title="0">{
160                 return "", "", err
161         }</span>
162
163         // Sign the identity in the entity
164         <span class="cov10" title="3">for _, id := range entity.Identities </span><span class="cov10" title="3">{
165                 err = id.SelfSignature.SignUserId(id.UserId.Id, entity.PrimaryKey, entity.PrivateKey, nil)
166                 if smslogger.CheckError(err, "Sign Entity") != nil </span><span class="cov0" title="0">{
167                         return "", "", err
168                 }</span>
169         }
170
171         // Sign the subkey in the entity
172         <span class="cov10" title="3">for _, subkey := range entity.Subkeys </span><span class="cov10" title="3">{
173                 err := subkey.Sig.SignKey(subkey.PublicKey, entity.PrivateKey, nil)
174                 if smslogger.CheckError(err, "Sign Subkey") != nil </span><span class="cov0" title="0">{
175                         return "", "", err
176                 }</span>
177         }
178
179         <span class="cov10" title="3">buffer := new(bytes.Buffer)
180         entity.Serialize(buffer)
181         pbkey := base64.StdEncoding.EncodeToString(buffer.Bytes())
182
183         buffer.Reset()
184         entity.SerializePrivate(buffer, nil)
185         prkey := base64.StdEncoding.EncodeToString(buffer.Bytes())
186
187         return pbkey, prkey, nil</span>
188 }
189
190 // EncryptPGPString takes data and a public key and encrypts using that
191 // public key
192 func EncryptPGPString(data string, pbKey string) (string, error) <span class="cov6" title="2">{
193
194         pbKeyBytes, err := base64.StdEncoding.DecodeString(pbKey)
195         if smslogger.CheckError(err, "Decoding Base64 Public Key") != nil </span><span class="cov0" title="0">{
196                 return "", err
197         }</span>
198
199         <span class="cov6" title="2">dataBytes := []byte(data)
200
201         pbEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(pbKeyBytes)))
202         if smslogger.CheckError(err, "Reading entity from PGP key") != nil </span><span class="cov0" title="0">{
203                 return "", err
204         }</span>
205
206         // encrypt string
207         <span class="cov6" title="2">buf := new(bytes.Buffer)
208         out, err := openpgp.Encrypt(buf, []*openpgp.Entity{pbEntity}, nil, nil, nil)
209         if smslogger.CheckError(err, "Creating Encryption Pipe") != nil </span><span class="cov0" title="0">{
210                 return "", err
211         }</span>
212
213         <span class="cov6" title="2">_, err = out.Write(dataBytes)
214         if smslogger.CheckError(err, "Writing to Encryption Pipe") != nil </span><span class="cov0" title="0">{
215                 return "", err
216         }</span>
217
218         <span class="cov6" title="2">err = out.Close()
219         if smslogger.CheckError(err, "Closing Encryption Pipe") != nil </span><span class="cov0" title="0">{
220                 return "", err
221         }</span>
222
223         <span class="cov6" title="2">crp := base64.StdEncoding.EncodeToString(buf.Bytes())
224         return crp, nil</span>
225 }
226
227 // DecryptPGPString decrypts a PGP encoded input string and returns
228 // a base64 representation of the decoded string
229 func DecryptPGPString(data string, prKey string) (string, error) <span class="cov1" title="1">{
230
231         // Convert private key to bytes from base64
232         prKeyBytes, err := base64.StdEncoding.DecodeString(prKey)
233         if smslogger.CheckError(err, "Decoding Base64 Private Key") != nil </span><span class="cov0" title="0">{
234                 return "", err
235         }</span>
236
237         <span class="cov1" title="1">dataBytes, err := base64.StdEncoding.DecodeString(data)
238         if smslogger.CheckError(err, "Decoding base64 data") != nil </span><span class="cov0" title="0">{
239                 return "", err
240         }</span>
241
242         <span class="cov1" title="1">prEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(prKeyBytes)))
243         if smslogger.CheckError(err, "Read Entity") != nil </span><span class="cov0" title="0">{
244                 return "", err
245         }</span>
246
247         <span class="cov1" title="1">prEntityList := &amp;openpgp.EntityList{prEntity}
248         message, err := openpgp.ReadMessage(bytes.NewBuffer(dataBytes), prEntityList, nil, nil)
249         if smslogger.CheckError(err, "Decrypting Message") != nil </span><span class="cov0" title="0">{
250                 return "", err
251         }</span>
252
253         <span class="cov1" title="1">var retBuf bytes.Buffer
254         retBuf.ReadFrom(message.UnverifiedBody)
255
256         return retBuf.String(), nil</span>
257 }
258
259 // ReadFromFile reads a file and loads the PGP key into
260 // a string
261 func ReadFromFile(fileName string) (string, error) <span class="cov6" title="2">{
262
263         data, err := ioutil.ReadFile(fileName)
264         if smslogger.CheckError(err, "Read from file") != nil </span><span class="cov0" title="0">{
265                 return "", err
266         }</span>
267         <span class="cov6" title="2">return string(data), nil</span>
268 }
269
270 // WriteToFile writes a PGP key into a file.
271 // It will truncate the file if it exists
272 func WriteToFile(data string, fileName string) error <span class="cov0" title="0">{
273
274         err := ioutil.WriteFile(fileName, []byte(data), 0600)
275         if smslogger.CheckError(err, "Write to file") != nil </span><span class="cov0" title="0">{
276                 return err
277         }</span>
278         <span class="cov0" title="0">return nil</span>
279 }
280 </pre>
281                 
282                 <pre class="file" id="file1" style="display: none">/*
283  * Copyright 2018 Intel Corporation, Inc
284  *
285  * Licensed under the Apache License, Version 2.0 (the "License");
286  * you may not use this file except in compliance with the License.
287  * You may obtain a copy of the License at
288  *
289  *     http://www.apache.org/licenses/LICENSE-2.0
290  *
291  * Unless required by applicable law or agreed to in writing, software
292  * distributed under the License is distributed on an "AS IS" BASIS,
293  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
294  * See the License for the specific language governing permissions and
295  * limitations under the License.
296  */
297
298 package backend
299
300 import (
301         smsconfig "sms/config"
302         smslogger "sms/log"
303 )
304
305 // SecretDomain is where Secrets are stored.
306 // A single domain can have any number of secrets
307 type SecretDomain struct {
308         UUID string `json:"uuid"`
309         Name string `json:"name"`
310 }
311
312 // Secret is the struct that defines the structure of a secret
313 // It consists of a name and map containing key value pairs
314 type Secret struct {
315         Name   string                 `json:"name"`
316         Values map[string]interface{} `json:"values"`
317 }
318
319 // SecretBackend interface that will be implemented for various secret backends
320 type SecretBackend interface {
321         Init() error
322         GetStatus() (bool, error)
323         Unseal(shard string) error
324         RegisterQuorum(pgpkey string) (string, error)
325
326         GetSecret(dom string, sec string) (Secret, error)
327         ListSecret(dom string) ([]string, error)
328
329         CreateSecretDomain(name string) (SecretDomain, error)
330         CreateSecret(dom string, sec Secret) error
331
332         DeleteSecretDomain(name string) error
333         DeleteSecret(dom string, name string) error
334 }
335
336 // InitSecretBackend returns an interface implementation
337 func InitSecretBackend() (SecretBackend, error) <span class="cov8" title="1">{
338         backendImpl := &amp;Vault{
339                 vaultAddress: smsconfig.SMSConfig.BackendAddress,
340                 vaultToken:   smsconfig.SMSConfig.VaultToken,
341         }
342
343         err := backendImpl.Init()
344         if smslogger.CheckError(err, "InitSecretBackend") != nil </span><span class="cov0" title="0">{
345                 return nil, err
346         }</span>
347
348         <span class="cov8" title="1">return backendImpl, nil</span>
349 }
350
351 // LoginBackend Interface that will be implemented for various login backends
352 type LoginBackend interface {
353 }
354 </pre>
355                 
356                 <pre class="file" id="file2" style="display: none">/*
357  * Copyright 2018 Intel Corporation, Inc
358  *
359  * Licensed under the Apache License, Version 2.0 (the "License");
360  * you may not use this file except in compliance with the License.
361  * You may obtain a copy of the License at
362  *
363  *     http://www.apache.org/licenses/LICENSE-2.0
364  *
365  * Unless required by applicable law or agreed to in writing, software
366  * distributed under the License is distributed on an "AS IS" BASIS,
367  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
368  * See the License for the specific language governing permissions and
369  * limitations under the License.
370  */
371
372 package backend
373
374 import (
375         uuid "github.com/hashicorp/go-uuid"
376         vaultapi "github.com/hashicorp/vault/api"
377         smsauth "sms/auth"
378         smslogger "sms/log"
379
380         "errors"
381         "fmt"
382         "strings"
383         "sync"
384         "time"
385 )
386
387 // Vault is the main Struct used in Backend to initialize the struct
388 type Vault struct {
389         sync.Mutex
390         initRoleDone          bool
391         policyName            string
392         roleID                string
393         secretID              string
394         vaultAddress          string
395         vaultClient           *vaultapi.Client
396         vaultMountPrefix      string
397         internalDomain        string
398         internalDomainMounted bool
399         vaultTempTokenTTL     time.Time
400         vaultToken            string
401         shards                []string
402         prkey                 string
403 }
404
405 // initVaultClient will create the initial
406 // Vault strcuture and populate it with the
407 // right values and it will also create
408 // a vault client
409 func (v *Vault) initVaultClient() error <span class="cov6" title="11">{
410
411         vaultCFG := vaultapi.DefaultConfig()
412         vaultCFG.Address = v.vaultAddress
413         client, err := vaultapi.NewClient(vaultCFG)
414         if smslogger.CheckError(err, "Create new vault client") != nil </span><span class="cov0" title="0">{
415                 return err
416         }</span>
417
418         <span class="cov6" title="11">v.initRoleDone = false
419         v.policyName = "smsvaultpolicy"
420         v.vaultClient = client
421         v.vaultMountPrefix = "sms"
422         v.internalDomain = "smsinternaldomain"
423         v.internalDomainMounted = false
424         v.prkey = ""
425         return nil</span>
426 }
427
428 // Init will initialize the vault connection
429 // It will also initialize vault if it is not
430 // already initialized.
431 // The initial policy will also be created
432 func (v *Vault) Init() error <span class="cov1" title="1">{
433
434         v.initVaultClient()
435         // Initialize vault if it is not already
436         // Returns immediately if it is initialized
437         v.initializeVault()
438
439         err := v.initRole()
440         if smslogger.CheckError(err, "InitRole First Attempt") != nil </span><span class="cov0" title="0">{
441                 smslogger.WriteInfo("InitRole will try again later")
442         }</span>
443
444         <span class="cov1" title="1">return nil</span>
445 }
446
447 // GetStatus returns the current seal status of vault
448 func (v *Vault) GetStatus() (bool, error) <span class="cov3" title="3">{
449
450         sys := v.vaultClient.Sys()
451         sealStatus, err := sys.SealStatus()
452         if smslogger.CheckError(err, "Getting Status") != nil </span><span class="cov0" title="0">{
453                 return false, errors.New("Error getting status")
454         }</span>
455
456         <span class="cov3" title="3">return sealStatus.Sealed, nil</span>
457 }
458
459 // RegisterQuorum registers the PGP public key for a quorum client
460 // We will return a shard to the client that is registering
461 func (v *Vault) RegisterQuorum(pgpkey string) (string, error) <span class="cov0" title="0">{
462
463         v.Lock()
464         defer v.Unlock()
465
466         if v.shards == nil </span><span class="cov0" title="0">{
467                 smslogger.WriteError("Invalid operation in RegisterQuorum")
468                 return "", errors.New("Invalid operation")
469         }</span>
470         // Pop the slice
471         <span class="cov0" title="0">var sh string
472         sh, v.shards = v.shards[len(v.shards)-1], v.shards[:len(v.shards)-1]
473         if len(v.shards) == 0 </span><span class="cov0" title="0">{
474                 v.shards = nil
475         }</span>
476
477         // Decrypt with SMS pgp Key
478         <span class="cov0" title="0">sh, _ = smsauth.DecryptPGPString(sh, v.prkey)
479         // Encrypt with Quorum client pgp key
480         sh, _ = smsauth.EncryptPGPString(sh, pgpkey)
481
482         return sh, nil</span>
483 }
484
485 // Unseal is a passthrough API that allows any
486 // unseal or initialization processes for the backend
487 func (v *Vault) Unseal(shard string) error <span class="cov0" title="0">{
488
489         sys := v.vaultClient.Sys()
490         _, err := sys.Unseal(shard)
491         if smslogger.CheckError(err, "Unseal Operation") != nil </span><span class="cov0" title="0">{
492                 return errors.New("Unable to execute unseal operation with specified shard")
493         }</span>
494
495         <span class="cov0" title="0">return nil</span>
496 }
497
498 // GetSecret returns a secret mounted on a particular domain name
499 // The secret itself is referenced via its name which translates to
500 // a mount path in vault
501 func (v *Vault) GetSecret(dom string, name string) (Secret, error) <span class="cov5" title="7">{
502
503         err := v.checkToken()
504         if smslogger.CheckError(err, "Tocken Check") != nil </span><span class="cov0" title="0">{
505                 return Secret{}, errors.New("Token check failed")
506         }</span>
507
508         <span class="cov5" title="7">dom = v.vaultMountPrefix + "/" + dom
509
510         sec, err := v.vaultClient.Logical().Read(dom + "/" + name)
511         if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{
512                 return Secret{}, errors.New("Unable to read Secret at provided path")
513         }</span>
514
515         // sec and err are nil in the case where a path does not exist
516         <span class="cov5" title="7">if sec == nil </span><span class="cov0" title="0">{
517                 smslogger.WriteWarn("Vault read was empty. Invalid Path")
518                 return Secret{}, errors.New("Secret not found at the provided path")
519         }</span>
520
521         <span class="cov5" title="7">return Secret{Name: name, Values: sec.Data}, nil</span>
522 }
523
524 // ListSecret returns a list of secret names on a particular domain
525 // The values of the secret are not returned
526 func (v *Vault) ListSecret(dom string) ([]string, error) <span class="cov3" title="3">{
527
528         err := v.checkToken()
529         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
530                 return nil, errors.New("Token check failed")
531         }</span>
532
533         <span class="cov3" title="3">dom = v.vaultMountPrefix + "/" + dom
534
535         sec, err := v.vaultClient.Logical().List(dom)
536         if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{
537                 return nil, errors.New("Unable to read Secret at provided path")
538         }</span>
539
540         // sec and err are nil in the case where a path does not exist
541         <span class="cov3" title="3">if sec == nil </span><span class="cov0" title="0">{
542                 smslogger.WriteWarn("Vaultclient returned empty data")
543                 return nil, errors.New("Secret not found at the provided path")
544         }</span>
545
546         <span class="cov3" title="3">val, ok := sec.Data["keys"].([]interface{})
547         if !ok </span><span class="cov0" title="0">{
548                 smslogger.WriteError("Secret not found at the provided path")
549                 return nil, errors.New("Secret not found at the provided path")
550         }</span>
551
552         <span class="cov3" title="3">retval := make([]string, len(val))
553         for i, v := range val </span><span class="cov5" title="7">{
554                 retval[i] = fmt.Sprint(v)
555         }</span>
556
557         <span class="cov3" title="3">return retval, nil</span>
558 }
559
560 // Mounts the internal Domain if its not already mounted
561 func (v *Vault) mountInternalDomain(name string) error <span class="cov5" title="8">{
562
563         if v.internalDomainMounted </span><span class="cov1" title="1">{
564                 return nil
565         }</span>
566
567         <span class="cov5" title="7">name = strings.TrimSpace(name)
568         mountPath := v.vaultMountPrefix + "/" + name
569         mountInput := &amp;vaultapi.MountInput{
570                 Type:        "kv",
571                 Description: "Mount point for domain: " + name,
572                 Local:       false,
573                 SealWrap:    false,
574                 Config:      vaultapi.MountConfigInput{},
575         }
576
577         err := v.vaultClient.Sys().Mount(mountPath, mountInput)
578         if smslogger.CheckError(err, "Mount internal Domain") != nil </span><span class="cov1" title="1">{
579                 if strings.Contains(err.Error(), "existing mount") </span><span class="cov1" title="1">{
580                         // It is already mounted
581                         v.internalDomainMounted = true
582                         return nil
583                 }</span>
584                 // Ran into some other error mounting it.
585                 <span class="cov0" title="0">return errors.New("Unable to mount internal Domain")</span>
586         }
587
588         <span class="cov5" title="6">v.internalDomainMounted = true
589         return nil</span>
590 }
591
592 // Stores the UUID created for secretdomain in vault
593 // under v.vaultMountPrefix / smsinternal domain
594 func (v *Vault) storeUUID(uuid string, name string) error <span class="cov5" title="8">{
595
596         // Check if token is still valid
597         err := v.checkToken()
598         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
599                 return errors.New("Token Check failed")
600         }</span>
601
602         <span class="cov5" title="8">err = v.mountInternalDomain(v.internalDomain)
603         if smslogger.CheckError(err, "Mount Internal Domain") != nil </span><span class="cov0" title="0">{
604                 return err
605         }</span>
606
607         <span class="cov5" title="8">secret := Secret{
608                 Name: name,
609                 Values: map[string]interface{}{
610                         "uuid": uuid,
611                 },
612         }
613
614         err = v.CreateSecret(v.internalDomain, secret)
615         if smslogger.CheckError(err, "Write UUID to domain") != nil </span><span class="cov0" title="0">{
616                 return err
617         }</span>
618
619         <span class="cov5" title="8">return nil</span>
620 }
621
622 // CreateSecretDomain mounts the kv backend on a path with the given name
623 func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span class="cov5" title="8">{
624
625         // Check if token is still valid
626         err := v.checkToken()
627         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
628                 return SecretDomain{}, errors.New("Token Check failed")
629         }</span>
630
631         <span class="cov5" title="8">name = strings.TrimSpace(name)
632         mountPath := v.vaultMountPrefix + "/" + name
633         mountInput := &amp;vaultapi.MountInput{
634                 Type:        "kv",
635                 Description: "Mount point for domain: " + name,
636                 Local:       false,
637                 SealWrap:    false,
638                 Config:      vaultapi.MountConfigInput{},
639         }
640
641         err = v.vaultClient.Sys().Mount(mountPath, mountInput)
642         if smslogger.CheckError(err, "Create Domain") != nil </span><span class="cov0" title="0">{
643                 return SecretDomain{}, errors.New("Unable to create Secret Domain")
644         }</span>
645
646         <span class="cov5" title="8">uuid, _ := uuid.GenerateUUID()
647         err = v.storeUUID(uuid, name)
648         if smslogger.CheckError(err, "Store UUID") != nil </span><span class="cov0" title="0">{
649                 // Mount was successful at this point.
650                 // Rollback the mount operation since we could not
651                 // store the UUID for the mount.
652                 v.vaultClient.Sys().Unmount(mountPath)
653                 return SecretDomain{}, errors.New("Unable to store Secret Domain UUID. Retry")
654         }</span>
655
656         <span class="cov5" title="8">return SecretDomain{uuid, name}, nil</span>
657 }
658
659 // CreateSecret creates a secret mounted on a particular domain name
660 // The secret itself is mounted on a path specified by name
661 func (v *Vault) CreateSecret(dom string, sec Secret) error <span class="cov7" title="18">{
662
663         err := v.checkToken()
664         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
665                 return errors.New("Token check failed")
666         }</span>
667
668         <span class="cov7" title="18">dom = v.vaultMountPrefix + "/" + dom
669
670         // Vault return is empty on successful write
671         // TODO: Check if values is not empty
672         _, err = v.vaultClient.Logical().Write(dom+"/"+sec.Name, sec.Values)
673         if smslogger.CheckError(err, "Create Secret") != nil </span><span class="cov0" title="0">{
674                 return errors.New("Unable to create Secret at provided path")
675         }</span>
676
677         <span class="cov7" title="18">return nil</span>
678 }
679
680 // DeleteSecretDomain deletes a secret domain which translates to
681 // an unmount operation on the given path in Vault
682 func (v *Vault) DeleteSecretDomain(name string) error <span class="cov3" title="3">{
683
684         err := v.checkToken()
685         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
686                 return errors.New("Token Check Failed")
687         }</span>
688
689         <span class="cov3" title="3">name = strings.TrimSpace(name)
690         mountPath := v.vaultMountPrefix + "/" + name
691
692         err = v.vaultClient.Sys().Unmount(mountPath)
693         if smslogger.CheckError(err, "Delete Domain") != nil </span><span class="cov0" title="0">{
694                 return errors.New("Unable to delete domain specified")
695         }</span>
696
697         <span class="cov3" title="3">return nil</span>
698 }
699
700 // DeleteSecret deletes a secret mounted on the path provided
701 func (v *Vault) DeleteSecret(dom string, name string) error <span class="cov5" title="7">{
702
703         err := v.checkToken()
704         if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
705                 return errors.New("Token check failed")
706         }</span>
707
708         <span class="cov5" title="7">dom = v.vaultMountPrefix + "/" + dom
709
710         // Vault return is empty on successful delete
711         _, err = v.vaultClient.Logical().Delete(dom + "/" + name)
712         if smslogger.CheckError(err, "Delete Secret") != nil </span><span class="cov0" title="0">{
713                 return errors.New("Unable to delete Secret at provided path")
714         }</span>
715
716         <span class="cov5" title="7">return nil</span>
717 }
718
719 // initRole is called only once during SMS bring up
720 // It initially creates a role and secret id associated with
721 // that role. Later restarts will use the existing role-id
722 // and secret-id stored on disk
723 func (v *Vault) initRole() error <span class="cov10" title="56">{
724
725         if v.initRoleDone </span><span class="cov9" title="48">{
726                 return nil
727         }</span>
728
729         // Use the root token once here
730         <span class="cov5" title="8">v.vaultClient.SetToken(v.vaultToken)
731         defer v.vaultClient.ClearToken()
732
733         // Check if roleID and secretID has already been created
734         rID, error := smsauth.ReadFromFile("auth/role")
735         if error != nil </span><span class="cov5" title="7">{
736                 smslogger.WriteWarn("Unable to find RoleID. Generating...")
737         }</span><span class="cov1" title="1"> else {
738                 sID, error := smsauth.ReadFromFile("auth/secret")
739                 if error != nil </span><span class="cov0" title="0">{
740                         smslogger.WriteWarn("Unable to find secretID. Generating...")
741                 }</span><span class="cov1" title="1"> else {
742                         v.roleID = rID
743                         v.secretID = sID
744                         v.initRoleDone = true
745                         return nil
746                 }</span>
747         }
748
749         <span class="cov5" title="7">rules := `path "sms/*" { capabilities = ["create", "read", "update", "delete", "list"] }
750                         path "sys/mounts/sms*" { capabilities = ["update","delete","create"] }`
751         err := v.vaultClient.Sys().PutPolicy(v.policyName, rules)
752         if smslogger.CheckError(err, "Creating Policy") != nil </span><span class="cov0" title="0">{
753                 return errors.New("Unable to create policy for approle creation")
754         }</span>
755
756         //Check if applrole is mounted
757         <span class="cov5" title="7">authMounts, err := v.vaultClient.Sys().ListAuth()
758         if smslogger.CheckError(err, "Mount Auth Backend") != nil </span><span class="cov0" title="0">{
759                 return errors.New("Unable to get mounted auth backends")
760         }</span>
761
762         <span class="cov5" title="7">approleMounted := false
763         for k, v := range authMounts </span><span class="cov5" title="7">{
764                 if v.Type == "approle" &amp;&amp; k == "approle/" </span><span class="cov0" title="0">{
765                         approleMounted = true
766                         break</span>
767                 }
768         }
769
770         // Mount approle in case its not already mounted
771         <span class="cov5" title="7">if !approleMounted </span><span class="cov5" title="7">{
772                 v.vaultClient.Sys().EnableAuth("approle", "approle", "")
773         }</span>
774
775         <span class="cov5" title="7">rName := v.vaultMountPrefix + "-role"
776         data := map[string]interface{}{
777                 "token_ttl": "60m",
778                 "policies":  [2]string{"default", v.policyName},
779         }
780
781         // Create a role-id
782         v.vaultClient.Logical().Write("auth/approle/role/"+rName, data)
783         sec, err := v.vaultClient.Logical().Read("auth/approle/role/" + rName + "/role-id")
784         if smslogger.CheckError(err, "Create RoleID") != nil </span><span class="cov0" title="0">{
785                 return errors.New("Unable to create role ID for approle")
786         }</span>
787         <span class="cov5" title="7">v.roleID = sec.Data["role_id"].(string)
788
789         // Create a secret-id to go with it
790         sec, err = v.vaultClient.Logical().Write("auth/approle/role/"+rName+"/secret-id",
791                 map[string]interface{}{})
792         if smslogger.CheckError(err, "Create SecretID") != nil </span><span class="cov0" title="0">{
793                 return errors.New("Unable to create secret ID for role")
794         }</span>
795
796         <span class="cov5" title="7">v.secretID = sec.Data["secret_id"].(string)
797         v.initRoleDone = true
798         /*
799         * Revoke the Root token.
800         * If a new Root Token is needed, it will need to be created
801         * using the unseal shards.
802          */
803         err = v.vaultClient.Auth().Token().RevokeSelf(v.vaultToken)
804         if smslogger.CheckError(err, "Revoke Root Token") != nil </span><span class="cov0" title="0">{
805                 smslogger.WriteWarn("Unable to Revoke Token")
806         }</span><span class="cov5" title="7"> else {
807                 // Revoked successfully and clear it
808                 v.vaultToken = ""
809         }</span>
810
811         // Store the role-id and secret-id
812         // We will need this if SMS restarts
813         <span class="cov5" title="7">smsauth.WriteToFile(v.roleID, "auth/role")
814         smsauth.WriteToFile(v.secretID, "auth/secret")
815
816         return nil</span>
817 }
818
819 // Function checkToken() gets called multiple times to create
820 // temporary tokens
821 func (v *Vault) checkToken() error <span class="cov9" title="54">{
822
823         v.Lock()
824         defer v.Unlock()
825
826         // Init Role if it is not yet done
827         // Role needs to be created before token can be created
828         err := v.initRole()
829         if err != nil </span><span class="cov0" title="0">{
830                 smslogger.WriteError(err.Error())
831                 return errors.New("Unable to initRole in checkToken")
832         }</span>
833
834         // Return immediately if token still has life
835         <span class="cov9" title="54">if v.vaultClient.Token() != "" &amp;&amp;
836                 time.Since(v.vaultTempTokenTTL) &lt; time.Minute*50 </span><span class="cov9" title="47">{
837                 return nil
838         }</span>
839
840         // Create a temporary token using our roleID and secretID
841         <span class="cov5" title="7">out, err := v.vaultClient.Logical().Write("auth/approle/login",
842                 map[string]interface{}{"role_id": v.roleID, "secret_id": v.secretID})
843         if smslogger.CheckError(err, "Create Temp Token") != nil </span><span class="cov0" title="0">{
844                 return errors.New("Unable to create Temporary Token for Role")
845         }</span>
846
847         <span class="cov5" title="7">tok, err := out.TokenID()
848
849         v.vaultTempTokenTTL = time.Now()
850         v.vaultClient.SetToken(tok)
851         return nil</span>
852 }
853
854 // vaultInit() is used to initialize the vault in cases where it is not
855 // initialized. This happens once during intial bring up.
856 func (v *Vault) initializeVault() error <span class="cov2" title="2">{
857
858         // Check for vault init status and don't exit till it is initialized
859         for </span><span class="cov2" title="2">{
860                 init, err := v.vaultClient.Sys().InitStatus()
861                 if smslogger.CheckError(err, "Get Vault Init Status") != nil </span><span class="cov0" title="0">{
862                         smslogger.WriteInfo("Trying again in 10s...")
863                         time.Sleep(time.Second * 10)
864                         continue</span>
865                 }
866                 // Did not get any error
867                 <span class="cov2" title="2">if init == true </span><span class="cov1" title="1">{
868                         smslogger.WriteInfo("Vault is already Initialized")
869                         return nil
870                 }</span>
871
872                 // init status is false
873                 // break out of loop and finish initialization
874                 <span class="cov1" title="1">smslogger.WriteInfo("Vault is not initialized. Initializing...")
875                 break</span>
876         }
877
878         // Hardcoded this to 3. We should make this configurable
879         // in the future
880         <span class="cov1" title="1">initReq := &amp;vaultapi.InitRequest{
881                 SecretShares:    3,
882                 SecretThreshold: 3,
883         }
884
885         pbkey, prkey, err := smsauth.GeneratePGPKeyPair()
886
887         if smslogger.CheckError(err, "Generating PGP Keys") != nil </span><span class="cov0" title="0">{
888                 smslogger.WriteError("Error Generating PGP Keys. Vault Init will not use encryption!")
889         }</span><span class="cov1" title="1"> else {
890                 initReq.PGPKeys = []string{pbkey, pbkey, pbkey}
891                 initReq.RootTokenPGPKey = pbkey
892         }</span>
893
894         <span class="cov1" title="1">resp, err := v.vaultClient.Sys().Init(initReq)
895         if smslogger.CheckError(err, "Initialize Vault") != nil </span><span class="cov0" title="0">{
896                 return errors.New("FATAL: Unable to initialize Vault")
897         }</span>
898
899         <span class="cov1" title="1">if resp != nil </span><span class="cov1" title="1">{
900                 v.prkey = prkey
901                 v.shards = resp.KeysB64
902                 v.vaultToken, _ = smsauth.DecryptPGPString(resp.RootToken, prkey)
903                 return nil
904         }</span>
905
906         <span class="cov0" title="0">return errors.New("FATAL: Init response was empty")</span>
907 }
908 </pre>
909                 
910                 <pre class="file" id="file3" style="display: none">/*
911  * Copyright 2018 Intel Corporation, Inc
912  *
913  * Licensed under the Apache License, Version 2.0 (the "License");
914  * you may not use this file except in compliance with the License.
915  * You may obtain a copy of the License at
916  *
917  *     http://www.apache.org/licenses/LICENSE-2.0
918  *
919  * Unless required by applicable law or agreed to in writing, software
920  * distributed under the License is distributed on an "AS IS" BASIS,
921  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
922  * See the License for the specific language governing permissions and
923  * limitations under the License.
924  */
925
926 package config
927
928 import (
929         "encoding/json"
930         "os"
931         smslogger "sms/log"
932 )
933
934 // SMSConfiguration loads up all the values that are used to configure
935 // backend implementations
936 // TODO: Review these and see if they can be created/discovered dynamically
937 type SMSConfiguration struct {
938         CAFile     string `json:"cafile"`
939         ServerCert string `json:"servercert"`
940         ServerKey  string `json:"serverkey"`
941
942         BackendAddress            string `json:"smsdbaddress"`
943         VaultToken                string `json:"vaulttoken"`
944         DisableTLS                bool   `json:"disable_tls"`
945         BackendAddressEnvVariable string `json:"smsdburlenv"`
946 }
947
948 // SMSConfig is the structure that stores the configuration
949 var SMSConfig *SMSConfiguration
950
951 // ReadConfigFile reads the specified smsConfig file to setup some env variables
952 func ReadConfigFile(file string) (*SMSConfiguration, error) <span class="cov10" title="3">{
953         if SMSConfig == nil </span><span class="cov10" title="3">{
954                 f, err := os.Open(file)
955                 if err != nil </span><span class="cov1" title="1">{
956                         return nil, err
957                 }</span>
958                 <span class="cov6" title="2">defer f.Close()
959
960                 // Default behaviour is to enable TLS
961                 SMSConfig = &amp;SMSConfiguration{DisableTLS: false}
962                 decoder := json.NewDecoder(f)
963                 err = decoder.Decode(SMSConfig)
964                 if err != nil </span><span class="cov0" title="0">{
965                         return nil, err
966                 }</span>
967
968                 <span class="cov6" title="2">if SMSConfig.BackendAddress == "" &amp;&amp; SMSConfig.BackendAddressEnvVariable != "" </span><span class="cov0" title="0">{
969                         // Get the value from ENV variable
970                         smslogger.WriteInfo("Using Environment Variable: " + SMSConfig.BackendAddressEnvVariable)
971                         SMSConfig.BackendAddress = os.Getenv(SMSConfig.BackendAddressEnvVariable)
972                 }</span>
973         }
974
975         <span class="cov6" title="2">return SMSConfig, nil</span>
976 }
977 </pre>
978                 
979                 <pre class="file" id="file4" style="display: none">/*
980  * Copyright 2018 Intel Corporation, Inc
981  *
982  * Licensed under the Apache License, Version 2.0 (the "License");
983  * you may not use this file except in compliance with the License.
984  * You may obtain a copy of the License at
985  *
986  *     http://www.apache.org/licenses/LICENSE-2.0
987  *
988  * Unless required by applicable law or agreed to in writing, software
989  * distributed under the License is distributed on an "AS IS" BASIS,
990  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
991  * See the License for the specific language governing permissions and
992  * limitations under the License.
993  */
994
995 package handler
996
997 import (
998         "encoding/json"
999         "github.com/gorilla/mux"
1000         "net/http"
1001
1002         smsbackend "sms/backend"
1003         smslogger "sms/log"
1004 )
1005
1006 // handler stores two interface implementations that implement
1007 // the backend functionality
1008 type handler struct {
1009         secretBackend smsbackend.SecretBackend
1010         loginBackend  smsbackend.LoginBackend
1011 }
1012
1013 // createSecretDomainHandler creates a secret domain with a name provided
1014 func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="3">{
1015         var d smsbackend.SecretDomain
1016
1017         err := json.NewDecoder(r.Body).Decode(&amp;d)
1018         if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
1019                 http.Error(w, err.Error(), http.StatusBadRequest)
1020                 return
1021         }</span>
1022
1023         <span class="cov6" title="3">dom, err := h.secretBackend.CreateSecretDomain(d.Name)
1024         if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
1025                 http.Error(w, err.Error(), http.StatusInternalServerError)
1026                 return
1027         }</span>
1028
1029         <span class="cov6" title="3">w.Header().Set("Content-Type", "application/json")
1030         w.WriteHeader(http.StatusCreated)
1031         err = json.NewEncoder(w).Encode(dom)
1032         if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
1033                 http.Error(w, err.Error(), http.StatusInternalServerError)
1034                 return
1035         }</span>
1036 }
1037
1038 // deleteSecretDomainHandler deletes a secret domain with the name provided
1039 func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="3">{
1040         vars := mux.Vars(r)
1041         domName := vars["domName"]
1042
1043         err := h.secretBackend.DeleteSecretDomain(domName)
1044         if smslogger.CheckError(err, "DeleteSecretDomainHandler") != nil </span><span class="cov0" title="0">{
1045                 http.Error(w, err.Error(), http.StatusInternalServerError)
1046                 return
1047         }</span>
1048
1049         <span class="cov6" title="3">w.WriteHeader(http.StatusNoContent)</span>
1050 }
1051
1052 // createSecretHandler handles creation of secrets on a given domain name
1053 func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov10" title="7">{
1054         // Get domain name from URL
1055         vars := mux.Vars(r)
1056         domName := vars["domName"]
1057
1058         // Get secrets to be stored from body
1059         var b smsbackend.Secret
1060         err := json.NewDecoder(r.Body).Decode(&amp;b)
1061         if smslogger.CheckError(err, "CreateSecretHandler") != nil </span><span class="cov0" title="0">{
1062                 http.Error(w, err.Error(), http.StatusBadRequest)
1063                 return
1064         }</span>
1065
1066         <span class="cov10" title="7">err = h.secretBackend.CreateSecret(domName, b)
1067         if smslogger.CheckError(err, "CreateSecretHandler") != nil </span><span class="cov0" title="0">{
1068                 http.Error(w, err.Error(), http.StatusInternalServerError)
1069                 return
1070         }</span>
1071
1072         <span class="cov10" title="7">w.WriteHeader(http.StatusCreated)</span>
1073 }
1074
1075 // getSecretHandler handles reading a secret by given domain name and secret name
1076 func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov10" title="7">{
1077         vars := mux.Vars(r)
1078         domName := vars["domName"]
1079         secName := vars["secretName"]
1080
1081         sec, err := h.secretBackend.GetSecret(domName, secName)
1082         if smslogger.CheckError(err, "GetSecretHandler") != nil </span><span class="cov0" title="0">{
1083                 http.Error(w, err.Error(), http.StatusInternalServerError)
1084                 return
1085         }</span>
1086
1087         <span class="cov10" title="7">w.Header().Set("Content-Type", "application/json")
1088         err = json.NewEncoder(w).Encode(sec)
1089         if smslogger.CheckError(err, "GetSecretHandler") != nil </span><span class="cov0" title="0">{
1090                 http.Error(w, err.Error(), http.StatusInternalServerError)
1091                 return
1092         }</span>
1093 }
1094
1095 // listSecretHandler handles listing all secrets under a particular domain name
1096 func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="3">{
1097         vars := mux.Vars(r)
1098         domName := vars["domName"]
1099
1100         secList, err := h.secretBackend.ListSecret(domName)
1101         if smslogger.CheckError(err, "ListSecretHandler") != nil </span><span class="cov0" title="0">{
1102                 http.Error(w, err.Error(), http.StatusInternalServerError)
1103                 return
1104         }</span>
1105
1106         // Creating an anonymous struct to store the returned list of data
1107         <span class="cov6" title="3">var retStruct = struct {
1108                 SecretNames []string `json:"secretnames"`
1109         }{
1110                 secList,
1111         }
1112
1113         w.Header().Set("Content-Type", "application/json")
1114         err = json.NewEncoder(w).Encode(retStruct)
1115         if smslogger.CheckError(err, "ListSecretHandler") != nil </span><span class="cov0" title="0">{
1116                 http.Error(w, err.Error(), http.StatusInternalServerError)
1117                 return
1118         }</span>
1119 }
1120
1121 // deleteSecretHandler handles deleting a secret by given domain name and secret name
1122 func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) <span class="cov10" title="7">{
1123         vars := mux.Vars(r)
1124         domName := vars["domName"]
1125         secName := vars["secretName"]
1126
1127         err := h.secretBackend.DeleteSecret(domName, secName)
1128         if smslogger.CheckError(err, "DeleteSecretHandler") != nil </span><span class="cov0" title="0">{
1129                 http.Error(w, err.Error(), http.StatusInternalServerError)
1130                 return
1131         }</span>
1132
1133         <span class="cov10" title="7">w.WriteHeader(http.StatusNoContent)</span>
1134 }
1135
1136 // statusHandler returns information related to SMS and SMS backend services
1137 func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) <span class="cov7" title="4">{
1138         s, err := h.secretBackend.GetStatus()
1139         if smslogger.CheckError(err, "StatusHandler") != nil </span><span class="cov0" title="0">{
1140                 http.Error(w, err.Error(), http.StatusInternalServerError)
1141                 return
1142         }</span>
1143
1144         <span class="cov7" title="4">status := struct {
1145                 Seal bool `json:"sealstatus"`
1146         }{
1147                 s,
1148         }
1149
1150         w.Header().Set("Content-Type", "application/json")
1151         err = json.NewEncoder(w).Encode(status)
1152         if smslogger.CheckError(err, "StatusHandler") != nil </span><span class="cov0" title="0">{
1153                 http.Error(w, err.Error(), http.StatusInternalServerError)
1154                 return
1155         }</span>
1156 }
1157
1158 // loginHandler handles login via password and username
1159 func (h handler) loginHandler(w http.ResponseWriter, r *http.Request) {<span class="cov0" title="0">
1160
1161 }</span>
1162
1163 // unsealHandler is a pass through that sends requests from quorum client
1164 // to the backend.
1165 func (h handler) unsealHandler(w http.ResponseWriter, r *http.Request) <span class="cov0" title="0">{
1166         // Get shards to be used for unseal
1167         type unsealStruct struct {
1168                 UnsealShard string `json:"unsealshard"`
1169         }
1170
1171         var inp unsealStruct
1172         decoder := json.NewDecoder(r.Body)
1173         decoder.DisallowUnknownFields()
1174         err := decoder.Decode(&amp;inp)
1175         if smslogger.CheckError(err, "UnsealHandler") != nil </span><span class="cov0" title="0">{
1176                 http.Error(w, "Bad input JSON", http.StatusBadRequest)
1177                 return
1178         }</span>
1179
1180         <span class="cov0" title="0">err = h.secretBackend.Unseal(inp.UnsealShard)
1181         if smslogger.CheckError(err, "UnsealHandler") != nil </span><span class="cov0" title="0">{
1182                 http.Error(w, err.Error(), http.StatusInternalServerError)
1183                 return
1184         }</span>
1185 }
1186
1187 // registerHandler allows the quorum clients to register with SMS
1188 // with their PGP public keys that are then used by sms for backend
1189 // initialization
1190 func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) <span class="cov1" title="1">{
1191         // Get shards to be used for unseal
1192         type registerStruct struct {
1193                 PGPKey   string `json:"pgpkey"`
1194                 QuorumID string `json:"quorumid"`
1195         }
1196
1197         var inp registerStruct
1198         decoder := json.NewDecoder(r.Body)
1199         decoder.DisallowUnknownFields()
1200         err := decoder.Decode(&amp;inp)
1201         if smslogger.CheckError(err, "RegisterHandler") != nil </span><span class="cov0" title="0">{
1202                 http.Error(w, "Bad input JSON", http.StatusBadRequest)
1203                 return
1204         }</span>
1205
1206         <span class="cov1" title="1">sh, err := h.secretBackend.RegisterQuorum(inp.PGPKey)
1207         if smslogger.CheckError(err, "RegisterHandler") != nil </span><span class="cov0" title="0">{
1208                 http.Error(w, err.Error(), http.StatusInternalServerError)
1209                 return
1210         }</span>
1211
1212         // Creating a struct for return data
1213         <span class="cov1" title="1">shStruct := struct {
1214                 Shard string `json:"shard"`
1215         }{
1216                 sh,
1217         }
1218
1219         w.Header().Set("Content-Type", "application/json")
1220         err = json.NewEncoder(w).Encode(shStruct)
1221         if smslogger.CheckError(err, "RegisterHandler") != nil </span><span class="cov0" title="0">{
1222                 http.Error(w, err.Error(), http.StatusInternalServerError)
1223                 return
1224         }</span>
1225 }
1226
1227 // CreateRouter returns an http.Handler for the registered URLs
1228 // Takes an interface implementation as input
1229 func CreateRouter(b smsbackend.SecretBackend) http.Handler <span class="cov4" title="2">{
1230         h := handler{secretBackend: b}
1231
1232         // Create a new mux to handle URL endpoints
1233         router := mux.NewRouter()
1234
1235         router.HandleFunc("/v1/sms/login", h.loginHandler).Methods("POST")
1236
1237         // Initialization APIs which will be used by quorum client
1238         // to unseal and to provide root token to sms service
1239         router.HandleFunc("/v1/sms/quorum/status", h.statusHandler).Methods("GET")
1240         router.HandleFunc("/v1/sms/quorum/unseal", h.unsealHandler).Methods("POST")
1241         router.HandleFunc("/v1/sms/quorum/register", h.registerHandler).Methods("POST")
1242
1243         router.HandleFunc("/v1/sms/domain", h.createSecretDomainHandler).Methods("POST")
1244         router.HandleFunc("/v1/sms/domain/{domName}", h.deleteSecretDomainHandler).Methods("DELETE")
1245
1246         router.HandleFunc("/v1/sms/domain/{domName}/secret", h.createSecretHandler).Methods("POST")
1247         router.HandleFunc("/v1/sms/domain/{domName}/secret", h.listSecretHandler).Methods("GET")
1248         router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.getSecretHandler).Methods("GET")
1249         router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.deleteSecretHandler).Methods("DELETE")
1250
1251         return router
1252 }</span>
1253 </pre>
1254                 
1255                 <pre class="file" id="file5" style="display: none">/*
1256  * Copyright 2018 Intel Corporation, Inc
1257  *
1258  * Licensed under the Apache License, Version 2.0 (the "License");
1259  * you may not use this file except in compliance with the License.
1260  * You may obtain a copy of the License at
1261  *
1262  *     http://www.apache.org/licenses/LICENSE-2.0
1263  *
1264  * Unless required by applicable law or agreed to in writing, software
1265  * distributed under the License is distributed on an "AS IS" BASIS,
1266  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1267  * See the License for the specific language governing permissions and
1268  * limitations under the License.
1269  */
1270
1271 package log
1272
1273 import (
1274         "fmt"
1275         "log"
1276         "os"
1277 )
1278
1279 var errL, warnL, infoL *log.Logger
1280 var stdErr, stdWarn, stdInfo *log.Logger
1281
1282 // Init will be called by sms.go before any other packages use it
1283 func Init(filePath string) <span class="cov1" title="1">{
1284
1285         stdErr = log.New(os.Stderr, "ERROR: ", log.Lshortfile|log.LstdFlags)
1286         stdWarn = log.New(os.Stdout, "WARNING: ", log.Lshortfile|log.LstdFlags)
1287         stdInfo = log.New(os.Stdout, "INFO: ", log.Lshortfile|log.LstdFlags)
1288
1289         if filePath == "" </span><span class="cov0" title="0">{
1290                 // We will just to std streams
1291                 return
1292         }</span>
1293
1294         <span class="cov1" title="1">f, err := os.Create(filePath)
1295         if err != nil </span><span class="cov0" title="0">{
1296                 stdErr.Println("Unable to create log file: " + err.Error())
1297                 return
1298         }</span>
1299
1300         <span class="cov1" title="1">errL = log.New(f, "ERROR: ", log.Lshortfile|log.LstdFlags)
1301         warnL = log.New(f, "WARNING: ", log.Lshortfile|log.LstdFlags)
1302         infoL = log.New(f, "INFO: ", log.Lshortfile|log.LstdFlags)</span>
1303 }
1304
1305 // WriteError writes output to the writer we have
1306 // defined during its creation with ERROR prefix
1307 func WriteError(msg string) <span class="cov0" title="0">{
1308         if errL != nil </span><span class="cov0" title="0">{
1309                 errL.Output(2, fmt.Sprintln(msg))
1310         }</span>
1311         <span class="cov0" title="0">if stdErr != nil </span><span class="cov0" title="0">{
1312                 stdErr.Output(2, fmt.Sprintln(msg))
1313         }</span>
1314 }
1315
1316 // WriteWarn writes output to the writer we have
1317 // defined during its creation with WARNING prefix
1318 func WriteWarn(msg string) <span class="cov0" title="0">{
1319         if warnL != nil </span><span class="cov0" title="0">{
1320                 warnL.Output(2, fmt.Sprintln(msg))
1321         }</span>
1322         <span class="cov0" title="0">if stdWarn != nil </span><span class="cov0" title="0">{
1323                 stdWarn.Output(2, fmt.Sprintln(msg))
1324         }</span>
1325 }
1326
1327 // WriteInfo writes output to the writer we have
1328 // defined during its creation with INFO prefix
1329 func WriteInfo(msg string) <span class="cov1" title="1">{
1330         if infoL != nil </span><span class="cov1" title="1">{
1331                 infoL.Output(2, fmt.Sprintln(msg))
1332         }</span>
1333         <span class="cov1" title="1">if stdInfo != nil </span><span class="cov1" title="1">{
1334                 stdInfo.Output(2, fmt.Sprintln(msg))
1335         }</span>
1336 }
1337
1338 //CheckError is a helper function to reduce
1339 //repitition of error checkign blocks of code
1340 func CheckError(err error, topic string) error <span class="cov10" title="116">{
1341         if err != nil </span><span class="cov1" title="1">{
1342                 msg := topic + ": " + err.Error()
1343                 if errL != nil </span><span class="cov1" title="1">{
1344                         errL.Output(2, fmt.Sprintln(msg))
1345                 }</span>
1346                 <span class="cov1" title="1">if stdErr != nil </span><span class="cov1" title="1">{
1347                         stdErr.Output(2, fmt.Sprintln(msg))
1348                 }</span>
1349                 <span class="cov1" title="1">return err</span>
1350         }
1351         <span class="cov9" title="115">return nil</span>
1352 }
1353 </pre>
1354                 
1355                 <pre class="file" id="file6" style="display: none">/*
1356  * Copyright 2018 Intel Corporation, Inc
1357  *
1358  * Licensed under the Apache License, Version 2.0 (the "License");
1359  * you may not use this file except in compliance with the License.
1360  * You may obtain a copy of the License at
1361  *
1362  *     http://www.apache.org/licenses/LICENSE-2.0
1363  *
1364  * Unless required by applicable law or agreed to in writing, software
1365  * distributed under the License is distributed on an "AS IS" BASIS,
1366  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1367  * See the License for the specific language governing permissions and
1368  * limitations under the License.
1369  */
1370
1371 package main
1372
1373 import (
1374         "context"
1375         "log"
1376         "net/http"
1377         "os"
1378         "os/signal"
1379
1380         smsauth "sms/auth"
1381         smsbackend "sms/backend"
1382         smsconfig "sms/config"
1383         smshandler "sms/handler"
1384         smslogger "sms/log"
1385 )
1386
1387 func main() <span class="cov8" title="1">{
1388         // Initialize logger
1389         smslogger.Init("sms.log")
1390
1391         // Read Configuration File
1392         smsConf, err := smsconfig.ReadConfigFile("smsconfig.json")
1393         if err != nil </span><span class="cov0" title="0">{
1394                 log.Fatal(err)
1395         }</span>
1396
1397         <span class="cov8" title="1">backendImpl, err := smsbackend.InitSecretBackend()
1398         if err != nil </span><span class="cov0" title="0">{
1399                 log.Fatal(err)
1400         }</span>
1401
1402         <span class="cov8" title="1">httpRouter := smshandler.CreateRouter(backendImpl)
1403
1404         httpServer := &amp;http.Server{
1405                 Handler: httpRouter,
1406                 Addr:    ":10443",
1407         }
1408
1409         // Listener for SIGINT so that it returns cleanly
1410         connectionsClose := make(chan struct{})
1411         go func() </span><span class="cov8" title="1">{
1412                 c := make(chan os.Signal, 1)
1413                 signal.Notify(c, os.Interrupt)
1414                 &lt;-c
1415                 httpServer.Shutdown(context.Background())
1416                 close(connectionsClose)
1417         }</span>()
1418
1419         // Start in TLS mode by default
1420         <span class="cov8" title="1">if smsConf.DisableTLS == true </span><span class="cov0" title="0">{
1421                 smslogger.WriteWarn("TLS is Disabled")
1422                 err = httpServer.ListenAndServe()
1423         }</span><span class="cov8" title="1"> else {
1424                 // TODO: Use CA certificate from AAF
1425                 tlsConfig, err := smsauth.GetTLSConfig(smsConf.CAFile)
1426                 if err != nil </span><span class="cov0" title="0">{
1427                         log.Fatal(err)
1428                 }</span>
1429
1430                 <span class="cov8" title="1">httpServer.TLSConfig = tlsConfig
1431                 err = httpServer.ListenAndServeTLS(smsConf.ServerCert, smsConf.ServerKey)</span>
1432         }
1433
1434         <span class="cov8" title="1">if err != nil &amp;&amp; err != http.ErrServerClosed </span><span class="cov0" title="0">{
1435                 log.Fatal(err)
1436         }</span>
1437
1438         <span class="cov8" title="1">&lt;-connectionsClose</span>
1439 }
1440 </pre>
1441                 
1442                 </div>
1443         </body>
1444         <script>
1445         (function() {
1446                 var files = document.getElementById('files');
1447                 var visible;
1448                 files.addEventListener('change', onChange, false);
1449                 function select(part) {
1450                         if (visible)
1451                                 visible.style.display = 'none';
1452                         visible = document.getElementById(part);
1453                         if (!visible)
1454                                 return;
1455                         files.value = part;
1456                         visible.style.display = 'block';
1457                         location.hash = part;
1458                 }
1459                 function onChange() {
1460                         select(files.value);
1461                         window.scrollTo(0, 0);
1462                 }
1463                 if (location.hash != "") {
1464                         select(location.hash.substr(1));
1465                 }
1466                 if (!visible) {
1467                         select("file0");
1468                 }
1469         })();
1470         </script>
1471 </html>