Skip to content

Commit fa7faec

Browse files
committed
Access control at QSCC
This change-set does the following: 1. Add access control to qscc by verifying that the caller has read access to the channel. A new test has been added to cover this access control This change-set comes in the context of: 1. https://jira.hyperledger.org/browse/FAB-2969 Change-Id: Ieca0babd3b65ecffda450b29cc82797a101f8671 Signed-off-by: Angelo De Caro <[email protected]>
1 parent 7a3af1d commit fa7faec

File tree

5 files changed

+171
-56
lines changed

5 files changed

+171
-56
lines changed

core/chaincode/shim/mockstub.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ type MockStub struct {
6161
TxID string
6262

6363
TxTimestamp *timestamp.Timestamp
64+
65+
// mocked signedProposal
66+
signedProposal *pb.SignedProposal
6467
}
6568

6669
func (stub *MockStub) GetTxID() string {
@@ -96,11 +99,13 @@ func (stub *MockStub) GetFunctionAndParameters() (function string, params []stri
9699
// MockStub doesn't support concurrent transactions at present.
97100
func (stub *MockStub) MockTransactionStart(txid string) {
98101
stub.TxID = txid
102+
stub.setSignedProposal(&pb.SignedProposal{})
99103
stub.setTxTimestamp(util.CreateUtcTimestamp())
100104
}
101105

102106
// End a mocked transaction, clearing the UUID.
103107
func (stub *MockStub) MockTransactionEnd(uuid string) {
108+
stub.signedProposal = nil
104109
stub.TxID = ""
105110
}
106111

@@ -129,6 +134,16 @@ func (stub *MockStub) MockInvoke(uuid string, args [][]byte) pb.Response {
129134
return res
130135
}
131136

137+
// Invoke this chaincode, also starts and ends a transaction.
138+
func (stub *MockStub) MockInvokeWithSignedProposal(uuid string, args [][]byte, sp *pb.SignedProposal) pb.Response {
139+
stub.args = args
140+
stub.MockTransactionStart(uuid)
141+
stub.signedProposal = sp
142+
res := stub.cc.Invoke(stub)
143+
stub.MockTransactionEnd(uuid)
144+
return res
145+
}
146+
132147
// GetState retrieves the value for a given key from the ledger
133148
func (stub *MockStub) GetState(key string) ([]byte, error) {
134149
value := stub.State[key]
@@ -272,7 +287,11 @@ func (stub *MockStub) GetBinding() ([]byte, error) {
272287

273288
// Not implemented
274289
func (stub *MockStub) GetSignedProposal() (*pb.SignedProposal, error) {
275-
return nil, nil
290+
return stub.signedProposal, nil
291+
}
292+
293+
func (stub *MockStub) setSignedProposal(sp *pb.SignedProposal) {
294+
stub.signedProposal = sp
276295
}
277296

278297
// Not implemented

core/policy/mocks.go

+36-36
Original file line numberDiff line numberDiff line change
@@ -29,93 +29,93 @@ import (
2929
mspproto "github.com/hyperledger/fabric/protos/msp"
3030
)
3131

32-
type mockChannelPolicyManagerGetter struct {
33-
managers map[string]policies.Manager
32+
type MockChannelPolicyManagerGetter struct {
33+
Managers map[string]policies.Manager
3434
}
3535

36-
func (c *mockChannelPolicyManagerGetter) Manager(channelID string) (policies.Manager, bool) {
37-
return c.managers[channelID], true
36+
func (c *MockChannelPolicyManagerGetter) Manager(channelID string) (policies.Manager, bool) {
37+
return c.Managers[channelID], true
3838
}
3939

40-
type mockChannelPolicyManager struct {
41-
mockPolicy policies.Policy
40+
type MockChannelPolicyManager struct {
41+
MockPolicy policies.Policy
4242
}
4343

44-
func (m *mockChannelPolicyManager) GetPolicy(id string) (policies.Policy, bool) {
45-
return m.mockPolicy, true
44+
func (m *MockChannelPolicyManager) GetPolicy(id string) (policies.Policy, bool) {
45+
return m.MockPolicy, true
4646
}
4747

48-
func (m *mockChannelPolicyManager) Manager(path []string) (policies.Manager, bool) {
48+
func (m *MockChannelPolicyManager) Manager(path []string) (policies.Manager, bool) {
4949
panic("Not implemented")
5050
}
5151

52-
func (m *mockChannelPolicyManager) BasePath() string {
52+
func (m *MockChannelPolicyManager) BasePath() string {
5353
panic("Not implemented")
5454
}
5555

56-
func (m *mockChannelPolicyManager) PolicyNames() []string {
56+
func (m *MockChannelPolicyManager) PolicyNames() []string {
5757
panic("Not implemented")
5858
}
5959

60-
type mockPolicy struct {
61-
deserializer msp.IdentityDeserializer
60+
type MockPolicy struct {
61+
Deserializer msp.IdentityDeserializer
6262
}
6363

6464
// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy
65-
func (m *mockPolicy) Evaluate(signatureSet []*common.SignedData) error {
65+
func (m *MockPolicy) Evaluate(signatureSet []*common.SignedData) error {
6666
fmt.Printf("Evaluate [%s], [% x], [% x]\n", string(signatureSet[0].Identity), string(signatureSet[0].Data), string(signatureSet[0].Signature))
67-
identity, err := m.deserializer.DeserializeIdentity(signatureSet[0].Identity)
67+
identity, err := m.Deserializer.DeserializeIdentity(signatureSet[0].Identity)
6868
if err != nil {
6969
return err
7070
}
7171

7272
return identity.Verify(signatureSet[0].Data, signatureSet[0].Signature)
7373
}
7474

75-
type mockIdentityDeserializer struct {
76-
identity []byte
77-
msg []byte
75+
type MockIdentityDeserializer struct {
76+
Identity []byte
77+
Msg []byte
7878
}
7979

80-
func (d *mockIdentityDeserializer) DeserializeIdentity(serializedIdentity []byte) (msp.Identity, error) {
81-
fmt.Printf("id : [%s], [%s]\n", string(serializedIdentity), string(d.identity))
82-
if bytes.Equal(d.identity, serializedIdentity) {
83-
fmt.Printf("GOT : [%s], [%s]\n", string(serializedIdentity), string(d.identity))
84-
return &mockIdentity{identity: d.identity, msg: d.msg}, nil
80+
func (d *MockIdentityDeserializer) DeserializeIdentity(serializedIdentity []byte) (msp.Identity, error) {
81+
fmt.Printf("id : [%s], [%s]\n", string(serializedIdentity), string(d.Identity))
82+
if bytes.Equal(d.Identity, serializedIdentity) {
83+
fmt.Printf("GOT : [%s], [%s]\n", string(serializedIdentity), string(d.Identity))
84+
return &MockIdentity{identity: d.Identity, msg: d.Msg}, nil
8585
}
8686

87-
return nil, errors.New("Invalid identity")
87+
return nil, errors.New("Invalid Identity")
8888
}
8989

90-
type mockIdentity struct {
90+
type MockIdentity struct {
9191
identity []byte
9292
msg []byte
9393
}
9494

95-
func (id *mockIdentity) SatisfiesPrincipal(p *mspproto.MSPPrincipal) error {
95+
func (id *MockIdentity) SatisfiesPrincipal(p *mspproto.MSPPrincipal) error {
9696
if !bytes.Equal(id.identity, p.Principal) {
9797
return fmt.Errorf("Different identities [% x]!=[% x]", id.identity, p.Principal)
9898
}
9999
return nil
100100
}
101101

102-
func (id *mockIdentity) GetIdentifier() *msp.IdentityIdentifier {
102+
func (id *MockIdentity) GetIdentifier() *msp.IdentityIdentifier {
103103
return &msp.IdentityIdentifier{Mspid: "mock", Id: "mock"}
104104
}
105105

106-
func (id *mockIdentity) GetMSPIdentifier() string {
106+
func (id *MockIdentity) GetMSPIdentifier() string {
107107
return "mock"
108108
}
109109

110-
func (id *mockIdentity) Validate() error {
110+
func (id *MockIdentity) Validate() error {
111111
return nil
112112
}
113113

114-
func (id *mockIdentity) GetOrganizationalUnits() []string {
114+
func (id *MockIdentity) GetOrganizationalUnits() []string {
115115
return []string{"dunno"}
116116
}
117117

118-
func (id *mockIdentity) Verify(msg []byte, sig []byte) error {
118+
func (id *MockIdentity) Verify(msg []byte, sig []byte) error {
119119
fmt.Printf("VERIFY [% x], [% x], [% x]\n", string(id.msg), string(msg), string(sig))
120120
if bytes.Equal(id.msg, msg) {
121121
if bytes.Equal(msg, sig) {
@@ -126,22 +126,22 @@ func (id *mockIdentity) Verify(msg []byte, sig []byte) error {
126126
return errors.New("Invalid Signature")
127127
}
128128

129-
func (id *mockIdentity) VerifyOpts(msg []byte, sig []byte, opts msp.SignatureOpts) error {
129+
func (id *MockIdentity) VerifyOpts(msg []byte, sig []byte, opts msp.SignatureOpts) error {
130130
return nil
131131
}
132132

133-
func (id *mockIdentity) VerifyAttributes(proof []byte, spec *msp.AttributeProofSpec) error {
133+
func (id *MockIdentity) VerifyAttributes(proof []byte, spec *msp.AttributeProofSpec) error {
134134
return nil
135135
}
136136

137-
func (id *mockIdentity) Serialize() ([]byte, error) {
137+
func (id *MockIdentity) Serialize() ([]byte, error) {
138138
return []byte("cert"), nil
139139
}
140140

141-
type mockMSPPrincipalGetter struct {
141+
type MockMSPPrincipalGetter struct {
142142
Principal []byte
143143
}
144144

145-
func (m *mockMSPPrincipalGetter) Get(role string) (*mspproto.MSPPrincipal, error) {
145+
func (m *MockMSPPrincipalGetter) Get(role string) (*mspproto.MSPPrincipal, error) {
146146
return &mspproto.MSPPrincipal{Principal: m.Principal}, nil
147147
}

core/policy/policy_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,18 @@ import (
2626
)
2727

2828
func TestPolicyChecker(t *testing.T) {
29-
policyManagerGetter := &mockChannelPolicyManagerGetter{
29+
policyManagerGetter := &MockChannelPolicyManagerGetter{
3030
map[string]policies.Manager{
31-
"A": &mockChannelPolicyManager{&mockPolicy{&mockIdentityDeserializer{[]byte("Alice"), []byte("msg1")}}},
32-
"B": &mockChannelPolicyManager{&mockPolicy{&mockIdentityDeserializer{[]byte("Bob"), []byte("msg2")}}},
33-
"C": &mockChannelPolicyManager{&mockPolicy{&mockIdentityDeserializer{[]byte("Alice"), []byte("msg3")}}},
31+
"A": &MockChannelPolicyManager{&MockPolicy{&MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")}}},
32+
"B": &MockChannelPolicyManager{&MockPolicy{&MockIdentityDeserializer{[]byte("Bob"), []byte("msg2")}}},
33+
"C": &MockChannelPolicyManager{&MockPolicy{&MockIdentityDeserializer{[]byte("Alice"), []byte("msg3")}}},
3434
},
3535
}
36-
identityDeserializer := &mockIdentityDeserializer{[]byte("Alice"), []byte("msg1")}
36+
identityDeserializer := &MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")}
3737
pc := NewPolicyChecker(
3838
policyManagerGetter,
3939
identityDeserializer,
40-
&mockMSPPrincipalGetter{Principal: []byte("Alice")},
40+
&MockMSPPrincipalGetter{Principal: []byte("Alice")},
4141
)
4242

4343
// Check that (non-empty channel, empty policy) fails
@@ -58,7 +58,7 @@ func TestPolicyChecker(t *testing.T) {
5858

5959
// Validate Alice signatures against channel A's readers
6060
sProp, _ := utils.MockSignedEndorserProposalOrPanic("A", &peer.ChaincodeSpec{}, []byte("Alice"), []byte("msg1"))
61-
policyManagerGetter.managers["A"].(*mockChannelPolicyManager).mockPolicy.(*mockPolicy).deserializer.(*mockIdentityDeserializer).msg = sProp.ProposalBytes
61+
policyManagerGetter.Managers["A"].(*MockChannelPolicyManager).MockPolicy.(*MockPolicy).Deserializer.(*MockIdentityDeserializer).Msg = sProp.ProposalBytes
6262
sProp.Signature = sProp.ProposalBytes
6363
err = pc.CheckPolicy("A", "readers", sProp)
6464
assert.NoError(t, err)
@@ -72,7 +72,7 @@ func TestPolicyChecker(t *testing.T) {
7272
assert.Error(t, err)
7373

7474
// Alice is a member of the local MSP, policy check must succeed
75-
identityDeserializer.msg = sProp.ProposalBytes
75+
identityDeserializer.Msg = sProp.ProposalBytes
7676
err = pc.CheckPolicyNoChannel("member", sProp)
7777
assert.NoError(t, err)
7878

core/scc/qscc/query.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ import (
2222

2323
"github.com/op/go-logging"
2424

25+
"github.com/hyperledger/fabric/common/policies"
2526
"github.com/hyperledger/fabric/core/chaincode/shim"
2627
"github.com/hyperledger/fabric/core/ledger"
2728
"github.com/hyperledger/fabric/core/peer"
29+
"github.com/hyperledger/fabric/core/policy"
30+
"github.com/hyperledger/fabric/msp/mgmt"
2831
pb "github.com/hyperledger/fabric/protos/peer"
2932
"github.com/hyperledger/fabric/protos/utils"
3033
)
@@ -35,6 +38,7 @@ import (
3538
// - GetBlockByHash returns a block
3639
// - GetTransactionByID returns a transaction
3740
type LedgerQuerier struct {
41+
policyChecker policy.PolicyChecker
3842
}
3943

4044
var qscclogger = logging.MustGetLogger("qscc")
@@ -54,6 +58,13 @@ const (
5458
func (e *LedgerQuerier) Init(stub shim.ChaincodeStubInterface) pb.Response {
5559
qscclogger.Info("Init QSCC")
5660

61+
// Init policy checker for access control
62+
e.policyChecker = policy.NewPolicyChecker(
63+
peer.NewChannelPolicyManagerGetter(),
64+
mgmt.GetLocalMSP(),
65+
mgmt.NewLocalMSPPrincipalGetter(),
66+
)
67+
5768
return shim.Success(nil)
5869
}
5970

@@ -85,7 +96,17 @@ func (e *LedgerQuerier) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
8596
qscclogger.Debugf("Invoke function: %s on chain: %s", fname, cid)
8697
}
8798

88-
// TODO: Handle ACL
99+
// Handle ACL:
100+
// 1. get the signed proposal
101+
sp, err := stub.GetSignedProposal()
102+
if err != nil {
103+
return shim.Error(fmt.Sprintf("Failed getting signed proposal from stub, %s: %s", cid, err))
104+
}
105+
106+
// 2. check the channel reader policy
107+
if err = e.policyChecker.CheckPolicy(cid, policies.ChannelApplicationReaders, sp); err != nil {
108+
return shim.Error(fmt.Sprintf("Authorization request failed %s: %s", cid, err))
109+
}
89110

90111
switch fname {
91112
case GetTransactionByID:

0 commit comments

Comments
 (0)