Skip to content
Snippets Groups Projects
handler.go 6.49 KiB
Newer Older
Viktor Popov's avatar
Viktor Popov committed
/*
Copyright (c) 2018 Vereign AG [https://www.vereign.com]

This is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package handler

import (
	"io/ioutil"
Viktor Popov's avatar
Viktor Popov committed
	"strings"

	"code.vereign.com/code/viam-apis/versions"
	"github.com/golang/protobuf/proto"

	"code.vereign.com/code/viam-apis/authentication"
	"code.vereign.com/code/viam-apis/data-storage-agent/client"
	"code.vereign.com/code/viam-apis/key-storage-agent/api"
	"code.vereign.com/code/viam-apis/utils"
	"golang.org/x/net/context"
	"google.golang.org/grpc/metadata"
)

// Server represents the gRPC server
type KeyStorageServerImpl struct {
	DataStorageUrl            string
	CertFilePath              string
	VereignCertFilePath       string
	VereignPrivateKeyFilePath string
Viktor Popov's avatar
Viktor Popov committed
}

func (s *KeyStorageServerImpl) CreateAuthentication(ctx context.Context) *authentication.Authentication {
	if md, ok := metadata.FromIncomingContext(ctx); ok {
		uuid := strings.Join(md["uuid"], "")
		session := strings.Join(md["session"], "")

		auth := &authentication.Authentication{
			Uuid:    uuid,
			Session: session,
		}

		return auth
	}

	return nil
}

func (s *KeyStorageServerImpl) GetKey(ctx context.Context, in *api.GetKeyRequest) (*api.GetKeyResponse, error) {
Viktor Popov's avatar
Viktor Popov committed
	auth := s.CreateAuthentication(ctx)

	client := &client.DataStorageClientImpl{}
	client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath)
Viktor Popov's avatar
Viktor Popov committed
	defer client.CloseClient()

	getKeyResponse := &api.GetKeyResponse{}
Viktor Popov's avatar
Viktor Popov committed

	if in.KeyType == api.KeyType_CERTIFICATE && in.Uuid == "root" {
		key := &api.Key{}
		data, err := ioutil.ReadFile(s.VereignCertFilePath)

		if err != nil {
			getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList,
				"400", api.StatusType_ERROR, "Can not get root certificate")
			return getKeyResponse, nil
		}

		key.Content = data
		key.Revoked = false

		getKeyResponse.Key = key
		return getKeyResponse, nil
	}

	if in.KeyType == api.KeyType_KT_EMPTY {
		getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList,
			"400", api.StatusType_ERROR, "KeyType cannot be empty")
		return getKeyResponse, nil
	}

	data, _ := client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType))
Viktor Popov's avatar
Viktor Popov committed

	if data.Errors != "" {
		getKeyResponse.Key = nil
		getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList,
			"500", api.StatusType_ERROR, data.Errors)
Viktor Popov's avatar
Viktor Popov committed
	} else {
		key := &api.Key{}
Viktor Popov's avatar
Viktor Popov committed
		proto.Unmarshal(data.Data.Data, key)
		getKeyResponse.Key = key
Viktor Popov's avatar
Viktor Popov committed
	}

	return getKeyResponse, nil
Viktor Popov's avatar
Viktor Popov committed
}

func (s *KeyStorageServerImpl) SetKey(ctx context.Context, in *api.SetKeyRequest) (*api.SetKeyResponse, error) {
Viktor Popov's avatar
Viktor Popov committed
	auth := s.CreateAuthentication(ctx)

	client := &client.DataStorageClientImpl{}
	client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath)
Viktor Popov's avatar
Viktor Popov committed
	defer client.CloseClient()

	setKeyResponse := &api.SetKeyResponse{}

	if in.Uuid == "root" {
		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
			"400", api.StatusType_ERROR, "Can not set root CA keys")
		return setKeyResponse, nil
	}

	if in.KeyType == api.KeyType_KT_EMPTY {
		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
			"400", api.StatusType_ERROR, "KeyType cannot be empty")
		return setKeyResponse, nil
Viktor Popov's avatar
Viktor Popov committed

	data, _ := client.DoGetDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType))
Viktor Popov's avatar
Viktor Popov committed

	if data.Errors != "" {
		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
			"400", api.StatusType_ERROR, data.Errors)
		return setKeyResponse, nil
	}

	key := &api.Key{}
	proto.Unmarshal(data.Data.Data, key)
	if key != nil && key.Content != nil && len(key.Content) > 0 {
		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
			"400", api.StatusType_ERROR, "Key is already set")
		return setKeyResponse, nil
Viktor Popov's avatar
Viktor Popov committed
	}

	result, errors, err := client.DoPutDataCall("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType), in.Key, versions.EntitiesManagementAgentApiVersion)
	setKeyResponse.StatusList = handlePutDataErrors(setKeyResponse.StatusList, errors, err)

	if setKeyResponse.StatusList == nil || len(setKeyResponse.StatusList) == 0 {
		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
			"200", api.StatusType_INFO, result)
	}

	return setKeyResponse, nil
Viktor Popov's avatar
Viktor Popov committed
}

func (s *KeyStorageServerImpl) ReserveKeyUUID(ctx context.Context, in *api.ReserveKeyUUIDRequest) (*api.ReserveKeyUUIDResponse, error) {
	auth := s.CreateAuthentication(ctx)

	client := &client.DataStorageClientImpl{}
	client.SetUpClient(auth, s.DataStorageUrl, s.CertFilePath)
	defer client.CloseClient()

	reserveKeyUUIDResponse := &api.ReserveKeyUUIDResponse{}
	uuid, err := generateUnusedUUID(client)
	if err != nil {
		reserveKeyUUIDResponse.StatusList = utils.AddStatus(reserveKeyUUIDResponse.StatusList,
			"500", api.StatusType_INFO, err.Error())
	}

	emptyKey := &api.Key{
		Content: []byte{},
	}

	result, errors, err := client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE), emptyKey, versions.EntitiesManagementAgentApiVersion)
	reserveKeyUUIDResponse.StatusList = handlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)

	if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
		result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC), emptyKey, versions.EntitiesManagementAgentApiVersion)
		reserveKeyUUIDResponse.StatusList = handlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
	}

	if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
		result, errors, err = client.DoPutDataCall("keys", uuid+"/"+api.KeyType.String(api.KeyType_CERTIFICATE), emptyKey, versions.EntitiesManagementAgentApiVersion)
		reserveKeyUUIDResponse.StatusList = handlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
	}

	if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
		reserveKeyUUIDResponse.Uuid = uuid
		reserveKeyUUIDResponse.StatusList = utils.AddStatus(reserveKeyUUIDResponse.StatusList,
			"200", api.StatusType_INFO, result)
Viktor Popov's avatar
Viktor Popov committed

	return reserveKeyUUIDResponse, nil
}