summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sms-service/doc/coverage.html861
-rw-r--r--sms-service/doc/coverage.md (renamed from sms-service/src/sms/coverage.md)0
-rw-r--r--sms-service/src/quorumclient/quorumclient.go22
-rw-r--r--sms-service/src/sms/Gopkg.lock2
-rw-r--r--sms-service/src/sms/auth/auth.go82
-rw-r--r--sms-service/src/sms/backend/backend.go3
-rw-r--r--sms-service/src/sms/backend/vault.go105
-rw-r--r--sms-service/src/sms/backend/vault_test.go38
-rw-r--r--sms-service/src/sms/handler/handler.go54
-rw-r--r--sms-service/src/sms/handler/handler_test.go45
-rw-r--r--sms-service/src/sms/log/logger.go73
11 files changed, 809 insertions, 476 deletions
diff --git a/sms-service/doc/coverage.html b/sms-service/doc/coverage.html
index d03ddde..39ee191 100644
--- a/sms-service/doc/coverage.html
+++ b/sms-service/doc/coverage.html
@@ -54,19 +54,19 @@
<div id="nav">
<select id="files">
- <option value="file0">sms/auth/auth.go (17.6%)</option>
+ <option value="file0">sms/auth/auth.go (76.1%)</option>
- <option value="file1">sms/backend/backend.go (66.7%)</option>
+ <option value="file1">sms/backend/backend.go (80.0%)</option>
- <option value="file2">sms/backend/vault.go (60.5%)</option>
+ <option value="file2">sms/backend/vault.go (72.5%)</option>
- <option value="file3">sms/config/config.go (90.9%)</option>
+ <option value="file3">sms/config/config.go (78.6%)</option>
- <option value="file4">sms/handler/handler.go (55.1%)</option>
+ <option value="file4">sms/handler/handler.go (63.0%)</option>
- <option value="file5">sms/log/logger.go (31.2%)</option>
+ <option value="file5">sms/log/logger.go (65.6%)</option>
- <option value="file6">sms/sms.go (82.6%)</option>
+ <option value="file6">sms/sms.go (77.8%)</option>
</select>
</div>
@@ -109,6 +109,7 @@ package auth
import (
"bytes"
+ "crypto"
"crypto/tls"
"crypto/x509"
"encoding/base64"
@@ -119,63 +120,63 @@ import (
smslogger "sms/log"
)
-var tlsConfig *tls.Config
-
// GetTLSConfig initializes a tlsConfig using the CA's certificate
// This config is then used to enable the server for mutual TLS
func GetTLSConfig(caCertFile string) (*tls.Config, error) <span class="cov10" title="3">{
+
// Initialize tlsConfig once
- if tlsConfig == nil </span><span class="cov10" title="3">{
- caCert, err := ioutil.ReadFile(caCertFile)
+ caCert, err := ioutil.ReadFile(caCertFile)
- if err != nil </span><span class="cov1" title="1">{
- return nil, err
- }</span>
+ if err != nil </span><span class="cov1" title="1">{
+ return nil, err
+ }</span>
- <span class="cov6" title="2">caCertPool := x509.NewCertPool()
- caCertPool.AppendCertsFromPEM(caCert)
+ <span class="cov6" title="2">caCertPool := x509.NewCertPool()
+ caCertPool.AppendCertsFromPEM(caCert)
- tlsConfig = &amp;tls.Config{
- ClientAuth: tls.RequireAndVerifyClientCert,
- ClientCAs: caCertPool,
- MinVersion: tls.VersionTLS12,
- }
- tlsConfig.BuildNameToCertificate()</span>
+ tlsConfig := &amp;tls.Config{
+ // Change to RequireAndVerify once we have mandatory certs
+ ClientAuth: tls.VerifyClientCertIfGiven,
+ ClientCAs: caCertPool,
+ MinVersion: tls.VersionTLS12,
}
- <span class="cov6" title="2">return tlsConfig, nil</span>
+ tlsConfig.BuildNameToCertificate()
+ return tlsConfig, nil</span>
}
// GeneratePGPKeyPair produces a PGP key pair and returns
// two things:
// A base64 encoded form of the public part of the entity
// A base64 encoded form of the private key
-func GeneratePGPKeyPair() (string, string, error) <span class="cov0" title="0">{
+func GeneratePGPKeyPair() (string, string, error) <span class="cov10" title="3">{
+
var entity *openpgp.Entity
- entity, err := openpgp.NewEntity("aaf.sms.init", "PGP Key for unsealing", "", nil)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ config := &amp;packet.Config{
+ DefaultHash: crypto.SHA256,
+ }
+
+ entity, err := openpgp.NewEntity("aaf.sms.init", "PGP Key for unsealing", "", config)
+ if smslogger.CheckError(err, "Create Entity") != nil </span><span class="cov0" title="0">{
return "", "", err
}</span>
// Sign the identity in the entity
- <span class="cov0" title="0">for _, id := range entity.Identities </span><span class="cov0" title="0">{
+ <span class="cov10" title="3">for _, id := range entity.Identities </span><span class="cov10" title="3">{
err = id.SelfSignature.SignUserId(id.UserId.Id, entity.PrimaryKey, entity.PrivateKey, nil)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Sign Entity") != nil </span><span class="cov0" title="0">{
return "", "", err
}</span>
}
// Sign the subkey in the entity
- <span class="cov0" title="0">for _, subkey := range entity.Subkeys </span><span class="cov0" title="0">{
+ <span class="cov10" title="3">for _, subkey := range entity.Subkeys </span><span class="cov10" title="3">{
err := subkey.Sig.SignKey(subkey.PublicKey, entity.PrivateKey, nil)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Sign Subkey") != nil </span><span class="cov0" title="0">{
return "", "", err
}</span>
}
- <span class="cov0" title="0">buffer := new(bytes.Buffer)
+ <span class="cov10" title="3">buffer := new(bytes.Buffer)
entity.Serialize(buffer)
pbkey := base64.StdEncoding.EncodeToString(buffer.Bytes())
@@ -186,40 +187,96 @@ func GeneratePGPKeyPair() (string, string, error) <span class="cov0" title="0">{
return pbkey, prkey, nil</span>
}
-// DecryptPGPBytes decrypts a PGP encoded input string and returns
+// EncryptPGPString takes data and a public key and encrypts using that
+// public key
+func EncryptPGPString(data string, pbKey string) (string, error) <span class="cov6" title="2">{
+
+ pbKeyBytes, err := base64.StdEncoding.DecodeString(pbKey)
+ if smslogger.CheckError(err, "Decoding Base64 Public Key") != nil </span><span class="cov0" title="0">{
+ return "", err
+ }</span>
+
+ <span class="cov6" title="2">dataBytes := []byte(data)
+
+ pbEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(pbKeyBytes)))
+ if smslogger.CheckError(err, "Reading entity from PGP key") != nil </span><span class="cov0" title="0">{
+ return "", err
+ }</span>
+
+ // encrypt string
+ <span class="cov6" title="2">buf := new(bytes.Buffer)
+ out, err := openpgp.Encrypt(buf, []*openpgp.Entity{pbEntity}, nil, nil, nil)
+ if smslogger.CheckError(err, "Creating Encryption Pipe") != nil </span><span class="cov0" title="0">{
+ return "", err
+ }</span>
+
+ <span class="cov6" title="2">_, err = out.Write(dataBytes)
+ if smslogger.CheckError(err, "Writing to Encryption Pipe") != nil </span><span class="cov0" title="0">{
+ return "", err
+ }</span>
+
+ <span class="cov6" title="2">err = out.Close()
+ if smslogger.CheckError(err, "Closing Encryption Pipe") != nil </span><span class="cov0" title="0">{
+ return "", err
+ }</span>
+
+ <span class="cov6" title="2">crp := base64.StdEncoding.EncodeToString(buf.Bytes())
+ return crp, nil</span>
+}
+
+// DecryptPGPString decrypts a PGP encoded input string and returns
// a base64 representation of the decoded string
-func DecryptPGPBytes(data string, prKey string) (string, error) <span class="cov0" title="0">{
+func DecryptPGPString(data string, prKey string) (string, error) <span class="cov1" title="1">{
+
// Convert private key to bytes from base64
prKeyBytes, err := base64.StdEncoding.DecodeString(prKey)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError("Error Decoding base64 private key: " + err.Error())
+ if smslogger.CheckError(err, "Decoding Base64 Private Key") != nil </span><span class="cov0" title="0">{
return "", err
}</span>
- <span class="cov0" title="0">dataBytes, err := base64.StdEncoding.DecodeString(data)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError("Error Decoding base64 data: " + err.Error())
+ <span class="cov1" title="1">dataBytes, err := base64.StdEncoding.DecodeString(data)
+ if smslogger.CheckError(err, "Decoding base64 data") != nil </span><span class="cov0" title="0">{
return "", err
}</span>
- <span class="cov0" title="0">prEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(prKeyBytes)))
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError("Error reading entity from PGP key: " + err.Error())
+ <span class="cov1" title="1">prEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(prKeyBytes)))
+ if smslogger.CheckError(err, "Read Entity") != nil </span><span class="cov0" title="0">{
return "", err
}</span>
- <span class="cov0" title="0">prEntityList := &amp;openpgp.EntityList{prEntity}
+ <span class="cov1" title="1">prEntityList := &amp;openpgp.EntityList{prEntity}
message, err := openpgp.ReadMessage(bytes.NewBuffer(dataBytes), prEntityList, nil, nil)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError("Error Decrypting message: " + err.Error())
+ if smslogger.CheckError(err, "Decrypting Message") != nil </span><span class="cov0" title="0">{
return "", err
}</span>
- <span class="cov0" title="0">var retBuf bytes.Buffer
+ <span class="cov1" title="1">var retBuf bytes.Buffer
retBuf.ReadFrom(message.UnverifiedBody)
return retBuf.String(), nil</span>
}
+
+// ReadFromFile reads a file and loads the PGP key into
+// a string
+func ReadFromFile(fileName string) (string, error) <span class="cov6" title="2">{
+
+ data, err := ioutil.ReadFile(fileName)
+ if smslogger.CheckError(err, "Read from file") != nil </span><span class="cov0" title="0">{
+ return "", err
+ }</span>
+ <span class="cov6" title="2">return string(data), nil</span>
+}
+
+// WriteToFile writes a PGP key into a file.
+// It will truncate the file if it exists
+func WriteToFile(data string, fileName string) error <span class="cov0" title="0">{
+
+ err := ioutil.WriteFile(fileName, []byte(data), 0600)
+ if smslogger.CheckError(err, "Write to file") != nil </span><span class="cov0" title="0">{
+ return err
+ }</span>
+ <span class="cov0" title="0">return nil</span>
+}
</pre>
<pre class="file" id="file1" style="display: none">/*
@@ -264,6 +321,7 @@ type SecretBackend interface {
Init() error
GetStatus() (bool, error)
Unseal(shard string) error
+ RegisterQuorum(pgpkey string) (string, error)
GetSecret(dom string, sec string) (Secret, error)
ListSecret(dom string) ([]string, error)
@@ -276,19 +334,18 @@ type SecretBackend interface {
}
// InitSecretBackend returns an interface implementation
-func InitSecretBackend() (SecretBackend, error) <span class="cov10" title="2">{
+func InitSecretBackend() (SecretBackend, error) <span class="cov8" title="1">{
backendImpl := &amp;Vault{
- vaultAddress: smsconfig.SMSConfig.VaultAddress,
+ vaultAddress: smsconfig.SMSConfig.BackendAddress,
vaultToken: smsconfig.SMSConfig.VaultToken,
}
err := backendImpl.Init()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "InitSecretBackend") != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
- <span class="cov10" title="2">return backendImpl, nil</span>
+ <span class="cov8" title="1">return backendImpl, nil</span>
}
// LoginBackend Interface that will be implemented for various login backends
@@ -330,68 +387,108 @@ import (
// Vault is the main Struct used in Backend to initialize the struct
type Vault struct {
sync.Mutex
- engineType string
- initRoleDone bool
- policyName string
- roleID string
- secretID string
- vaultAddress string
- vaultClient *vaultapi.Client
- vaultMount string
- vaultTempTokenTTL time.Time
- vaultToken string
- unsealShards []string
- rootToken string
- pgpPub string
- pgpPr string
+ initRoleDone bool
+ policyName string
+ roleID string
+ secretID string
+ vaultAddress string
+ vaultClient *vaultapi.Client
+ vaultMountPrefix string
+ internalDomain string
+ internalDomainMounted bool
+ vaultTempTokenTTL time.Time
+ vaultToken string
+ shards []string
+ prkey string
}
-// Init will initialize the vault connection
-// It will also create the initial policy if it does not exist
-// TODO: Check to see if we need to wait for vault to be running
-func (v *Vault) Init() error <span class="cov4" title="3">{
+// initVaultClient will create the initial
+// Vault strcuture and populate it with the
+// right values and it will also create
+// a vault client
+func (v *Vault) initVaultClient() error <span class="cov6" title="11">{
+
vaultCFG := vaultapi.DefaultConfig()
vaultCFG.Address = v.vaultAddress
client, err := vaultapi.NewClient(vaultCFG)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
- return errors.New("Unable to create new vault client")
+ if smslogger.CheckError(err, "Create new vault client") != nil </span><span class="cov0" title="0">{
+ return err
}</span>
- <span class="cov4" title="3">v.engineType = "kv"
- v.initRoleDone = false
+ <span class="cov6" title="11">v.initRoleDone = false
v.policyName = "smsvaultpolicy"
v.vaultClient = client
- v.vaultMount = "sms"
+ v.vaultMountPrefix = "sms"
+ v.internalDomain = "smsinternaldomain"
+ v.internalDomainMounted = false
+ v.prkey = ""
+ return nil</span>
+}
- err = v.initRole()
- if err != nil </span><span class="cov2" title="2">{
- smslogger.WriteError(err.Error())
+// Init will initialize the vault connection
+// It will also initialize vault if it is not
+// already initialized.
+// The initial policy will also be created
+func (v *Vault) Init() error <span class="cov1" title="1">{
+
+ v.initVaultClient()
+ // Initialize vault if it is not already
+ // Returns immediately if it is initialized
+ v.initializeVault()
+
+ err := v.initRole()
+ if smslogger.CheckError(err, "InitRole First Attempt") != nil </span><span class="cov0" title="0">{
smslogger.WriteInfo("InitRole will try again later")
}</span>
- <span class="cov4" title="3">return nil</span>
+ <span class="cov1" title="1">return nil</span>
}
// GetStatus returns the current seal status of vault
-func (v *Vault) GetStatus() (bool, error) <span class="cov4" title="3">{
+func (v *Vault) GetStatus() (bool, error) <span class="cov3" title="3">{
+
sys := v.vaultClient.Sys()
sealStatus, err := sys.SealStatus()
- if err != nil </span><span class="cov1" title="1">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Getting Status") != nil </span><span class="cov0" title="0">{
return false, errors.New("Error getting status")
}</span>
- <span class="cov2" title="2">return sealStatus.Sealed, nil</span>
+ <span class="cov3" title="3">return sealStatus.Sealed, nil</span>
+}
+
+// RegisterQuorum registers the PGP public key for a quorum client
+// We will return a shard to the client that is registering
+func (v *Vault) RegisterQuorum(pgpkey string) (string, error) <span class="cov0" title="0">{
+
+ v.Lock()
+ defer v.Unlock()
+
+ if v.shards == nil </span><span class="cov0" title="0">{
+ smslogger.WriteError("Invalid operation in RegisterQuorum")
+ return "", errors.New("Invalid operation")
+ }</span>
+ // Pop the slice
+ <span class="cov0" title="0">var sh string
+ sh, v.shards = v.shards[len(v.shards)-1], v.shards[:len(v.shards)-1]
+ if len(v.shards) == 0 </span><span class="cov0" title="0">{
+ v.shards = nil
+ }</span>
+
+ // Decrypt with SMS pgp Key
+ <span class="cov0" title="0">sh, _ = smsauth.DecryptPGPString(sh, v.prkey)
+ // Encrypt with Quorum client pgp key
+ sh, _ = smsauth.EncryptPGPString(sh, pgpkey)
+
+ return sh, nil</span>
}
// Unseal is a passthrough API that allows any
// unseal or initialization processes for the backend
func (v *Vault) Unseal(shard string) error <span class="cov0" title="0">{
+
sys := v.vaultClient.Sys()
_, err := sys.Unseal(shard)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Unseal Operation") != nil </span><span class="cov0" title="0">{
return errors.New("Unable to execute unseal operation with specified shard")
}</span>
@@ -401,80 +498,140 @@ func (v *Vault) Unseal(shard string) error <span class="cov0" title="0">{
// GetSecret returns a secret mounted on a particular domain name
// The secret itself is referenced via its name which translates to
// a mount path in vault
-func (v *Vault) GetSecret(dom string, name string) (Secret, error) <span class="cov6" title="6">{
+func (v *Vault) GetSecret(dom string, name string) (Secret, error) <span class="cov5" title="7">{
+
err := v.checkToken()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Tocken Check") != nil </span><span class="cov0" title="0">{
return Secret{}, errors.New("Token check failed")
}</span>
- <span class="cov6" title="6">dom = v.vaultMount + "/" + dom
+ <span class="cov5" title="7">dom = v.vaultMountPrefix + "/" + dom
sec, err := v.vaultClient.Logical().Read(dom + "/" + name)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{
return Secret{}, errors.New("Unable to read Secret at provided path")
}</span>
// sec and err are nil in the case where a path does not exist
- <span class="cov6" title="6">if sec == nil </span><span class="cov0" title="0">{
+ <span class="cov5" title="7">if sec == nil </span><span class="cov0" title="0">{
smslogger.WriteWarn("Vault read was empty. Invalid Path")
return Secret{}, errors.New("Secret not found at the provided path")
}</span>
- <span class="cov6" title="6">return Secret{Name: name, Values: sec.Data}, nil</span>
+ <span class="cov5" title="7">return Secret{Name: name, Values: sec.Data}, nil</span>
}
// ListSecret returns a list of secret names on a particular domain
// The values of the secret are not returned
-func (v *Vault) ListSecret(dom string) ([]string, error) <span class="cov2" title="2">{
+func (v *Vault) ListSecret(dom string) ([]string, error) <span class="cov3" title="3">{
+
err := v.checkToken()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
return nil, errors.New("Token check failed")
}</span>
- <span class="cov2" title="2">dom = v.vaultMount + "/" + dom
+ <span class="cov3" title="3">dom = v.vaultMountPrefix + "/" + dom
sec, err := v.vaultClient.Logical().List(dom)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Read Secret") != nil </span><span class="cov0" title="0">{
return nil, errors.New("Unable to read Secret at provided path")
}</span>
// sec and err are nil in the case where a path does not exist
- <span class="cov2" title="2">if sec == nil </span><span class="cov0" title="0">{
+ <span class="cov3" title="3">if sec == nil </span><span class="cov0" title="0">{
smslogger.WriteWarn("Vaultclient returned empty data")
return nil, errors.New("Secret not found at the provided path")
}</span>
- <span class="cov2" title="2">val, ok := sec.Data["keys"].([]interface{})
+ <span class="cov3" title="3">val, ok := sec.Data["keys"].([]interface{})
if !ok </span><span class="cov0" title="0">{
smslogger.WriteError("Secret not found at the provided path")
return nil, errors.New("Secret not found at the provided path")
}</span>
- <span class="cov2" title="2">retval := make([]string, len(val))
- for i, v := range val </span><span class="cov6" title="6">{
+ <span class="cov3" title="3">retval := make([]string, len(val))
+ for i, v := range val </span><span class="cov5" title="7">{
retval[i] = fmt.Sprint(v)
}</span>
- <span class="cov2" title="2">return retval, nil</span>
+ <span class="cov3" title="3">return retval, nil</span>
+}
+
+// Mounts the internal Domain if its not already mounted
+func (v *Vault) mountInternalDomain(name string) error <span class="cov5" title="8">{
+
+ if v.internalDomainMounted </span><span class="cov1" title="1">{
+ return nil
+ }</span>
+
+ <span class="cov5" title="7">name = strings.TrimSpace(name)
+ mountPath := v.vaultMountPrefix + "/" + name
+ mountInput := &amp;vaultapi.MountInput{
+ Type: "kv",
+ Description: "Mount point for domain: " + name,
+ Local: false,
+ SealWrap: false,
+ Config: vaultapi.MountConfigInput{},
+ }
+
+ err := v.vaultClient.Sys().Mount(mountPath, mountInput)
+ if smslogger.CheckError(err, "Mount internal Domain") != nil </span><span class="cov1" title="1">{
+ if strings.Contains(err.Error(), "existing mount") </span><span class="cov1" title="1">{
+ // It is already mounted
+ v.internalDomainMounted = true
+ return nil
+ }</span>
+ // Ran into some other error mounting it.
+ <span class="cov0" title="0">return errors.New("Unable to mount internal Domain")</span>
+ }
+
+ <span class="cov5" title="6">v.internalDomainMounted = true
+ return nil</span>
+}
+
+// Stores the UUID created for secretdomain in vault
+// under v.vaultMountPrefix / smsinternal domain
+func (v *Vault) storeUUID(uuid string, name string) error <span class="cov5" title="8">{
+
+ // Check if token is still valid
+ err := v.checkToken()
+ if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
+ return errors.New("Token Check failed")
+ }</span>
+
+ <span class="cov5" title="8">err = v.mountInternalDomain(v.internalDomain)
+ if smslogger.CheckError(err, "Mount Internal Domain") != nil </span><span class="cov0" title="0">{
+ return err
+ }</span>
+
+ <span class="cov5" title="8">secret := Secret{
+ Name: name,
+ Values: map[string]interface{}{
+ "uuid": uuid,
+ },
+ }
+
+ err = v.CreateSecret(v.internalDomain, secret)
+ if smslogger.CheckError(err, "Write UUID to domain") != nil </span><span class="cov0" title="0">{
+ return err
+ }</span>
+
+ <span class="cov5" title="8">return nil</span>
}
// CreateSecretDomain mounts the kv backend on a path with the given name
-func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span class="cov2" title="2">{
+func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span class="cov5" title="8">{
+
// Check if token is still valid
err := v.checkToken()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
return SecretDomain{}, errors.New("Token Check failed")
}</span>
- <span class="cov2" title="2">name = strings.TrimSpace(name)
- mountPath := v.vaultMount + "/" + name
+ <span class="cov5" title="8">name = strings.TrimSpace(name)
+ mountPath := v.vaultMountPrefix + "/" + name
mountInput := &amp;vaultapi.MountInput{
- Type: v.engineType,
+ Type: "kv",
Description: "Mount point for domain: " + name,
Local: false,
SealWrap: false,
@@ -482,171 +639,212 @@ func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) <span clas
}
err = v.vaultClient.Sys().Mount(mountPath, mountInput)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create Domain") != nil </span><span class="cov0" title="0">{
return SecretDomain{}, errors.New("Unable to create Secret Domain")
}</span>
- <span class="cov2" title="2">uuid, _ := uuid.GenerateUUID()
- return SecretDomain{uuid, name}, nil</span>
+ <span class="cov5" title="8">uuid, _ := uuid.GenerateUUID()
+ err = v.storeUUID(uuid, name)
+ if smslogger.CheckError(err, "Store UUID") != nil </span><span class="cov0" title="0">{
+ // Mount was successful at this point.
+ // Rollback the mount operation since we could not
+ // store the UUID for the mount.
+ v.vaultClient.Sys().Unmount(mountPath)
+ return SecretDomain{}, errors.New("Unable to store Secret Domain UUID. Retry")
+ }</span>
+
+ <span class="cov5" title="8">return SecretDomain{uuid, name}, nil</span>
}
// CreateSecret creates a secret mounted on a particular domain name
// The secret itself is mounted on a path specified by name
-func (v *Vault) CreateSecret(dom string, sec Secret) error <span class="cov6" title="6">{
+func (v *Vault) CreateSecret(dom string, sec Secret) error <span class="cov7" title="18">{
+
err := v.checkToken()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
return errors.New("Token check failed")
}</span>
- <span class="cov6" title="6">dom = v.vaultMount + "/" + dom
+ <span class="cov7" title="18">dom = v.vaultMountPrefix + "/" + dom
// Vault return is empty on successful write
// TODO: Check if values is not empty
_, err = v.vaultClient.Logical().Write(dom+"/"+sec.Name, sec.Values)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create Secret") != nil </span><span class="cov0" title="0">{
return errors.New("Unable to create Secret at provided path")
}</span>
- <span class="cov6" title="6">return nil</span>
+ <span class="cov7" title="18">return nil</span>
}
// DeleteSecretDomain deletes a secret domain which translates to
// an unmount operation on the given path in Vault
-func (v *Vault) DeleteSecretDomain(name string) error <span class="cov2" title="2">{
+func (v *Vault) DeleteSecretDomain(name string) error <span class="cov3" title="3">{
+
err := v.checkToken()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
return errors.New("Token Check Failed")
}</span>
- <span class="cov2" title="2">name = strings.TrimSpace(name)
- mountPath := v.vaultMount + "/" + name
+ <span class="cov3" title="3">name = strings.TrimSpace(name)
+ mountPath := v.vaultMountPrefix + "/" + name
err = v.vaultClient.Sys().Unmount(mountPath)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Delete Domain") != nil </span><span class="cov0" title="0">{
return errors.New("Unable to delete domain specified")
}</span>
- <span class="cov2" title="2">return nil</span>
+ <span class="cov3" title="3">return nil</span>
}
// DeleteSecret deletes a secret mounted on the path provided
-func (v *Vault) DeleteSecret(dom string, name string) error <span class="cov6" title="6">{
+func (v *Vault) DeleteSecret(dom string, name string) error <span class="cov5" title="7">{
+
err := v.checkToken()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil </span><span class="cov0" title="0">{
return errors.New("Token check failed")
}</span>
- <span class="cov6" title="6">dom = v.vaultMount + "/" + dom
+ <span class="cov5" title="7">dom = v.vaultMountPrefix + "/" + dom
// Vault return is empty on successful delete
_, err = v.vaultClient.Logical().Delete(dom + "/" + name)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Delete Secret") != nil </span><span class="cov0" title="0">{
return errors.New("Unable to delete Secret at provided path")
}</span>
- <span class="cov6" title="6">return nil</span>
+ <span class="cov5" title="7">return nil</span>
}
-// initRole is called only once during the service bring up
-func (v *Vault) initRole() error <span class="cov4" title="3">{
+// initRole is called only once during SMS bring up
+// It initially creates a role and secret id associated with
+// that role. Later restarts will use the existing role-id
+// and secret-id stored on disk
+func (v *Vault) initRole() error <span class="cov10" title="56">{
+
+ if v.initRoleDone </span><span class="cov9" title="48">{
+ return nil
+ }</span>
+
// Use the root token once here
- v.vaultClient.SetToken(v.vaultToken)
+ <span class="cov5" title="8">v.vaultClient.SetToken(v.vaultToken)
defer v.vaultClient.ClearToken()
- rules := `path "sms/*" { capabilities = ["create", "read", "update", "delete", "list"] }
+ // Check if roleID and secretID has already been created
+ rID, error := smsauth.ReadFromFile("auth/role")
+ if error != nil </span><span class="cov5" title="7">{
+ smslogger.WriteWarn("Unable to find RoleID. Generating...")
+ }</span><span class="cov1" title="1"> else {
+ sID, error := smsauth.ReadFromFile("auth/secret")
+ if error != nil </span><span class="cov0" title="0">{
+ smslogger.WriteWarn("Unable to find secretID. Generating...")
+ }</span><span class="cov1" title="1"> else {
+ v.roleID = rID
+ v.secretID = sID
+ v.initRoleDone = true
+ return nil
+ }</span>
+ }
+
+ <span class="cov5" title="7">rules := `path "sms/*" { capabilities = ["create", "read", "update", "delete", "list"] }
path "sys/mounts/sms*" { capabilities = ["update","delete","create"] }`
err := v.vaultClient.Sys().PutPolicy(v.policyName, rules)
- if err != nil </span><span class="cov2" title="2">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Creating Policy") != nil </span><span class="cov0" title="0">{
return errors.New("Unable to create policy for approle creation")
}</span>
- <span class="cov1" title="1">rName := v.vaultMount + "-role"
- data := map[string]interface{}{
- "token_ttl": "60m",
- "policies": [2]string{"default", v.policyName},
- }
-
//Check if applrole is mounted
- authMounts, err := v.vaultClient.Sys().ListAuth()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ <span class="cov5" title="7">authMounts, err := v.vaultClient.Sys().ListAuth()
+ if smslogger.CheckError(err, "Mount Auth Backend") != nil </span><span class="cov0" title="0">{
return errors.New("Unable to get mounted auth backends")
}</span>
- <span class="cov1" title="1">approleMounted := false
- for k, v := range authMounts </span><span class="cov1" title="1">{
- if v.Type == "approle" &amp;&amp; k == "approle/" </span><span class="cov1" title="1">{
+ <span class="cov5" title="7">approleMounted := false
+ for k, v := range authMounts </span><span class="cov5" title="7">{
+ if v.Type == "approle" &amp;&amp; k == "approle/" </span><span class="cov0" title="0">{
approleMounted = true
break</span>
}
}
// Mount approle in case its not already mounted
- <span class="cov1" title="1">if !approleMounted </span><span class="cov0" title="0">{
+ <span class="cov5" title="7">if !approleMounted </span><span class="cov5" title="7">{
v.vaultClient.Sys().EnableAuth("approle", "approle", "")
}</span>
+ <span class="cov5" title="7">rName := v.vaultMountPrefix + "-role"
+ data := map[string]interface{}{
+ "token_ttl": "60m",
+ "policies": [2]string{"default", v.policyName},
+ }
+
// Create a role-id
- <span class="cov1" title="1">v.vaultClient.Logical().Write("auth/approle/role/"+rName, data)
+ v.vaultClient.Logical().Write("auth/approle/role/"+rName, data)
sec, err := v.vaultClient.Logical().Read("auth/approle/role/" + rName + "/role-id")
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create RoleID") != nil </span><span class="cov0" title="0">{
return errors.New("Unable to create role ID for approle")
}</span>
- <span class="cov1" title="1">v.roleID = sec.Data["role_id"].(string)
+ <span class="cov5" title="7">v.roleID = sec.Data["role_id"].(string)
// Create a secret-id to go with it
sec, err = v.vaultClient.Logical().Write("auth/approle/role/"+rName+"/secret-id",
map[string]interface{}{})
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create SecretID") != nil </span><span class="cov0" title="0">{
return errors.New("Unable to create secret ID for role")
}</span>
- <span class="cov1" title="1">v.secretID = sec.Data["secret_id"].(string)
+ <span class="cov5" title="7">v.secretID = sec.Data["secret_id"].(string)
v.initRoleDone = true
+ /*
+ * Revoke the Root token.
+ * If a new Root Token is needed, it will need to be created
+ * using the unseal shards.
+ */
+ err = v.vaultClient.Auth().Token().RevokeSelf(v.vaultToken)
+ if smslogger.CheckError(err, "Revoke Root Token") != nil </span><span class="cov0" title="0">{
+ smslogger.WriteWarn("Unable to Revoke Token")
+ }</span><span class="cov5" title="7"> else {
+ // Revoked successfully and clear it
+ v.vaultToken = ""
+ }</span>
+
+ // Store the role-id and secret-id
+ // We will need this if SMS restarts
+ <span class="cov5" title="7">smsauth.WriteToFile(v.roleID, "auth/role")
+ smsauth.WriteToFile(v.secretID, "auth/secret")
+
return nil</span>
}
// Function checkToken() gets called multiple times to create
// temporary tokens
-func (v *Vault) checkToken() error <span class="cov10" title="24">{
+func (v *Vault) checkToken() error <span class="cov9" title="54">{
+
v.Lock()
defer v.Unlock()
// Init Role if it is not yet done
// Role needs to be created before token can be created
- if v.initRoleDone == false </span><span class="cov0" title="0">{
- err := v.initRole()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
- return errors.New("Unable to initRole in checkToken")
- }</span>
- }
+ err := v.initRole()
+ if err != nil </span><span class="cov0" title="0">{
+ smslogger.WriteError(err.Error())
+ return errors.New("Unable to initRole in checkToken")
+ }</span>
// Return immediately if token still has life
- <span class="cov10" title="24">if v.vaultClient.Token() != "" &amp;&amp;
- time.Since(v.vaultTempTokenTTL) &lt; time.Minute*50 </span><span class="cov9" title="23">{
+ <span class="cov9" title="54">if v.vaultClient.Token() != "" &amp;&amp;
+ time.Since(v.vaultTempTokenTTL) &lt; time.Minute*50 </span><span class="cov9" title="47">{
return nil
}</span>
// Create a temporary token using our roleID and secretID
- <span class="cov1" title="1">out, err := v.vaultClient.Logical().Write("auth/approle/login",
+ <span class="cov5" title="7">out, err := v.vaultClient.Logical().Write("auth/approle/login",
map[string]interface{}{"role_id": v.roleID, "secret_id": v.secretID})
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create Temp Token") != nil </span><span class="cov0" title="0">{
return errors.New("Unable to create Temporary Token for Role")
}</span>
- <span class="cov1" title="1">tok, err := out.TokenID()
+ <span class="cov5" title="7">tok, err := out.TokenID()
v.vaultTempTokenTTL = time.Now()
v.vaultClient.SetToken(tok)
@@ -655,31 +853,53 @@ func (v *Vault) checkToken() error <span class="cov10" title="24">{
// vaultInit() is used to initialize the vault in cases where it is not
// initialized. This happens once during intial bring up.
-func (v *Vault) initializeVault() error <span class="cov0" title="0">{
- initReq := &amp;vaultapi.InitRequest{
- SecretShares: 5,
+func (v *Vault) initializeVault() error <span class="cov2" title="2">{
+
+ // Check for vault init status and don't exit till it is initialized
+ for </span><span class="cov2" title="2">{
+ init, err := v.vaultClient.Sys().InitStatus()
+ if smslogger.CheckError(err, "Get Vault Init Status") != nil </span><span class="cov0" title="0">{
+ smslogger.WriteInfo("Trying again in 10s...")
+ time.Sleep(time.Second * 10)
+ continue</span>
+ }
+ // Did not get any error
+ <span class="cov2" title="2">if init == true </span><span class="cov1" title="1">{
+ smslogger.WriteInfo("Vault is already Initialized")
+ return nil
+ }</span>
+
+ // init status is false
+ // break out of loop and finish initialization
+ <span class="cov1" title="1">smslogger.WriteInfo("Vault is not initialized. Initializing...")
+ break</span>
+ }
+
+ // Hardcoded this to 3. We should make this configurable
+ // in the future
+ <span class="cov1" title="1">initReq := &amp;vaultapi.InitRequest{
+ SecretShares: 3,
SecretThreshold: 3,
}
pbkey, prkey, err := smsauth.GeneratePGPKeyPair()
- if err != nil </span><span class="cov0" title="0">{
+
+ if smslogger.CheckError(err, "Generating PGP Keys") != nil </span><span class="cov0" title="0">{
smslogger.WriteError("Error Generating PGP Keys. Vault Init will not use encryption!")
- }</span><span class="cov0" title="0"> else {
- initReq.PGPKeys = []string{pbkey, pbkey, pbkey, pbkey, pbkey}
+ }</span><span class="cov1" title="1"> else {
+ initReq.PGPKeys = []string{pbkey, pbkey, pbkey}
initReq.RootTokenPGPKey = pbkey
- v.pgpPub = pbkey
- v.pgpPr = prkey
}</span>
- <span class="cov0" title="0">resp, err := v.vaultClient.Sys().Init(initReq)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ <span class="cov1" title="1">resp, err := v.vaultClient.Sys().Init(initReq)
+ if smslogger.CheckError(err, "Initialize Vault") != nil </span><span class="cov0" title="0">{
return errors.New("FATAL: Unable to initialize Vault")
}</span>
- <span class="cov0" title="0">if resp != nil </span><span class="cov0" title="0">{
- v.unsealShards = resp.KeysB64
- v.rootToken = resp.RootToken
+ <span class="cov1" title="1">if resp != nil </span><span class="cov1" title="1">{
+ v.prkey = prkey
+ v.shards = resp.KeysB64
+ v.vaultToken, _ = smsauth.DecryptPGPString(resp.RootToken, prkey)
return nil
}</span>
@@ -708,6 +928,7 @@ package config
import (
"encoding/json"
"os"
+ smslogger "sms/log"
)
// SMSConfiguration loads up all the values that are used to configure
@@ -718,8 +939,10 @@ type SMSConfiguration struct {
ServerCert string `json:"servercert"`
ServerKey string `json:"serverkey"`
- VaultAddress string `json:"vaultaddress"`
- VaultToken string `json:"vaulttoken"`
+ BackendAddress string `json:"smsdbaddress"`
+ VaultToken string `json:"vaulttoken"`
+ DisableTLS bool `json:"disable_tls"`
+ BackendAddressEnvVariable string `json:"smsdburlenv"`
}
// SMSConfig is the structure that stores the configuration
@@ -734,12 +957,19 @@ func ReadConfigFile(file string) (*SMSConfiguration, error) <span class="cov10"
}</span>
<span class="cov6" title="2">defer f.Close()
- SMSConfig = &amp;SMSConfiguration{}
+ // Default behaviour is to enable TLS
+ SMSConfig = &amp;SMSConfiguration{DisableTLS: false}
decoder := json.NewDecoder(f)
err = decoder.Decode(SMSConfig)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
+
+ <span class="cov6" title="2">if SMSConfig.BackendAddress == "" &amp;&amp; SMSConfig.BackendAddressEnvVariable != "" </span><span class="cov0" title="0">{
+ // Get the value from ENV variable
+ smslogger.WriteInfo("Using Environment Variable: " + SMSConfig.BackendAddressEnvVariable)
+ SMSConfig.BackendAddress = os.Getenv(SMSConfig.BackendAddressEnvVariable)
+ }</span>
}
<span class="cov6" title="2">return SMSConfig, nil</span>
@@ -785,29 +1015,24 @@ func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Reques
var d smsbackend.SecretDomain
err := json.NewDecoder(r.Body).Decode(&amp;d)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusBadRequest)
return
}</span>
<span class="cov6" title="3">dom, err := h.secretBackend.CreateSecretDomain(d.Name)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
- <span class="cov6" title="3">jdata, err := json.Marshal(dom)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ <span class="cov6" title="3">w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+ err = json.NewEncoder(w).Encode(dom)
+ if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
-
- <span class="cov6" title="3">w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusCreated)
- w.Write(jdata)</span>
}
// deleteSecretDomainHandler deletes a secret domain with the name provided
@@ -816,8 +1041,7 @@ func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Reques
domName := vars["domName"]
err := h.secretBackend.DeleteSecretDomain(domName)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "DeleteSecretDomainHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
@@ -834,15 +1058,13 @@ func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) <sp
// Get secrets to be stored from body
var b smsbackend.Secret
err := json.NewDecoder(r.Body).Decode(&amp;b)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "CreateSecretHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusBadRequest)
return
}</span>
<span class="cov10" title="7">err = h.secretBackend.CreateSecret(domName, b)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "CreateSecretHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
@@ -857,21 +1079,17 @@ func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) <span
secName := vars["secretName"]
sec, err := h.secretBackend.GetSecret(domName, secName)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "GetSecretHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
- <span class="cov10" title="7">jdata, err := json.Marshal(sec)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ <span class="cov10" title="7">w.Header().Set("Content-Type", "application/json")
+ err = json.NewEncoder(w).Encode(sec)
+ if smslogger.CheckError(err, "GetSecretHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
-
- <span class="cov10" title="7">w.Header().Set("Content-Type", "application/json")
- w.Write(jdata)</span>
}
// listSecretHandler handles listing all secrets under a particular domain name
@@ -880,8 +1098,7 @@ func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) <span
domName := vars["domName"]
secList, err := h.secretBackend.ListSecret(domName)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "ListSecretHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
@@ -893,15 +1110,12 @@ func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) <span
secList,
}
- jdata, err := json.Marshal(retStruct)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ w.Header().Set("Content-Type", "application/json")
+ err = json.NewEncoder(w).Encode(retStruct)
+ if smslogger.CheckError(err, "ListSecretHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
-
- <span class="cov6" title="3">w.Header().Set("Content-Type", "application/json")
- w.Write(jdata)</span>
}
// deleteSecretHandler handles deleting a secret by given domain name and secret name
@@ -911,37 +1125,34 @@ func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) <sp
secName := vars["secretName"]
err := h.secretBackend.DeleteSecret(domName, secName)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "DeleteSecretHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
-}
-// struct that tracks various status items for SMS and backend
-type backendStatus struct {
- Seal bool `json:"sealstatus"`
+ <span class="cov10" title="7">w.WriteHeader(http.StatusNoContent)</span>
}
// statusHandler returns information related to SMS and SMS backend services
-func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) <span class="cov6" title="3">{
+func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) <span class="cov7" title="4">{
s, err := h.secretBackend.GetStatus()
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "StatusHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
- <span class="cov6" title="3">status := backendStatus{Seal: s}
- jdata, err := json.Marshal(status)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ <span class="cov7" title="4">status := struct {
+ Seal bool `json:"sealstatus"`
+ }{
+ s,
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ err = json.NewEncoder(w).Encode(status)
+ if smslogger.CheckError(err, "StatusHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
-
- <span class="cov6" title="3">w.Header().Set("Content-Type", "application/json")
- w.Write(jdata)</span>
}
// loginHandler handles login via password and username
@@ -961,15 +1172,53 @@ func (h handler) unsealHandler(w http.ResponseWriter, r *http.Request) <span cla
decoder := json.NewDecoder(r.Body)
decoder.DisallowUnknownFields()
err := decoder.Decode(&amp;inp)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "UnsealHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, "Bad input JSON", http.StatusBadRequest)
return
}</span>
<span class="cov0" title="0">err = h.secretBackend.Unseal(inp.UnsealShard)
- if err != nil </span><span class="cov0" title="0">{
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "UnsealHandler") != nil </span><span class="cov0" title="0">{
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }</span>
+}
+
+// registerHandler allows the quorum clients to register with SMS
+// with their PGP public keys that are then used by sms for backend
+// initialization
+func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) <span class="cov1" title="1">{
+ // Get shards to be used for unseal
+ type registerStruct struct {
+ PGPKey string `json:"pgpkey"`
+ QuorumID string `json:"quorumid"`
+ }
+
+ var inp registerStruct
+ decoder := json.NewDecoder(r.Body)
+ decoder.DisallowUnknownFields()
+ err := decoder.Decode(&amp;inp)
+ if smslogger.CheckError(err, "RegisterHandler") != nil </span><span class="cov0" title="0">{
+ http.Error(w, "Bad input JSON", http.StatusBadRequest)
+ return
+ }</span>
+
+ <span class="cov1" title="1">sh, err := h.secretBackend.RegisterQuorum(inp.PGPKey)
+ if smslogger.CheckError(err, "RegisterHandler") != nil </span><span class="cov0" title="0">{
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }</span>
+
+ // Creating a struct for return data
+ <span class="cov1" title="1">shStruct := struct {
+ Shard string `json:"shard"`
+ }{
+ sh,
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ err = json.NewEncoder(w).Encode(shStruct)
+ if smslogger.CheckError(err, "RegisterHandler") != nil </span><span class="cov0" title="0">{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}</span>
@@ -987,8 +1236,9 @@ func CreateRouter(b smsbackend.SecretBackend) http.Handler <span class="cov4" ti
// Initialization APIs which will be used by quorum client
// to unseal and to provide root token to sms service
- router.HandleFunc("/v1/sms/status", h.statusHandler).Methods("GET")
- router.HandleFunc("/v1/sms/unseal", h.unsealHandler).Methods("POST")
+ router.HandleFunc("/v1/sms/quorum/status", h.statusHandler).Methods("GET")
+ router.HandleFunc("/v1/sms/quorum/unseal", h.unsealHandler).Methods("POST")
+ router.HandleFunc("/v1/sms/quorum/register", h.registerHandler).Methods("POST")
router.HandleFunc("/v1/sms/domain", h.createSecretDomainHandler).Methods("POST")
router.HandleFunc("/v1/sms/domain/{domName}", h.deleteSecretDomainHandler).Methods("DELETE")
@@ -1021,53 +1271,85 @@ func CreateRouter(b smsbackend.SecretBackend) http.Handler <span class="cov4" ti
package log
import (
+ "fmt"
"log"
"os"
)
-var errLogger *log.Logger
-var warnLogger *log.Logger
-var infoLogger *log.Logger
+var errL, warnL, infoL *log.Logger
+var stdErr, stdWarn, stdInfo *log.Logger
// Init will be called by sms.go before any other packages use it
-func Init(filePath string) <span class="cov8" title="1">{
- f, err := os.Create(filePath)
+func Init(filePath string) <span class="cov1" title="1">{
+
+ stdErr = log.New(os.Stderr, "ERROR: ", log.Lshortfile|log.LstdFlags)
+ stdWarn = log.New(os.Stdout, "WARNING: ", log.Lshortfile|log.LstdFlags)
+ stdInfo = log.New(os.Stdout, "INFO: ", log.Lshortfile|log.LstdFlags)
+
+ if filePath == "" </span><span class="cov0" title="0">{
+ // We will just to std streams
+ return
+ }</span>
+
+ <span class="cov1" title="1">f, err := os.Create(filePath)
if err != nil </span><span class="cov0" title="0">{
- log.Println("Unable to create a log file")
- log.Println(err)
- errLogger = log.New(os.Stderr, "ERROR: ", log.Lshortfile|log.LstdFlags)
- warnLogger = log.New(os.Stdout, "WARNING: ", log.Lshortfile|log.LstdFlags)
- infoLogger = log.New(os.Stdout, "INFO: ", log.Lshortfile|log.LstdFlags)
- }</span><span class="cov8" title="1"> else {
- errLogger = log.New(f, "ERROR: ", log.Lshortfile|log.LstdFlags)
- warnLogger = log.New(f, "WARNING: ", log.Lshortfile|log.LstdFlags)
- infoLogger = log.New(f, "INFO: ", log.Lshortfile|log.LstdFlags)
+ stdErr.Println("Unable to create log file: " + err.Error())
+ return
}</span>
+
+ <span class="cov1" title="1">errL = log.New(f, "ERROR: ", log.Lshortfile|log.LstdFlags)
+ warnL = log.New(f, "WARNING: ", log.Lshortfile|log.LstdFlags)
+ infoL = log.New(f, "INFO: ", log.Lshortfile|log.LstdFlags)</span>
}
// WriteError writes output to the writer we have
-// defined durint its creation with ERROR prefix
+// defined during its creation with ERROR prefix
func WriteError(msg string) <span class="cov0" title="0">{
- if errLogger != nil </span><span class="cov0" title="0">{
- errLogger.Println(msg)
+ if errL != nil </span><span class="cov0" title="0">{
+ errL.Output(2, fmt.Sprintln(msg))
+ }</span>
+ <span class="cov0" title="0">if stdErr != nil </span><span class="cov0" title="0">{
+ stdErr.Output(2, fmt.Sprintln(msg))
}</span>
}
// WriteWarn writes output to the writer we have
-// defined durint its creation with WARNING prefix
+// defined during its creation with WARNING prefix
func WriteWarn(msg string) <span class="cov0" title="0">{
- if warnLogger != nil </span><span class="cov0" title="0">{
- warnLogger.Println(msg)
+ if warnL != nil </span><span class="cov0" title="0">{
+ warnL.Output(2, fmt.Sprintln(msg))
+ }</span>
+ <span class="cov0" title="0">if stdWarn != nil </span><span class="cov0" title="0">{
+ stdWarn.Output(2, fmt.Sprintln(msg))
}</span>
}
// WriteInfo writes output to the writer we have
-// defined durint its creation with INFO prefix
-func WriteInfo(msg string) <span class="cov0" title="0">{
- if infoLogger != nil </span><span class="cov0" title="0">{
- infoLogger.Println(msg)
+// defined during its creation with INFO prefix
+func WriteInfo(msg string) <span class="cov1" title="1">{
+ if infoL != nil </span><span class="cov1" title="1">{
+ infoL.Output(2, fmt.Sprintln(msg))
+ }</span>
+ <span class="cov1" title="1">if stdInfo != nil </span><span class="cov1" title="1">{
+ stdInfo.Output(2, fmt.Sprintln(msg))
}</span>
}
+
+//CheckError is a helper function to reduce
+//repitition of error checkign blocks of code
+func CheckError(err error, topic string) error <span class="cov10" title="116">{
+ if err != nil </span><span class="cov1" title="1">{
+ msg := topic + ": " + err.Error()
+ if errL != nil </span><span class="cov1" title="1">{
+ errL.Output(2, fmt.Sprintln(msg))
+ }</span>
+ <span class="cov1" title="1">if stdErr != nil </span><span class="cov1" title="1">{
+ stdErr.Output(2, fmt.Sprintln(msg))
+ }</span>
+ <span class="cov1" title="1">return err</span>
+ }
+ <span class="cov9" title="115">return nil</span>
+}
</pre>
<pre class="file" id="file6" style="display: none">/*
@@ -1119,16 +1401,9 @@ func main() <span class="cov8" title="1">{
<span class="cov8" title="1">httpRouter := smshandler.CreateRouter(backendImpl)
- // TODO: Use CA certificate from AAF
- tlsConfig, err := smsauth.GetTLSConfig(smsConf.CAFile)
- if err != nil </span><span class="cov0" title="0">{
- log.Fatal(err)
- }</span>
-
- <span class="cov8" title="1">httpServer := &amp;http.Server{
- Handler: httpRouter,
- Addr: ":10443",
- TLSConfig: tlsConfig,
+ httpServer := &amp;http.Server{
+ Handler: httpRouter,
+ Addr: ":10443",
}
// Listener for SIGINT so that it returns cleanly
@@ -1141,8 +1416,22 @@ func main() <span class="cov8" title="1">{
close(connectionsClose)
}</span>()
- <span class="cov8" title="1">err = httpServer.ListenAndServeTLS(smsConf.ServerCert, smsConf.ServerKey)
- if err != nil &amp;&amp; err != http.ErrServerClosed </span><span class="cov0" title="0">{
+ // Start in TLS mode by default
+ <span class="cov8" title="1">if smsConf.DisableTLS == true </span><span class="cov0" title="0">{
+ smslogger.WriteWarn("TLS is Disabled")
+ err = httpServer.ListenAndServe()
+ }</span><span class="cov8" title="1"> else {
+ // TODO: Use CA certificate from AAF
+ tlsConfig, err := smsauth.GetTLSConfig(smsConf.CAFile)
+ if err != nil </span><span class="cov0" title="0">{
+ log.Fatal(err)
+ }</span>
+
+ <span class="cov8" title="1">httpServer.TLSConfig = tlsConfig
+ err = httpServer.ListenAndServeTLS(smsConf.ServerCert, smsConf.ServerKey)</span>
+ }
+
+ <span class="cov8" title="1">if err != nil &amp;&amp; err != http.ErrServerClosed </span><span class="cov0" title="0">{
log.Fatal(err)
}</span>
diff --git a/sms-service/src/sms/coverage.md b/sms-service/doc/coverage.md
index 6168342..6168342 100644
--- a/sms-service/src/sms/coverage.md
+++ b/sms-service/doc/coverage.md
diff --git a/sms-service/src/quorumclient/quorumclient.go b/sms-service/src/quorumclient/quorumclient.go
index 05fc967..dfa1a26 100644
--- a/sms-service/src/quorumclient/quorumclient.go
+++ b/sms-service/src/quorumclient/quorumclient.go
@@ -37,13 +37,13 @@ func loadPGPKeys(prKeyPath string, pbKeyPath string) (string, string, error) {
var pbkey, prkey string
generated := false
prkey, err := smsauth.ReadFromFile(prKeyPath)
- if err != nil {
- smslogger.WriteWarn("No Private Key found. Generating...")
+ if smslogger.CheckError(err, "LoadPGP Private Key") != nil {
+ smslogger.WriteInfo("No Private Key found. Generating...")
pbkey, prkey, _ = smsauth.GeneratePGPKeyPair()
generated = true
} else {
pbkey, err = smsauth.ReadFromFile(pbKeyPath)
- if err != nil {
+ if smslogger.CheckError(err, "LoadPGP Public Key") != nil {
smslogger.WriteWarn("No Public Key found. Generating...")
pbkey, prkey, _ = smsauth.GeneratePGPKeyPair()
generated = true
@@ -70,7 +70,7 @@ func main() {
prKeyPath := filepath.Join("auth", podName, "prkey")
shardPath := filepath.Join("auth", podName, "shard")
- smslogger.Init("")
+ smslogger.Init("quorum.log")
smslogger.WriteInfo("Starting Log for Quorum Client")
/*
@@ -80,7 +80,7 @@ func main() {
In Kubernetes, pod restarts will also change the hostname
*/
myID, err := smsauth.ReadFromFile(idFilePath)
- if err != nil {
+ if smslogger.CheckError(err, "Read ID") != nil {
smslogger.WriteWarn("Unable to find an ID for this client. Generating...")
myID, _ = uuid.GenerateUUID()
smsauth.WriteToFile(myID, idFilePath)
@@ -93,7 +93,7 @@ func main() {
*/
registrationDone := true
myShard, err := smsauth.ReadFromFile(shardPath)
- if err != nil {
+ if smslogger.CheckError(err, "Read Shard") != nil {
smslogger.WriteWarn("Unable to find a shard file. Registering with SMS...")
registrationDone = false
}
@@ -160,8 +160,7 @@ func main() {
//URL and Port is configured in config file
response, err := client.Get(cfg.BackEndURL + "/v1/sms/quorum/status")
- if err != nil {
- smslogger.WriteError("Unable to connect to SMS. Retrying...")
+ if smslogger.CheckError(err, "Connect to SMS") != nil {
continue
}
@@ -178,8 +177,7 @@ func main() {
if !registrationDone {
body := strings.NewReader(`{"pgpkey":"` + pbkey + `","quorumid":"` + myID + `"}`)
res, err := client.Post(cfg.BackEndURL+"/v1/sms/quorum/register", "application/json", body)
- if err != nil {
- smslogger.WriteError("Ran into error during registration. Retrying...")
+ if smslogger.CheckError(err, "Register with SMS") != nil {
continue
}
registrationDone = true
@@ -195,8 +193,8 @@ func main() {
body := strings.NewReader(`{"unsealshard":"` + decShard + `"}`)
//URL and PORT is configured via config file
response, err = client.Post(cfg.BackEndURL+"/v1/sms/quorum/unseal", "application/json", body)
- if err != nil {
- smslogger.WriteError("Error unsealing vault. Retrying... " + err.Error())
+ if smslogger.CheckError(err, "Unsealing Vault") != nil {
+ continue
}
}
}
diff --git a/sms-service/src/sms/Gopkg.lock b/sms-service/src/sms/Gopkg.lock
index c7684c7..2c09256 100644
--- a/sms-service/src/sms/Gopkg.lock
+++ b/sms-service/src/sms/Gopkg.lock
@@ -477,6 +477,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
- inputs-digest = "d19e17a023506ab731b0f26c6fcfebe581d4d5194af094aecea5e72daddd3ead"
+ inputs-digest = "8280cde72a3ab78ad00d13c192de5920d188f3052f45884563896cab659469f9"
solver-name = "gps-cdcl"
solver-version = 1
diff --git a/sms-service/src/sms/auth/auth.go b/sms-service/src/sms/auth/auth.go
index 7172505..038e31d 100644
--- a/sms-service/src/sms/auth/auth.go
+++ b/sms-service/src/sms/auth/auth.go
@@ -29,39 +29,27 @@ import (
smslogger "sms/log"
)
-var tlsConfig *tls.Config
-
-func checkError(err error, topic string) error {
- if err != nil {
- smslogger.WriteError(topic + ": " + err.Error())
- return err
- }
-
- return nil
-}
-
// GetTLSConfig initializes a tlsConfig using the CA's certificate
// This config is then used to enable the server for mutual TLS
func GetTLSConfig(caCertFile string) (*tls.Config, error) {
+
// Initialize tlsConfig once
- if tlsConfig == nil {
- caCert, err := ioutil.ReadFile(caCertFile)
+ caCert, err := ioutil.ReadFile(caCertFile)
- if err != nil {
- return nil, err
- }
+ if err != nil {
+ return nil, err
+ }
- caCertPool := x509.NewCertPool()
- caCertPool.AppendCertsFromPEM(caCert)
+ caCertPool := x509.NewCertPool()
+ caCertPool.AppendCertsFromPEM(caCert)
- tlsConfig = &tls.Config{
- // Change to RequireAndVerify once we have mandatory certs
- ClientAuth: tls.VerifyClientCertIfGiven,
- ClientCAs: caCertPool,
- MinVersion: tls.VersionTLS12,
- }
- tlsConfig.BuildNameToCertificate()
+ tlsConfig := &tls.Config{
+ // Change to RequireAndVerify once we have mandatory certs
+ ClientAuth: tls.VerifyClientCertIfGiven,
+ ClientCAs: caCertPool,
+ MinVersion: tls.VersionTLS12,
}
+ tlsConfig.BuildNameToCertificate()
return tlsConfig, nil
}
@@ -70,22 +58,21 @@ func GetTLSConfig(caCertFile string) (*tls.Config, error) {
// A base64 encoded form of the public part of the entity
// A base64 encoded form of the private key
func GeneratePGPKeyPair() (string, string, error) {
+
var entity *openpgp.Entity
config := &packet.Config{
DefaultHash: crypto.SHA256,
}
entity, err := openpgp.NewEntity("aaf.sms.init", "PGP Key for unsealing", "", config)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create Entity") != nil {
return "", "", err
}
// Sign the identity in the entity
for _, id := range entity.Identities {
err = id.SelfSignature.SignUserId(id.UserId.Id, entity.PrimaryKey, entity.PrivateKey, nil)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Sign Entity") != nil {
return "", "", err
}
}
@@ -93,8 +80,7 @@ func GeneratePGPKeyPair() (string, string, error) {
// Sign the subkey in the entity
for _, subkey := range entity.Subkeys {
err := subkey.Sig.SignKey(subkey.PublicKey, entity.PrivateKey, nil)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Sign Subkey") != nil {
return "", "", err
}
}
@@ -113,32 +99,33 @@ func GeneratePGPKeyPair() (string, string, error) {
// EncryptPGPString takes data and a public key and encrypts using that
// public key
func EncryptPGPString(data string, pbKey string) (string, error) {
+
pbKeyBytes, err := base64.StdEncoding.DecodeString(pbKey)
- if checkError(err, "Decoding Base64 Public Key") != nil {
+ if smslogger.CheckError(err, "Decoding Base64 Public Key") != nil {
return "", err
}
dataBytes := []byte(data)
pbEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(pbKeyBytes)))
- if checkError(err, "Reading entity from PGP key") != nil {
+ if smslogger.CheckError(err, "Reading entity from PGP key") != nil {
return "", err
}
// encrypt string
buf := new(bytes.Buffer)
out, err := openpgp.Encrypt(buf, []*openpgp.Entity{pbEntity}, nil, nil, nil)
- if checkError(err, "Creating Encryption Pipe") != nil {
+ if smslogger.CheckError(err, "Creating Encryption Pipe") != nil {
return "", err
}
_, err = out.Write(dataBytes)
- if checkError(err, "Writing to Encryption Pipe") != nil {
+ if smslogger.CheckError(err, "Writing to Encryption Pipe") != nil {
return "", err
}
err = out.Close()
- if checkError(err, "Closing Encryption Pipe") != nil {
+ if smslogger.CheckError(err, "Closing Encryption Pipe") != nil {
return "", err
}
@@ -149,29 +136,26 @@ func EncryptPGPString(data string, pbKey string) (string, error) {
// DecryptPGPString decrypts a PGP encoded input string and returns
// a base64 representation of the decoded string
func DecryptPGPString(data string, prKey string) (string, error) {
+
// Convert private key to bytes from base64
prKeyBytes, err := base64.StdEncoding.DecodeString(prKey)
- if err != nil {
- smslogger.WriteError("Error Decoding base64 private key: " + err.Error())
+ if smslogger.CheckError(err, "Decoding Base64 Private Key") != nil {
return "", err
}
dataBytes, err := base64.StdEncoding.DecodeString(data)
- if err != nil {
- smslogger.WriteError("Error Decoding base64 data: " + err.Error())
+ if smslogger.CheckError(err, "Decoding base64 data") != nil {
return "", err
}
prEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(prKeyBytes)))
- if err != nil {
- smslogger.WriteError("Error reading entity from PGP key: " + err.Error())
+ if smslogger.CheckError(err, "Read Entity") != nil {
return "", err
}
prEntityList := &openpgp.EntityList{prEntity}
message, err := openpgp.ReadMessage(bytes.NewBuffer(dataBytes), prEntityList, nil, nil)
- if err != nil {
- smslogger.WriteError("Error Decrypting message: " + err.Error())
+ if smslogger.CheckError(err, "Decrypting Message") != nil {
return "", err
}
@@ -186,13 +170,10 @@ func DecryptPGPString(data string, prKey string) (string, error) {
func ReadFromFile(fileName string) (string, error) {
data, err := ioutil.ReadFile(fileName)
- if err != nil {
- smslogger.WriteError(err.Error())
- smslogger.WriteError("Cannot read file: " + fileName)
+ if smslogger.CheckError(err, "Read from file") != nil {
return "", err
}
return string(data), nil
-
}
// WriteToFile writes a PGP key into a file.
@@ -200,11 +181,8 @@ func ReadFromFile(fileName string) (string, error) {
func WriteToFile(data string, fileName string) error {
err := ioutil.WriteFile(fileName, []byte(data), 0600)
- if err != nil {
- smslogger.WriteError(err.Error())
- smslogger.WriteError("Cannot write to file: " + fileName)
+ if smslogger.CheckError(err, "Write to file") != nil {
return err
}
return nil
-
}
diff --git a/sms-service/src/sms/backend/backend.go b/sms-service/src/sms/backend/backend.go
index c137636..d7662ef 100644
--- a/sms-service/src/sms/backend/backend.go
+++ b/sms-service/src/sms/backend/backend.go
@@ -60,8 +60,7 @@ func InitSecretBackend() (SecretBackend, error) {
}
err := backendImpl.Init()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "InitSecretBackend") != nil {
return nil, err
}
diff --git a/sms-service/src/sms/backend/vault.go b/sms-service/src/sms/backend/vault.go
index e26baff..7fee097 100644
--- a/sms-service/src/sms/backend/vault.go
+++ b/sms-service/src/sms/backend/vault.go
@@ -56,9 +56,8 @@ func (v *Vault) initVaultClient() error {
vaultCFG := vaultapi.DefaultConfig()
vaultCFG.Address = v.vaultAddress
client, err := vaultapi.NewClient(vaultCFG)
- if err != nil {
- smslogger.WriteError(err.Error())
- return errors.New("Unable to create new vault client")
+ if smslogger.CheckError(err, "Create new vault client") != nil {
+ return err
}
v.initRoleDone = false
@@ -69,7 +68,6 @@ func (v *Vault) initVaultClient() error {
v.internalDomainMounted = false
v.prkey = ""
return nil
-
}
// Init will initialize the vault connection
@@ -84,8 +82,7 @@ func (v *Vault) Init() error {
v.initializeVault()
err := v.initRole()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "InitRole First Attempt") != nil {
smslogger.WriteInfo("InitRole will try again later")
}
@@ -94,10 +91,10 @@ func (v *Vault) Init() error {
// GetStatus returns the current seal status of vault
func (v *Vault) GetStatus() (bool, error) {
+
sys := v.vaultClient.Sys()
sealStatus, err := sys.SealStatus()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Getting Status") != nil {
return false, errors.New("Error getting status")
}
@@ -112,7 +109,7 @@ func (v *Vault) RegisterQuorum(pgpkey string) (string, error) {
defer v.Unlock()
if v.shards == nil {
- smslogger.WriteError("Invalid operation")
+ smslogger.WriteError("Invalid operation in RegisterQuorum")
return "", errors.New("Invalid operation")
}
// Pop the slice
@@ -133,10 +130,10 @@ func (v *Vault) RegisterQuorum(pgpkey string) (string, error) {
// Unseal is a passthrough API that allows any
// unseal or initialization processes for the backend
func (v *Vault) Unseal(shard string) error {
+
sys := v.vaultClient.Sys()
_, err := sys.Unseal(shard)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Unseal Operation") != nil {
return errors.New("Unable to execute unseal operation with specified shard")
}
@@ -147,17 +144,16 @@ func (v *Vault) Unseal(shard string) error {
// The secret itself is referenced via its name which translates to
// a mount path in vault
func (v *Vault) GetSecret(dom string, name string) (Secret, error) {
+
err := v.checkToken()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Tocken Check") != nil {
return Secret{}, errors.New("Token check failed")
}
dom = v.vaultMountPrefix + "/" + dom
sec, err := v.vaultClient.Logical().Read(dom + "/" + name)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Read Secret") != nil {
return Secret{}, errors.New("Unable to read Secret at provided path")
}
@@ -173,17 +169,16 @@ func (v *Vault) GetSecret(dom string, name string) (Secret, error) {
// ListSecret returns a list of secret names on a particular domain
// The values of the secret are not returned
func (v *Vault) ListSecret(dom string) ([]string, error) {
+
err := v.checkToken()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil {
return nil, errors.New("Token check failed")
}
dom = v.vaultMountPrefix + "/" + dom
sec, err := v.vaultClient.Logical().List(dom)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Read Secret") != nil {
return nil, errors.New("Unable to read Secret at provided path")
}
@@ -209,6 +204,7 @@ func (v *Vault) ListSecret(dom string) ([]string, error) {
// Mounts the internal Domain if its not already mounted
func (v *Vault) mountInternalDomain(name string) error {
+
if v.internalDomainMounted {
return nil
}
@@ -224,14 +220,13 @@ func (v *Vault) mountInternalDomain(name string) error {
}
err := v.vaultClient.Sys().Mount(mountPath, mountInput)
- if err != nil {
+ if smslogger.CheckError(err, "Mount internal Domain") != nil {
if strings.Contains(err.Error(), "existing mount") {
// It is already mounted
v.internalDomainMounted = true
return nil
}
// Ran into some other error mounting it.
- smslogger.WriteError(err.Error())
return errors.New("Unable to mount internal Domain")
}
@@ -242,16 +237,15 @@ func (v *Vault) mountInternalDomain(name string) error {
// Stores the UUID created for secretdomain in vault
// under v.vaultMountPrefix / smsinternal domain
func (v *Vault) storeUUID(uuid string, name string) error {
+
// Check if token is still valid
err := v.checkToken()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil {
return errors.New("Token Check failed")
}
err = v.mountInternalDomain(v.internalDomain)
- if err != nil {
- smslogger.WriteError("Could not mount internal domain")
+ if smslogger.CheckError(err, "Mount Internal Domain") != nil {
return err
}
@@ -263,8 +257,7 @@ func (v *Vault) storeUUID(uuid string, name string) error {
}
err = v.CreateSecret(v.internalDomain, secret)
- if err != nil {
- smslogger.WriteError("Unable to write UUID to internal domain")
+ if smslogger.CheckError(err, "Write UUID to domain") != nil {
return err
}
@@ -273,10 +266,10 @@ func (v *Vault) storeUUID(uuid string, name string) error {
// CreateSecretDomain mounts the kv backend on a path with the given name
func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) {
+
// Check if token is still valid
err := v.checkToken()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil {
return SecretDomain{}, errors.New("Token Check failed")
}
@@ -291,14 +284,13 @@ func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) {
}
err = v.vaultClient.Sys().Mount(mountPath, mountInput)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create Domain") != nil {
return SecretDomain{}, errors.New("Unable to create Secret Domain")
}
uuid, _ := uuid.GenerateUUID()
err = v.storeUUID(uuid, name)
- if err != nil {
+ if smslogger.CheckError(err, "Store UUID") != nil {
// Mount was successful at this point.
// Rollback the mount operation since we could not
// store the UUID for the mount.
@@ -312,9 +304,9 @@ func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) {
// CreateSecret creates a secret mounted on a particular domain name
// The secret itself is mounted on a path specified by name
func (v *Vault) CreateSecret(dom string, sec Secret) error {
+
err := v.checkToken()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil {
return errors.New("Token check failed")
}
@@ -323,8 +315,7 @@ func (v *Vault) CreateSecret(dom string, sec Secret) error {
// Vault return is empty on successful write
// TODO: Check if values is not empty
_, err = v.vaultClient.Logical().Write(dom+"/"+sec.Name, sec.Values)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create Secret") != nil {
return errors.New("Unable to create Secret at provided path")
}
@@ -334,9 +325,9 @@ func (v *Vault) CreateSecret(dom string, sec Secret) error {
// DeleteSecretDomain deletes a secret domain which translates to
// an unmount operation on the given path in Vault
func (v *Vault) DeleteSecretDomain(name string) error {
+
err := v.checkToken()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil {
return errors.New("Token Check Failed")
}
@@ -344,8 +335,7 @@ func (v *Vault) DeleteSecretDomain(name string) error {
mountPath := v.vaultMountPrefix + "/" + name
err = v.vaultClient.Sys().Unmount(mountPath)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Delete Domain") != nil {
return errors.New("Unable to delete domain specified")
}
@@ -356,8 +346,7 @@ func (v *Vault) DeleteSecretDomain(name string) error {
func (v *Vault) DeleteSecret(dom string, name string) error {
err := v.checkToken()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Token Check") != nil {
return errors.New("Token check failed")
}
@@ -365,8 +354,7 @@ func (v *Vault) DeleteSecret(dom string, name string) error {
// Vault return is empty on successful delete
_, err = v.vaultClient.Logical().Delete(dom + "/" + name)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Delete Secret") != nil {
return errors.New("Unable to delete Secret at provided path")
}
@@ -406,15 +394,13 @@ func (v *Vault) initRole() error {
rules := `path "sms/*" { capabilities = ["create", "read", "update", "delete", "list"] }
path "sys/mounts/sms*" { capabilities = ["update","delete","create"] }`
err := v.vaultClient.Sys().PutPolicy(v.policyName, rules)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Creating Policy") != nil {
return errors.New("Unable to create policy for approle creation")
}
//Check if applrole is mounted
authMounts, err := v.vaultClient.Sys().ListAuth()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Mount Auth Backend") != nil {
return errors.New("Unable to get mounted auth backends")
}
@@ -440,8 +426,7 @@ func (v *Vault) initRole() error {
// Create a role-id
v.vaultClient.Logical().Write("auth/approle/role/"+rName, data)
sec, err := v.vaultClient.Logical().Read("auth/approle/role/" + rName + "/role-id")
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create RoleID") != nil {
return errors.New("Unable to create role ID for approle")
}
v.roleID = sec.Data["role_id"].(string)
@@ -449,8 +434,7 @@ func (v *Vault) initRole() error {
// Create a secret-id to go with it
sec, err = v.vaultClient.Logical().Write("auth/approle/role/"+rName+"/secret-id",
map[string]interface{}{})
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create SecretID") != nil {
return errors.New("Unable to create secret ID for role")
}
@@ -462,8 +446,7 @@ func (v *Vault) initRole() error {
* using the unseal shards.
*/
err = v.vaultClient.Auth().Token().RevokeSelf(v.vaultToken)
- if err != nil {
- smslogger.WriteWarn(err.Error())
+ if smslogger.CheckError(err, "Revoke Root Token") != nil {
smslogger.WriteWarn("Unable to Revoke Token")
} else {
// Revoked successfully and clear it
@@ -481,6 +464,7 @@ func (v *Vault) initRole() error {
// Function checkToken() gets called multiple times to create
// temporary tokens
func (v *Vault) checkToken() error {
+
v.Lock()
defer v.Unlock()
@@ -501,8 +485,7 @@ func (v *Vault) checkToken() error {
// Create a temporary token using our roleID and secretID
out, err := v.vaultClient.Logical().Write("auth/approle/login",
map[string]interface{}{"role_id": v.roleID, "secret_id": v.secretID})
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Create Temp Token") != nil {
return errors.New("Unable to create Temporary Token for Role")
}
@@ -516,11 +499,12 @@ func (v *Vault) checkToken() error {
// vaultInit() is used to initialize the vault in cases where it is not
// initialized. This happens once during intial bring up.
func (v *Vault) initializeVault() error {
+
// Check for vault init status and don't exit till it is initialized
for {
init, err := v.vaultClient.Sys().InitStatus()
- if err != nil {
- smslogger.WriteError("Unable to get initStatus, trying again in 10s: " + err.Error())
+ if smslogger.CheckError(err, "Get Vault Init Status") != nil {
+ smslogger.WriteInfo("Trying again in 10s...")
time.Sleep(time.Second * 10)
continue
}
@@ -545,7 +529,7 @@ func (v *Vault) initializeVault() error {
pbkey, prkey, err := smsauth.GeneratePGPKeyPair()
- if err != nil {
+ if smslogger.CheckError(err, "Generating PGP Keys") != nil {
smslogger.WriteError("Error Generating PGP Keys. Vault Init will not use encryption!")
} else {
initReq.PGPKeys = []string{pbkey, pbkey, pbkey}
@@ -553,8 +537,7 @@ func (v *Vault) initializeVault() error {
}
resp, err := v.vaultClient.Sys().Init(initReq)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "Initialize Vault") != nil {
return errors.New("FATAL: Unable to initialize Vault")
}
diff --git a/sms-service/src/sms/backend/vault_test.go b/sms-service/src/sms/backend/vault_test.go
index 484c395..4862665 100644
--- a/sms-service/src/sms/backend/vault_test.go
+++ b/sms-service/src/sms/backend/vault_test.go
@@ -17,9 +17,11 @@
package backend
import (
+ vaultapi "github.com/hashicorp/vault/api"
credAppRole "github.com/hashicorp/vault/builtin/credential/approle"
vaulthttp "github.com/hashicorp/vault/http"
vaultlogical "github.com/hashicorp/vault/logical"
+ vaultinmem "github.com/hashicorp/vault/physical/inmem"
vaulttesting "github.com/hashicorp/vault/vault"
"reflect"
smslog "sms/log"
@@ -229,3 +231,39 @@ func TestDeleteSecret(t *testing.T) {
t.Fatal("DeleteSecret: Error Creating secret")
}
}
+
+func TestInitializeVault(t *testing.T) {
+
+ inm, err := vaultinmem.NewInmem(nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ core, err := vaulttesting.NewCore(&vaulttesting.CoreConfig{
+ DisableMlock: true,
+ DisableCache: true,
+ Physical: inm,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ln, addr := vaulthttp.TestServer(t, core)
+ defer ln.Close()
+
+ client, err := vaultapi.NewClient(&vaultapi.Config{
+ Address: addr,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ v := &Vault{}
+ v.initVaultClient()
+ v.vaultClient = client
+
+ err = v.initializeVault()
+ if err != nil {
+ t.Fatal("InitializeVault: Error initializing Vault")
+ }
+}
diff --git a/sms-service/src/sms/handler/handler.go b/sms-service/src/sms/handler/handler.go
index dbf3f93..7ce9e01 100644
--- a/sms-service/src/sms/handler/handler.go
+++ b/sms-service/src/sms/handler/handler.go
@@ -37,15 +37,13 @@ func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Reques
var d smsbackend.SecretDomain
err := json.NewDecoder(r.Body).Decode(&d)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
dom, err := h.secretBackend.CreateSecretDomain(d.Name)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -53,8 +51,7 @@ func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Reques
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
err = json.NewEncoder(w).Encode(dom)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "CreateSecretDomainHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -66,8 +63,7 @@ func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Reques
domName := vars["domName"]
err := h.secretBackend.DeleteSecretDomain(domName)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "DeleteSecretDomainHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -84,15 +80,13 @@ func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) {
// Get secrets to be stored from body
var b smsbackend.Secret
err := json.NewDecoder(r.Body).Decode(&b)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "CreateSecretHandler") != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = h.secretBackend.CreateSecret(domName, b)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "CreateSecretHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -107,16 +101,14 @@ func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) {
secName := vars["secretName"]
sec, err := h.secretBackend.GetSecret(domName, secName)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "GetSecretHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(sec)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "GetSecretHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -128,8 +120,7 @@ func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) {
domName := vars["domName"]
secList, err := h.secretBackend.ListSecret(domName)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "ListSecretHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -143,8 +134,7 @@ func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(retStruct)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "ListSecretHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -157,8 +147,7 @@ func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) {
secName := vars["secretName"]
err := h.secretBackend.DeleteSecret(domName, secName)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "DeleteSecretHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -169,8 +158,7 @@ func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) {
// statusHandler returns information related to SMS and SMS backend services
func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) {
s, err := h.secretBackend.GetStatus()
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "StatusHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -183,8 +171,7 @@ func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(status)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "StatusHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -207,15 +194,13 @@ func (h handler) unsealHandler(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
decoder.DisallowUnknownFields()
err := decoder.Decode(&inp)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "UnsealHandler") != nil {
http.Error(w, "Bad input JSON", http.StatusBadRequest)
return
}
err = h.secretBackend.Unseal(inp.UnsealShard)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "UnsealHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -235,15 +220,13 @@ func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
decoder.DisallowUnknownFields()
err := decoder.Decode(&inp)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "RegisterHandler") != nil {
http.Error(w, "Bad input JSON", http.StatusBadRequest)
return
}
sh, err := h.secretBackend.RegisterQuorum(inp.PGPKey)
- if err != nil {
- smslogger.WriteError(err.Error())
+ if smslogger.CheckError(err, "RegisterHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -257,8 +240,7 @@ func (h handler) registerHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(shStruct)
- if err != nil {
- smslogger.WriteError("Unable to encode response: " + err.Error())
+ if smslogger.CheckError(err, "RegisterHandler") != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
diff --git a/sms-service/src/sms/handler/handler_test.go b/sms-service/src/sms/handler/handler_test.go
index 52637f3..c1e55ed 100644
--- a/sms-service/src/sms/handler/handler_test.go
+++ b/sms-service/src/sms/handler/handler_test.go
@@ -48,7 +48,7 @@ func (b *TestBackend) Unseal(shard string) error {
}
func (b *TestBackend) RegisterQuorum(pgpkey string) (string, error) {
- return "", nil
+ return "N8z4eD2Zgv0eDJrgkkUq3Lh5n2p6Y1Zsui1NIHePlLU=", nil
}
func (b *TestBackend) GetSecret(dom string, sec string) (smsbackend.Secret, error) {
@@ -127,8 +127,49 @@ func TestStatusHandler(t *testing.T) {
}
}
+func TestRegisterHandler(t *testing.T) {
+ body := `{
+ "pgpkey":"asdasdasdasdgkjgljoiwera",
+ "quorumid":"123e4567-e89b-12d3-a456-426655440000"
+ }`
+ reader := strings.NewReader(body)
+ req, err := http.NewRequest("POST", "/v1/sms/quorum/register", reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(h.registerHandler)
+
+ hr.ServeHTTP(rr, req)
+
+ ret := rr.Code
+ if ret != http.StatusOK {
+ t.Errorf("registerHandler returned wrong status code: %v vs %v",
+ ret, http.StatusOK)
+ }
+
+ expected := struct {
+ Shard string `json:"shard"`
+ }{
+ "N8z4eD2Zgv0eDJrgkkUq3Lh5n2p6Y1Zsui1NIHePlLU=",
+ }
+ got := struct {
+ Shard string `json:"shard"`
+ }{}
+
+ json.NewDecoder(rr.Body).Decode(&got)
+
+ if reflect.DeepEqual(expected, got) == false {
+ t.Errorf("statusHandler returned unexpected body: got %v vs %v",
+ rr.Body.String(), expected)
+ }
+}
+
func TestUnsealHandler(t *testing.T) {
- req, err := http.NewRequest("GET", "/v1/sms/quorum/unseal", nil)
+ body := `{"unsealshard":"N8z4eD2Zgv0eDJrgkkUq3Lh5n2p6Y1Zsui1NIHePlLU="}`
+ reader := strings.NewReader(body)
+ req, err := http.NewRequest("POST", "/v1/sms/quorum/unseal", reader)
if err != nil {
t.Fatal(err)
}
diff --git a/sms-service/src/sms/log/logger.go b/sms-service/src/sms/log/logger.go
index 25da593..660f1ce 100644
--- a/sms-service/src/sms/log/logger.go
+++ b/sms-service/src/sms/log/logger.go
@@ -17,57 +17,82 @@
package log
import (
+ "fmt"
"log"
"os"
)
-var errLogger *log.Logger
-var warnLogger *log.Logger
-var infoLogger *log.Logger
+var errL, warnL, infoL *log.Logger
+var stdErr, stdWarn, stdInfo *log.Logger
// Init will be called by sms.go before any other packages use it
func Init(filePath string) {
+
+ stdErr = log.New(os.Stderr, "ERROR: ", log.Lshortfile|log.LstdFlags)
+ stdWarn = log.New(os.Stdout, "WARNING: ", log.Lshortfile|log.LstdFlags)
+ stdInfo = log.New(os.Stdout, "INFO: ", log.Lshortfile|log.LstdFlags)
+
if filePath == "" {
- errLogger = log.New(os.Stderr, "ERROR: ", log.Lshortfile|log.LstdFlags)
- warnLogger = log.New(os.Stdout, "WARNING: ", log.Lshortfile|log.LstdFlags)
- infoLogger = log.New(os.Stdout, "INFO: ", log.Lshortfile|log.LstdFlags)
+ // We will just to std streams
return
}
f, err := os.Create(filePath)
if err != nil {
- log.Println("Unable to create a log file")
- log.Println(err)
- errLogger = log.New(os.Stderr, "ERROR: ", log.Lshortfile|log.LstdFlags)
- warnLogger = log.New(os.Stdout, "WARNING: ", log.Lshortfile|log.LstdFlags)
- infoLogger = log.New(os.Stdout, "INFO: ", log.Lshortfile|log.LstdFlags)
- } else {
- errLogger = log.New(f, "ERROR: ", log.Lshortfile|log.LstdFlags)
- warnLogger = log.New(f, "WARNING: ", log.Lshortfile|log.LstdFlags)
- infoLogger = log.New(f, "INFO: ", log.Lshortfile|log.LstdFlags)
+ stdErr.Println("Unable to create log file: " + err.Error())
+ return
}
+
+ errL = log.New(f, "ERROR: ", log.Lshortfile|log.LstdFlags)
+ warnL = log.New(f, "WARNING: ", log.Lshortfile|log.LstdFlags)
+ infoL = log.New(f, "INFO: ", log.Lshortfile|log.LstdFlags)
}
// WriteError writes output to the writer we have
-// defined durint its creation with ERROR prefix
+// defined during its creation with ERROR prefix
func WriteError(msg string) {
- if errLogger != nil {
- errLogger.Println(msg)
+ if errL != nil {
+ errL.Output(2, fmt.Sprintln(msg))
+ }
+ if stdErr != nil {
+ stdErr.Output(2, fmt.Sprintln(msg))
}
}
// WriteWarn writes output to the writer we have
-// defined durint its creation with WARNING prefix
+// defined during its creation with WARNING prefix
func WriteWarn(msg string) {
- if warnLogger != nil {
- warnLogger.Println(msg)
+ if warnL != nil {
+ warnL.Output(2, fmt.Sprintln(msg))
+ }
+ if stdWarn != nil {
+ stdWarn.Output(2, fmt.Sprintln(msg))
}
}
// WriteInfo writes output to the writer we have
-// defined durint its creation with INFO prefix
+// defined during its creation with INFO prefix
func WriteInfo(msg string) {
- if infoLogger != nil {
- infoLogger.Println(msg)
+ if infoL != nil {
+ infoL.Output(2, fmt.Sprintln(msg))
+ }
+ if stdInfo != nil {
+ stdInfo.Output(2, fmt.Sprintln(msg))
+ }
+}
+
+//CheckError is a helper function to reduce
+//repitition of error checkign blocks of code
+func CheckError(err error, topic string) error {
+ if err != nil {
+ msg := topic + ": " + err.Error()
+ if errL != nil {
+ errL.Output(2, fmt.Sprintln(msg))
+ }
+ if stdErr != nil {
+ stdErr.Output(2, fmt.Sprintln(msg))
+ }
+ return err
}
+ return nil
}