@@ -3,6 +3,7 @@ package grant_test
33import (
44 "context"
55 "errors"
6+ "fmt"
67 "testing"
78 "time"
89
@@ -23,6 +24,8 @@ type ServiceTestSuite struct {
2324 mockRepository * mocks.Repository
2425 mockProviderService * mocks.ProviderService
2526 mockResourceService * mocks.ResourceService
27+ mockAuditLogger * mocks.AuditLogger
28+ mockNotifier * mocks.Notifier
2629 service * grant.Service
2730}
2831
@@ -34,12 +37,16 @@ func (s *ServiceTestSuite) setup() {
3437 s .mockRepository = new (mocks.Repository )
3538 s .mockProviderService = new (mocks.ProviderService )
3639 s .mockResourceService = new (mocks.ResourceService )
40+ s .mockAuditLogger = new (mocks.AuditLogger )
41+ s .mockNotifier = new (mocks.Notifier )
3742 s .service = grant .NewService (grant.ServiceDeps {
3843 Repository : s .mockRepository ,
3944 Logger : log .NewNoop (),
4045 Validator : validator .New (),
4146 ProviderService : s .mockProviderService ,
4247 ResourceService : s .mockResourceService ,
48+ Notifier : s .mockNotifier ,
49+ AuditLogger : s .mockAuditLogger ,
4350 })
4451}
4552
@@ -122,6 +129,190 @@ func (s *ServiceTestSuite) TestGetByID() {
122129 })
123130}
124131
132+ func (s * ServiceTestSuite ) TestRevoke () {
133+ id := uuid .New ().String ()
134+ 135+ reason := "test reason"
136+ expectedGrantDetails := & domain.Grant {
137+ ID : id ,
138+ AccountID : "test-account-id" ,
139+ AccountType : "user" ,
140+ Resource : & domain.Resource {
141+ ID : "test-resource-id" ,
142+ },
143+ }
144+
145+ s .Run ("should revoke grant on success" , func () {
146+ s .setup ()
147+
148+ s .mockRepository .EXPECT ().
149+ GetByID (mock .AnythingOfType ("*context.emptyCtx" ), id ).
150+ Return (expectedGrantDetails , nil ).Once ()
151+ s .mockRepository .EXPECT ().
152+ Update (mock .AnythingOfType ("*context.emptyCtx" ), mock .AnythingOfType ("*domain.Grant" )).
153+ Run (func (_a0 context.Context , _a1 * domain.Grant ) {
154+ s .Equal (id , _a1 .ID )
155+ s .Equal (actor , _a1 .RevokedBy )
156+ s .Equal (reason , _a1 .RevokeReason )
157+ s .NotNil (_a1 .RevokedAt )
158+ }).
159+ Return (nil ).Once ()
160+ s .mockProviderService .EXPECT ().
161+ RevokeAccess (mock .AnythingOfType ("*context.emptyCtx" ), mock .AnythingOfType ("domain.Grant" )).
162+ Run (func (_a0 context.Context , _a1 domain.Grant ) {
163+ s .Equal (id , _a1 .ID )
164+ s .Equal (expectedGrantDetails .AccountID , _a1 .AccountID )
165+ s .Equal (expectedGrantDetails .AccountType , _a1 .AccountType )
166+ s .Equal (expectedGrantDetails .Resource .ID , _a1 .Resource .ID )
167+ }).
168+ Return (nil ).Once ()
169+
170+ s .mockNotifier .EXPECT ().
171+ Notify ([]domain.Notification {{
172+ User : expectedGrantDetails .CreatedBy ,
173+ Message : domain.NotificationMessage {
174+ Type : domain .NotificationTypeAccessRevoked ,
175+ Variables : map [string ]interface {}{
176+ "resource_name" : fmt .Sprintf ("%s (%s: %s)" , expectedGrantDetails .Resource .Name , expectedGrantDetails .Resource .ProviderType , expectedGrantDetails .Resource .URN ),
177+ "role" : expectedGrantDetails .Role ,
178+ "account_type" : expectedGrantDetails .AccountType ,
179+ "account_id" : expectedGrantDetails .AccountID ,
180+ "requestor" : expectedGrantDetails .Owner ,
181+ },
182+ },
183+ }}).
184+ Return (nil ).Once ()
185+ s .mockAuditLogger .EXPECT ().
186+ Log (mock .AnythingOfType ("*context.emptyCtx" ), grant .AuditKeyRevoke , map [string ]interface {}{
187+ "grant_id" : id ,
188+ "reason" : reason ,
189+ }).
190+ Return (nil ).Once ()
191+
192+ expectedGrant , err := s .service .Revoke (context .Background (), id , actor , reason )
193+
194+ s .NoError (err )
195+ s .Equal (id , expectedGrant .ID )
196+ s .Equal (actor , expectedGrant .RevokedBy )
197+ s .Equal (reason , expectedGrant .RevokeReason )
198+ s .NotNil (expectedGrant .RevokedAt )
199+ s .Less (* expectedGrant .RevokedAt , time .Now ())
200+ s .mockRepository .AssertExpectations (s .T ())
201+ })
202+
203+ s .Run ("should skip revoke in provider and notifications as configured" , func () {
204+ s .setup ()
205+
206+ s .mockRepository .EXPECT ().
207+ GetByID (mock .AnythingOfType ("*context.emptyCtx" ), id ).
208+ Return (expectedGrantDetails , nil ).Once ()
209+ s .mockRepository .EXPECT ().
210+ Update (mock .AnythingOfType ("*context.emptyCtx" ), mock .AnythingOfType ("*domain.Grant" )).
211+ Run (func (_a0 context.Context , _a1 * domain.Grant ) {
212+ s .Equal (id , _a1 .ID )
213+ s .Equal (actor , _a1 .RevokedBy )
214+ s .Equal (reason , _a1 .RevokeReason )
215+ s .NotNil (_a1 .RevokedAt )
216+ }).
217+ Return (nil ).Once ()
218+
219+ s .mockAuditLogger .EXPECT ().
220+ Log (mock .AnythingOfType ("*context.emptyCtx" ), grant .AuditKeyRevoke , map [string ]interface {}{
221+ "grant_id" : id ,
222+ "reason" : reason ,
223+ }).
224+ Return (nil ).Once ()
225+
226+ expectedGrant , err := s .service .Revoke (context .Background (), id , actor , reason , grant .SkipRevokeAccessInProvider (), grant .SkipNotifications ())
227+
228+ s .NoError (err )
229+ s .Equal (id , expectedGrant .ID )
230+ s .Equal (actor , expectedGrant .RevokedBy )
231+ s .Equal (reason , expectedGrant .RevokeReason )
232+ s .NotNil (expectedGrant .RevokedAt )
233+ s .Less (* expectedGrant .RevokedAt , time .Now ())
234+ s .mockRepository .AssertExpectations (s .T ())
235+ })
236+ }
237+
238+ func (s * ServiceTestSuite ) TestBulkRevoke () {
239+ 240+ reason := "test reason"
241+ filter := domain.RevokeGrantsFilter {
242+ AccountIDs : []string {"test-account-id" },
243+ }
244+ expectedGrants := []domain.Grant {
245+ {
246+ ID : "id1" ,
247+ AccountID : "test-account-id" ,
248+ AccountType : "user" ,
249+ Resource : & domain.Resource {
250+ ID : "test-resource-id" ,
251+ },
252+ },
253+ {
254+ ID : "id2" ,
255+ AccountID : "test-account-id" ,
256+ AccountType : "user" ,
257+ Resource : & domain.Resource {
258+ ID : "test-resource-id" ,
259+ },
260+ },
261+ }
262+
263+ s .Run ("should return revoked grants on success" , func () {
264+ s .setup ()
265+
266+ expectedListGrantsFilter := domain.ListGrantsFilter {
267+ Statuses : []string {string (domain .GrantStatusActive )},
268+ AccountIDs : filter .AccountIDs ,
269+ ProviderTypes : filter .ProviderTypes ,
270+ ProviderURNs : filter .ProviderURNs ,
271+ ResourceTypes : filter .ResourceTypes ,
272+ ResourceURNs : filter .ResourceURNs ,
273+ }
274+
275+ s .mockRepository .EXPECT ().
276+ List (mock .AnythingOfType ("*context.emptyCtx" ), expectedListGrantsFilter ).
277+ Return (expectedGrants , nil ).Once ()
278+ for _ , g := range expectedGrants {
279+ grant := g
280+ s .mockProviderService .EXPECT ().
281+ RevokeAccess (mock .AnythingOfType ("*context.emptyCtx" ), mock .AnythingOfType ("domain.Grant" )).
282+ Run (func (_a0 context.Context , _a1 domain.Grant ) {
283+ s .Equal (grant .ID , _a1 .ID )
284+ s .Equal (grant .AccountID , _a1 .AccountID )
285+ s .Equal (grant .AccountType , _a1 .AccountType )
286+ s .Equal (grant .Resource .ID , _a1 .Resource .ID )
287+ }).
288+ Return (nil ).Once ()
289+
290+ s .mockRepository .EXPECT ().
291+ Update (mock .AnythingOfType ("*context.emptyCtx" ), mock .AnythingOfType ("*domain.Grant" )).
292+ Run (func (_a0 context.Context , _a1 * domain.Grant ) {
293+ s .Equal (grant .ID , _a1 .ID )
294+ s .Equal (actor , _a1 .RevokedBy )
295+ s .Equal (reason , _a1 .RevokeReason )
296+ s .NotNil (_a1 .RevokedAt )
297+ }).
298+ Return (nil ).Once ()
299+ }
300+
301+ revokedGrants , actualError := s .service .BulkRevoke (context .Background (), filter , actor , reason )
302+
303+ s .NoError (actualError )
304+ for i , g := range revokedGrants {
305+ revokedGrant := g
306+ expectedGrant := expectedGrants [i ]
307+ s .Equal (expectedGrant .ID , revokedGrant .ID )
308+ s .Equal (actor , revokedGrant .RevokedBy )
309+ s .Equal (reason , revokedGrant .RevokeReason )
310+ s .NotNil (revokedGrant .RevokedAt )
311+ s .Less (* revokedGrant .RevokedAt , time .Now ())
312+ }
313+ })
314+ }
315+
125316func (s * ServiceTestSuite ) TestPrepare () {
126317 s .Run ("should return error if appeal is invalid" , func () {
127318 testCases := []struct {
@@ -339,7 +530,7 @@ func (s *ServiceTestSuite) TestImportFromProvider() {
339530 {
340531 AccountID : "test-account-id-2" ,
341532 AccountType : "serviceAccount" ,
342- Permission : "test-permission" ,
533+ Permission : "test-permission-2 " ,
343534 },
344535 },
345536 },
@@ -362,8 +553,8 @@ func (s *ServiceTestSuite) TestImportFromProvider() {
362553 ResourceID : "test-resource-id" ,
363554 AccountID : "test-account-id-2" ,
364555 AccountType : "serviceAccount" ,
365- Role : "test-role-id " ,
366- Permissions : []string {"test-permission" },
556+ Role : "test-permission-2 " ,
557+ Permissions : []string {"test-permission-2 " },
367558 IsPermanent : true ,
368559 Status : domain .GrantStatusActive ,
369560 StatusInProvider : domain .GrantStatusActive ,
0 commit comments