409 lines
14 KiB
Go
409 lines
14 KiB
Go
/*
|
|
Copyright IBM Corp. 2017 All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package policydsl
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/hyperledger/fabric-protos-go/common"
|
|
"github.com/hyperledger/fabric-protos-go/msp"
|
|
"github.com/hyperledger/fabric/protoutil"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestOutOf1(t *testing.T) {
|
|
p1, err := FromString("OutOf(1, 'A.member', 'B.member')")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "A"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "B"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: NOutOf(1, []*common.SignaturePolicy{SignedBy(0), SignedBy(1)}),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.Equal(t, p1, p2)
|
|
}
|
|
|
|
func TestOutOf2(t *testing.T) {
|
|
p1, err := FromString("OutOf(2, 'A.member', 'B.member')")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "A"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "B"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: NOutOf(2, []*common.SignaturePolicy{SignedBy(0), SignedBy(1)}),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.Equal(t, p1, p2)
|
|
}
|
|
|
|
func TestAnd(t *testing.T) {
|
|
p1, err := FromString("AND('A.member', 'B.member')")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "A"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "B"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: And(SignedBy(0), SignedBy(1)),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.Equal(t, p1, p2)
|
|
}
|
|
|
|
func TestAndClientPeerOrderer(t *testing.T) {
|
|
p1, err := FromString("AND('A.client', 'B.peer')")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_CLIENT, MspIdentifier: "A"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_PEER, MspIdentifier: "B"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: And(SignedBy(0), SignedBy(1)),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.True(t, reflect.DeepEqual(p1, p2))
|
|
}
|
|
|
|
func TestOr(t *testing.T) {
|
|
p1, err := FromString("OR('A.member', 'B.member')")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "A"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "B"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: Or(SignedBy(0), SignedBy(1)),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.Equal(t, p1, p2)
|
|
}
|
|
|
|
func TestComplex1(t *testing.T) {
|
|
p1, err := FromString("OR('A.member', AND('B.member', 'C.member'))")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "B"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "C"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "A"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: Or(SignedBy(2), And(SignedBy(0), SignedBy(1))),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.Equal(t, p1, p2)
|
|
}
|
|
|
|
func TestComplex2(t *testing.T) {
|
|
p1, err := FromString("OR(AND('A.member', 'B.member'), OR('C.admin', 'D.member'))")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "A"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "B"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_ADMIN, MspIdentifier: "C"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "D"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: Or(And(SignedBy(0), SignedBy(1)), Or(SignedBy(2), SignedBy(3))),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.Equal(t, p1, p2)
|
|
}
|
|
|
|
func TestMSPIDWIthSpecialChars(t *testing.T) {
|
|
p1, err := FromString("OR('MSP.member', 'MSP.WITH.DOTS.member', 'MSP-WITH-DASHES.member')")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "MSP"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "MSP.WITH.DOTS"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "MSP-WITH-DASHES"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: NOutOf(1, []*common.SignaturePolicy{SignedBy(0), SignedBy(1), SignedBy(2)}),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.Equal(t, p1, p2)
|
|
}
|
|
|
|
func TestBadStringsNoPanic(t *testing.T) {
|
|
_, err := FromString("OR('A.member', Bmember)") // error after 1st Evaluate()
|
|
require.EqualError(t, err, "unrecognized token 'Bmember' in policy string")
|
|
|
|
_, err = FromString("OR('A.member', 'Bmember')") // error after 2nd Evalute()
|
|
require.EqualError(t, err, "unrecognized token 'Bmember' in policy string")
|
|
|
|
_, err = FromString(`OR('A.member', '\'Bmember\'')`) // error after 3rd Evalute()
|
|
require.EqualError(t, err, "unrecognized token 'Bmember' in policy string")
|
|
}
|
|
|
|
func TestNodeOUs(t *testing.T) {
|
|
p1, err := FromString("OR('A.peer', 'B.admin', 'C.orderer', 'D.client')")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_PEER, MspIdentifier: "A"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_ADMIN, MspIdentifier: "B"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_ORDERER, MspIdentifier: "C"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_CLIENT, MspIdentifier: "D"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: NOutOf(1, []*common.SignaturePolicy{SignedBy(0), SignedBy(1), SignedBy(2), SignedBy(3)}),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.Equal(t, p1, p2)
|
|
}
|
|
|
|
func TestOutOfNumIsString(t *testing.T) {
|
|
p1, err := FromString("OutOf('1', 'A.member', 'B.member')")
|
|
require.NoError(t, err)
|
|
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "A"}),
|
|
})
|
|
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "B"}),
|
|
})
|
|
|
|
p2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: NOutOf(1, []*common.SignaturePolicy{SignedBy(0), SignedBy(1)}),
|
|
Identities: principals,
|
|
}
|
|
|
|
require.Equal(t, p1, p2)
|
|
}
|
|
|
|
func TestOutOfErrorCase(t *testing.T) {
|
|
p1, err1 := FromString("") // 1st NewEvaluableExpressionWithFunctions() returns an error
|
|
require.Nil(t, p1)
|
|
require.EqualError(t, err1, "Unexpected end of expression")
|
|
|
|
p2, err2 := FromString("OutOf(1)") // outof() if len(args)<2
|
|
require.Nil(t, p2)
|
|
require.EqualError(t, err2, "expected at least two arguments to NOutOf. Given 1")
|
|
|
|
p3, err3 := FromString("OutOf(true, 'A.member')") // outof() }else{. 1st arg is non of float, int, string
|
|
require.Nil(t, p3)
|
|
require.EqualError(t, err3, "unexpected type bool")
|
|
|
|
p4, err4 := FromString("OutOf(1, 2)") // oufof() switch default. 2nd arg is not string.
|
|
require.Nil(t, p4)
|
|
require.EqualError(t, err4, "unexpected type float64")
|
|
|
|
p5, err5 := FromString("OutOf(1, 'true')") // firstPass() switch default
|
|
require.Nil(t, p5)
|
|
require.EqualError(t, err5, "unexpected type bool")
|
|
|
|
p6, err6 := FromString(`OutOf('\'\\\'A\\\'\'', 'B.member')`) // secondPass() switch args[1].(type) default
|
|
require.Nil(t, p6)
|
|
require.EqualError(t, err6, "unrecognized type, expected a number, got string")
|
|
|
|
p7, err7 := FromString(`OutOf(1, '\'1\'')`) // secondPass() switch args[1].(type) default
|
|
require.Nil(t, p7)
|
|
require.EqualError(t, err7, "unrecognized type, expected a principal or a policy, got float64")
|
|
|
|
p8, err8 := FromString(`''`) // 2nd NewEvaluateExpressionWithFunction() returns an error
|
|
require.Nil(t, p8)
|
|
require.EqualError(t, err8, "Unexpected end of expression")
|
|
|
|
p9, err9 := FromString(`'\'\''`) // 3rd NewEvaluateExpressionWithFunction() returns an error
|
|
require.Nil(t, p9)
|
|
require.EqualError(t, err9, "Unexpected end of expression")
|
|
}
|
|
|
|
func TestBadStringBeforeFAB11404_ThisCanDeleteAfterFAB11404HasMerged(t *testing.T) {
|
|
s1 := "1" // ineger in string
|
|
p1, err1 := FromString(s1)
|
|
require.Nil(t, p1)
|
|
require.EqualError(t, err1, `invalid policy string '1'`)
|
|
|
|
s2 := "'1'" // quoted ineger in string
|
|
p2, err2 := FromString(s2)
|
|
require.Nil(t, p2)
|
|
require.EqualError(t, err2, `invalid policy string ''1''`)
|
|
|
|
s3 := `'\'1\''` // nested quoted ineger in string
|
|
p3, err3 := FromString(s3)
|
|
require.Nil(t, p3)
|
|
require.EqualError(t, err3, `invalid policy string ''\'1\'''`)
|
|
}
|
|
|
|
func TestSecondPassBoundaryCheck(t *testing.T) {
|
|
// Check lower boundary
|
|
// Prohibit t<0
|
|
p0, err0 := FromString("OutOf(-1, 'A.member', 'B.member')")
|
|
require.Nil(t, p0)
|
|
require.EqualError(t, err0, "invalid t-out-of-n predicate, t -1, n 2")
|
|
|
|
// Permit t==0 : always satisfied policy
|
|
// There is no clear usecase of t=0, but somebody may already use it, so we don't treat as an error.
|
|
p1, err1 := FromString("OutOf(0, 'A.member', 'B.member')")
|
|
require.NoError(t, err1)
|
|
principals := make([]*msp.MSPPrincipal, 0)
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "A"}),
|
|
})
|
|
principals = append(principals, &msp.MSPPrincipal{
|
|
PrincipalClassification: msp.MSPPrincipal_ROLE,
|
|
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{Role: msp.MSPRole_MEMBER, MspIdentifier: "B"}),
|
|
})
|
|
expected1 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: NOutOf(0, []*common.SignaturePolicy{SignedBy(0), SignedBy(1)}),
|
|
Identities: principals,
|
|
}
|
|
require.Equal(t, expected1, p1)
|
|
|
|
// Check upper boundary
|
|
// Permit t==n+1 : never satisfied policy
|
|
// Usecase: To create immutable ledger key
|
|
p2, err2 := FromString("OutOf(3, 'A.member', 'B.member')")
|
|
require.NoError(t, err2)
|
|
expected2 := &common.SignaturePolicyEnvelope{
|
|
Version: 0,
|
|
Rule: NOutOf(3, []*common.SignaturePolicy{SignedBy(0), SignedBy(1)}),
|
|
Identities: principals,
|
|
}
|
|
require.Equal(t, expected2, p2)
|
|
|
|
// Prohibit t>n + 1
|
|
p3, err3 := FromString("OutOf(4, 'A.member', 'B.member')")
|
|
require.Nil(t, p3)
|
|
require.EqualError(t, err3, "invalid t-out-of-n predicate, t 4, n 2")
|
|
}
|