Skip to content
Snippets Groups Projects
handler.go 9.42 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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 (
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	"encoding/base64"
    	"errors"
    
    	"log"
    
    Viktor Popov's avatar
    Viktor Popov committed
    	"strings"
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	"code.vereign.com/code/viam-apis/clientutils"
    
    Viktor Popov's avatar
    Viktor Popov committed
    
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	"code.vereign.com/code/key-storage-agent/config"
    
    	keyutils "code.vereign.com/code/key-storage-agent/utils"
    
    Viktor Popov's avatar
    Viktor Popov committed
    	"code.vereign.com/code/viam-apis/authentication"
    	"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"
    )
    
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    const (
    	keyToKeyIdTable = "authenticationKeyToKeyId"
    )
    
    
    Viktor Popov's avatar
    Viktor Popov committed
    // Server represents the gRPC server
    type KeyStorageServerImpl struct {
    
    	DataStorageUrl       string
    	CertPEM              []byte
    	KeyPEM               []byte
    	CaCertPEM            []byte
    	VereignCertPEM       []byte
    	VereignPrivateKeyPEM []byte
    	MaxMessageSize       int
    
    Viktor Popov's avatar
    Viktor Popov committed
    }
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    var version = "undefined"
    
    
    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 := keyutils.CreateDataStorageClient(auth)
    
    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 {
    
    			log.Printf("Error: %v", err)
    
    			getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList,
    				"400", api.StatusType_ERROR, "Can not get root certificate")
    			return getKeyResponse, nil
    
    		key.Content = s.VereignCertPEM
    
    		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")
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    		return getKeyResponse, errors.New("KeyType cannot be empty")
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    	key := &api.Key{}
    
    	hasData, errorsString, err := client.GetData("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType), key)
    
    Alexander Holodov's avatar
    Alexander Holodov committed
    	if err != nil {
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    		log.Printf("grpc call GetData to DataStorage failed: %s", err)
    
    Alexander Holodov's avatar
    Alexander Holodov committed
    		getKeyResponse.Key = nil
    		getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList,
    			"500", api.StatusType_ERROR, err.Error())
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    		return getKeyResponse, err
    
    Alexander Holodov's avatar
    Alexander Holodov committed
    	}
    
    Viktor Popov's avatar
    Viktor Popov committed
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    	if errorsString != "" {
    
    		getKeyResponse.Key = nil
    
    		getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList,
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    			"500", api.StatusType_ERROR, errorsString)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    		return nil, errors.New(errorsString)
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    	if !hasData {
    		log.Println("No such key " + in.Uuid)
    		getKeyResponse.Key = nil
    		getKeyResponse.StatusList = utils.AddStatus(getKeyResponse.StatusList,
    
    			"500", api.StatusType_ERROR, "No such key " + in.Uuid)
    		return getKeyResponse, errors.New("No such key " + in.Uuid)
    
    Viktor Popov's avatar
    Viktor Popov committed
    	}
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    	getKeyResponse.Key = key
    
    	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 := keyutils.CreateDataStorageClient(auth)
    
    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")
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    		return setKeyResponse, errors.New("Can not set root CA keys")
    
    	if in.KeyType == api.KeyType_KT_EMPTY {
    
    		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
    			"400", api.StatusType_ERROR, "KeyType cannot be empty")
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    		return setKeyResponse, errors.New("KeyType cannot be empty")
    
    Viktor Popov's avatar
    Viktor Popov committed
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    	key := &api.Key{}
    
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	if config.ReplaceKey == false {
    
    		_, _, err := client.GetData("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType), key)
    		if err != nil {
    			log.Printf("grpc call GetData to DataStorage failed: %s", err)
    			setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
    				"500", api.StatusType_ERROR, err.Error())
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    			return setKeyResponse, err
    
    Viktor Popov's avatar
    Viktor Popov committed
    
    
    		if len(key.Content) > 0 {
    			setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
    				"400", api.StatusType_ERROR, "Key is already set")
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    			return setKeyResponse, errors.New("Key is already set")
    
    Viktor Popov's avatar
    Viktor Popov committed
    	}
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    	result, errors, err := client.PutData("keys", in.Uuid+"/"+api.KeyType.String(in.KeyType), in.Key)
    
    	setKeyResponse.StatusList = keyutils.HandlePutDataErrors(setKeyResponse.StatusList, errors, err)
    
    
    	if setKeyResponse.StatusList == nil || len(setKeyResponse.StatusList) == 0 {
    
    		setKeyResponse.StatusList = utils.AddStatus(setKeyResponse.StatusList,
    			"200", api.StatusType_INFO, result)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	if in.KeyType == api.KeyType_PUBLIC {
    		keyContent := base64.StdEncoding.EncodeToString(in.Key.Content)
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    		_, _, err = client.PutString(keyToKeyIdTable, keyContent, in.Uuid)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    		if err != nil {
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    			log.Printf("can't PutString: %s", err)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    			return nil, err
    		}
    	}
    
    
    	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 := keyutils.CreateDataStorageClient(auth)
    
    	defer client.CloseClient()
    
    
    	reserveKeyUUIDResponse := &api.ReserveKeyUUIDResponse{}
    
    	uuid, err := keyutils.GenerateUnusedUUID(client)
    
    	if err != nil {
    
    		log.Printf("Error: %v", err)
    
    		reserveKeyUUIDResponse.StatusList = utils.AddStatus(reserveKeyUUIDResponse.StatusList,
    			"500", api.StatusType_INFO, err.Error())
    
    	}
    
    	emptyKey := &api.Key{
    		Content: []byte{},
    	}
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    	result, errors, err := client.PutData("keys", uuid+"/"+api.KeyType.String(api.KeyType_PRIVATE), emptyKey)
    
    	reserveKeyUUIDResponse.StatusList = keyutils.HandlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
    
    
    	if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    		result, errors, err = client.PutData("keys", uuid+"/"+api.KeyType.String(api.KeyType_PUBLIC), emptyKey)
    
    		reserveKeyUUIDResponse.StatusList = keyutils.HandlePutDataErrors(reserveKeyUUIDResponse.StatusList, errors, err)
    
    	}
    
    	if reserveKeyUUIDResponse.StatusList == nil || len(reserveKeyUUIDResponse.StatusList) == 0 {
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    		result, errors, err = client.PutData("keys", uuid+"/"+api.KeyType.String(api.KeyType_CERTIFICATE), emptyKey)
    
    		reserveKeyUUIDResponse.StatusList = keyutils.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
    }
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    func (s *KeyStorageServerImpl) GetKeyId(ctx context.Context, in *api.GetKeyIdByKeyRequest) (*api.GetKeyIdByKeyResponse, error) {
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	auth := s.CreateAuthentication(ctx)
    	//in.PublicKey
    	entitiesMagamentClient := keyutils.CreateEntitiesManagementClient(auth)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	defer entitiesMagamentClient.CloseClient()
    
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	dataStorageClient := keyutils.CreateDataStorageClient(auth)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	defer dataStorageClient.CloseClient()
    
    	keyIdResponse := &api.GetKeyIdByKeyResponse{}
    
    
    	keyId, errorsString, err := dataStorageClient.GetString(keyToKeyIdTable, in.PublicKey)
    	if err == nil && errorsString == "" && keyId != "" {
    		keyIdResponse.KeyId = keyId
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    		return keyIdResponse, nil
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	} else {
    		if err != nil {
    			return nil, err
    		} else {
    			return nil, errors.New("Can not get public key")
    		}
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	}
    
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    	entity, err := clientutils.GetLastEntity(entitiesMagamentClient, in.EntityUUID)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    
    	if err != nil {
    		return nil, err
    	}
    
    	for _, checkID := range entity.AuthenticationKeys {
    		key := &api.Key{}
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    		hasData, errorsString, err := dataStorageClient.GetData("keys", checkID+"/"+api.KeyType_PUBLIC.String(), key)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    
    		if err != nil {
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    			log.Printf("grpc call GetData to DataStorage failed: %s", err)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    			return nil, err
    		}
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    		if errorsString != "" {
    			log.Printf("Error: %s", errorsString)
    			return nil, errors.New(errorsString)
    		}
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    		if !hasData {
    			log.Println("No such checkID " + checkID)
    			return nil, errors.New("No such checkID " + checkID)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    		}
    
    		keyFromStorage := base64.StdEncoding.EncodeToString(key.Content)
    
    		if in.PublicKey != keyFromStorage {
    			continue
    		}
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    		_, _, err = dataStorageClient.PutString(keyToKeyIdTable, in.PublicKey, checkID)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    		if err != nil {
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    			log.Printf("can't PutString: %s", err)
    
    Gospodin Bodurov's avatar
    Gospodin Bodurov committed
    
    			return nil, err
    		}
    
    		keyIdResponse.KeyId = checkID
    		return keyIdResponse, nil
    	}
    
    	//getKeyFromContent
    	return keyIdResponse, nil
    }
    
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    func (s *KeyStorageServerImpl) GetVersionKSA(ctx context.Context, in *api.GetVersionKSAMessage) (*api.GetVersionKSAResponseMessage, error) {
    
    	log.Println("Version: " + version)
    
    Olgun Cengiz's avatar
    Olgun Cengiz committed
    	return &api.GetVersionKSAResponseMessage{Version: version, Errors: ""}, nil