diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..cfa4370189676c011d73d45d4111e383ea8f3b27 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +bin/ +vendor/ +Gopkg.lock + diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000000000000000000000000000000000000..6e4954b45287512568d441b89e2ef45c00efcee1 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,27 @@ +[[constraint]] + branch = "master" + name = "code.vereign.com/code/viam-apis" + +[[constraint]] + branch = "master" + name = "code.vereign.com/code/data-storage-agent" + +[[constraint]] + name = "github.com/golang/protobuf" + version = "1.1.0" + +[[constraint]] + name = "github.com/grpc-ecosystem/grpc-gateway" + version = "1.4.1" + +[[constraint]] + branch = "master" + name = "golang.org/x/net" + +[[constraint]] + name = "google.golang.org/grpc" + version = "1.13.0" + +[prune] + go-tests = true + unused-packages = true diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..e84137fd9f75576cddc61728006ea28dc499862f --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ + +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/>. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d95e1e5cec40a31c8f4fee3b276f5e0c0d439673 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +SERVER_OUT := "bin/server" +PKG := "code.vereign.com/code/key-storage-agent" +SERVER_PKG_BUILD := "${PKG}" +PKG_LIST := $(shell go list ${PKG}/... | grep -v /vendor/) + +.PHONY: all api server + +all: server + +dep: ## Get the dependencies + dep ensure -update +server: dep ## Build the binary file for server + @go build -i -v -o $(SERVER_OUT) $(SERVER_PKG_BUILD) + +clean: ## Remove previous builds + @rm $(SERVER_OUT) + +help: ## Display this help screen + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/cert/server.crt b/cert/server.crt new file mode 100644 index 0000000000000000000000000000000000000000..ffc52d260e9fac51405c58e02317690c9e79cfa2 --- /dev/null +++ b/cert/server.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPjCCAiYCCQDpx954xyvbgjANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJG +UjEMMAoGA1UECAwDaWRmMQ4wDAYDVQQHDAVQYXJpczESMBAGA1UECgwJUGFudG9t +YXRoMQwwCgYDVQQLDANub2MxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNzEwMDUx +NTI5MzZaFw0yNzEwMDMxNTI5MzZaMGExCzAJBgNVBAYTAkZSMQwwCgYDVQQIDANp +ZGYxDjAMBgNVBAcMBVBhcmlzMRIwEAYDVQQKDAlQYW50b21hdGgxDDAKBgNVBAsM +A25vYzESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA9UFeeiJ5Gyi5MZGEI0ME8v4IikVByiBgwqn6PH/bYuJwRoR3acZg +tiiMS1pyfUBSQ2iTLRzrkvFd5rXByXWK4+6MeqYdAzAyQzgk6/1U58oPzGrZCRYe +b3Bm7QvS9rl00keO37gE8ETpatL8rCQt9Qsl88ah1BfCVuDdFtBdOW2Qz1i6qGUv +pkTSJDZBmE3gjWGHIp4UjcdshFlTEjmFfcKtNJtMuhnKZIgo6KZcN1Trvyf4aUUM +zQbPFm2jGd5lUFZJQvSQ00k+TF4YrbuDVfhozoxBrbsoaRXkVWVYC1fYey89FY1n +9zFyxB6OF32EIry4Kn5Tu6AG9+9z/CU3gwIDAQABMA0GCSqGSIb3DQEBCwUAA4IB +AQDUeByNiVS/XZgc4BXO5JPXY98orVZKfXEEWKzMfzPDxW925k2IpnnCpT4WkAe4 +sUR7C5efGPyv0TMTzNeXGrkB7lK/9WGWRrlR/bI0kdad7/p7Qx+5hC/nE2HWZYQo +5JYj8tEfetY3aV64rFllcq2hfI71dMML05GwoVaKaMc9Q1ccwIZAbkXR2Sifwsn9 ++UNNsP5hR+7kQh+Dqd/+qEySp1+0ZJ1LmRmRes37MlJI9KSoC1uANwcB5+4ZFrba +LHrkszk9nxk09Y/tLGYlvvf23y1BdhcqT2EbUZX7jD/jEDC0kZ5yxDE1UDk+pnZp +UaEcVsgg/b9dMESt38f6ICK/ +-----END CERTIFICATE----- diff --git a/cert/server.csr b/cert/server.csr new file mode 100644 index 0000000000000000000000000000000000000000..5662bf115417fa8cc05a5c987aa46e4bfbb229dd --- /dev/null +++ b/cert/server.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICpjCCAY4CAQAwYTELMAkGA1UEBhMCRlIxDDAKBgNVBAgMA2lkZjEOMAwGA1UE +BwwFUGFyaXMxEjAQBgNVBAoMCVBhbnRvbWF0aDEMMAoGA1UECwwDbm9jMRIwEAYD +VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD1 +QV56InkbKLkxkYQjQwTy/giKRUHKIGDCqfo8f9ti4nBGhHdpxmC2KIxLWnJ9QFJD +aJMtHOuS8V3mtcHJdYrj7ox6ph0DMDJDOCTr/VTnyg/MatkJFh5vcGbtC9L2uXTS +R47fuATwROlq0vysJC31CyXzxqHUF8JW4N0W0F05bZDPWLqoZS+mRNIkNkGYTeCN +YYcinhSNx2yEWVMSOYV9wq00m0y6GcpkiCjoplw3VOu/J/hpRQzNBs8WbaMZ3mVQ +VklC9JDTST5MXhitu4NV+GjOjEGtuyhpFeRVZVgLV9h7Lz0VjWf3MXLEHo4XfYQi +vLgqflO7oAb373P8JTeDAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAES8c7EOs +rU0eu3whtUumllhotNvvqBP4x46arQQE2ud0GkLkxvxqbUuGQxLWi5KCcdads+Cx +EramC/UAUgAFFj8Ll1EuSZxy1+sb5GL00uJMxatpDBHwr78fhllAWkM7jiZbh2ad +FHOg9kQcDtdfFB6XP7JM7uiXluEQRyxIutoOzIkhZZva6zg/7iWE+u6DGz3r8dWQ +WNH8gsWA3D85ZyTDVrCvp6omGx35pzwuQOoWH6nO3dCsR2smf58ShnMtE+c6uLbF +qoZRTXGAiCaH3/Cn3TXkcrclZdneCCOWidHG2ICTsTqfujDYz/CCYM23AGkqQb1Y +QMQl0LGZ+k+HAQ== +-----END CERTIFICATE REQUEST----- diff --git a/cert/server.key b/cert/server.key new file mode 100644 index 0000000000000000000000000000000000000000..e4633619d4877c9d199a723e3334cf887dece536 --- /dev/null +++ b/cert/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEA9UFeeiJ5Gyi5MZGEI0ME8v4IikVByiBgwqn6PH/bYuJwRoR3 +acZgtiiMS1pyfUBSQ2iTLRzrkvFd5rXByXWK4+6MeqYdAzAyQzgk6/1U58oPzGrZ +CRYeb3Bm7QvS9rl00keO37gE8ETpatL8rCQt9Qsl88ah1BfCVuDdFtBdOW2Qz1i6 +qGUvpkTSJDZBmE3gjWGHIp4UjcdshFlTEjmFfcKtNJtMuhnKZIgo6KZcN1Trvyf4 +aUUMzQbPFm2jGd5lUFZJQvSQ00k+TF4YrbuDVfhozoxBrbsoaRXkVWVYC1fYey89 +FY1n9zFyxB6OF32EIry4Kn5Tu6AG9+9z/CU3gwIDAQABAoIBAQDcQdXAaD9NRdh0 +DNSX+nNyavRugV5hUYy0poTmWolDmEru+b5oj1GBpo7Aib0ygVaf1UYACO4D7KLB +NNCRxe9zXmRpLc/2cg1h0wVNrxjWheCEXB0IjQXOXSsCjlDrZYjl5IAKqTA+PBVI +660iR+fCHz35XZUubhwJfC7yczSWAe8nlnFHrcUzSeqLctI18JGsq3hDf5Fy+97+ +4uuJFPwQ0mLsgOdzKvCB79ecSZdQ18hkidgpnARaM1sI501b1Tp/uUQOLUmdVnvh +/MFEWndm1th3i+gMotsBwrBCyPPeWVrcvKI2sf0LJmgaMl4/sBB0UsSKLhcbBLsj +jvABikmJAoGBAP1z/WeNDaEaypXBSOKZlMu9YuPOemS2DY5GEc204Fi0dYNDlMEh +CAu7mEsEvH66hwKn+xMnpb5hIuxQv3/2hUFTME9au2htj2MX0+qk1bqMQMlDEdda +WWybxy+jW1mYJFMVHFwAAE7hXS5peH9ZCihAu/szYt8zPdZ4X3EEEqqfAoGBAPe4 +Slp2GVd742ZA3VBpfv6802C/DA98gIdHqWNF5vJzi1HU29m+2zY6mMGl9CP3ICeX +gLL6a3bqIc8aPgJ8ULAhegKOcFqruhGFIjmd+FPRtwjiYC9jJRXbMUSmTrR0XsxG +GkK2UmBNxVNGUj++1hwji39OfsMnf6OvfVhnmOydAoGBAJk5OgUUHR08WSTXyPxU +5MOXJuWZuhyQgvl0GudFZiu6TSCiBpgLJBYTvyn7HwluMpjEfOFDosvJZZd/6YWu +vziS1i3jKFEliv3ZNeAw7pTsnW4PAgYzNMSYGH8QPvWXKL6hkJd92LHXRMH+OT6j +0aQsHnjqw+czzzqNYwWr9Kz5AoGBAKvxBeLuUD6x5jAGW9dBsn08MXfYg5WINGox +qngWf+vPmWdOWN81o1BrsbXP67q/AFmaxiD0wnzCnH701w/Am/z074wws/mrcrZQ +c2YMqN39FY+cGWkq5wXZo8Pjr4N/toERM48Un+7qbEmV6OcIHfNgFKZjpIbutqC1 +4UnodnPdAoGBANzcLKz99NXBBuAiYHgmOckh6I2RCcORgE6WDbj57qrdMco0NToU +wU9ute0SBEm6VEnBf9i3jlrPZr69f3VT4OFWeo9RoHkVmVDD+LEY5P7xqftj/XZy +2r+uvgkqZWBC3rpAORGq3F7MgD4nFcyssFKwylEGyCVCfyGIsv5+ZKMr +-----END RSA PRIVATE KEY----- diff --git a/handler/handler.go b/handler/handler.go new file mode 100644 index 0000000000000000000000000000000000000000..5184a9d1190891328b552d9b1342ae907834e724 --- /dev/null +++ b/handler/handler.go @@ -0,0 +1,142 @@ +/* +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 ( + "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 + CertPath string +} + +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) GetPrivateKey(ctx context.Context, in *api.GetPrivateKeyRequest) (*api.GetPrivateKeyResponse, error) { + auth := s.CreateAuthentication(ctx) + + client := &client.DataStorageClientImpl{} + client.SetUpClient(auth, s.DataStorageUrl, s.CertPath) + defer client.CloseClient() + + data, _ := client.DoGetDataCall("privatekeys", in.Name) + + getPrivateKeyResponse := &api.GetPrivateKeyResponse{} + + if data.Errors != "" { + getPrivateKeyResponse.Key = nil + getPrivateKeyResponse.StatusList = utils.AddStatus(getPrivateKeyResponse.StatusList, "500", "Internal server error", data.Errors) + } else { + key := &api.PrivateKey{} + proto.Unmarshal(data.Data.Data, key) + getPrivateKeyResponse.Key = key + } + + return getPrivateKeyResponse, nil +} + +func (s *KeyStorageServerImpl) GetPublicKey(ctx context.Context, in *api.GetPublicKeyRequest) (*api.GetPublicKeyResponse, error) { + auth := s.CreateAuthentication(ctx) + + client := &client.DataStorageClientImpl{} + client.SetUpClient(auth, s.DataStorageUrl, s.CertPath) + defer client.CloseClient() + + data, _ := client.DoGetDataCall("publickeys", in.Name) + + getPublicKeyResponse := &api.GetPublicKeyResponse{} + + if data.Errors != "" { + getPublicKeyResponse.Key = nil + getPublicKeyResponse.StatusList = utils.AddStatus(getPublicKeyResponse.StatusList, "500", "Internal server error", data.Errors) + } else { + key := &api.PublicKey{} + proto.Unmarshal(data.Data.Data, key) + getPublicKeyResponse.Key = key + } + + return getPublicKeyResponse, nil +} + +func (s *KeyStorageServerImpl) SetPrivateKey(ctx context.Context, in *api.SetPrivateKeyRequest) (*api.SetPrivateKeyResponse, error) { + auth := s.CreateAuthentication(ctx) + + client := &client.DataStorageClientImpl{} + client.SetUpClient(auth, s.DataStorageUrl, s.CertPath) + defer client.CloseClient() + + result, errors, err := client.DoPutDataCall("privatekeys", in.Key.Name, in.Key, versions.EntitiesManagementAgentApiVersion) + + setPrivateKeyResponse := &api.SetPrivateKeyResponse{} + if err != nil { + setPrivateKeyResponse.StatusList = utils.AddStatus(setPrivateKeyResponse.StatusList, "500", "error", err.Error()) + } else if errors != "" { + setPrivateKeyResponse.StatusList = utils.AddStatus(setPrivateKeyResponse.StatusList, "500", "error", errors) + } else { + setPrivateKeyResponse.StatusList = utils.AddStatus(setPrivateKeyResponse.StatusList, "200", "info", result) + } + + return setPrivateKeyResponse, nil +} + +func (s *KeyStorageServerImpl) SetPublicKey(ctx context.Context, in *api.SetPublicKeyRequest) (*api.SetPublicKeyResponse, error) { + auth := s.CreateAuthentication(ctx) + + client := &client.DataStorageClientImpl{} + client.SetUpClient(auth, s.DataStorageUrl, s.CertPath) + defer client.CloseClient() + + result, errors, err := client.DoPutDataCall("publickeys", in.Key.Name, in.Key, versions.EntitiesManagementAgentApiVersion) + + setPublicKeyResponse := &api.SetPublicKeyResponse{} + if err != nil { + setPublicKeyResponse.StatusList = utils.AddStatus(setPublicKeyResponse.StatusList, "500", "error", err.Error()) + } else if errors != "" { + setPublicKeyResponse.StatusList = utils.AddStatus(setPublicKeyResponse.StatusList, "500", "error", errors) + } else { + setPublicKeyResponse.StatusList = utils.AddStatus(setPublicKeyResponse.StatusList, "200", "info", result) + } + + return setPublicKeyResponse, nil +} diff --git a/kill.sh b/kill.sh new file mode 100755 index 0000000000000000000000000000000000000000..40d73ddc80314f22e053c5dd8353dc5c8b233579 --- /dev/null +++ b/kill.sh @@ -0,0 +1,3 @@ +#!/bin/bash +PIDFILE="$HOME/tmp/key-storage-agent.pid" +kill -9 `cat $PIDFILE` diff --git a/main.go b/main.go new file mode 100644 index 0000000000000000000000000000000000000000..8cadaaafeb8faa93c0a0383cadb741b23c9a615a --- /dev/null +++ b/main.go @@ -0,0 +1,64 @@ +/* +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 main + +import ( + "fmt" + "log" + + "code.vereign.com/code/key-storage-agent/server" + "code.vereign.com/code/viam-apis/utils" +) + +// main start a gRPC server and waits for connection +func main() { + + // TODO this should be done via configuration or even a certificate repository + certDir := utils.GetCertDirFromFlags() + if certDir == "" { + log.Printf("cert-dir cannot be empty") + return + } + + grpcAddress := fmt.Sprintf("%s:%d", "localhost", 7877) + restAddress := fmt.Sprintf("%s:%d", "localhost", 7878) + dataStorageAddress := fmt.Sprintf("%s:%d", "localhost", 7777) + + certFile := certDir + "/server.crt" + keyFile := certDir + "/server.key" + + // fire the gRPC server in a goroutine + go func() { + err := server.StartGRPCServer(grpcAddress, certFile, keyFile, dataStorageAddress) + if err != nil { + log.Fatalf("failed to start gRPC server: %s", err) + } + }() + + // fire the REST server in a goroutine + go func() { + err := server.StartRESTServer(restAddress, grpcAddress, certFile) + if err != nil { + log.Fatalf("failed to start gRPC server: %s", err) + } + }() + + // infinite loop + log.Printf("Entering infinite loop") + select {} +} diff --git a/run.sh b/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..ddfaeae8a956962a9c11ff73a110f88f18893a07 --- /dev/null +++ b/run.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +mkdir -p "$HOME/tmp" +PIDFILE="$HOME/tmp/key-storage-agent.pid" + +if [ -e "${PIDFILE}" ] && (ps -u $(whoami) -opid= | + grep -P "^\s*$(cat ${PIDFILE})$" &> /dev/null); then + echo "Already running." + exit 99 +fi + +PATH=$PATH:/usr/local/bin + +nohup $GOPATH/src/code.vereign.com/code/key-storage-agent/bin/server --cert-dir $GOPATH/src/code.vereign.com/code/key-storage-agent/cert > $HOME/key-storage-agent.log 2>&1 & + +echo $! > "${PIDFILE}" +chmod 644 "${PIDFILE}" diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000000000000000000000000000000000000..fa6892a8ba25068b898872887bdca0f0940a8d20 --- /dev/null +++ b/server/server.go @@ -0,0 +1,174 @@ +package server + +/* +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/>. +*/ + +import ( + "fmt" + "log" + "net" + "net/http" + "strings" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + + "golang.org/x/net/context" + + "code.vereign.com/code/key-storage-agent/handler" + "code.vereign.com/code/key-storage-agent/session" + "code.vereign.com/code/viam-apis/authentication" + "code.vereign.com/code/viam-apis/data-storage-agent/client" + api "code.vereign.com/code/viam-apis/key-storage-agent/api" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/metadata" +) + +// private type for Context keys +type contextKey int + +const ( + clientIDKey contextKey = iota +) + +var pkgCertFile string + +func credMatcher(headerName string) (mdName string, ok bool) { + if headerName == "Session" { + return headerName, true + } + return "", false +} + +// authenticateAgent check the client credentials +func authenticateClient(ctx context.Context, s *handler.KeyStorageServerImpl, invokedMethod string) (string, error) { + if md, ok := metadata.FromIncomingContext(ctx); ok { + + clientAuth := &authentication.Authentication{ + Uuid: strings.Join(md["uuid"], ""), + Session: strings.Join(md["session"], ""), + } + + viamAuth := &authentication.Authentication{ + Uuid: "viam-system", + Session: "viam-session", + } + + sessionClient := &client.DataStorageClientImpl{} + sessionClient.SetUpClient(viamAuth, "localhost:7777", pkgCertFile) + defer sessionClient.CloseClient() + + if clientAuth.Uuid == viamAuth.Uuid { + if clientAuth.Session != viamAuth.Session { + return "", fmt.Errorf("bad session %s", clientAuth.Session) + } + } else { + if session.CheckSession(clientAuth.Uuid, clientAuth.Session, sessionClient) == false { + return "", fmt.Errorf("bad session %s", clientAuth.Session) + } + } + + log.Printf("authenticated uuid: %s", clientAuth.Uuid) + + return clientAuth.Uuid, nil + } + return "", fmt.Errorf("missing credentials") +} + +// unaryInterceptor call authenticateClient with current context +func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler1 grpc.UnaryHandler) (interface{}, error) { + s, ok := info.Server.(*handler.KeyStorageServerImpl) + fmt.Println("Invoked method: " + info.FullMethod) + if !ok { + return nil, fmt.Errorf("unable to cast server") + } + clientID, err := authenticateClient(ctx, s, info.FullMethod) + if err != nil { + return nil, err + } + + ctx = context.WithValue(ctx, clientIDKey, clientID) + + return handler1(ctx, req) +} + +func StartGRPCServer(address, certFile, keyFile, dataStorageAddress string) error { + pkgCertFile = certFile + + // create a listener on TCP port + lis, err := net.Listen("tcp", address) + if err != nil { + return fmt.Errorf("failed to listen: %v", err) + } + + // create a server instance + s := handler.KeyStorageServerImpl{ + DataStorageUrl: dataStorageAddress, + CertPath: certFile, + } + + // Create the TLS credentials + creds, err := credentials.NewServerTLSFromFile(certFile, keyFile) + if err != nil { + return fmt.Errorf("could not load TLS keys: %s", err) + } + + // Create an array of gRPC options with the credentials + opts := []grpc.ServerOption{grpc.Creds(creds), + grpc.UnaryInterceptor(unaryInterceptor)} + + // create a gRPC server object + grpcServer := grpc.NewServer(opts...) + + // attach the CalcMinimumDistance service to the server + api.RegisterKeyStorageServer(grpcServer, &s) + + // start the server + log.Printf("starting HTTP/2 gRPC server on %s", address) + if err := grpcServer.Serve(lis); err != nil { + return fmt.Errorf("failed to serve: %s", err) + } + + return nil +} + +func StartRESTServer(address, grpcAddress, certFile string) error { + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + mux := runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(credMatcher)) + + creds, err := credentials.NewClientTLSFromFile(certFile, "") + if err != nil { + return fmt.Errorf("could not load TLS certificate: %s", err) + } + + // Setup the client gRPC options + opts := []grpc.DialOption{grpc.WithTransportCredentials(creds)} + + // Register RedisStorageServer + err = api.RegisterKeyStorageHandlerFromEndpoint(ctx, mux, grpcAddress, opts) + if err != nil { + return fmt.Errorf("could not register service RedisStorageServer: %s", err) + } + + log.Printf("starting HTTP/1.1 REST server on %s", address) + http.ListenAndServe(address, mux) + + return nil +} diff --git a/server/server_test.go b/server/server_test.go new file mode 100644 index 0000000000000000000000000000000000000000..1c0fda7aef278d34358541a5655ee47faaf6c305 --- /dev/null +++ b/server/server_test.go @@ -0,0 +1,132 @@ +/* +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 server + +import ( + "log" + "os" + "testing" + "time" + + dataStorageServer "code.vereign.com/code/data-storage-agent/server" + "code.vereign.com/code/data-storage-agent/utils" + "code.vereign.com/code/viam-apis/authentication" + ksapi "code.vereign.com/code/viam-apis/key-storage-agent/api" + ksclient "code.vereign.com/code/viam-apis/key-storage-agent/client" +) + +const ( + dataStorageGrpcAddress = "localhost:7777" + keyStorageGrpcAddress = "localhost:7877" + certFile = "../cert/server.crt" + keyFile = "../cert/server.key" +) + +func TestSetAndGetKeys(t *testing.T) { + dataStorageClient := utils.CreateClientFromUuidAndSession("viam-system", "viam-session", dataStorageGrpcAddress, certFile) + + keyStorageAuth := &authentication.Authentication{ + Uuid: "some-uuid", + Session: "some-session", + } + + _, _, _ = dataStorageClient.RenewSession(keyStorageAuth.Uuid, keyStorageAuth.Session) + + keyStorageClient := &ksclient.KeyStorageClientImpl{} + keyStorageClient.SetUpClient(keyStorageAuth, keyStorageGrpcAddress, certFile) + defer keyStorageClient.CloseClient() + + privateKey := &ksapi.PrivateKey{ + Name: "privkey1", + PublicKeyReference: "pubkey1", + Content: []byte{0, 1, 4}, + } + + statusList, _ := keyStorageClient.DoSetPrivateKey(privateKey) + for _, status := range statusList { + if status.StatusType == "error" { + t.Errorf("DoSetPrivateKey, returned error: %s.", status.Code+":"+status.Description) + } + } + + privateKeyResult, statusList, _ := keyStorageClient.DoGetPrivateKey("privkey1") + for _, status := range statusList { + if status.StatusType == "error" { + t.Errorf("DoGetPrivateKey, returned error: %s.", status.Code+":"+status.Description) + } + } + if privateKeyResult.Content == nil || !utils.CompareByteArrays(privateKeyResult.Content, []byte{0, 1, 4}) { + t.Errorf("DoGetPrivateKey, incorrect keyResult.Content, expected: %v, but was: %v", + []byte{0, 1, 2}, privateKeyResult.Content) + } + + publicKey := &ksapi.PublicKey{ + Name: "pubkey1", + Content: []byte{3, 4, 2}, + Certificate: []byte{5, 1, 6}, + } + + statusList, _ = keyStorageClient.DoSetPublicKey(publicKey) + for _, status := range statusList { + if status.StatusType == "error" { + t.Errorf("DoSetPublicKey, returned error: %s.", status.Code+":"+status.Description) + } + } + + publicKeyResult, statusList, _ := keyStorageClient.DoGetPublicKey("pubkey1") + for _, status := range statusList { + if status.StatusType == "error" { + t.Errorf("DoGetPublicKey, returned error: %s.", status.Code+":"+status.Description) + } + } + if publicKeyResult.Content == nil || !utils.CompareByteArrays(publicKeyResult.Content, []byte{3, 4, 2}) { + t.Errorf("DoGetPublicKey, incorrect publicKeyResult.Content, expected: %v, but was: %v", + []byte{3, 4, 2}, publicKeyResult.Content) + } + if publicKeyResult.Certificate == nil || !utils.CompareByteArrays(publicKeyResult.Certificate, []byte{5, 1, 6}) { + t.Errorf("DoGetPublicKey, incorrect publicKeyResult.Certificate, expected: %v, but was: %v", + []byte{5, 1, 6}, publicKeyResult.Certificate) + } +} + +func TestMain(m *testing.M) { + // fire the gRPC server in a goroutine + go func() { + err := dataStorageServer.StartGRPCServer(dataStorageGrpcAddress, certFile, keyFile) + if err != nil { + log.Fatalf("failed to start gRPC server: %s", err) + } + }() + + // wait a second for the server to start + time.Sleep(time.Duration(1) * time.Second) + + // fire the gRPC server in a goroutine + go func() { + err := StartGRPCServer(keyStorageGrpcAddress, certFile, keyFile, dataStorageGrpcAddress) + if err != nil { + log.Fatalf("failed to start gRPC server: %s", err) + } + }() + + // wait a second for the server to start + time.Sleep(time.Duration(1) * time.Second) + + retCode := m.Run() + os.Exit(retCode) +} diff --git a/session/session.go b/session/session.go new file mode 100644 index 0000000000000000000000000000000000000000..14793a89303df97561b0e64975fe40ab0a22ee2a --- /dev/null +++ b/session/session.go @@ -0,0 +1,31 @@ +/* +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 session + +import ( + client "code.vereign.com/code/viam-apis/data-storage-agent/client" +) + +func CheckSession(uuid string, session string, sessionClient *client.DataStorageClientImpl) bool { + hasSession, _, err := sessionClient.HasSession(uuid, session) + if err != nil { + return false + } + + return hasSession +}