Skip to content

Commit 556ab7f

Browse files
adecarombjoerkqvist
authored andcommitted
[FAB-11524] Prover: Request Import
This change-set does the following: - Introduces the Prover service - Implements support for the SignedCommand related to a request import - Local interfaces have been introduces to reduce dependency from TMS, MSP and AccessControl - Implement Access Control based on channel's policies Future change-sets will provide: - enablement of the Prover at peer's bootstrap Change-Id: I64f57a82c2db2acc98411d9700b5ccb859cc4801 Signed-off-by: Angelo De Caro <adc@zurich.ibm.com> Signed-off-by: Matthew Sykes <sykesmat@us.ibm.com> Signed-off-by: Mathias Bjoerkqvist <mbj@zurich.ibm.com>
1 parent 111ae61 commit 556ab7f

16 files changed

+1676
-0
lines changed

Gopkg.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

token/server/accesscontrol.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
package server
7+
8+
import (
9+
"github.com/hyperledger/fabric/common/policies"
10+
"github.com/hyperledger/fabric/protos/common"
11+
"github.com/hyperledger/fabric/protos/token"
12+
"github.com/pkg/errors"
13+
)
14+
15+
//go:generate counterfeiter -o mock/signed_data_policy_checker.go -fake-name SignedDataPolicyChecker . SignedDataPolicyChecker
16+
17+
type SignedDataPolicyChecker interface {
18+
// CheckPolicyBySignedData checks that the provided signed data is valid with respect to
19+
// specified policy for the specified channel.
20+
CheckPolicyBySignedData(channelID, policyName string, sd []*common.SignedData) error
21+
}
22+
23+
// PolicyBasedAccessControl implements token command access control functions.
24+
type PolicyBasedAccessControl struct {
25+
SignedDataPolicyChecker SignedDataPolicyChecker
26+
}
27+
28+
func (ac *PolicyBasedAccessControl) Check(sc *token.SignedCommand, c *token.Command) error {
29+
switch t := c.GetPayload().(type) {
30+
31+
case *token.Command_ImportRequest:
32+
return ac.SignedDataPolicyChecker.CheckPolicyBySignedData(
33+
c.Header.ChannelId,
34+
policies.ChannelApplicationWriters,
35+
[]*common.SignedData{{
36+
Identity: c.Header.Creator,
37+
Data: sc.Command,
38+
Signature: sc.Signature,
39+
}},
40+
)
41+
42+
default:
43+
return errors.Errorf("command type not recognized: %T", t)
44+
}
45+
}

token/server/accesscontrol_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package server_test
8+
9+
import (
10+
. "github.com/onsi/ginkgo"
11+
. "github.com/onsi/gomega"
12+
"github.com/pkg/errors"
13+
14+
"github.com/hyperledger/fabric/common/policies"
15+
"github.com/hyperledger/fabric/protos/common"
16+
"github.com/hyperledger/fabric/protos/token"
17+
"github.com/hyperledger/fabric/token/server"
18+
"github.com/hyperledger/fabric/token/server/mock"
19+
)
20+
21+
var _ = Describe("AccessControl", func() {
22+
var (
23+
fakePolicyChecker *mock.SignedDataPolicyChecker
24+
pbac *server.PolicyBasedAccessControl
25+
26+
importRequest *token.ImportRequest
27+
command *token.Command
28+
marshaledCommand []byte
29+
signedCommand *token.SignedCommand
30+
)
31+
32+
BeforeEach(func() {
33+
fakePolicyChecker = &mock.SignedDataPolicyChecker{}
34+
pbac = &server.PolicyBasedAccessControl{
35+
SignedDataPolicyChecker: fakePolicyChecker,
36+
}
37+
38+
importRequest = &token.ImportRequest{}
39+
command = &token.Command{
40+
Header: &token.Header{
41+
ChannelId: "channel-id",
42+
Creator: []byte("creator"),
43+
},
44+
Payload: &token.Command_ImportRequest{
45+
ImportRequest: importRequest,
46+
},
47+
}
48+
49+
marshaledCommand = ProtoMarshal(command)
50+
signedCommand = &token.SignedCommand{
51+
Command: marshaledCommand,
52+
Signature: []byte("signature"),
53+
}
54+
})
55+
56+
It("checks the policy", func() {
57+
err := pbac.Check(signedCommand, command)
58+
Expect(err).NotTo(HaveOccurred())
59+
60+
Expect(fakePolicyChecker.CheckPolicyBySignedDataCallCount()).To(Equal(1))
61+
channelID, policyName, signedData := fakePolicyChecker.CheckPolicyBySignedDataArgsForCall(0)
62+
Expect(channelID).To(Equal("channel-id"))
63+
Expect(policyName).To(Equal(policies.ChannelApplicationWriters))
64+
Expect(signedData).To(ConsistOf(&common.SignedData{
65+
Data: marshaledCommand,
66+
Identity: []byte("creator"),
67+
Signature: []byte("signature"),
68+
}))
69+
})
70+
71+
Context("when the policy checker returns an error", func() {
72+
BeforeEach(func() {
73+
fakePolicyChecker.CheckPolicyBySignedDataReturns(errors.New("no-can-do"))
74+
})
75+
76+
It("returns the error", func() {
77+
err := pbac.Check(signedCommand, command)
78+
Expect(err).To(MatchError("no-can-do"))
79+
})
80+
})
81+
82+
Context("when the command payload type is not recognized", func() {
83+
BeforeEach(func() {
84+
command.Payload = nil
85+
})
86+
87+
It("skips the access control check", func() {
88+
pbac.Check(signedCommand, command)
89+
Expect(fakePolicyChecker.CheckPolicyBySignedDataCallCount()).To(Equal(0))
90+
})
91+
92+
It("returns a error", func() {
93+
err := pbac.Check(signedCommand, command)
94+
Expect(err).To(MatchError("command type not recognized: <nil>"))
95+
})
96+
})
97+
})

token/server/marshal.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package server
8+
9+
import (
10+
"time"
11+
12+
"github.com/golang/protobuf/proto"
13+
"github.com/golang/protobuf/ptypes"
14+
"github.com/hyperledger/fabric/common/util"
15+
"github.com/hyperledger/fabric/protos/token"
16+
"github.com/pkg/errors"
17+
)
18+
19+
// UnmarshalCommand unmarshal token.Command messages
20+
func UnmarshalCommand(raw []byte) (*token.Command, error) {
21+
command := &token.Command{}
22+
err := proto.Unmarshal(raw, command)
23+
if err != nil {
24+
return nil, err
25+
}
26+
27+
return command, nil
28+
}
29+
30+
type TimeFunc func() time.Time
31+
32+
// ResponseMarshaler produces token.SignedCommandResponse
33+
type ResponseMarshaler struct {
34+
Signer Signer
35+
Creator []byte
36+
Time TimeFunc
37+
}
38+
39+
func NewResponseMarshaler(signerID SignerIdentity) (*ResponseMarshaler, error) {
40+
creator, err := signerID.Serialize()
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
return &ResponseMarshaler{
46+
Signer: signerID,
47+
Creator: creator,
48+
Time: time.Now,
49+
}, nil
50+
}
51+
52+
func (s *ResponseMarshaler) MarshalCommandResponse(command []byte, responsePayload interface{}) (*token.SignedCommandResponse, error) {
53+
cr, err := commandResponseFromPayload(responsePayload)
54+
if err != nil {
55+
return nil, err
56+
}
57+
58+
ts, err := ptypes.TimestampProto(s.Time())
59+
if err != nil {
60+
return nil, err
61+
}
62+
63+
cr.Header = &token.CommandResponseHeader{
64+
Creator: s.Creator,
65+
CommandHash: util.ComputeSHA256(command),
66+
Timestamp: ts,
67+
}
68+
69+
return s.createSignedCommandResponse(cr)
70+
}
71+
72+
func (s *ResponseMarshaler) createSignedCommandResponse(cr *token.CommandResponse) (*token.SignedCommandResponse, error) {
73+
raw, err := proto.Marshal(cr)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
signature, err := s.Signer.Sign(raw)
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
return &token.SignedCommandResponse{
84+
Response: raw,
85+
Signature: signature,
86+
}, nil
87+
}
88+
89+
func commandResponseFromPayload(payload interface{}) (*token.CommandResponse, error) {
90+
switch t := payload.(type) {
91+
case *token.CommandResponse_TokenTransaction:
92+
return &token.CommandResponse{Payload: t}, nil
93+
case *token.CommandResponse_Err:
94+
return &token.CommandResponse{Payload: t}, nil
95+
default:
96+
return nil, errors.Errorf("command type not recognized: %T", t)
97+
}
98+
}

0 commit comments

Comments
 (0)