Activities of "alexander.nikonov"

What I have noticed:

if I remove [AuthGuard]:

then logging out from any page brings me to site Login dialog. Which looks like if the user IS logged out:

If I click "Login" - I am brought to Identity Server Login page (note: I am not automatically logged in!)

However, using AuthGuard for a default route ('') causes this behavior I've described in the very beginning. Though, I don't want to go to the first login form, so this "workaround" does not suit me.

I also took a look at Identity Server log (this is the fragment of what is happening after pressing "Logout") and the following looks weird to me: why the authorize request is sent straight after successful token revocation? The configuration of Identity Server looks usual to me, we have not changed it, but probably some configuration aspects are missing?

2023-09-18 01:10:05.334 -05:00 [DBG] Refresh token revoked 2023-09-18 01:10:06.116 -05:00 [INF] Token revocation complete 2023-09-18 01:10:06.116 -05:00 [INF] {"ClientId":"XXX","ClientName":"XXX","TokenType":"refresh_token","Token":"****6492","Category":"Token","Name":"Token Revoked Success","EventType":"Success","Id":2010,"Message":null,"ActivityId":"800001b8-0004-f900-b63f-84710c7967bb","TimeStamp":"2023-09-18T06:10:06.0000000Z","ProcessId":24860,"LocalIpAddress":"::1:44357","RemoteIpAddress":"::1","$type":"TokenRevokedSuccessEvent"} 2023-09-18 01:10:06.707 -05:00 [INF] Request finished HTTP/1.1 POST https://localhost:44357/connect/revocation application/x-www-form-urlencoded 149 - 200 - - 5005.9323ms 2023-09-18 01:10:06.808 -05:00 [INF] Request starting HTTP/1.1 GET https://localhost:44357/connect/authorize?response_type=code&client_id=XXX&state=YYY&redirect_uri=https%3A%2F%2Flocalhost%3A4200&scope=ZZZ&code_challenge=MMM&code_challenge_method=S256&nonce=NNN&culture=en&ui-culture=en - - 2023-09-18 01:10:06.840 -05:00 [DBG] Request path /connect/authorize matched to endpoint type Authorize 2023-09-18 01:10:06.859 -05:00 [DBG] Endpoint enabled: Authorize, successfully created handler: IdentityServer4.Endpoints.AuthorizeEndpoint 2023-09-18 01:10:06.859 -05:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize 2023-09-18 01:10:06.862 -05:00 [DBG] Start authorize request

There is a lot of information here - cut - but finally there is also the error (which does not prevent user logging in):

2023-09-18 01:10:06.926 -05:00 [DBG] client configuration validation for client XXX succeeded. 2023-09-18 01:10:06.926 -05:00 [DBG] Checking for PKCE parameters 2023-09-18 01:10:07.021 -05:00 [INF] {"Details":"System.Threading.Tasks.TaskCanceledException: A task was canceled.\r\n at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)\r\n at Oracle.EntityFrameworkCore.Storage.Internal.OracleRelationalCommandBuilderFactory.OracleRelationalCommandBuilder.OracleRelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)\r\n at Oracle.EntityFrameworkCore.Storage.Internal.OracleExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable1.AsyncEnumerator.MoveNextAsync()\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)\r\n at Volo.Abp.IdentityServer.IdentityResources.IdentityResourceRepository.GetListByScopeNameAsync(String[] scopeNames, Boolean includeDetails, CancellationToken cancellationToken)\r\n at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync()\r\n at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed)\r\n at Volo.Abp.IdentityServer.ResourceStore.<FindIdentityResourcesByScopeNameAsync>b__34_0(String[] keys)\r\n at Volo.Abp.IdentityServer.ResourceStore.GetCacheItemsAsync[TEntity,TModel](IDistributedCache1 cache, IEnumerable1 keys, Func2 entityFactory, Func3 cacheItemsFactory, String cacheKeyPrefix)\r\n at Volo.Abp.IdentityServer.ResourceStore.FindIdentityResourcesByScopeNameAsync(IEnumerable1 scopeNames)\r\n at IdentityServer4.Stores.IResourceStoreExtensions.FindResourcesByScopeAsync(IResourceStore store, IEnumerable1 scopeNames)\r\n at IdentityServer4.Stores.IResourceStoreExtensions.FindEnabledResourcesByScopeAsync(IResourceStore store, IEnumerable1 scopeNames)\r\n at IdentityServer4.Validation.DefaultResourceValidator.ValidateRequestedResourcesAsync(ResourceValidationRequest request)\r\n at IdentityServer4.Validation.AuthorizeRequestValidator.ValidateScopeAsync(ValidatedAuthorizeRequest request)\r\n at IdentityServer4.Validation.AuthorizeRequestValidator.ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject)\r\n at IdentityServer4.Endpoints.AuthorizeEndpointBase.ProcessAuthorizeRequestAsync(NameValueCollection parameters, ClaimsPrincipal user, ConsentResponse consent)\r\n at IdentityServer4.Endpoints.AuthorizeEndpoint.ProcessAsync(HttpContext context)\r\n at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events, IBackChannelLogoutService backChannelLogoutService)","Category":"Error","Name":"Unhandled Exception","EventType":"Error","Id":3000,"Message":"A task was canceled.","ActivityId":"800000d9-0007-ff00-b63f-84710c7967bb","TimeStamp":"2023-09-18T06:10:07.0000000Z","ProcessId":24860,"LocalIpAddress":"::1:44357","RemoteIpAddress":"::1","$type":"UnhandledExceptionEvent"} 2023-09-18 01:10:07.021 -05:00 [INF] {"Details":"System.Threading.Tasks.TaskCanceledException: A task was canceled.\r\n at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)\r\n at Oracle.EntityFrameworkCore.Storage.Internal.OracleRelationalCommandBuilderFactory.OracleRelationalCommandBuilder.OracleRelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)\r\n at Oracle.EntityFrameworkCore.Storage.Internal.OracleExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable1.AsyncEnumerator.MoveNextAsync()\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)\r\n at Volo.Abp.IdentityServer.IdentityResources.IdentityResourceRepository.GetListByScopeNameAsync(String[] scopeNames, Boolean includeDetails, CancellationToken cancellationToken)\r\n at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync()\r\n at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)\r\n at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed)\r\n at Volo.Abp.IdentityServer.ResourceStore.<FindIdentityResourcesByScopeNameAsync>b__34_0(String[] keys)\r\n at Volo.Abp.IdentityServer.ResourceStore.GetCacheItemsAsync[TEntity,TModel](IDistributedCache1 cache, IEnumerable1 keys, Func2 entityFactory, Func3 cacheItemsFactory, String cacheKeyPrefix)\r\n at Volo.Abp.IdentityServer.ResourceStore.FindIdentityResourcesByScopeNameAsync(IEnumerable1 scopeNames)\r\n at IdentityServer4.Stores.IResourceStoreExtensions.FindResourcesByScopeAsync(IResourceStore store, IEnumerable1 scopeNames)\r\n at IdentityServer4.Stores.IResourceStoreExtensions.FindEnabledResourcesByScopeAsync(IResourceStore store, IEnumerable1 scopeNames)\r\n at IdentityServer4.Validation.DefaultResourceValidator.ValidateRequestedResourcesAsync(ResourceValidationRequest request)\r\n at IdentityServer4.Validation.AuthorizeRequestValidator.ValidateScopeAsync(ValidatedAuthorizeRequest request)\r\n at IdentityServer4.Validation.AuthorizeRequestValidator.ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject)\r\n at IdentityServer4.Endpoints.AuthorizeEndpointBase.ProcessAuthorizeRequestAsync(NameValueCollection parameters, ClaimsPrincipal user, ConsentResponse consent)\r\n at IdentityServer4.Endpoints.AuthorizeEndpoint.ProcessAsync(HttpContext context)\r\n at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events, IBackChannelLogoutService backChannelLogoutService)","Category":"Error","Name":"Unhandled Exception","EventType":"Error","Id":3000,"Message":"A task was canceled.","ActivityId":"800001e1-0004-f500-b63f-84710c7967bb","TimeStamp":"2023-09-18T06:10:07.0000000Z","ProcessId":24860,"LocalIpAddress":"::1:44357","RemoteIpAddress":"::1","$type":"UnhandledExceptionEvent"} 2023-09-18 01:10:07.021 -05:00 [FTL] Unhandled exception: A task was canceled.

  • ABP Framework version: v7.0.1
  • UI Type: Angular
  • Database System: EF Core (Oracle)
  • Auth Server Separated

I have custom Permission Definition Provider:

    using AbxEps.CT.Core.Extensions;
    using AbxEps.CT.Core.Localization;
    using AbxEps.CT.Core.PortalMenu;
    using Microsoft.Extensions.DependencyInjection;
    using System;
    using System.Threading.Tasks;
    using Volo.Abp.Authorization.Permissions;
    using Volo.Abp.Localization;
    using Volo.Abp.Threading;
    using Volo.Abp.Users;

    namespace AbxEps.CT.Core.Permissions
    {
        public class CorePermissionDefinitionProvider : PermissionDefinitionProvider
        {
            private readonly ICurrentUser _currentUser;
            private readonly IAbxPortalsMenuAppService _abxPortalsMenuAppService;
    
            public CorePermissionDefinitionProvider
            (
                IAbxPortalsMenuAppService abxPortalsMenuAppService,
                ICurrentUser currentUser
             )
            {
                _abxPortalsMenuAppService = abxPortalsMenuAppService;
                _currentUser = currentUser;
            }
    
            public override void Define(IPermissionDefinitionContext context)
            {
                var coreCtGroup = context.AddGroup(CorePermissions.GroupName, L("Permission:Core"));
                var fileMngPermission = coreCtGroup.AddPermission(CorePermissions.FileManager.Read, L("Permission:FileManager:Read"));
                fileMngPermission.AddChild(CorePermissions.FileManager.Modify, L("Permission:FileManager:Modify"));
                if (_currentUser.IsAuthenticated)
                {
                    AsyncHelper.RunSync(() => InitPortalAccessPermissionsAsync(context)); // Not called, because when the host is started the user is still not authenticated - so "if" condition is not invoked
                }
            }
    
            private async Task InitPortalAccessPermissionsAsync(IPermissionDefinitionContext context)
            {
                ...
            }
        }
    }
        

Whereas the permissions which are supposed to be added unconditionally (fileMngPermissions) are added successfully when host is running, the permissions which need to be added only after the user is authenticated (portalAccessPermissions) are obviously not added and not visible via IPermissionAppService:

    var allPermissionsForRole = await _permissionAppService.GetAsync("R", "Role 1");
    

How to add a whole CorePermissionDefinitionProvider or the part of its relevant permissions (portalAccessPermissions) conditionally - once the user got authenticated?

P.S. I'd prefer not to use Middleware, because its Invoke method is invoked on each request. Instead, I need to add my CorePermissionDefinitionProvider or its authentication-related permissions once after the user authentication was successful. I use external authentication via Identity Server. So this functionality needs to reside inside the application project, not Identity Server project.

Making PermissionDefinitionManager a ITransientDependency (or probably I can make CorePermissionDefinitionProvider transient too) does not sound good either: I dot not want to trigger the check each time. I just need to trigger it ONCE, but after the user has been authenticated.

I do not have ngOnInit override from component's base class. So I put the breakpoint in the base class ngOnInit method. And this method is only invoked when the user is authenticated.

  • ABP Framework version: v7.0.1.
  • UI Type: Angular
  • Database System: EF Core
  • Auth Server Separated

Hi. I can't say for sure in which moment it has begun, but now if I try to logout from the page OTHER than Home page (root page) - the logout does not happen. Here is the workflow of what is happening when I'm clicking "Logout" button in my Angular app: First connect/revocation request contains "access_token". Next "connect/revocation" request contains "refresh_token. Eventually I am just redirected to Home page. Also the whole process is very slow and not attractive visually: at first the navigation and top menu gets disappears, so I see only the current page instead of being instantly redirected to Identity Server Login box (where I do not get at all in my case). I don't know where to look at: is it a problem of front-end or back-end. Please point me in right direction.

Additionaly details: we DO have "AuthGuard" in app-routing.module.ts for each page we are trying to logout from.

Marked in red is yet another issue which is still not resolved: the subscribed API calls in the current Component: seems like at some point the user IS getting logged out (and thus is not authorized), so these requests are not allowed (but later the user is kind of logged-in again automatically).

Sorry I cannot share the source code with you. So I will be glad to follow your recommendations in troubleshooting the logout scenario.

They have it in the App Routing module: The component routing module does not have it: UPDATE: to save your time a bit, I've duplicated "canActive" in my Component's routing module. But the problem did not go away.

currently app.component.ts is the bootstraped component https://angular.io/guide/bootstrapping so if you place any api call in there it will be called so you have to use conditional operator there to calling api when the state is not authenticated.

Sorry, but i didn't get it. I have a lot of different components like the one below - with a bunch of API calls triggered based on different conditions - button clicks, subscriptions, route parameter values, etc.:

    @Component({ ... })
    export class ComponentHHH extends BaseComponent {
    
        //Condition method can be invoked based on various conditions in unknown moment of time
        ConditionMethodAAA() {
            ....
            this.apiServiceXXX.apiMethodYYY(...).pipe(takeUntil(this.unsubscriber$))
                .subscribe((response) => { ... });
            ....
            this.apiServiceZZZ.apiMethodAAA(...).pipe(takeUntil(this.unsubscriber$))
                .subscribe((response) => { ... });
            ....
        }

        ConditionMethodBBB() {
            ....
            this.apiServiceDDD.apiMethodSSS(...).pipe(takeUntil(this.unsubscriber$))
                .subscribe((response) => { ... });
            ....
        }
    }

If I activate another component in the menu - this.unsubscriber$ (property in "BaseComponent" class) receives null and completes. Due to this and to using "takeUntil", no matter which API calls were active, they all will be removed. I've tried to subcribe to "logout" event in "BaseComponent" and do the same I do with this.unsubscriber$ in "ngOnDestroy". However this does not work - API calls keep being invoked. Even more now: logout works only from Home page (probably these two things are unrelated, but I am not sure). I have not found explanation to this.

So you suggest to summon "app.component.ts" to resolve the problem. But I cannot figure out, how it can help here: there is no connection between AppComponent and another components API calls.

Hi Anjali.

First of all, ngOnDestroy with the suggested code already present in the base class HomeComponent is inherited from. Nevertheless, I've added ngOnDestroy here for test, too.

Also I've replace this.oAuthService.events with your suggestion.

After pressing "Logout" button I'm getting "Logout event received" message. But API call is STILL invoked as always. There has to be explanation WHY it is called though.

P.S. Please hold on - I want to check something...

UPDATE: I made some experiments. Good news: In the given specific case the API call I mentioned before was also invoked by other service - this was the reason it "resurrected" all the time after logout; Bad news: In a common case, only using if (this.authService.isAuthenticated) check or similar like you suggested helps resolving the initial problem. However, it is not a good approach: we have hundreds of API calls from hundreds of components. It is not a way to go to add hundreds of "if". Instead, it is supposed that for both component destroying and user logout action unsubscriber$ needs to received proper null value and be completed:

this.apiService
  .apiCall(...)
  .pipe(
    finalize(() => (...)),
    takeUntil(this.unsubscriber$) //this has to be enough for all cases
  )
  .subscribe((...) => {
      ...
  });

The problem is that for some reason using logout event does not help to resolve this issue. I use this in Component base class (no matter, "tap" or "subscribe" actually) and this block DOES get triggered, however eventually API is still invoked for unknown for me reason:

  ngOnInit(): void {
    this.oAuthService.events
      .pipe
      (
        filter(event => event?.type === 'logout'),
        takeUntil(this.unsubscriber$),
        tap(() => {
          this.unsubscriber$.next(null);
          this.unsubscriber$.complete();
        })
      )
      .subscribe();
      

I've tried to make unsubscriber$ as ReplaySubject and create its new with buffer == 1, but it does not change the things.

I am confused even more now: it appeared that logging out works only for Home page: if I take any page - even the ABP page - after clicking "logout" button the user is eventually redirected to Home page again without landing at Identity Server Login page: and then - all the rest our services required for the page are loaded as usual... And this is workflow when I click "Logout" on Home page: Afterwards I'm redirected to Identity Server Login page as expected. All the relevant pages have canActivate: [AuthGuard] It's absolutely strange given that "Logout" functionality is the same for all pages, i.e. the same code has to be invoked. Do you have any clues? If required, I will create a new ticket for this issue...

I had additional experiment. Please have a look:

I've modified ngOnInit a bit:

this.oAuthService.events
  .pipe(
    filter(event => event?.type === 'logout'),
    tap(() => {
      this.unsubscriber$.next(null);
      this.unsubscriber$.complete();
      console.log('unsubscriber null!');
    }))
    .subscribe();

if (this.authService.isAuthenticated) {
  this.homeService.getNewsForHomePage()
    .pipe(tap(() => console.log('getNewsForHomePage still invoked')), takeUntil(this.unsubscriber$))
    .subscribe((newsResponse) => {
      this.newsForHomePage = newsResponse.items;
    });
  this.homeService.getUrlsForHomePage()
    .pipe(tap(() => console.log('getUrlsForHomePage still invoked')), takeUntil(this.unsubscriber$))
    .subscribe((newsUrlParameterResponse) => {
      this.urls = newsUrlParameterResponse.items;
      this.urlDigimedia = this.urls.filter(i => i.columnValue === 'DM')[0]?.stringValue;
      this.urlMasterData = this.urls.filter(i => i.columnValue === 'MD')[0]?.stringValue;
    });
}

I got 'unsubscriber null' message instantly after clicking "Logout" button. Despite this, shortly after, the method was still being invoked (getUrlsForHomePage matches '/api/ct/central-tool/parameters/values' API route). I cannot explain what's going on: The messages "getNewsForHomePage still invoked" and "getUrlsForHomePage still invoked" were never shown - obviosly because this.authService.isAuthenticated was false by the moment.

I thought it could have something to do with using guards. But even if I remove guard for Home page, the given API call is still invoked.

Hi

Now after logout i guess your api will also not get called, can you check please?

The API is still called though - after I click Logout, but before actual logging out is complete.

Hi,

you can directly redirect to login page by attaching you root page or home component a authguard.

Great! Thank you so much - this part is now resolved.

Showing 91 to 100 of 318 entries
Made with ❤️ on ABP v9.0.0-preview Updated on September 20, 2024, 08:30