Skip to content
This repository has been archived by the owner on Nov 8, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1703 from candysmurf/tls-api-v2
Browse files Browse the repository at this point in the history
SDI-2730: Add SSL/TLS capability to snap-cli
  • Loading branch information
candysmurf authored Aug 15, 2017
2 parents 364d5fc + b3563eb commit 5351697
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 36 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
sudo: true
language: go
go:
- 1.8.1
- 1.7.3
before_install:
- bash scripts/gitcookie.sh
Expand Down
127 changes: 91 additions & 36 deletions mgmt/rest/v2/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ import (
"github.com/julienschmidt/httprouter"
)

const (
// TLSCertPrefix defines a prefix for file fragment carrying path to TLS certificate
TLSCertPrefix = "crt."
// TLSKeyPrefix defines a prefix for file fragment carrying path to TLS private key
TLSKeyPrefix = "key."
// TLSCACertsPrefix defines a prefix for file fragment carrying paths to TLS CA certificates
TLSCACertsPrefix = "cacerts."
)

// PluginResponse represents the response from plugin operations.
//
// swagger:response PluginResponse
Expand Down Expand Up @@ -122,6 +131,21 @@ type PluginPostParams struct {
//
// swagger:file
PluginData *bytes.Buffer `json:"plugin_data"`
// Plugin GRPC TLS server key
//
// in: formData
//
PluginKey string `json:"plugin_key"`
// Plugin GRPC TLS server certification
//
// in: formData
//
PluginCert string `json:"plugin_cert"`
// CA root certification
//
// in: formData
//
CACerts string `json:"ca_certs"`
}

// Name plugin name string
Expand Down Expand Up @@ -149,10 +173,11 @@ func (s *apiV2) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter.
}

if strings.HasPrefix(mediaType, "multipart/") {
var certPath, keyPath, caCertPaths string
var signature []byte
var checkSum [sha256.Size]byte
mr := multipart.NewReader(r.Body, params["boundary"])
var i int

for {
var b []byte
p, err := mr.NextPart()
Expand Down Expand Up @@ -183,40 +208,33 @@ func (s *apiV2) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter.
}
}

// A little sanity checking for files being passed into the API server.
// First file passed in should be the plugin. If the first file is a signature
// file, an error is returned. The signature file should be the second
// file passed to the API server. If the second file does not have the ".asc"
// extension, an error is returned.
// If we loop around more than twice before receiving io.EOF, then
// an error is returned.

switch {
case i == 0:
if filepath.Ext(p.FileName()) == ".asc" {
e := errors.New("Error: first file passed to load plugin api can not be signature file")
Write(400, FromError(e), w)
return
}
if rp, err = core.NewRequestedPlugin(p.FileName(), s.metricManager.GetTempDir(), b); err != nil {
switch p.FormName() {
case "ca_certs":
caCertPaths = string(b)
handleError(caCertPaths, w)
case "plugin_key":
keyPath = string(b)
handleError(keyPath, w)
case "plugin_cert":
certPath = string(b)
handleError(certPath, w)
// plugin_data is from REST API and snap-plugins is from rest_v2_test.go.
case "plugin_data", "snap-plugins":
rp, err = core.NewRequestedPlugin(p.FileName(), s.metricManager.GetTempDir(), b)
if err != nil {
Write(500, FromError(err), w)
return
}
checkSum = sha256.Sum256(b)
case i == 1:
default:
if filepath.Ext(p.FileName()) == ".asc" {
signature = b
} else {
e := errors.New("Error: second file passed was not a signature file")
e := errors.New("Error: An unknown file found " + p.FileName())
Write(400, FromError(e), w)
return
}
case i == 2:
e := errors.New("Error: More than two files passed to the load plugin api")
Write(400, FromError(e), w)
return
}
i++
}

// Sanity check, verify the checkSum on the file sent is the same
Expand All @@ -226,7 +244,24 @@ func (s *apiV2) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter.
Write(400, FromError(e), w)
return
}

// check if one of TLS params (cert or key) has been provided; if not, skip the part related to TLS
if hasTLS(certPath, keyPath) {
// check if both of required params have been provided to setup TLS connection;
// if not, return an appropriate error
if isTLSEnabled(certPath, keyPath) {
rp.SetTLSEnabled(true)
rp.SetCACertPaths(caCertPaths)
rp.SetCertPath(certPath)
rp.SetKeyPath(keyPath)
} else {
e := errors.New("Error: TLS setup incomplete - Both plugin TLS certificate and the key are required")
Write(500, FromError(e), w)
return
}
}
rp.SetSignature(signature)

restLogger.Info("Loading plugin: ", rp.Path())
pl, err := s.metricManager.Load(rp)
if err != nil {
Expand All @@ -251,6 +286,27 @@ func (s *apiV2) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter.
}
}

func handleError(p string, w http.ResponseWriter) {
if _, err := os.Stat(p); os.IsNotExist(err) {
Write(500, FromError(err), w)
return
}
}

func hasTLS(cert, key string) bool {
if cert == "" && key == "" {
return false
}
return true
}

func isTLSEnabled(cert, key string) bool {
if cert != "" && key != "" {
return true
}
return false
}

func pluginParameters(p httprouter.Params) (string, string, int, map[string]interface{}, serror.SnapError) {
plName := p.ByName("name")
plType := p.ByName("type")
Expand Down Expand Up @@ -442,17 +498,16 @@ func (s *apiV2) getPlugin(w http.ResponseWriter, r *http.Request, p httprouter.P
}
w.WriteHeader(200)
return
} else {
pluginRet := Plugin{
Name: plugin.Name(),
Version: plugin.Version(),
Type: plugin.TypeName(),
Signed: plugin.IsSigned(),
Status: plugin.Status(),
LoadedTimestamp: plugin.LoadedTimestamp().Unix(),
Href: pluginURI(r.Host, plugin),
ConfigPolicy: configPolicy,
}
Write(200, pluginRet, w)
}
pluginRet := Plugin{
Name: plugin.Name(),
Version: plugin.Version(),
Type: plugin.TypeName(),
Signed: plugin.IsSigned(),
Status: plugin.Status(),
LoadedTimestamp: plugin.LoadedTimestamp().Unix(),
Href: pluginURI(r.Host, plugin),
ConfigPolicy: configPolicy,
}
Write(200, pluginRet, w)
}
21 changes: 21 additions & 0 deletions swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,27 @@
"description": "loads a plugin.",
"name": "plugin_data",
"in": "formData"
},
{
"type": "string",
"x-go-name": "PluginKey",
"description": "Plugin GRPC TLS server key",
"name": "plugin_key",
"in": "formData"
},
{
"type": "string",
"x-go-name": "PluginCert",
"description": "Plugin GRPC TLS server certification",
"name": "plugin_cert",
"in": "formData"
},
{
"type": "string",
"x-go-name": "CACerts",
"description": "CA root certification",
"name": "ca_certs",
"in": "formData"
}
],
"responses": {
Expand Down

0 comments on commit 5351697

Please sign in to comment.