/* * Copyright 2018 Intel Corporation, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package auth import ( "bytes" "crypto/tls" "crypto/x509" "encoding/base64" "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/packet" "io/ioutil" 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) { // Initialize tlsConfig once if tlsConfig == nil { caCert, err := ioutil.ReadFile(caCertFile) if err != nil { return nil, err } caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) tlsConfig = &tls.Config{ ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: caCertPool, MinVersion: tls.VersionTLS12, } tlsConfig.BuildNameToCertificate() } return tlsConfig, nil } // 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) { var entity *openpgp.Entity entity, err := openpgp.NewEntity("aaf.sms.init", "PGP Key for unsealing", "", nil) if err != nil { smslogger.WriteError(err.Error()) 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()) return "", "", err } } // 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()) return "", "", err } } buffer := new(bytes.Buffer) entity.Serialize(buffer) pbkey := base64.StdEncoding.EncodeToString(buffer.Bytes()) buffer.Reset() entity.SerializePrivate(buffer, nil) prkey := base64.StdEncoding.EncodeToString(buffer.Bytes()) return pbkey, prkey, nil } // DecryptPGPBytes decrypts a PGP encoded input string and returns // a base64 representation of the decoded string func DecryptPGPBytes(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()) return "", err } dataBytes, err := base64.StdEncoding.DecodeString(data) if err != nil { smslogger.WriteError("Error Decoding base64 data: " + err.Error()) return "", err } prEntity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(prKeyBytes))) if err != nil { smslogger.WriteError("Error reading entity from PGP key: " + err.Error()) 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()) return "", err } var retBuf bytes.Buffer retBuf.ReadFrom(message.UnverifiedBody) return retBuf.String(), nil }
/* * Copyright 2018 Intel Corporation, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package backend import ( smsconfig "sms/config" smslogger "sms/log" ) // SecretDomain is where Secrets are stored. // A single domain can have any number of secrets type SecretDomain struct { UUID string `json:"uuid"` Name string `json:"name"` } // Secret is the struct that defines the structure of a secret // It consists of a name and map containing key value pairs type Secret struct { Name string `json:"name"` Values map[string]interface{} `json:"values"` } // SecretBackend interface that will be implemented for various secret backends type SecretBackend interface { Init() error GetStatus() (bool, error) Unseal(shard string) error GetSecret(dom string, sec string) (Secret, error) ListSecret(dom string) ([]string, error) CreateSecretDomain(name string) (SecretDomain, error) CreateSecret(dom string, sec Secret) error DeleteSecretDomain(name string) error DeleteSecret(dom string, name string) error } // InitSecretBackend returns an interface implementation func InitSecretBackend() (SecretBackend, error) { backendImpl := &Vault{ vaultAddress: smsconfig.SMSConfig.VaultAddress, vaultToken: smsconfig.SMSConfig.VaultToken, } err := backendImpl.Init() if err != nil { smslogger.WriteError(err.Error()) return nil, err } return backendImpl, nil } // LoginBackend Interface that will be implemented for various login backends type LoginBackend interface { }
/* * Copyright 2018 Intel Corporation, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package backend import ( uuid "github.com/hashicorp/go-uuid" vaultapi "github.com/hashicorp/vault/api" smsauth "sms/auth" smslogger "sms/log" "errors" "fmt" "strings" "sync" "time" ) // 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 } // 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 { 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") } v.engineType = "kv" v.initRoleDone = false v.policyName = "smsvaultpolicy" v.vaultClient = client v.vaultMount = "sms" err = v.initRole() if err != nil { smslogger.WriteError(err.Error()) smslogger.WriteInfo("InitRole will try again later") } return nil } // 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()) return false, errors.New("Error getting status") } return sealStatus.Sealed, nil } // 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()) return errors.New("Unable to execute unseal operation with specified shard") } return nil } // 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) { err := v.checkToken() if err != nil { smslogger.WriteError(err.Error()) return Secret{}, errors.New("Token check failed") } dom = v.vaultMount + "/" + dom sec, err := v.vaultClient.Logical().Read(dom + "/" + name) if err != nil { smslogger.WriteError(err.Error()) return Secret{}, errors.New("Unable to read Secret at provided path") } // sec and err are nil in the case where a path does not exist if sec == nil { smslogger.WriteWarn("Vault read was empty. Invalid Path") return Secret{}, errors.New("Secret not found at the provided path") } return Secret{Name: name, Values: sec.Data}, nil } // 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()) return nil, errors.New("Token check failed") } dom = v.vaultMount + "/" + dom sec, err := v.vaultClient.Logical().List(dom) if err != nil { smslogger.WriteError(err.Error()) return nil, errors.New("Unable to read Secret at provided path") } // sec and err are nil in the case where a path does not exist if sec == nil { smslogger.WriteWarn("Vaultclient returned empty data") return nil, errors.New("Secret not found at the provided path") } val, ok := sec.Data["keys"].([]interface{}) if !ok { smslogger.WriteError("Secret not found at the provided path") return nil, errors.New("Secret not found at the provided path") } retval := make([]string, len(val)) for i, v := range val { retval[i] = fmt.Sprint(v) } return retval, nil } // 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()) return SecretDomain{}, errors.New("Token Check failed") } name = strings.TrimSpace(name) mountPath := v.vaultMount + "/" + name mountInput := &vaultapi.MountInput{ Type: v.engineType, Description: "Mount point for domain: " + name, Local: false, SealWrap: false, Config: vaultapi.MountConfigInput{}, } err = v.vaultClient.Sys().Mount(mountPath, mountInput) if err != nil { smslogger.WriteError(err.Error()) return SecretDomain{}, errors.New("Unable to create Secret Domain") } uuid, _ := uuid.GenerateUUID() return SecretDomain{uuid, name}, nil } // 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()) return errors.New("Token check failed") } dom = v.vaultMount + "/" + 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 { smslogger.WriteError(err.Error()) return errors.New("Unable to create Secret at provided path") } return nil } // 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()) return errors.New("Token Check Failed") } name = strings.TrimSpace(name) mountPath := v.vaultMount + "/" + name err = v.vaultClient.Sys().Unmount(mountPath) if err != nil { smslogger.WriteError(err.Error()) return errors.New("Unable to delete domain specified") } return nil } // DeleteSecret deletes a secret mounted on the path provided func (v *Vault) DeleteSecret(dom string, name string) error { err := v.checkToken() if err != nil { smslogger.WriteError(err.Error()) return errors.New("Token check failed") } dom = v.vaultMount + "/" + dom // Vault return is empty on successful delete _, err = v.vaultClient.Logical().Delete(dom + "/" + name) if err != nil { smslogger.WriteError(err.Error()) return errors.New("Unable to delete Secret at provided path") } return nil } // initRole is called only once during the service bring up func (v *Vault) initRole() error { // Use the root token once here v.vaultClient.SetToken(v.vaultToken) defer v.vaultClient.ClearToken() 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()) return errors.New("Unable to create policy for approle creation") } 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 { smslogger.WriteError(err.Error()) return errors.New("Unable to get mounted auth backends") } approleMounted := false for k, v := range authMounts { if v.Type == "approle" && k == "approle/" { approleMounted = true break } } // Mount approle in case its not already mounted if !approleMounted { v.vaultClient.Sys().EnableAuth("approle", "approle", "") } // 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()) return errors.New("Unable to create role ID for approle") } 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 { smslogger.WriteError(err.Error()) return errors.New("Unable to create secret ID for role") } v.secretID = sec.Data["secret_id"].(string) v.initRoleDone = true return nil } // Function checkToken() gets called multiple times to create // temporary tokens func (v *Vault) checkToken() error { 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 { err := v.initRole() if err != nil { smslogger.WriteError(err.Error()) return errors.New("Unable to initRole in checkToken") } } // Return immediately if token still has life if v.vaultClient.Token() != "" && time.Since(v.vaultTempTokenTTL) < time.Minute*50 { return nil } // 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()) return errors.New("Unable to create Temporary Token for Role") } tok, err := out.TokenID() v.vaultTempTokenTTL = time.Now() v.vaultClient.SetToken(tok) return nil } // 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 { initReq := &vaultapi.InitRequest{ SecretShares: 5, SecretThreshold: 3, } pbkey, prkey, err := smsauth.GeneratePGPKeyPair() if err != nil { smslogger.WriteError("Error Generating PGP Keys. Vault Init will not use encryption!") } else { initReq.PGPKeys = []string{pbkey, pbkey, pbkey, pbkey, pbkey} initReq.RootTokenPGPKey = pbkey v.pgpPub = pbkey v.pgpPr = prkey } resp, err := v.vaultClient.Sys().Init(initReq) if err != nil { smslogger.WriteError(err.Error()) return errors.New("FATAL: Unable to initialize Vault") } if resp != nil { v.unsealShards = resp.KeysB64 v.rootToken = resp.RootToken return nil } return errors.New("FATAL: Init response was empty") }
/* * Copyright 2018 Intel Corporation, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package config import ( "encoding/json" "os" ) // SMSConfiguration loads up all the values that are used to configure // backend implementations // TODO: Review these and see if they can be created/discovered dynamically type SMSConfiguration struct { CAFile string `json:"cafile"` ServerCert string `json:"servercert"` ServerKey string `json:"serverkey"` VaultAddress string `json:"vaultaddress"` VaultToken string `json:"vaulttoken"` } // SMSConfig is the structure that stores the configuration var SMSConfig *SMSConfiguration // ReadConfigFile reads the specified smsConfig file to setup some env variables func ReadConfigFile(file string) (*SMSConfiguration, error) { if SMSConfig == nil { f, err := os.Open(file) if err != nil { return nil, err } defer f.Close() SMSConfig = &SMSConfiguration{} decoder := json.NewDecoder(f) err = decoder.Decode(SMSConfig) if err != nil { return nil, err } } return SMSConfig, nil }
/* * Copyright 2018 Intel Corporation, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package handler import ( "encoding/json" "github.com/gorilla/mux" "net/http" smsbackend "sms/backend" smslogger "sms/log" ) // handler stores two interface implementations that implement // the backend functionality type handler struct { secretBackend smsbackend.SecretBackend loginBackend smsbackend.LoginBackend } // createSecretDomainHandler creates a secret domain with a name provided func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Request) { var d smsbackend.SecretDomain err := json.NewDecoder(r.Body).Decode(&d) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusBadRequest) return } dom, err := h.secretBackend.CreateSecretDomain(d.Name) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } jdata, err := json.Marshal(dom) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) w.Write(jdata) } // deleteSecretDomainHandler deletes a secret domain with the name provided func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) domName := vars["domName"] err := h.secretBackend.DeleteSecretDomain(domName) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) } // createSecretHandler handles creation of secrets on a given domain name func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) { // Get domain name from URL vars := mux.Vars(r) domName := vars["domName"] // 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()) http.Error(w, err.Error(), http.StatusBadRequest) return } err = h.secretBackend.CreateSecret(domName, b) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusCreated) } // getSecretHandler handles reading a secret by given domain name and secret name func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) domName := vars["domName"] secName := vars["secretName"] sec, err := h.secretBackend.GetSecret(domName, secName) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } jdata, err := json.Marshal(sec) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(jdata) } // listSecretHandler handles listing all secrets under a particular domain name func (h handler) listSecretHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) domName := vars["domName"] secList, err := h.secretBackend.ListSecret(domName) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } // Creating an anonymous struct to store the returned list of data var retStruct = struct { SecretNames []string `json:"secretnames"` }{ secList, } jdata, err := json.Marshal(retStruct) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(jdata) } // deleteSecretHandler handles deleting a secret by given domain name and secret name func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) domName := vars["domName"] secName := vars["secretName"] err := h.secretBackend.DeleteSecret(domName, secName) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } } // struct that tracks various status items for SMS and backend type backendStatus struct { Seal bool `json:"sealstatus"` } // 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()) http.Error(w, err.Error(), http.StatusInternalServerError) return } status := backendStatus{Seal: s} jdata, err := json.Marshal(status) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(jdata) } // loginHandler handles login via password and username func (h handler) loginHandler(w http.ResponseWriter, r *http.Request) { } // unsealHandler is a pass through that sends requests from quorum client // to the backend. func (h handler) unsealHandler(w http.ResponseWriter, r *http.Request) { // Get shards to be used for unseal type unsealStruct struct { UnsealShard string `json:"unsealshard"` } var inp unsealStruct decoder := json.NewDecoder(r.Body) decoder.DisallowUnknownFields() err := decoder.Decode(&inp) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, "Bad input JSON", http.StatusBadRequest) return } err = h.secretBackend.Unseal(inp.UnsealShard) if err != nil { smslogger.WriteError(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } } // CreateRouter returns an http.Handler for the registered URLs // Takes an interface implementation as input func CreateRouter(b smsbackend.SecretBackend) http.Handler { h := handler{secretBackend: b} // Create a new mux to handle URL endpoints router := mux.NewRouter() router.HandleFunc("/v1/sms/login", h.loginHandler).Methods("POST") // 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/domain", h.createSecretDomainHandler).Methods("POST") router.HandleFunc("/v1/sms/domain/{domName}", h.deleteSecretDomainHandler).Methods("DELETE") router.HandleFunc("/v1/sms/domain/{domName}/secret", h.createSecretHandler).Methods("POST") router.HandleFunc("/v1/sms/domain/{domName}/secret", h.listSecretHandler).Methods("GET") router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.getSecretHandler).Methods("GET") router.HandleFunc("/v1/sms/domain/{domName}/secret/{secretName}", h.deleteSecretHandler).Methods("DELETE") return router }
/* * Copyright 2018 Intel Corporation, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package log import ( "log" "os" ) var errLogger *log.Logger var warnLogger *log.Logger var infoLogger *log.Logger // Init will be called by sms.go before any other packages use it func Init(filePath string) { 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) } } // WriteError writes output to the writer we have // defined durint its creation with ERROR prefix func WriteError(msg string) { if errLogger != nil { errLogger.Println(msg) } } // WriteWarn writes output to the writer we have // defined durint its creation with WARNING prefix func WriteWarn(msg string) { if warnLogger != nil { warnLogger.Println(msg) } } // WriteInfo writes output to the writer we have // defined durint its creation with INFO prefix func WriteInfo(msg string) { if infoLogger != nil { infoLogger.Println(msg) } }
/* * Copyright 2018 Intel Corporation, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package main import ( "context" "log" "net/http" "os" "os/signal" smsauth "sms/auth" smsbackend "sms/backend" smsconfig "sms/config" smshandler "sms/handler" smslogger "sms/log" ) func main() { // Initialize logger smslogger.Init("sms.log") // Read Configuration File smsConf, err := smsconfig.ReadConfigFile("smsconfig.json") if err != nil { log.Fatal(err) } backendImpl, err := smsbackend.InitSecretBackend() if err != nil { log.Fatal(err) } httpRouter := smshandler.CreateRouter(backendImpl) // TODO: Use CA certificate from AAF tlsConfig, err := smsauth.GetTLSConfig(smsConf.CAFile) if err != nil { log.Fatal(err) } httpServer := &http.Server{ Handler: httpRouter, Addr: ":10443", TLSConfig: tlsConfig, } // Listener for SIGINT so that it returns cleanly connectionsClose := make(chan struct{}) go func() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) <-c httpServer.Shutdown(context.Background()) close(connectionsClose) }() err = httpServer.ListenAndServeTLS(smsConf.ServerCert, smsConf.ServerKey) if err != nil && err != http.ErrServerClosed { log.Fatal(err) } <-connectionsClose }