Skip to content

Commit 6a976ba

Browse files
committedMay 10, 2018
[FAB-9478] Principal set filtering based on role
This change set implements filtering of principal sets based on their role and MSP ID. This is needed for collection support for service discovery: When a chaincode has several possible endorsement combinations that each combination is a principal set, but the user wants to perform a collection read/write - then the response should contain only principal sets which are "authorized" by the collection config. For this - we need a way to filter out principal sets that there exists a principal among them which isn't "authorized" by the collection config. This change set implements this filtering while taking into account the different MSP roles, for instance- if the endorsement policy has Peer roles in it, or OU roles, but the collection config has members, then it would still work because a peer is also a member (but not vice versa) Change-Id: I5b4c1a031b81e78ecdf535ae363a4c45a8a44967 Signed-off-by: yacovm <yacovm@il.ibm.com>
1 parent 715be74 commit 6a976ba

File tree

2 files changed

+358
-0
lines changed

2 files changed

+358
-0
lines changed
 

‎common/policies/inquire/compare.go

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package inquire
8+
9+
import (
10+
"bytes"
11+
12+
"github.com/golang/protobuf/proto"
13+
"github.com/hyperledger/fabric/common/policies"
14+
"github.com/hyperledger/fabric/protos/msp"
15+
)
16+
17+
// ComparablePrincipal defines an MSPPrincipal that can be compared to other principals
18+
type ComparablePrincipal struct {
19+
principal *msp.MSPPrincipal
20+
ou *msp.OrganizationUnit
21+
role *msp.MSPRole
22+
mspID string
23+
}
24+
25+
// NewComparablePrincipal creates a ComparablePrincipal out of the given MSPPrincipal.
26+
// Returns nil if a failure occurs.
27+
func NewComparablePrincipal(principal *msp.MSPPrincipal) *ComparablePrincipal {
28+
if principal == nil {
29+
logger.Warning("Principal is nil")
30+
return nil
31+
}
32+
cp := &ComparablePrincipal{
33+
principal: principal,
34+
}
35+
switch principal.PrincipalClassification {
36+
case msp.MSPPrincipal_ROLE:
37+
return cp.ToRole()
38+
case msp.MSPPrincipal_ORGANIZATION_UNIT:
39+
return cp.ToOURole()
40+
}
41+
mapping := msp.MSPPrincipal_Classification_name[int32(principal.PrincipalClassification)]
42+
logger.Warning("Received an unsupported principal type:", principal.PrincipalClassification, "mapped to", mapping)
43+
return nil
44+
}
45+
46+
// IsFound returns whether the ComparablePrincipal is found among the given set of ComparablePrincipals
47+
// For the ComparablePrincipal x to be found, there needs to be some ComparablePrincipal y in the set
48+
// such that x.IsA(y) will be true.
49+
func (cp *ComparablePrincipal) IsFound(set ...*ComparablePrincipal) bool {
50+
for _, cp2 := range set {
51+
if cp.IsA(cp2) {
52+
return true
53+
}
54+
}
55+
return false
56+
}
57+
58+
// IsA determines whether all identities that satisfy this ComparablePrincipal
59+
// also satisfy the other ComparablePrincipal.
60+
// Example: if this ComparablePrincipal is a Peer role,
61+
// and the other ComparablePrincipal is a Member role, then
62+
// all identities that satisfy this ComparablePrincipal (are peers)
63+
// also satisfy the other principal (are members).
64+
func (cp *ComparablePrincipal) IsA(other *ComparablePrincipal) bool {
65+
this := cp
66+
67+
if other == nil {
68+
return false
69+
}
70+
if this.principal == nil || other.principal == nil {
71+
logger.Warning("Used an un-initialized ComparablePrincipal")
72+
return false
73+
}
74+
// Compare the MSP ID
75+
if this.mspID != other.mspID {
76+
return false
77+
}
78+
79+
// If the other Principal is a member, then any role or OU role
80+
// fits, because every role or OU role is also a member of the MSP
81+
if other.role != nil && other.role.Role == msp.MSPRole_MEMBER {
82+
return true
83+
}
84+
85+
// Check if we're both OU roles
86+
if this.ou != nil && other.ou != nil {
87+
sameOU := this.ou.OrganizationalUnitIdentifier == other.ou.OrganizationalUnitIdentifier
88+
sameIssuer := bytes.Equal(this.ou.CertifiersIdentifier, other.ou.CertifiersIdentifier)
89+
return sameOU && sameIssuer
90+
}
91+
92+
// Check if we're both the same MSP Role
93+
if this.role != nil && other.role != nil {
94+
return this.role.Role == other.role.Role
95+
}
96+
97+
// Else, we can't say anything, because we have no knowledge
98+
// about the OUs that make up the MSP roles - so return false
99+
return false
100+
}
101+
102+
// ToOURole converts this ComparablePrincipal to OU principal, and returns nil on failure
103+
func (cp *ComparablePrincipal) ToOURole() *ComparablePrincipal {
104+
ouRole := &msp.OrganizationUnit{}
105+
err := proto.Unmarshal(cp.principal.Principal, ouRole)
106+
if err != nil {
107+
logger.Warning("Failed unmarshaling principal:", err)
108+
return nil
109+
}
110+
cp.mspID = ouRole.MspIdentifier
111+
cp.ou = ouRole
112+
return cp
113+
}
114+
115+
// ToRole converts this ComparablePrincipal to MSP Role, and returns nil if the conversion failed
116+
func (cp *ComparablePrincipal) ToRole() *ComparablePrincipal {
117+
mspRole := &msp.MSPRole{}
118+
err := proto.Unmarshal(cp.principal.Principal, mspRole)
119+
if err != nil {
120+
logger.Warning("Failed unmarshaling principal:", err)
121+
return nil
122+
}
123+
cp.mspID = mspRole.MspIdentifier
124+
cp.role = mspRole
125+
return cp
126+
}
127+
128+
// ComparablePrincipalSet aggregates ComparablePrincipals
129+
type ComparablePrincipalSet []*ComparablePrincipal
130+
131+
// NewComparablePrincipalSet constructs a ComparablePrincipalSet out of the given PrincipalSet
132+
func NewComparablePrincipalSet(set policies.PrincipalSet) ComparablePrincipalSet {
133+
var res ComparablePrincipalSet
134+
for _, principal := range set {
135+
cp := NewComparablePrincipal(principal)
136+
if cp == nil {
137+
return nil
138+
}
139+
res = append(res, cp)
140+
}
141+
return res
142+
}
143+
144+
// IsCoveredBy returns whether the ComparablePrincipalSet is covered by the given ComparablePrincipalSet.
145+
// A ComparablePrincipalSet X is covered by another ComparablePrincipalSet Y if:
146+
// for each ComparablePrincipal x in X there is a ComparablePrincipal y in Y,
147+
// such that x.IsA(y) is true.
148+
// This method is useful for determining if the all elements of a ComparablePrincipalSet
149+
// are accepted by another ComparablePrincipalSet.
150+
func (cps ComparablePrincipalSet) IsCoveredBy(set ComparablePrincipalSet) bool {
151+
for _, cp := range cps {
152+
if !cp.IsFound(set...) {
153+
return false
154+
}
155+
}
156+
return true
157+
}
+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package inquire
8+
9+
import (
10+
"testing"
11+
12+
"github.com/hyperledger/fabric/common/policies"
13+
"github.com/hyperledger/fabric/protos/msp"
14+
"github.com/hyperledger/fabric/protos/utils"
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func TestNewComparablePrincipal(t *testing.T) {
19+
mspID := "Org1MSP"
20+
21+
t.Run("Nil input", func(t *testing.T) {
22+
assert.Nil(t, NewComparablePrincipal(nil))
23+
})
24+
25+
t.Run("Invalid principal type", func(t *testing.T) {
26+
assert.Nil(t, NewComparablePrincipal(identity(mspID)))
27+
})
28+
29+
t.Run("Invalid principal input", func(t *testing.T) {
30+
member := member(mspID)
31+
member.Principal = append(member.Principal, 0)
32+
assert.Nil(t, NewComparablePrincipal(member))
33+
34+
ou := ou(mspID)
35+
ou.Principal = append(ou.Principal, 0)
36+
assert.Nil(t, NewComparablePrincipal(ou))
37+
})
38+
39+
t.Run("Role", func(t *testing.T) {
40+
expectedMember := &msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: mspID}
41+
expectedPrincipal := &ComparablePrincipal{
42+
role: expectedMember, mspID: mspID,
43+
principal: &msp.MSPPrincipal{
44+
PrincipalClassification: msp.MSPPrincipal_ROLE,
45+
Principal: utils.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: mspID}),
46+
},
47+
}
48+
assert.Equal(t, expectedPrincipal, NewComparablePrincipal(member(mspID)))
49+
})
50+
51+
t.Run("OU", func(t *testing.T) {
52+
expectedOURole := &msp.OrganizationUnit{OrganizationalUnitIdentifier: "ou", MspIdentifier: mspID}
53+
expectedPrincipal := &ComparablePrincipal{
54+
ou: expectedOURole,
55+
mspID: mspID,
56+
principal: &msp.MSPPrincipal{
57+
PrincipalClassification: msp.MSPPrincipal_ORGANIZATION_UNIT,
58+
Principal: utils.MarshalOrPanic(&msp.OrganizationUnit{OrganizationalUnitIdentifier: "ou", MspIdentifier: mspID}),
59+
},
60+
}
61+
assert.Equal(t, expectedPrincipal, NewComparablePrincipal(ou(mspID)))
62+
})
63+
}
64+
65+
func TestIsA(t *testing.T) {
66+
member1 := NewComparablePrincipal(member("Org1MSP"))
67+
member2 := NewComparablePrincipal(member("Org2MSP"))
68+
peer1 := NewComparablePrincipal(peer("Org1MSP"))
69+
peer2 := NewComparablePrincipal(peer("Org2MSP"))
70+
ou1 := NewComparablePrincipal(ou("Org1MSP"))
71+
ou1ButDifferentIssuer := NewComparablePrincipal(ou("Org1MSP"))
72+
ou1ButDifferentIssuer.ou.CertifiersIdentifier = []byte{1, 2, 3}
73+
ou2 := NewComparablePrincipal(ou("Org2MSP"))
74+
75+
t.Run("Nil input", func(t *testing.T) {
76+
assert.False(t, member1.IsA(nil))
77+
})
78+
79+
t.Run("Incorrect state", func(t *testing.T) {
80+
assert.False(t, (&ComparablePrincipal{}).IsA(member1))
81+
})
82+
83+
t.Run("Same MSP ID", func(t *testing.T) {
84+
assert.True(t, member1.IsA(NewComparablePrincipal(member("Org1MSP"))))
85+
})
86+
87+
t.Run("A peer is also a member", func(t *testing.T) {
88+
assert.True(t, peer1.IsA(member1))
89+
})
90+
91+
t.Run("A member isn't a peer", func(t *testing.T) {
92+
assert.False(t, member1.IsA(peer1))
93+
})
94+
95+
t.Run("Different MSP IDs", func(t *testing.T) {
96+
assert.False(t, member1.IsA(member2))
97+
assert.False(t, peer2.IsA(peer1))
98+
})
99+
100+
t.Run("An OU member is also a member", func(t *testing.T) {
101+
assert.True(t, peer1.IsA(member1))
102+
})
103+
104+
t.Run("A member isn't an OU member", func(t *testing.T) {
105+
assert.False(t, member1.IsA(peer1))
106+
})
107+
108+
t.Run("Same OU", func(t *testing.T) {
109+
assert.True(t, ou1.IsA(NewComparablePrincipal(ou("Org1MSP"))))
110+
})
111+
112+
t.Run("Different OU", func(t *testing.T) {
113+
assert.False(t, ou1.IsA(ou2))
114+
})
115+
116+
t.Run("Same OU, different issuer", func(t *testing.T) {
117+
assert.False(t, ou1.IsA(ou1ButDifferentIssuer))
118+
})
119+
120+
t.Run("OUs and Peers aren't the same", func(t *testing.T) {
121+
assert.False(t, ou1.IsA(peer1))
122+
})
123+
}
124+
125+
func TestIsFound(t *testing.T) {
126+
member1 := NewComparablePrincipal(member("Org1MSP"))
127+
member2 := NewComparablePrincipal(member("Org2MSP"))
128+
peer1 := NewComparablePrincipal(peer("Org1MSP"))
129+
130+
assert.True(t, member1.IsFound(member1, member2))
131+
assert.False(t, member1.IsFound())
132+
assert.False(t, member1.IsFound(member2, peer1))
133+
assert.True(t, peer1.IsFound(member1, member2))
134+
}
135+
136+
func TestNewComparablePrincipalSet(t *testing.T) {
137+
t.Run("Invalid principal", func(t *testing.T) {
138+
principals := []*msp.MSPPrincipal{member("Org1MSP"), identity("Org1MSP")}
139+
assert.Nil(t, NewComparablePrincipalSet(policies.PrincipalSet(principals)))
140+
})
141+
142+
t.Run("Valid Principals", func(t *testing.T) {
143+
member1 := NewComparablePrincipal(member("Org1MSP"))
144+
peer2 := NewComparablePrincipal(peer("Org2MSP"))
145+
principals := []*msp.MSPPrincipal{member("Org1MSP"), peer("Org2MSP")}
146+
cps := NewComparablePrincipalSet(policies.PrincipalSet(principals))
147+
expected := ComparablePrincipalSet([]*ComparablePrincipal{member1, peer2})
148+
assert.Equal(t, expected, cps)
149+
})
150+
}
151+
152+
func TestIsCoveredBy(t *testing.T) {
153+
t.Run("Covered", func(t *testing.T) {
154+
ou1 := NewComparablePrincipal(ou("Org1MSP"))
155+
peer1 := NewComparablePrincipal(peer("Org1MSP"))
156+
member1 := NewComparablePrincipal(member("Org1MSP"))
157+
member2 := NewComparablePrincipal(member("Org2MSP"))
158+
159+
covered := ComparablePrincipalSet([]*ComparablePrincipal{ou1, peer1})
160+
cover := ComparablePrincipalSet([]*ComparablePrincipal{member1, member2})
161+
162+
assert.True(t, covered.IsCoveredBy(cover))
163+
assert.False(t, cover.IsCoveredBy(covered))
164+
})
165+
166+
t.Run("Not Covered", func(t *testing.T) {
167+
peer1 := NewComparablePrincipal(peer("Org1MSP"))
168+
peer2 := NewComparablePrincipal(peer("Org1MSP"))
169+
member1 := NewComparablePrincipal(member("Org1MSP"))
170+
171+
covered := ComparablePrincipalSet([]*ComparablePrincipal{peer1, peer2})
172+
cover := ComparablePrincipalSet([]*ComparablePrincipal{member1})
173+
174+
assert.False(t, cover.IsCoveredBy(covered))
175+
})
176+
}
177+
178+
func member(orgName string) *msp.MSPPrincipal {
179+
return &msp.MSPPrincipal{
180+
PrincipalClassification: msp.MSPPrincipal_ROLE,
181+
Principal: utils.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: orgName})}
182+
}
183+
184+
func peer(orgName string) *msp.MSPPrincipal {
185+
return &msp.MSPPrincipal{
186+
PrincipalClassification: msp.MSPPrincipal_ROLE,
187+
Principal: utils.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_PEER, MspIdentifier: orgName})}
188+
}
189+
190+
func ou(orgName string) *msp.MSPPrincipal {
191+
return &msp.MSPPrincipal{
192+
PrincipalClassification: msp.MSPPrincipal_ORGANIZATION_UNIT,
193+
Principal: utils.MarshalOrPanic(&msp.OrganizationUnit{OrganizationalUnitIdentifier: "ou", MspIdentifier: orgName})}
194+
}
195+
196+
func identity(orgName string) *msp.MSPPrincipal {
197+
return &msp.MSPPrincipal{
198+
PrincipalClassification: msp.MSPPrincipal_IDENTITY,
199+
Principal: utils.MarshalOrPanic(&msp.SerializedIdentity{Mspid: orgName, IdBytes: []byte("identity")}),
200+
}
201+
}

0 commit comments

Comments
 (0)
Please sign in to comment.