Commit 13dd77aa authored by Loïck Bonniot's avatar Loïck Bonniot

[p] Add GetContract API

parent 9c2d90f8
Pipeline #610 passed with stage
......@@ -83,6 +83,10 @@ func init() {
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion1
// Client API for Client service
type ClientClient interface {
......
......@@ -62,6 +62,10 @@ func init() {
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion1
// Client API for Demonstrator service
type DemonstratorClient interface {
......
This diff is collapsed.
......@@ -7,6 +7,7 @@ service Platform {
rpc Auth(AuthRequest) returns (RegisteredUser) {}
rpc Unregister(Empty) returns (ErrorCode) {}
rpc PostContract(PostContractRequest) returns (ErrorCode) {}
rpc GetContract(GetContractRequest) returns (Contract) {}
rpc JoinSignature(JoinSignatureRequest) returns (stream UserConnected) {}
rpc ReadySign(ReadySignRequest) returns (LaunchSignature) {} // Warning, LaunchSignature can be emitted with a very high delay
}
......@@ -63,6 +64,18 @@ message PostContractRequest {
string comment = 4;
}
// GetContractRequest message contains the uuid of the asked contract
message GetContractRequest {
string uuid = 1;
}
// Contract is the return value when a contract is fetched from the platform.
// The contract is in json format to avoid duplicating structures.
Please register or sign in to reply
message Contract {
ErrorCode errorCode = 1;
bytes json = 2;
}
// JoinSignatureRequest message contains the contract to join unique identifier
// and the port the client will be listening at
message JoinSignatureRequest {
......
......@@ -14,7 +14,6 @@ import (
"gopkg.in/mgo.v2/bson"
)
var err error
var collection *mgdb.MongoCollection
var manager *mgdb.MongoManager
var dbURI string
......@@ -28,6 +27,7 @@ func TestMain(m *testing.M) {
dbURI = "mongodb://localhost/dfss-test"
}
var err error
manager, err = mgdb.NewManager(dbURI)
if err != nil {
fmt.Println(err)
......@@ -157,16 +157,26 @@ func TestCheckAuthorization(t *testing.T) {
createDataset()
id := addTestContract()
assert.T(t, repository.CheckAuthorization(user1.CertHash, id))
assert.T(t, !repository.CheckAuthorization(user1.CertHash, bson.NewObjectId()))
assert.T(t, !repository.CheckAuthorization(user2.CertHash, id))
assert.T(t, !repository.CheckAuthorization(user2.CertHash, bson.NewObjectId()))
res, err := repository.GetWithSigner(user1.CertHash, id)
assert.Equal(t, nil, err)
assert.T(t, res != nil)
res, err = repository.GetWithSigner(user1.CertHash, bson.NewObjectId())
assert.Equal(t, nil, err)
assert.T(t, res == nil)
res, err = repository.GetWithSigner(user2.CertHash, id)
assert.Equal(t, nil, err)
assert.T(t, res == nil)
res, err = repository.GetWithSigner(user2.CertHash, bson.NewObjectId())
assert.Equal(t, nil, err)
assert.T(t, res == nil)
contract := entities.Contract{}
_ = repository.Collection.FindByID(entities.Contract{ID: id}, &contract)
contract.Ready = false
_, _ = repository.Collection.UpdateByID(contract)
// Not valid if contract is not ready
assert.T(t, !repository.CheckAuthorization(user1.CertHash, id))
// Still valid if contract is not ready
res, _ = repository.GetWithSigner(user1.CertHash, id)
assert.T(t, res != nil)
assert.T(t, !res.Ready)
}
......@@ -20,7 +20,6 @@ var user1, user2, user3 *entities.User
var defaultHash = sha512.Sum512([]byte{0})
func createDataset() {
user1 = entities.NewUser() // Regular user
user2 = entities.NewUser() // Regular user
user3 = entities.NewUser() // Non-auth user
......@@ -43,14 +42,11 @@ func createDataset() {
_, _ = manager.Get("users").Insert(user1)
_, _ = manager.Get("users").Insert(user2)
_, _ = manager.Get("users").Insert(user3)
}
func dropDataset() {
_ = manager.Get("users").Drop()
_ = manager.Get("contracts").Drop()
}
func clientTest(t *testing.T) api.PlatformClient {
......
package contract
import (
"dfss/dfssp/api"
"dfss/dfssp/entities"
"dfss/mgdb"
"gopkg.in/mgo.v2/bson"
)
// Fetch returns the protobuf message when asking a specific contract containing a specific user.
func Fetch(db *mgdb.MongoManager, contractUUID string, clientHash []byte) *api.Contract {
if !bson.IsObjectIdHex(contractUUID) {
return &api.Contract{
ErrorCode: &api.ErrorCode{Code: api.ErrorCode_INVARG},
}
}
repository := entities.NewContractRepository(db.Get("contracts"))
contract, _ := repository.GetWithSigner(clientHash, bson.ObjectIdHex(contractUUID))
if contract == nil {
return &api.Contract{
ErrorCode: &api.ErrorCode{Code: api.ErrorCode_BADAUTH},
}
}
data, err := GetJSON(contract, nil)
if err != nil {
return &api.Contract{
ErrorCode: &api.ErrorCode{Code: api.ErrorCode_INTERR},
}
}
return &api.Contract{
ErrorCode: &api.ErrorCode{Code: api.ErrorCode_SUCCESS},
Json: data,
}
}
package contract_test
import (
"encoding/json"
"testing"
"dfss/dfssp/api"
"dfss/dfssp/contract"
"dfss/dfssp/entities"
"github.com/bmizerany/assert"
"golang.org/x/net/context"
"gopkg.in/mgo.v2/bson"
)
var contract1 *entities.Contract
func insertTestContract(insertUser1 bool) {
contract1 = entities.NewContract()
if insertUser1 {
contract1.AddSigner(&user1.ID, user1.Email, user1.CertHash)
}
contract1.AddSigner(&user2.ID, user2.Email, user2.CertHash)
_, _ = manager.Get("contracts").Insert(contract1)
}
func TestGetContract(t *testing.T) {
dropDataset()
createDataset()
insertTestContract(true)
client := clientTest(t)
c, err := client.GetContract(context.Background(), &api.GetContractRequest{
Uuid: contract1.ID.Hex(),
})
assert.Equal(t, nil, err)
assert.Equal(t, api.ErrorCode_SUCCESS, c.ErrorCode.Code)
assert.T(t, len(c.Json) > 0)
// Trying to unmarshal contract
var entity contract.JSON
err = json.Unmarshal(c.Json, &entity)
assert.Equal(t, nil, err)
assert.Equal(t, 2, len(entity.Signers))
}
func TestGetContractWrongSigner(t *testing.T) {
dropDataset()
createDataset()
insertTestContract(false)
client := clientTest(t)
c, err := client.GetContract(context.Background(), &api.GetContractRequest{
Uuid: contract1.ID.Hex(),
})
assert.Equal(t, nil, err)
assert.Equal(t, api.ErrorCode_BADAUTH, c.ErrorCode.Code)
assert.Equal(t, 0, len(c.Json))
}
func TestGetContractWrongContract(t *testing.T) {
dropDataset()
createDataset()
insertTestContract(true)
client := clientTest(t)
c, err := client.GetContract(context.Background(), &api.GetContractRequest{
Uuid: bson.NewObjectId().Hex(),
})
assert.Equal(t, nil, err)
assert.Equal(t, api.ErrorCode_BADAUTH, c.ErrorCode.Code)
assert.Equal(t, 0, len(c.Json))
}
func TestGetContractWrongContractUUID(t *testing.T) {
dropDataset()
createDataset()
insertTestContract(true)
client := clientTest(t)
c, err := client.GetContract(context.Background(), &api.GetContractRequest{
Uuid: "wrongUUID",
})
assert.Equal(t, nil, err)
assert.Equal(t, api.ErrorCode_INVARG, c.ErrorCode.Code)
assert.Equal(t, 0, len(c.Json))
}
......@@ -39,7 +39,6 @@ type JSON struct {
// GetJSON returns indented json from a contract and some ttp information (nil allowed)
func GetJSON(c *entities.Contract, ttp *TTPJSON) ([]byte, error) {
data := JSON{
UUID: c.ID.Hex(),
Date: &c.Date,
......
......@@ -84,7 +84,8 @@ func checkJoinSignatureRequest(db *mgdb.MongoManager, stream *api.Platform_JoinS
}
repository := entities.NewContractRepository(db.Get("contracts"))
if !repository.CheckAuthorization(clientHash, bson.ObjectIdHex(contractUUID)) {
contract, _ := repository.GetWithSigner(clientHash, bson.ObjectIdHex(contractUUID))
if contract == nil || !contract.Ready {
_ = (*stream).Send(&api.UserConnected{
ErrorCode: &api.ErrorCode{
Code: api.ErrorCode_INVARG,
......
......@@ -4,6 +4,7 @@ import (
"dfss/mgdb"
"time"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
......@@ -94,16 +95,20 @@ func (r *ContractRepository) GetWaitingForUser(email string) ([]Contract, error)
return res, err
}
// CheckAuthorization checks that a client is allowed to sign a specific contract
func (r *ContractRepository) CheckAuthorization(signerHash []byte, contractID bson.ObjectId) bool {
count, _ := r.Collection.Collection.Find(bson.M{
"_id": contractID,
"ready": true,
// GetWithSigner returns the contract corresponding to an UUID and containing a specific signer, or nil if no contract matches.
func (r *ContractRepository) GetWithSigner(signerHash []byte, contractUUID bson.ObjectId) (contract *Contract, err error) {
contract = new(Contract)
err = r.Collection.Collection.Find(bson.M{
"_id": contractUUID,
"signers": bson.M{
"$elemMatch": bson.M{"hash": signerHash},
},
}).Count()
}).One(contract)
return count == 1
if err == mgo.ErrNotFound {
contract = nil
err = nil
return
}
return
}
......@@ -49,7 +49,6 @@ func (s *platformServer) Unregister(ctx context.Context, in *api.Empty) (*api.Er
//
// Handle incoming PostContractRequest messages
func (s *platformServer) PostContract(ctx context.Context, in *api.PostContractRequest) (*api.ErrorCode, error) {
cn := net.GetCN(&ctx)
if len(cn) == 0 {
return &api.ErrorCode{Code: api.ErrorCode_BADAUTH}, nil
......@@ -59,11 +58,21 @@ func (s *platformServer) PostContract(ctx context.Context, in *api.PostContractR
return builder.Execute(), nil
}
// GetContract handler
//
// Handle incoming GetContractRequest messages
func (s *platformServer) GetContract(ctx context.Context, in *api.GetContractRequest) (*api.Contract, error) {
hash := net.GetClientHash(&ctx)
if hash == nil {
return &api.Contract{ErrorCode: &api.ErrorCode{Code: api.ErrorCode_BADAUTH}}, nil
}
return contract.Fetch(s.DB, in.Uuid, hash), nil
}
// JoinSignature handler
//
// Handle incoming JoinSignatureRequest messages
func (s *platformServer) JoinSignature(in *api.JoinSignatureRequest, stream api.Platform_JoinSignatureServer) error {
ctx := stream.Context()
cn := net.GetCN(&ctx)
if len(cn) == 0 {
......
......@@ -74,6 +74,10 @@ func init() {
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion1
// Client API for TTP service
type TTPClient interface {
......
......@@ -49,6 +49,14 @@ func (s *mockServer) PostContract(ctx context.Context, in *api.PostContractReque
return fixtures.CreateFixture[in.Comment], nil
}
// GetContract handler
//
// Handle incoming GetContractRequest messages
func (s *mockServer) GetContract(ctx context.Context, in *api.GetContractRequest) (*api.Contract, error) {
// TODO
return nil, nil
}
// JoinSignature handler
//
// Handle incoming JoinSignatureRequest messages
......
......@@ -6,6 +6,7 @@ import (
"crypto/x509"
"net"
"dfss/auth"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
......@@ -73,3 +74,13 @@ func GetCN(ctx *context.Context) string {
}
return state.VerifiedChains[0][0].Subject.CommonName
}
// GetClientHash returns the current certificate hash of connected peer from grpc context.
// The returned slice is nil if encoutering a non-auth peer.
func GetClientHash(ctx *context.Context) []byte {
Please register or sign in to reply
state, _, ok := GetTLSState(ctx)
if !ok || len(state.VerifiedChains) == 0 {
return nil
}
return auth.GetCertificateHash(state.VerifiedChains[0][0])
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment