@@ -4,164 +4,133 @@ Copyright IBM Corp. All Rights Reserved.
4
4
SPDX-License-Identifier: Apache-2.0
5
5
*/
6
6
7
- package deliver
7
+ package deliver_test
8
8
9
9
import (
10
- "testing"
11
10
"time"
12
11
13
- "github.com/hyperledger/fabric/protos/common"
12
+ "github.com/hyperledger/fabric/common/deliver"
13
+ "github.com/hyperledger/fabric/common/deliver/mock"
14
+ cb "github.com/hyperledger/fabric/protos/common"
14
15
"github.com/hyperledger/fabric/protos/utils"
16
+ . "github.com/onsi/ginkgo"
17
+ . "github.com/onsi/gomega"
15
18
"github.com/pkg/errors"
16
- "github.com/stretchr/testify/assert"
17
- "github.com/stretchr/testify/mock"
18
19
)
19
20
20
- type mockACSupport struct {
21
- mock.Mock
22
- }
21
+ var _ = Describe ("SessionAccessControl" , func () {
22
+ var (
23
+ fakeChain * mock.Chain
24
+ envelope * cb.Envelope
25
+ fakePolicyChecker * mock.PolicyChecker
26
+ expiresAt deliver.ExpiresAtFunc
27
+ )
28
+
29
+ BeforeEach (func () {
30
+ envelope = & cb.Envelope {
31
+ Payload : utils .MarshalOrPanic (& cb.Payload {
32
+ Header : & cb.Header {},
33
+ }),
34
+ }
35
+
36
+ fakeChain = & mock.Chain {}
37
+ fakePolicyChecker = & mock.PolicyChecker {}
38
+ expiresAt = func ([]byte ) time.Time { return time.Time {} }
39
+ })
23
40
24
- func ( s * mockACSupport ) ExpiresAt ( identityBytes [] byte ) time. Time {
25
- return s . Called (). Get ( 0 ).(time. Time )
26
- }
41
+ It ( "evaluates the policy" , func () {
42
+ sac , err := deliver . NewSessionAC ( fakeChain , envelope , fakePolicyChecker , "chain-id" , expiresAt )
43
+ Expect ( err ). NotTo ( HaveOccurred ())
27
44
28
- func (s * mockACSupport ) Sequence () uint64 {
29
- return s .Called ().Get (0 ).(uint64 )
30
- }
45
+ err = sac .Evaluate ()
46
+ Expect (err ).NotTo (HaveOccurred ())
31
47
32
- func createEnvelope () * common.Envelope {
33
- chHdr := utils .MakeChannelHeader (common .HeaderType_DELIVER_SEEK_INFO , 0 , "mychannel" , 0 )
34
- siHdr := utils .MakeSignatureHeader (nil , nil )
35
- paylBytes := utils .MarshalOrPanic (& common.Payload {
36
- Header : utils .MakePayloadHeader (chHdr , siHdr ),
48
+ Expect (fakePolicyChecker .CheckPolicyCallCount ()).To (Equal (1 ))
49
+ env , cid := fakePolicyChecker .CheckPolicyArgsForCall (0 )
50
+ Expect (env ).To (Equal (envelope ))
51
+ Expect (cid ).To (Equal ("chain-id" ))
37
52
})
38
53
39
- return & common.Envelope {Payload : paylBytes }
40
- }
54
+ Context ("when policy evaluation returns an error" , func () {
55
+ BeforeEach (func () {
56
+ fakePolicyChecker .CheckPolicyReturns (errors .New ("no-access-for-you" ))
57
+ })
58
+
59
+ It ("returns the evaluation error" , func () {
60
+ sac , err := deliver .NewSessionAC (fakeChain , envelope , fakePolicyChecker , "chain-id" , expiresAt )
61
+ Expect (err ).NotTo (HaveOccurred ())
41
62
42
- type oneTimeInvoke struct {
43
- f func (* common.Envelope , string ) error
44
- invoked bool
45
- }
63
+ err = sac .Evaluate ()
64
+ Expect (err ).To (MatchError ("no-access-for-you" ))
65
+ })
66
+ })
67
+
68
+ It ("caches positive policy evaluation" , func () {
69
+ sac , err := deliver .NewSessionAC (fakeChain , envelope , fakePolicyChecker , "chain-id" , expiresAt )
70
+ Expect (err ).NotTo (HaveOccurred ())
46
71
47
- func (oti * oneTimeInvoke ) invokeOnce () func (* common.Envelope , string ) error {
48
- return func (env * common.Envelope , s string ) error {
49
- if oti .invoked {
50
- panic ("already invoked!" )
72
+ for i := 0 ; i < 5 ; i ++ {
73
+ err = sac .Evaluate ()
74
+ Expect (err ).NotTo (HaveOccurred ())
51
75
}
52
- oti .invoked = true
53
- return oti .f (env , s )
54
- }
55
- }
56
-
57
- func oneTimeFunction (f func (* common.Envelope , string ) error ) func (* common.Envelope , string ) error {
58
- oti := & oneTimeInvoke {f : f }
59
- return oti .invokeOnce ()
60
- }
61
-
62
- func TestOneTimeFunction (t * testing.T ) {
63
- acceptPolicyChecker := func (envelope * common.Envelope , channelID string ) error {
64
- return nil
65
- }
66
- f := oneTimeFunction (acceptPolicyChecker )
67
- // First time no panic
68
- assert .NotPanics (t , func () {
69
- f (nil , "" )
76
+ Expect (fakePolicyChecker .CheckPolicyCallCount ()).To (Equal (1 ))
70
77
})
71
78
72
- // Second time we panic
73
- assert .Panics (t , func () {
74
- f (nil , "" )
79
+ Context ("when the config sequence changes" , func () {
80
+ BeforeEach (func () {
81
+ fakePolicyChecker .CheckPolicyReturnsOnCall (2 , errors .New ("access-now-denied" ))
82
+ })
83
+
84
+ It ("re-evaluates the policy" , func () {
85
+ sac , err := deliver .NewSessionAC (fakeChain , envelope , fakePolicyChecker , "chain-id" , expiresAt )
86
+ Expect (err ).NotTo (HaveOccurred ())
87
+
88
+ Expect (sac .Evaluate ()).To (Succeed ())
89
+ Expect (fakePolicyChecker .CheckPolicyCallCount ()).To (Equal (1 ))
90
+ Expect (sac .Evaluate ()).To (Succeed ())
91
+ Expect (fakePolicyChecker .CheckPolicyCallCount ()).To (Equal (1 ))
92
+
93
+ fakeChain .SequenceReturns (2 )
94
+ Expect (sac .Evaluate ()).To (Succeed ())
95
+ Expect (fakePolicyChecker .CheckPolicyCallCount ()).To (Equal (2 ))
96
+ Expect (sac .Evaluate ()).To (Succeed ())
97
+ Expect (fakePolicyChecker .CheckPolicyCallCount ()).To (Equal (2 ))
98
+
99
+ fakeChain .SequenceReturns (3 )
100
+ Expect (sac .Evaluate ()).To (MatchError ("access-now-denied" ))
101
+ Expect (fakePolicyChecker .CheckPolicyCallCount ()).To (Equal (3 ))
102
+ })
75
103
})
76
- }
77
-
78
- func TestAC (t * testing.T ) {
79
- acceptPolicyChecker := func (envelope * common.Envelope , channelID string ) error {
80
- return nil
81
- }
82
-
83
- denyPolicyChecker := func (envelope * common.Envelope , channelID string ) error {
84
- return errors .New ("forbidden" )
85
- }
86
-
87
- sup := & mockACSupport {}
88
- // Scenario I: create empty header
89
- ac , err := newSessionAC (sup , & common.Envelope {}, nil , "mychannel" , sup .ExpiresAt )
90
- assert .Nil (t , ac )
91
- assert .Contains (t , err .Error (), "Missing Header" )
92
-
93
- // Scenario II: Identity has expired.
94
- sup = & mockACSupport {}
95
- sup .On ("ExpiresAt" ).Return (time .Now ().Add (- 1 * time .Second )).Once ()
96
- ac , err = newSessionAC (sup , createEnvelope (), oneTimeFunction (acceptPolicyChecker ), "mychannel" , sup .ExpiresAt )
97
- assert .NotNil (t , ac )
98
- assert .NoError (t , err )
99
- err = ac .evaluate ()
100
- assert .Contains (t , err .Error (), "expired" )
101
-
102
- // Scenario III: Identity hasn't expired, but is forbidden
103
- sup = & mockACSupport {}
104
- sup .On ("ExpiresAt" ).Return (time .Now ().Add (time .Second )).Once ()
105
- sup .On ("Sequence" ).Return (uint64 (0 )).Once ()
106
- ac , err = newSessionAC (sup , createEnvelope (), oneTimeFunction (denyPolicyChecker ), "mychannel" , sup .ExpiresAt )
107
- assert .NoError (t , err )
108
- err = ac .evaluate ()
109
- assert .Contains (t , err .Error (), "forbidden" )
110
-
111
- // Scenario IV: Identity hasn't expired, and is allowed
112
- // We actually check 2 sub-cases, the first one is if the identity can expire,
113
- // and the second one is if the identity can't expire (i.e an idemix identity currently can't expire)
114
- for _ , expirationTime := range []time.Time {time .Now ().Add (time .Second ), {}} {
115
- sup = & mockACSupport {}
116
- sup .On ("ExpiresAt" ).Return (expirationTime ).Once ()
117
- sup .On ("Sequence" ).Return (uint64 (0 )).Once ()
118
- ac , err = newSessionAC (sup , createEnvelope (), oneTimeFunction (acceptPolicyChecker ), "mychannel" , sup .ExpiresAt )
119
- assert .NoError (t , err )
120
- err = ac .evaluate ()
121
- assert .NoError (t , err )
122
- // Execute again. We should not evaluate the policy again.
123
- // If we do, the test fails with panic because the function can be invoked only once
124
- sup .On ("Sequence" ).Return (uint64 (0 )).Once ()
125
- err = ac .evaluate ()
126
- assert .NoError (t , err )
127
- }
128
-
129
- // Scenario V: Identity hasn't expired, and is allowed at first, but afterwards there
130
- // is a config change and afterwards it isn't allowed
131
- sup = & mockACSupport {}
132
- sup .On ("ExpiresAt" ).Return (time .Now ().Add (time .Second )).Once ()
133
- sup .On ("Sequence" ).Return (uint64 (0 )).Once ()
134
- sup .On ("Sequence" ).Return (uint64 (1 )).Once ()
135
-
136
- firstInvoke := true
137
- policyChecker := func (envelope * common.Envelope , channelID string ) error {
138
- if firstInvoke {
139
- firstInvoke = false
140
- return nil
141
- }
142
- return errors .New ("forbidden" )
143
- }
144
-
145
- ac , err = newSessionAC (sup , createEnvelope (), policyChecker , "mychannel" , sup .ExpiresAt )
146
- assert .NoError (t , err )
147
- err = ac .evaluate () // first time
148
- assert .NoError (t , err )
149
- err = ac .evaluate () // second time
150
- assert .Contains (t , err .Error (), "forbidden" )
151
-
152
- // Scenario VI: Identity hasn't expired at first, but expires at a later time,
153
- // and then it shouldn't be allowed to be serviced
154
- sup = & mockACSupport {}
155
- sup .On ("ExpiresAt" ).Return (time .Now ().Add (time .Millisecond * 500 )).Once ()
156
- sup .On ("Sequence" ).Return (uint64 (0 )).Times (3 )
157
- ac , err = newSessionAC (sup , createEnvelope (), oneTimeFunction (acceptPolicyChecker ), "mychannel" , sup .ExpiresAt )
158
- assert .NoError (t , err )
159
- err = ac .evaluate ()
160
- assert .NoError (t , err )
161
- err = ac .evaluate ()
162
- assert .NoError (t , err )
163
- time .Sleep (time .Second )
164
- err = ac .evaluate ()
165
- assert .Error (t , err )
166
- assert .Contains (t , err .Error (), "expired" )
167
- }
104
+
105
+ Context ("when an identity expires" , func () {
106
+ BeforeEach (func () {
107
+ expiresAt = func ([]byte ) time.Time {
108
+ return time .Now ().Add (250 * time .Millisecond )
109
+ }
110
+ })
111
+
112
+ It ("returns an identity expired error" , func () {
113
+ sac , err := deliver .NewSessionAC (fakeChain , envelope , fakePolicyChecker , "chain-id" , expiresAt )
114
+ Expect (err ).NotTo (HaveOccurred ())
115
+
116
+ err = sac .Evaluate ()
117
+ Expect (err ).NotTo (HaveOccurred ())
118
+
119
+ Eventually (sac .Evaluate ).Should (MatchError (ContainSubstring ("client identity expired" )))
120
+ })
121
+ })
122
+
123
+ Context ("when the envelope cannot be represented as signed data" , func () {
124
+ BeforeEach (func () {
125
+ envelope = & cb.Envelope {}
126
+ })
127
+
128
+ It ("returns an error" , func () {
129
+ _ , expectedError := envelope .AsSignedData ()
130
+ Expect (expectedError ).To (HaveOccurred ())
131
+
132
+ _ , err := deliver .NewSessionAC (fakeChain , envelope , fakePolicyChecker , "chain-id" , expiresAt )
133
+ Expect (err ).To (Equal (expectedError ))
134
+ })
135
+ })
136
+ })
0 commit comments