66using Umbraco . Cms . Core . Events ;
77using Umbraco . Cms . Core . Notifications ;
88using Umbraco . Cms . Core . Services ;
9+ using Umbraco . Cms . Core . Sync ;
910using Umbraco . Cms . Infrastructure . Security ;
1011
1112namespace Umbraco . Cms . Api . Delivery . Handlers ;
@@ -16,16 +17,21 @@ internal sealed class InitializeMemberApplicationNotificationHandler : INotifica
1617 private readonly ILogger < InitializeMemberApplicationNotificationHandler > _logger ;
1718 private readonly DeliveryApiSettings _deliveryApiSettings ;
1819 private readonly IServiceScopeFactory _serviceScopeFactory ;
20+ private readonly IServerRoleAccessor _serverRoleAccessor ;
21+ private static readonly SemaphoreSlim _locker = new ( 1 ) ;
22+ private static bool _isInitialized = false ;
1923
2024 public InitializeMemberApplicationNotificationHandler (
2125 IRuntimeState runtimeState ,
2226 IOptions < DeliveryApiSettings > deliveryApiSettings ,
2327 ILogger < InitializeMemberApplicationNotificationHandler > logger ,
24- IServiceScopeFactory serviceScopeFactory )
28+ IServiceScopeFactory serviceScopeFactory ,
29+ IServerRoleAccessor serverRoleAccessor )
2530 {
2631 _runtimeState = runtimeState ;
2732 _logger = logger ;
2833 _serviceScopeFactory = serviceScopeFactory ;
34+ _serverRoleAccessor = serverRoleAccessor ;
2935 _deliveryApiSettings = deliveryApiSettings . Value ;
3036 }
3137
@@ -36,34 +42,55 @@ public async Task HandleAsync(UmbracoApplicationStartingNotification notificatio
3642 return ;
3743 }
3844
39- // we cannot inject the IMemberApplicationManager because it ultimately takes a dependency on the DbContext ... and during
40- // install that is not allowed (no connection string means no DbContext)
41- using IServiceScope scope = _serviceScopeFactory . CreateScope ( ) ;
42- IMemberApplicationManager memberApplicationManager = scope . ServiceProvider . GetRequiredService < IMemberApplicationManager > ( ) ;
43-
44- if ( _deliveryApiSettings . MemberAuthorization ? . AuthorizationCodeFlow ? . Enabled is not true )
45+ if ( _serverRoleAccessor . CurrentServerRole is ServerRole . Subscriber )
4546 {
46- await memberApplicationManager . DeleteMemberApplicationAsync ( cancellationToken ) ;
47+ // subscriber instances should not alter the member application
4748 return ;
4849 }
4950
50- if ( ValidateRedirectUrls ( _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LoginRedirectUrls ) is false )
51+ try
5152 {
52- await memberApplicationManager . DeleteMemberApplicationAsync ( cancellationToken ) ;
53- return ;
54- }
53+ await _locker . WaitAsync ( cancellationToken ) ;
54+ if ( _isInitialized )
55+ {
56+ return ;
57+ }
58+
59+ _isInitialized = true ;
60+
61+ // we cannot inject the IMemberApplicationManager because it ultimately takes a dependency on the DbContext ... and during
62+ // install that is not allowed (no connection string means no DbContext)
63+ using IServiceScope scope = _serviceScopeFactory . CreateScope ( ) ;
64+ IMemberApplicationManager memberApplicationManager = scope . ServiceProvider . GetRequiredService < IMemberApplicationManager > ( ) ;
65+
66+ if ( _deliveryApiSettings . MemberAuthorization ? . AuthorizationCodeFlow ? . Enabled is not true )
67+ {
68+ await memberApplicationManager . DeleteMemberApplicationAsync ( cancellationToken ) ;
69+ return ;
70+ }
5571
56- if ( _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LogoutRedirectUrls . Any ( )
57- && ValidateRedirectUrls ( _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LogoutRedirectUrls ) is false )
72+ if ( ValidateRedirectUrls ( _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LoginRedirectUrls ) is false )
73+ {
74+ await memberApplicationManager . DeleteMemberApplicationAsync ( cancellationToken ) ;
75+ return ;
76+ }
77+
78+ if ( _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LogoutRedirectUrls . Any ( )
79+ && ValidateRedirectUrls ( _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LogoutRedirectUrls ) is false )
80+ {
81+ await memberApplicationManager . DeleteMemberApplicationAsync ( cancellationToken ) ;
82+ return ;
83+ }
84+
85+ await memberApplicationManager . EnsureMemberApplicationAsync (
86+ _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LoginRedirectUrls ,
87+ _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LogoutRedirectUrls ,
88+ cancellationToken ) ;
89+ }
90+ finally
5891 {
59- await memberApplicationManager . DeleteMemberApplicationAsync ( cancellationToken ) ;
60- return ;
92+ _locker . Release ( ) ;
6193 }
62-
63- await memberApplicationManager . EnsureMemberApplicationAsync (
64- _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LoginRedirectUrls ,
65- _deliveryApiSettings . MemberAuthorization . AuthorizationCodeFlow . LogoutRedirectUrls ,
66- cancellationToken ) ;
6794 }
6895
6996 private bool ValidateRedirectUrls ( Uri [ ] redirectUrls )
0 commit comments