This error is expected and normal, its failing correctly when attempting to add a new User with some dodgy data.
However its resulting in a big 403 Unhandled Exception, with a full stack trace dumped to the console, and a big "Unhandled Exception" error message to the user for what is basically a validation error.
With the Identity Module the User form as well as the API call and all surrounding work is handled by the ABP libraries, and I can't find any documentation on how to shim in our own exception handling so that we can swallow these kinds of errors and present a nicer and more useful error message to the user.
Is there any way to provide some nicer error messages to the end user from an ABP module that is completely standalone?
This one is only happening occasionally and only in certain environments, difficult to reproduce, must be a timing issue.
A user loads the site, clicks the Azure Login SSO button, redirects to the Azure Login page, authenticates successfully, redirects to the API, the user is then logged into the API and is redirected to the client. Then sometimes when the Blazor WASM client is loading it sends the /connect/token request back to the API which results in an HTTP 400 error. The client is then presented with a grey box with an error message approximating that they haven't been logged in correctly. Except that they have, the rest of the system is available and accessible and works just fine.
I'll need to try and replicate this on our clients environments to get some proper logs but unable to replicate in our development environments.
There's a weird disconnect with the authentication that has appeared after upgrading to v8.3.1 - reverting to v8.3.0 has resolved it. But weirdly these issues only appears to be happening to my local development build, the Release build to our test server isn't experiencing the issue.
We have the standard Web API Host connecting through to the Blazor client. Authentication is handled by OpenIddict inside the host before redirecting to the client. Session records in the database look correct but attempting to do anything requiring authentication on the API side, including the My Account settings, hard fail and kick me back to the login page. Logging in again just loads up the Blazor client, despite having the Account/Settings present in the ReturnUrl. Manually entering the Account/Settings URL doesn't load either, even immediately after reauthenticating. Oddly authenticating via Azure Entra using our SSO setup does allow access to the Account/Settings via the return URL, but once returning to the Blazor application this stops working. It's looking like once the Blazor client is loaded it's revoking the auth token for the Host side.
An exception was thrown by OpenIddict.Server.OpenIddictServerHandlers+Protection+CreateTokenEntry while handling the OpenIddict.Server.OpenIddictServerEvents+GenerateTokenContext event. Volo.Abp.Data.AbpDbConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded.
More logs are available.
2024-09-19 11:35:55.893 +12:00 [WRN] There is an entry which is not saved due to concurrency exception:
OpenIddictApplication {Id: 3a11f63e-2f3c-8f43-fb0b-787af845b4d9} Modified
2024-09-19 11:35:55.895 +12:00 [DBG] An exception was thrown by OpenIddict.Server.OpenIddictServerHandlers+Protection+CreateTokenEntry while handling the OpenIddict.Server.OpenIddictServerEvents+GenerateTokenContext event.
Volo.Abp.Data.AbpDbConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
---> Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
at Npgsql.EntityFrameworkCore.PostgreSQL.Update.Internal.NpgsqlModificationCommandBatch.ThrowAggregateUpdateConcurrencyExceptionAsync(RelationalDataReader reader, Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Update.Internal.NpgsqlModificationCommandBatch.Consume(RelationalDataReader reader, Boolean async, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable'1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable'1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable'1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList'1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func'4 operation, Func'4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Volo.Abp.EntityFrameworkCore.AbpDbContext'1.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Volo.Abp.EntityFrameworkCore.AbpDbContext'1.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository'2.InsertAsync(TEntity entity, Boolean autoSave, CancellationToken cancellationToken)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue'1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter'1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func'3 proceed)
at Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenStore.CreateAsync(OpenIddictTokenModel token, CancellationToken cancellationToken)
at OpenIddict.Core.OpenIddictTokenManager'1.CreateAsync(TToken token, CancellationToken cancellationToken)
at OpenIddict.Core.OpenIddictTokenManager'1.CreateAsync(OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
at OpenIddict.Core.OpenIddictTokenManager'1.OpenIddict.Abstractions.IOpenIddictTokenManager.CreateAsync(OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
at OpenIddict.Server.OpenIddictServerHandlers.Protection.CreateTokenEntry.HandleAsync(GenerateTokenContext context)
at OpenIddict.Server.OpenIddictServerDispatcher.DispatchAsync[TContext](TContext context)
2024-09-19 11:35:55.896 +12:00 [DBG] Added 0 entity changes to the current audit log
2024-09-19 11:35:55.898 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+GenerateTokenContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Protection+AttachTokenPayload.
2024-09-19 11:35:55.898 +12:00 [DBG] An exception was thrown by OpenIddict.Server.OpenIddictServerHandlers+GenerateAuthorizationCode while handling the OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext event.
Volo.Abp.Data.AbpDbConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
---> Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
at Npgsql.EntityFrameworkCore.PostgreSQL.Update.Internal.NpgsqlModificationCommandBatch.ThrowAggregateUpdateConcurrencyExceptionAsync(RelationalDataReader reader, Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Update.Internal.NpgsqlModificationCommandBatch.Consume(RelationalDataReader reader, Boolean async, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable'1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable'1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable'1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList'1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func'4 operation, Func'4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Volo.Abp.EntityFrameworkCore.AbpDbContext'1.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Volo.Abp.EntityFrameworkCore.AbpDbContext'1.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository'2.InsertAsync(TEntity entity, Boolean autoSave, CancellationToken cancellationToken)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue'1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter'1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func'3 proceed)
at Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenStore.CreateAsync(OpenIddictTokenModel token, CancellationToken cancellationToken)
at OpenIddict.Core.OpenIddictTokenManager'1.CreateAsync(TToken token, CancellationToken cancellationToken)
at OpenIddict.Core.OpenIddictTokenManager'1.CreateAsync(OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
at OpenIddict.Core.OpenIddictTokenManager'1.OpenIddict.Abstractions.IOpenIddictTokenManager.CreateAsync(OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
at OpenIddict.Server.OpenIddictServerHandlers.Protection.CreateTokenEntry.HandleAsync(GenerateTokenContext context)
at OpenIddict.Server.OpenIddictServerDispatcher.DispatchAsync[TContext](TContext context)
at OpenIddict.Server.OpenIddictServerDispatcher.DispatchAsync[TContext](TContext context)
at OpenIddict.Server.OpenIddictServerHandlers.GenerateAuthorizationCode.HandleAsync(ProcessSignInContext context)
at OpenIddict.Server.OpenIddictServerDispatcher.DispatchAsync[TContext](TContext context)
2024-09-19 11:35:55.899 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+GenerateAuthorizationCode.
2024-09-19 11:35:55.900 +12:00 [INF] Executed action Volo.Abp.OpenIddict.Controllers.AuthorizeController.HandleAsync (Volo.Abp.OpenIddict.AspNetCore) in 99.8638ms
2024-09-19 11:35:55.900 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+BeautifyGeneratedTokens.
2024-09-19 11:35:55.901 +12:00 [INF] Executed endpoint 'Volo.Abp.OpenIddict.Controllers.AuthorizeController.HandleAsync (Volo.Abp.OpenIddict.AspNetCore)'
2024-09-19 11:35:55.902 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+AttachSignInParameters.
2024-09-19 11:35:55.903 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+AttachRedirectUri.
2024-09-19 11:35:55.904 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+InferResponseMode.
2024-09-19 11:35:55.905 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+AttachResponseState.
2024-09-19 11:35:55.906 +12:00 [DBG] Added 0 entity changes to the current audit log
2024-09-19 11:35:55.906 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+AttachIssuer.
2024-09-19 11:35:55.908 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+AttachHttpResponseCode'1[[OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext, OpenIddict.Server, Version=5.5.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]].
2024-09-19 11:35:55.909 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+AttachCacheControlHeader'1[[OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext, OpenIddict.Server, Version=5.5.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]].
2024-09-19 11:35:55.910 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+Authentication+ProcessFormPostResponse.
2024-09-19 11:35:55.911 +12:00 [INF] The authorization response was successfully returned to 'CLIENT_URL' using the query response mode: {
"code": "[redacted]",
"state": "3d30fde778064b7d83699c8262749fc5",
"iss": "CLIENT_URL"
}.
2024-09-19 11:35:55.911 +12:00 [WRN] There is an entry which is not saved due to concurrency exception:
OpenIddictApplication {Id: 3a11f63e-2f3c-8f43-fb0b-787af845b4d9} Modified
2024-09-19 11:35:55.911 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+Authentication+ProcessQueryResponse.
2024-09-19 11:35:55.914 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was marked as handled by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+Authentication+ProcessQueryResponse.
2024-09-19 11:35:55.915 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+ApplyAuthorizationResponse'1[[OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext, OpenIddict.Server, Version=5.5.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]].
2024-09-19 11:35:55.916 +12:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was marked as handled by OpenIddict.Server.OpenIddictServerHandlers+Authentication+ApplyAuthorizationResponse'1[[OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext, OpenIddict.Server, Version=5.5.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]].
2024-09-19 11:35:55.916 +12:00 [INF] Executed action Volo.Abp.OpenIddict.Controllers.AuthorizeController.HandleAsync (Volo.Abp.OpenIddict.AspNetCore) in 115.4783ms
2024-09-19 11:35:55.917 +12:00 [INF] Executed endpoint 'Volo.Abp.OpenIddict.Controllers.AuthorizeController.HandleAsync (Volo.Abp.OpenIddict.AspNetCore)'
Convention is dictating that any service methods with an *Id parameter get added to to the path for that service, i.e. /api/app/widget/fetch/{*Id}
However if that parameter is optional and provided a default value it is still added to the path, i.e. /api/app/widget/fetch/{typeId=null}
Intention is to use that optional *Id parameter as a filter, however because it is added to the path it becomes required (even Swagger stating as such).
The ABP service injected into the Client doesn't recognise this however, so calling one of these methods and not providing the optional parameter causes it to fail to find the correct route. But this doesn't cause an error, instead as an async method it just returns a Task that never completes, causing the method calling it to hang.
Workaround is to replace the parameters with a proper filter DTO, although renaming the parameter probably also works (I didn't test that however).
The ABP Toolbar is useful but we have a number of actions we want to perform on Logout or navigation to the My Account pages that exist on the host.
I can't find any way to hook into those actions to perform actions before redirection. For Logout I've hooked into the OpenIddict event handlers to cleanup stuff but for the My Account link I can't find any events to hook into so have had to resort to some obvious error messages to alleviate issues users may face when returning to the main application.
Regardless hooking into the OpenIddict events on the Host side requires exposing more services to perform the needed actions, services already available on the client side.
Is there any way to hook into those actions on the client before redirection to the host?
Good Morning
We're prepping for a production deployment and were expecting 8.3 Final to be released last week, instead we got rc3. Is there a new release date scheduled for when 8.3 Final will be finished and released? Thanks.
End result is four active working browsers (2 in Chrome, 1 in Chrome Incognito, 1 in Firefox) with zero active sessions and Prevent Concurrent Login turned on. Refreshing any of the browsers causes the WASM page to reload, creating new sessions without asking for credentials.
Have logged on / off and restarted the Blazor and HttpApi.Host instance and rebuilt the project after setting the Prevent Concurrent Logins. Deleting all sessions out of the AbpSessions table also leaves all browsers active and logged in.
For security we've recently created a new database user with tightened up permissions for usual access (https://en.wikipedia.org/wiki/Principle_of_least_privilege), the user doesn't need to be a superuser or have any alter table permissions. Due to soft-deleting being common it shouldn't need Delete permission for most tables either.
The Volo.Abp.OpenIddict.Tokens.OpenIddictToken class is setup as a FullAuditedAggregateRoot which has soft-deleting enabled but it's not actually using it so when we revoked the delete permissions the system stopped working properly.
Quick fix is to re-grant the Delete permission, but the OpenIddictToken class should either be setup to use soft-deleting as its inheritance provides, or its inheritance should be changed so we don't have unnecessary unused columns present on the database table.