- 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.
12 Answer(s)
-
0
What I have noticed:
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.SplitQueryingEnumerable
1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)\r\n at Oracle.EntityFrameworkCore.Storage.Internal.OracleExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func
4 operation, Func4 verifySucceeded, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable
1.AsyncEnumerator.MoveNextAsync()\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable
1 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.CastleAsyncAbpInterceptorAdapter
1.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](IDistributedCache
1 cache, IEnumerable1 keys, Func
2 entityFactory, Func3 cacheItemsFactory, String cacheKeyPrefix)\r\n at Volo.Abp.IdentityServer.ResourceStore.FindIdentityResourcesByScopeNameAsync(IEnumerable
1 scopeNames)\r\n at IdentityServer4.Stores.IResourceStoreExtensions.FindResourcesByScopeAsync(IResourceStore store, IEnumerable1 scopeNames)\r\n at IdentityServer4.Stores.IResourceStoreExtensions.FindEnabledResourcesByScopeAsync(IResourceStore store, IEnumerable
1 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, Func
4 operation, Func4 verifySucceeded, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable
1.AsyncEnumerator.MoveNextAsync()\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken)\r\n at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable
1 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.CastleAsyncAbpInterceptorAdapter
1.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](IDistributedCache
1 cache, IEnumerable1 keys, Func
2 entityFactory, Func3 cacheItemsFactory, String cacheKeyPrefix)\r\n at Volo.Abp.IdentityServer.ResourceStore.FindIdentityResourcesByScopeNameAsync(IEnumerable
1 scopeNames)\r\n at IdentityServer4.Stores.IResourceStoreExtensions.FindResourcesByScopeAsync(IResourceStore store, IEnumerable1 scopeNames)\r\n at IdentityServer4.Stores.IResourceStoreExtensions.FindEnabledResourcesByScopeAsync(IResourceStore store, IEnumerable
1 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. -
0
-
0
Hi. I've used the Guard you provided and put breakpoint in
canActivate
method. So when I click "Logout" - I'm being redirected... by the moment the breakpoint is fired, thehasValidAccessToken
is true and I'm landed to Home page (instead of Login page of Identity Server). If it is the problem of server-side - like the revocation is not done correctly or some token is not cleared or something else - I ask you to help me sort this out. I've put the fragment of the log from Identity Server above if it could come in handy. Unfortunately, I cannot send the project (it's commercial) or reproduce this on some test project (it would take a while trying to create such project). What I can do is to follow your instructions as for what to check and where. -
0
When i have logged out my hasAccesToken is becomes false. Please make sure your in oauthService logout function works properly.
Unfortunately If i can't produce it locally i cant help you.
-
0
I understand. I suspect it could be a back-end issue with Identity Server, so that token revocation is not successful. Could you please tell me how to troubleshoot this? I may send our Identity Server log for the period of logging out, so maybe you would notice the root cause. Here are one (sometimes two) requests which triggers after I click the "Logout" button: Afterwards I'm getting API requests from my component which are not supposed to be run, because I'm logging out - so they produce error 401. And eventually I'm landed to Home page without logging out.
-
0
UPDATE: please have a look at what's going on during logout at Identity Server, probably would ring some bell to you: https://drive.google.com/open?id=12SCQSi6Je4G9cCTwPoxwf4CzFujMz0Rn&usp=drive_fs
To me it looks like concurrent calls to
Task<IdentityUser> FindAsync
(which is eventually cancelled as seen from the attached log) from:using AbxEps.CentralTools.AbxUsers; using AbxEps.CentralTools.Extensions; using AbxEps.CentralTools.Jobs; using AbxEps.CentralTools.Sessions; using AbxEps.CentralTools.Tenants; using IdentityServer4.Models; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using System; using System.Collections.Generic; using System.Security.Claims; using System.Security.Principal; using System.Threading.Tasks; using Volo.Abp.Identity; using Volo.Abp.IdentityServer.AspNetIdentity; using Volo.Abp.MultiTenancy; using Volo.Abp.PermissionManagement; using IdentityUser = Volo.Abp.Identity.IdentityUser; namespace AbxEps.CentralTools.IdentityServer.Profile { public class AbxProfileService : AbpProfileService { private readonly ITenantRepository _abxTenantRepository; private readonly IAbxUserRepository _abxUserRepository; private readonly ISessionRepository _abxSessionRepository; private readonly IJobRepository _abxJobRepository; private readonly IHttpContextAccessor _httpContextAccessor; public AbxProfileService ( IdentityUserManager userManager, IAbxUserRepository abxUserRepository, IUserClaimsPrincipalFactory<IdentityUser> claimsFactory, ICurrentTenant currentTenant, ITenantRepository abxTenantRepository, IHttpContextAccessor httpContextAccessor, ISessionRepository abxSessionRepository, IJobRepository abxJobRepository ) :base(userManager, claimsFactory, currentTenant) { _abxTenantRepository = abxTenantRepository; _abxUserRepository = abxUserRepository; _httpContextAccessor = httpContextAccessor; _abxSessionRepository = abxSessionRepository; _abxJobRepository = abxJobRepository; } public override async Task GetProfileDataAsync(ProfileDataRequestContext context) { using (CurrentTenant.Change(context.Subject.FindTenantId())) //is invoked a couple of times and probably is invoking Task<IdentityUser> FindAsync too below { await base.GetProfileDataAsync(context); ... } } public override async Task IsActiveAsync(IsActiveContext context) { using (CurrentTenant.Change(context.Subject.FindTenantId())) //is invoked a couple of times and invoking Task<IdentityUser> FindAsync below { var abpUser = await UserManager.GetUserAsync(context.Subject); var abxUser = abpUser == null ? null : await _abxUserRepository.GetAsync(abpUser.Id); await base.IsActiveAsync(context); ... } } } }
and the middleware:
private async Task OnSessionEndRequestAsync(HttpContext httpContext, IdentityUserManager userManager) { try { var user = await userManager.GetUserAsync(httpContext.User); // Cancellation exception! ... } catch(Exception ex) { _logger.LogError(ex, "Session End handling error"); } }
during logout...
-
0
Not resolved. Reopening.
-
0
hi @alexander.nikonov, we still cannot produce your case.
could you please tell us the steps of producing the problem in a new project. we would like to help you if we can.
-
0
Hi. The project is a customized version of ABP project. I don't think it would be possible to do what you offer. Neither I can share the source code - by sending it or demonstrating the screen. Could you please at least make some guesses what could go wrong looking at the attached logs and my comments? Thanks.
-
0
OK, please share all the logs. let's try to check it.
-
0
The log has been already attached (Google Drive link above).
-
0
Hi,
I have checked the log file.
But it's hard to find something, you seem to have customized a lot of services.
I can only give some suggestions.
Try comment some code to narrow down the problem, for example:
private async Task OnSessionEndRequestAsync(HttpContext httpContext, IdentityUserManager userManager) { try { // comment //var user = await userManager.GetUserAsync(httpContext.User); // Cancellation exception! ... } catch(Exception ex) { _logger.LogError(ex, "Session End handling error"); } }