1+ using Coalesce . Starter . Vue . Data . Models ;
2+ using IntelliTect . Coalesce ;
3+ using Microsoft . AspNetCore . Identity ;
4+
5+ namespace Coalesce . Starter . Vue . Data . Test ;
6+
7+ public class AdminSafetyTests : TestBase
8+ {
9+ [ Fact ]
10+ public async Task Role_CannotRemoveUserAdminPermission_WhenItWouldLeaveNoAdmins ( )
11+ {
12+ // Arrange
13+ var adminRole = new Role
14+ {
15+ Id = "admin-role" ,
16+ Name = "Admin" ,
17+ NormalizedName = "ADMIN" ,
18+ Permissions = new List < Permission > { Permission . UserAdmin , Permission . Admin }
19+ } ;
20+
21+ var user = new User
22+ {
23+ Id = "user1" ,
24+ UserName = "admin@test.com" ,
25+ NormalizedUserName = "ADMIN@TEST.COM" ,
26+ Email = "admin@test.com"
27+ } ;
28+
29+ var userRole = new UserRole { UserId = user . Id , RoleId = adminRole . Id } ;
30+
31+ Db . Roles . Add ( adminRole ) ;
32+ Db . Users . Add ( user ) ;
33+ Db . UserRoles . Add ( userRole ) ;
34+ await Db . SaveChangesAsync ( ) ;
35+
36+ RefreshServices ( ) ;
37+
38+ // Get fresh instances after saving
39+ var roleToUpdate = await Db . Roles . FindAsync ( adminRole . Id ) ;
40+ var behaviors = new Role . Behaviors ( Mocker . Get < RoleManager < Role > > ( ) , Mocker . Get < CrudContext < AppDbContext > > ( ) ) ;
41+
42+ // Act & Assert
43+ roleToUpdate ! . Permissions = new List < Permission > { Permission . Admin } ; // Remove UserAdmin permission
44+ var result = behaviors . BeforeSave ( SaveKind . Update , adminRole , roleToUpdate ) ;
45+
46+ Assert . False ( result . WasSuccessful ) ;
47+ Assert . Contains ( "no user administrators" , result . Message ) ;
48+ }
49+
50+ [ Fact ]
51+ public async Task Role_CanRemoveUserAdminPermission_WhenOtherAdminsExist ( )
52+ {
53+ // Arrange
54+ var adminRole1 = new Role
55+ {
56+ Id = "admin-role-1" ,
57+ Name = "Admin1" ,
58+ NormalizedName = "ADMIN1" ,
59+ Permissions = new List < Permission > { Permission . UserAdmin }
60+ } ;
61+
62+ var adminRole2 = new Role
63+ {
64+ Id = "admin-role-2" ,
65+ Name = "Admin2" ,
66+ NormalizedName = "ADMIN2" ,
67+ Permissions = new List < Permission > { Permission . UserAdmin }
68+ } ;
69+
70+ var user1 = new User
71+ {
72+ Id = "user1" ,
73+ UserName = "admin1@test.com" ,
74+ NormalizedUserName = "ADMIN1@TEST.COM"
75+ } ;
76+
77+ var user2 = new User
78+ {
79+ Id = "user2" ,
80+ UserName = "admin2@test.com" ,
81+ NormalizedUserName = "ADMIN2@TEST.COM"
82+ } ;
83+
84+ var userRole1 = new UserRole { UserId = user1 . Id , RoleId = adminRole1 . Id } ;
85+ var userRole2 = new UserRole { UserId = user2 . Id , RoleId = adminRole2 . Id } ;
86+
87+ Db . Roles . AddRange ( adminRole1 , adminRole2 ) ;
88+ Db . Users . AddRange ( user1 , user2 ) ;
89+ Db . UserRoles . AddRange ( userRole1 , userRole2 ) ;
90+ await Db . SaveChangesAsync ( ) ;
91+
92+ RefreshServices ( ) ;
93+
94+ var roleToUpdate = await Db . Roles . FindAsync ( adminRole1 . Id ) ;
95+ var behaviors = new Role . Behaviors ( Mocker . Get < RoleManager < Role > > ( ) , Mocker . Get < CrudContext < AppDbContext > > ( ) ) ;
96+
97+ // Act
98+ roleToUpdate ! . Permissions = new List < Permission > { Permission . Admin } ; // Remove UserAdmin permission
99+ var result = behaviors . BeforeSave ( SaveKind . Update , adminRole1 , roleToUpdate ) ;
100+
101+ // Assert
102+ Assert . True ( result . WasSuccessful ) ;
103+ }
104+
105+ [ Fact ]
106+ public async Task Role_CannotDeleteRole_WhenItWouldLeaveNoAdmins ( )
107+ {
108+ // Arrange
109+ var adminRole = new Role
110+ {
111+ Id = "admin-role" ,
112+ Name = "Admin" ,
113+ NormalizedName = "ADMIN" ,
114+ Permissions = new List < Permission > { Permission . UserAdmin }
115+ } ;
116+
117+ var user = new User
118+ {
119+ Id = "user1" ,
120+ UserName = "admin@test.com" ,
121+ NormalizedUserName = "ADMIN@TEST.COM"
122+ } ;
123+
124+ var userRole = new UserRole { UserId = user . Id , RoleId = adminRole . Id } ;
125+
126+ Db . Roles . Add ( adminRole ) ;
127+ Db . Users . Add ( user ) ;
128+ Db . UserRoles . Add ( userRole ) ;
129+ await Db . SaveChangesAsync ( ) ;
130+
131+ RefreshServices ( ) ;
132+
133+ var roleToDelete = await Db . Roles . FindAsync ( adminRole . Id ) ;
134+ var behaviors = new Role . Behaviors ( Mocker . Get < RoleManager < Role > > ( ) , Mocker . Get < CrudContext < AppDbContext > > ( ) ) ;
135+
136+ // Act & Assert
137+ var result = behaviors . BeforeDelete ( roleToDelete ! ) ;
138+
139+ Assert . False ( result . WasSuccessful ) ;
140+ Assert . Contains ( "no user administrators" , result . Message ) ;
141+ }
142+
143+ [ Fact ]
144+ public async Task Role_CanDeleteRole_WhenOtherAdminsExist ( )
145+ {
146+ // Arrange
147+ var adminRole1 = new Role
148+ {
149+ Id = "admin-role-1" ,
150+ Name = "Admin1" ,
151+ NormalizedName = "ADMIN1" ,
152+ Permissions = new List < Permission > { Permission . UserAdmin }
153+ } ;
154+
155+ var adminRole2 = new Role
156+ {
157+ Id = "admin-role-2" ,
158+ Name = "Admin2" ,
159+ NormalizedName = "ADMIN2" ,
160+ Permissions = new List < Permission > { Permission . UserAdmin }
161+ } ;
162+
163+ var user1 = new User
164+ {
165+ Id = "user1" ,
166+ UserName = "admin1@test.com" ,
167+ NormalizedUserName = "ADMIN1@TEST.COM"
168+ } ;
169+
170+ var user2 = new User
171+ {
172+ Id = "user2" ,
173+ UserName = "admin2@test.com" ,
174+ NormalizedUserName = "ADMIN2@TEST.COM"
175+ } ;
176+
177+ var userRole1 = new UserRole { UserId = user1 . Id , RoleId = adminRole1 . Id } ;
178+ var userRole2 = new UserRole { UserId = user2 . Id , RoleId = adminRole2 . Id } ;
179+
180+ Db . Roles . AddRange ( adminRole1 , adminRole2 ) ;
181+ Db . Users . AddRange ( user1 , user2 ) ;
182+ Db . UserRoles . AddRange ( userRole1 , userRole2 ) ;
183+ await Db . SaveChangesAsync ( ) ;
184+
185+ RefreshServices ( ) ;
186+
187+ var roleToDelete = await Db . Roles . FindAsync ( adminRole1 . Id ) ;
188+ var behaviors = new Role . Behaviors ( Mocker . Get < RoleManager < Role > > ( ) , Mocker . Get < CrudContext < AppDbContext > > ( ) ) ;
189+
190+ // Act
191+ var result = behaviors . BeforeDelete ( roleToDelete ! ) ;
192+
193+ // Assert
194+ Assert . True ( result . WasSuccessful ) ;
195+ }
196+
197+ [ Fact ]
198+ public async Task UserRole_CannotDeleteUserRole_WhenItWouldLeaveNoAdmins ( )
199+ {
200+ // Arrange
201+ var adminRole = new Role
202+ {
203+ Id = "admin-role" ,
204+ Name = "Admin" ,
205+ NormalizedName = "ADMIN" ,
206+ Permissions = new List < Permission > { Permission . UserAdmin }
207+ } ;
208+
209+ var user = new User
210+ {
211+ Id = "user1" ,
212+ UserName = "admin@test.com" ,
213+ NormalizedUserName = "ADMIN@TEST.COM"
214+ } ;
215+
216+ var userRole = new UserRole { UserId = user . Id , RoleId = adminRole . Id , Role = adminRole , User = user } ;
217+
218+ Db . Roles . Add ( adminRole ) ;
219+ Db . Users . Add ( user ) ;
220+ Db . UserRoles . Add ( userRole ) ;
221+ await Db . SaveChangesAsync ( ) ;
222+
223+ RefreshServices ( ) ;
224+
225+ var userRoleToDelete = await Db . UserRoles
226+ . Include ( ur => ur . Role )
227+ . FirstAsync ( ur => ur . UserId == user . Id && ur . RoleId == adminRole . Id ) ;
228+ var behaviors = new UserRole . Behaviors ( Mocker . Get < CrudContext < AppDbContext > > ( ) , Mocker . Get < SignInManager < User > > ( ) ) ;
229+
230+ // Act & Assert
231+ var result = behaviors . BeforeDelete ( userRoleToDelete ) ;
232+
233+ Assert . False ( result . WasSuccessful ) ;
234+ Assert . Contains ( "no user administrators" , result . Message ) ;
235+ }
236+
237+ [ Fact ]
238+ public async Task UserRole_CanDeleteUserRole_WhenOtherAdminsExist ( )
239+ {
240+ // Arrange
241+ var adminRole = new Role
242+ {
243+ Id = "admin-role" ,
244+ Name = "Admin" ,
245+ NormalizedName = "ADMIN" ,
246+ Permissions = new List < Permission > { Permission . UserAdmin }
247+ } ;
248+
249+ var user1 = new User
250+ {
251+ Id = "user1" ,
252+ UserName = "admin1@test.com" ,
253+ NormalizedUserName = "ADMIN1@TEST.COM"
254+ } ;
255+
256+ var user2 = new User
257+ {
258+ Id = "user2" ,
259+ UserName = "admin2@test.com" ,
260+ NormalizedUserName = "ADMIN2@TEST.COM"
261+ } ;
262+
263+ var userRole1 = new UserRole { UserId = user1 . Id , RoleId = adminRole . Id , Role = adminRole , User = user1 } ;
264+ var userRole2 = new UserRole { UserId = user2 . Id , RoleId = adminRole . Id , Role = adminRole , User = user2 } ;
265+
266+ Db . Roles . Add ( adminRole ) ;
267+ Db . Users . AddRange ( user1 , user2 ) ;
268+ Db . UserRoles . AddRange ( userRole1 , userRole2 ) ;
269+ await Db . SaveChangesAsync ( ) ;
270+
271+ RefreshServices ( ) ;
272+
273+ var userRoleToDelete = await Db . UserRoles
274+ . Include ( ur => ur . Role )
275+ . FirstAsync ( ur => ur . UserId == user1 . Id && ur . RoleId == adminRole . Id ) ;
276+ var behaviors = new UserRole . Behaviors ( Mocker . Get < CrudContext < AppDbContext > > ( ) , Mocker . Get < SignInManager < User > > ( ) ) ;
277+
278+ // Act
279+ var result = behaviors . BeforeDelete ( userRoleToDelete ) ;
280+
281+ // Assert
282+ Assert . True ( result . WasSuccessful ) ;
283+ }
284+
285+ #if Tenancy
286+ [ Fact ]
287+ public async Task Role_CanRemoveUserAdminPermission_WhenGlobalAdminExists ( )
288+ {
289+ // Arrange
290+ var adminRole = new Role
291+ {
292+ Id = "admin-role" ,
293+ Name = "Admin" ,
294+ NormalizedName = "ADMIN" ,
295+ Permissions = new List < Permission > { Permission . UserAdmin }
296+ } ;
297+
298+ var regularUser = new User
299+ {
300+ Id = "user1" ,
301+ UserName = "admin@test.com" ,
302+ NormalizedUserName = "ADMIN@TEST.COM"
303+ } ;
304+
305+ var globalAdmin = new User
306+ {
307+ Id = "user2" ,
308+ UserName = "global@test.com" ,
309+ NormalizedUserName = "GLOBAL@TEST.COM" ,
310+ IsGlobalAdmin = true
311+ } ;
312+
313+ var userRole = new UserRole { UserId = regularUser . Id , RoleId = adminRole . Id } ;
314+
315+ Db . Roles . Add ( adminRole ) ;
316+ Db . Users . AddRange ( regularUser , globalAdmin ) ;
317+ Db . UserRoles . Add ( userRole ) ;
318+ await Db . SaveChangesAsync ( ) ;
319+
320+ RefreshServices ( ) ;
321+
322+ var roleToUpdate = await Db . Roles . FindAsync ( adminRole . Id ) ;
323+ var behaviors = new Role . Behaviors ( Mocker . Get < RoleManager < Role > > ( ) , Mocker . Get < CrudContext < AppDbContext > > ( ) ) ;
324+
325+ // Act
326+ roleToUpdate ! . Permissions = new List < Permission > { Permission . Admin } ; // Remove UserAdmin permission
327+ var result = behaviors . BeforeSave ( SaveKind . Update , adminRole , roleToUpdate ) ;
328+
329+ // Assert
330+ Assert . True ( result . WasSuccessful ) ;
331+ }
332+
333+ [ Fact ]
334+ public async Task UserRole_CanDeleteUserRole_WhenGlobalAdminExists ( )
335+ {
336+ // Arrange
337+ var adminRole = new Role
338+ {
339+ Id = "admin-role" ,
340+ Name = "Admin" ,
341+ NormalizedName = "ADMIN" ,
342+ Permissions = new List < Permission > { Permission . UserAdmin }
343+ } ;
344+
345+ var regularUser = new User
346+ {
347+ Id = "user1" ,
348+ UserName = "admin@test.com" ,
349+ NormalizedUserName = "ADMIN@TEST.COM"
350+ } ;
351+
352+ var globalAdmin = new User
353+ {
354+ Id = "user2" ,
355+ UserName = "global@test.com" ,
356+ NormalizedUserName = "GLOBAL@TEST.COM" ,
357+ IsGlobalAdmin = true
358+ } ;
359+
360+ var userRole = new UserRole { UserId = regularUser . Id , RoleId = adminRole . Id , Role = adminRole , User = regularUser } ;
361+
362+ Db . Roles . Add ( adminRole ) ;
363+ Db . Users . AddRange ( regularUser , globalAdmin ) ;
364+ Db . UserRoles . Add ( userRole ) ;
365+ await Db . SaveChangesAsync ( ) ;
366+
367+ RefreshServices ( ) ;
368+
369+ var userRoleToDelete = await Db . UserRoles
370+ . Include ( ur => ur . Role )
371+ . FirstAsync ( ur => ur . UserId == regularUser . Id && ur . RoleId == adminRole . Id ) ;
372+ var behaviors = new UserRole . Behaviors ( Mocker . Get < CrudContext < AppDbContext > > ( ) , Mocker . Get < SignInManager < User > > ( ) ) ;
373+
374+ // Act
375+ var result = behaviors . BeforeDelete ( userRoleToDelete ) ;
376+
377+ // Assert
378+ Assert . True ( result . WasSuccessful ) ;
379+ }
380+ #endif
381+ }
0 commit comments