Open Closed

Random exception after switching from IdentityServer to OpenDict #7699


User avatar
0
alexander.nikonov created
  • ABP Framework version: v8.1.3
  • UI Type: Angular
  • Database System: EF Core (Oracle)
  • Auth Server Separated

This issue has been reported as a bug at GitHub, but ignored for many days, so I have to submit a commercial ticket to get a better attention.

2024-06-20 14:19:04.849 -05:00 INF () Lock is acquired for TokenCleanupBackgroundWorker

[14:19:04 INF] Lock is acquired for TokenCleanupBackgroundWorker

2024-06-20 14:19:04.859 -05:00 ERR () An exception was thrown while activating Volo.Abp.OpenIddict.Tokens.TokenCleanupService -> ?:OpenIddict.Abstractions.IOpenIddictTokenManager -> Volo.Abp.OpenIddict.Tokens.AbpTokenManager -> Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenCache -> Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenStore.Autofac.Core.DependencyResolutionException: An exception was thrown while activating Volo.Abp.OpenIddict.Tokens.TokenCleanupService -> ?:OpenIddict.Abstractions.IOpenIddictTokenManager -> Volo.Abp.OpenIddict.Tokens.AbpTokenManager -> Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenCache -> Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenStore.

---> Autofac.Core.DependencyResolutionException: None of the constructors found on type 'Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenStore' can be invoked with the available services and parameters:

Cannot resolve parameter 'Volo.Abp.OpenIddict.Tokens.IOpenIddictTokenRepository repository' of constructor 'Void .ctor(Volo.Abp.OpenIddict.Tokens.IOpenIddictTokenRepository, Volo.Abp.Uow.IUnitOfWorkManager, Volo.Abp.Guids.IGuidGenerator, Volo.Abp.OpenIddict.Applications.IOpenIddictApplicationRepository, Volo.Abp.OpenIddict.Authorizations.IOpenIddictAuthorizationRepository, Volo.Abp.OpenIddict.AbpOpenIddictIdentifierConverter, Volo.Abp.OpenIddict.IOpenIddictDbConcurrencyExceptionHandler)'.

We cannot provide the code of our solution. But the scenario we have been able to reproduce this is as follows (I guess there are other ones, this might just give you the idea where in the code to look at):

  1. Being logged in the front-end part (Angular), add some custom page to the browser favorites.
  2. Logout.
  3. Populate user credentials and click on ‘Login’ button.
  4. Open link from step 1 on the second tab of the browser while the first tab is trying to log in.

19 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you set your log level to Debug and reproduce the error then share the full logs?

    Thanks.

    public class Program
    {
        public async static Task<int> Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
                .Enrich.FromLogContext()
                .WriteTo.Async(c => c.File("Logs/logs.txt"))
                .WriteTo.Async(c => c.Console())
                .CreateLogger();
    
  • User Avatar
    0
    alexander.nikonov created

    Currently the above scenario did not help me reproduce the exception. I need to wait for another team member who managed to reproduce it such way. Please, wait and do not close the ticket.

    Though, I was able to get another kind of exception. Please have a look at this one so far.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    IsolationLevel must be ReadCommitted or Serializable (Parameter 'isolationLevel')

    Please configure AbpOpenIddictStoreOptions to set the IsolationLevel for your Oracle.

    public class AbpOpenIddictStoreOptions
    {
        public IsolationLevel? PruneIsolationLevel { get; set; }
    
        public IsolationLevel? DeleteIsolationLevel { get; set; }
    
        public AbpOpenIddictStoreOptions()
        {
            PruneIsolationLevel = IsolationLevel.RepeatableRead;
            DeleteIsolationLevel = IsolationLevel.Serializable;
        }
    }
    
    
  • User Avatar
    0
    alexander.nikonov created

    hi

    IsolationLevel must be ReadCommitted or Serializable (Parameter 'isolationLevel')

    Please configure AbpOpenIddictStoreOptions to set the IsolationLevel for your Oracle.

    public class AbpOpenIddictStoreOptions 
    { 
        public IsolationLevel? PruneIsolationLevel { get; set; } 
     
        public IsolationLevel? DeleteIsolationLevel { get; set; } 
     
        public AbpOpenIddictStoreOptions() 
        { 
            PruneIsolationLevel = IsolationLevel.RepeatableRead; 
            DeleteIsolationLevel = IsolationLevel.Serializable; 
        } 
    } 
     
    
    1. I can't find the way to add these options in my AuthServerModule. Logically, I've tried to use PreConfigureServices, but got lost among numerous extensions. BTW, the documentation does not describe it well either (https://abp.io/docs/latest/Modules/OpenIddict);
    2. Do i need to retain RepeatableRead for PruneIsolationLevel?
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The Oracle requires IsolationLevel must be ReadCommitted or Serializable

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        Configure<AbpOpenIddictStoreOptions>(options =>
        {
            options.DeleteIsolationLevel = IsolationLevel.ReadCommitted;
            options.PruneIsolationLevel = IsolationLevel.ReadCommitted;
        });
    }
    
  • User Avatar
    0
    alexander.nikonov created

    AbpOpenIddictStoreOptions

    No luck so far:

    using Volo.Abp.OpenIddict;

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Sorry this option is available on 8.2

    https://github.com/abpframework/abp/pull/19133

    You can try this: https://abp.io/support/questions/6741/Exception-in-OpenIdDict-TokenCleanupBackgroundWorker-with-Oracle-Devart-Driver-Transaction-isolation-level-RepeatableRead-not-supported#answer-3a10f6b7-4213-43ee-ed36-b567c77fc084

  • User Avatar
    0
    alexander.nikonov created

    This is now done, thank you, so this part is done. But let's wait a bit: I'm going to have the meeting with the colleague who managed to reproduce the first exception.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    ok, : )

  • User Avatar
    0
    alexander.nikonov created

    So while the initial exception reproducing still pending, I received this again:

    > [09:26:33 INF] Lock is acquired for TokenCleanupBackgroundWorker
    > [09:26:33 INF] Start cleanup.
    > [09:26:33 INF] Start cleanup tokens.
    > fail: Microsoft.EntityFrameworkCore.Infrastructure[0]
    > 2024-08-19 09:26:34.569195 ThreadID:500 (ERROR)   OracleExecutionStrategy.ExecuteAsync() :  System.ArgumentException: IsolationLevel must be ReadCommitted or Serializable (Parameter 'isolationLevel')
    > at Oracle.ManagedDataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel isolationLevel)
    > at Oracle.ManagedDataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel)
    > at System.Data.Common.DbConnection.BeginDbTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
    > --- End of stack trace from previous location ---
    > at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
    > at Oracle.EntityFrameworkCore.Storage.Internal.OracleExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
    > [09:26:34 ERR] IsolationLevel must be ReadCommitted or Serializable (Parameter 'isolationLevel')
    > System.ArgumentException: IsolationLevel must be ReadCommitted or Serializable (Parameter 'isolationLevel')
    > at Oracle.ManagedDataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel isolationLevel)
    > at Oracle.ManagedDataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel)
    > at System.Data.Common.DbConnection.BeginDbTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
    > --- End of stack trace from previous location ---
    > at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
    > at Oracle.EntityFrameworkCore.Storage.Internal.OracleExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
    > at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
    > at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextAsync(IUnitOfWork unitOfWork)
    > at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextAsync(IUnitOfWork unitOfWork, String connectionStringName, String connectionString)
    > at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.GetDbContextAsync()
    > at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.GetDbSetAsync()
    > at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.GetQueryableAsync()
    > at Volo.Abp.OpenIddict.Tokens.EfCoreOpenIddictTokenRepository.PruneAsync(DateTime date, 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.PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
    > at Volo.Abp.OpenIddict.Tokens.TokenCleanupService.CleanAsync()
    

    And it is happening after I replaced all the stores as you suggested. The code of the stores was copy-pasted from yours:

    context.Services.AddOpenIddict()
        .AddCore(builder =>
        {
            builder
                .AddApplicationStore&lt;AbxAbpOpenIddictApplicationStore&gt;()
                .AddAuthorizationStore&lt;AbxAbpOpenIddictAuthorizationStore&gt;()
                .AddTokenStore&lt;AbxAbpOpenIddictTokenStore&gt;();
        });
    

    Maybe I am adding this code too late inside ConfigureServices if the order matters at all here? What is it supposed to follow in OpenIDServer module?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

     at Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenStore.PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
    at Volo.Abp.OpenIddict.Tokens.TokenCleanupService.CleanAsync()
    

    Your custom AbxAbpOpenIddictTokenStore store is not take effected

    Please share your module code.

    Thanks

  • User Avatar
    0
    alexander.nikonov created
    	using AbxEps.MyApp.AuthServer.Grants;
    	using AbxEps.MyApp.AuthServer.Stores;
    	using AbxEps.MyApp.Cryptography;
    	using AbxEps.MyApp.EntityFrameworkCore;
    	using AbxEps.MyApp.Filters;
    	using AbxEps.MyApp.Localization;
    	using AbxEps.MyApp.Middlewares;
    	using AbxEps.MyApp.MultiTenancy;
    	using AbxEps.LanguageCodeConvertor.Extensions;
    	using AbxEps.Middleware.AbxRequestContext.Extensions;
    	using AbxEps.Middleware.CookieAccessToken.Extensions;
    	using Localization.Resources.AbpUi;
    	using Medallion.Threading;
    	using Medallion.Threading.Oracle;
    	using Microsoft.AspNetCore.Builder;
    	using Microsoft.AspNetCore.Cors;
    	using Microsoft.AspNetCore.DataProtection;
    	using Microsoft.AspNetCore.Extensions.DependencyInjection;
    	using Microsoft.AspNetCore.Mvc;
    	using Microsoft.Extensions.Configuration;
    	using Microsoft.Extensions.DependencyInjection;
    	using Microsoft.Extensions.Hosting;
    	using Microsoft.Net.Http.Headers;
    	using OpenIddict.Server.AspNetCore;
    	using OpenIddict.Validation.AspNetCore;
    	using Serilog;
    	using StackExchange.Redis;
    	using System;
    	using System.IO;
    	using System.Linq;
    	using System.Security.Cryptography.X509Certificates;
    	using Volo.Abp;
    	using Volo.Abp.Account;
    	using Volo.Abp.Account.Public.Web;
    	using Volo.Abp.Account.Public.Web.Impersonation;
    	using Volo.Abp.Account.Web;
    	using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
    	using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton;
    	using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Bundling;
    	using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
    	using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpApplicationPath;
    	using Volo.Abp.AspNetCore.Serilog;
    	using Volo.Abp.Auditing;
    	using Volo.Abp.Autofac;
    	using Volo.Abp.BackgroundJobs;
    	using Volo.Abp.Caching;
    	using Volo.Abp.Caching.StackExchangeRedis;
    	using Volo.Abp.DistributedLocking;
    	using Volo.Abp.FeatureManagement;
    	using Volo.Abp.Identity;
    	using Volo.Abp.Localization;
    	using Volo.Abp.Modularity;
    	using Volo.Abp.OpenIddict;
    	using Volo.Abp.OpenIddict.Applications;
    	using Volo.Abp.OpenIddict.Authorizations;
    	using Volo.Abp.OpenIddict.ExtensionGrantTypes;
    	using Volo.Abp.OpenIddict.Tokens;
    	using Volo.Abp.PermissionManagement;
    	using Volo.Abp.Ui.LayoutHooks;
    	using Volo.Abp.UI.Navigation.Urls;
    	using Volo.Abp.VirtualFileSystem;
    	using Volo.Saas.Host;
    	using AbxEps.CentralTools.AuthServer.Grants;
    	using AbxEps.CentralTools.AuthServer.Stores;
    	using AbxEps.CentralTools.Cryptography;
    	using AbxEps.CentralTools.Filters;
    	using AbxEps.CentralTools.Middlewares;
    	using Twilio.Rest.Microvisor.V1;
    
    	namespace AbxEps.MyApp;
    
    	[DependsOn(
    		typeof(AbpAutofacModule),
    		typeof(AbpCachingStackExchangeRedisModule),
    		typeof(AbpDistributedLockingModule),
    		typeof(AbpAspNetCoreSerilogModule),
    		typeof(AbpAccountPublicWebOpenIddictModule),
    		typeof(AbpAccountPublicHttpApiModule),
    		typeof(AbpAspNetCoreMvcUiLeptonThemeModule),
    		typeof(AbpAccountPublicApplicationModule),
    		typeof(AbpAccountPublicWebImpersonationModule),
    		typeof(SaasHostApplicationContractsModule),
    		typeof(MyAppEntityFrameworkCoreModule)
    		)]
    	public class MyAppAuthServerModule : AbpModule
    	{
    		private const string DefaultCorsPolicyName = "Default";
    
    		public override void PreConfigureServices(ServiceConfigurationContext context)
    		{
    			var configuration = context.Services.GetConfiguration();
    			var hostingEnvironment = context.Services.GetHostingEnvironment();
    
    			//var logger = context.Services.GetInitLogger&lt;MyAppAuthServerModule&gt;();
    
    			Log.Information($"*** {nameof(MyAppAuthServerModule)}.{nameof(PreConfigureServices)}: HostingEnvironment: {hostingEnvironment.EnvironmentName}");
    
    			PreConfigure&lt;AbpOpenIddictAspNetCoreOptions&gt;(options =>
    			{
    				// https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html
    				if (!hostingEnvironment.IsDevelopment())
    				{
    					options.AddDevelopmentEncryptionAndSigningCertificate = false;
    				}
    			});
    
    			PreConfigure&lt;OpenIddictServerBuilder&gt;(builder =>
    			{
    				// https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html
    
    				// not needed because default of AddDevelopmentEncryptionAndSigningCertificate is true in Development...
    				/*if (hostingEnvironment.IsDevelopment())
    				{
    					builder
    						.AddDevelopmentEncryptionCertificate()
    						.AddDevelopmentSigningCertificate();
    				}*/
    
    				if (!hostingEnvironment.IsDevelopment())
    				{
    					// Encryption
    					string encryptionCertThumbPrint = configuration["Certificates:Encryption:ThumbPrint"];
    					string encryptionCertFile = configuration["Certificates:Encryption:File"];
    					string encryptionCertPassword = configuration["Certificates:Encryption:Password"];
    
    					if (string.IsNullOrEmpty(encryptionCertThumbPrint) && string.IsNullOrEmpty(encryptionCertFile))
    					{
    						string message = "Neither Certificates:Encryption:ThumbPrint nor Certificates:Encryption:File is set!";
    						Log.Error($"*** {message}!");
    						throw new NotSupportedException(message);
    					}
    					if (!string.IsNullOrEmpty(encryptionCertFile) && !File.Exists(encryptionCertFile))
    					{
    						string message = $"Cannot find encryption certificate '{encryptionCertFile}'!";
    						Log.Error($"*** {message}!");
    						throw new NotSupportedException(message);
    					}
    
    					X509Certificate2 certificate = X509Helper.GetCertificate(encryptionCertThumbPrint, encryptionCertFile, encryptionCertPassword, Log.Logger);
    
    					if (certificate == null)
    					{
    						// throw exception, stop service...
    						string cert = string.IsNullOrEmpty(encryptionCertThumbPrint) ? encryptionCertFile : encryptionCertThumbPrint;
    						throw new NotSupportedException($"Encryption Certificate '{cert}' not found!");
    					}
    					else
    					{
    						Log.Debug($"Encryption Certificate: Issuer is '{certificate.Issuer}'");
    						builder.AddEncryptionCertificate(certificate);
    					}
    
    					// Signing Certificate
    					string signingCertThumbPrint = configuration["Certificates:Signing:ThumbPrint"];
    					string signingCertFile = configuration["Certificates:Signing:file"];
    					string signingCertPassword = configuration["Certificates:Signing:Password"];
    
    					if (string.IsNullOrEmpty(signingCertThumbPrint) && string.IsNullOrEmpty(signingCertFile))
    					{
    						string message = "Neither Certificates:Signing:ThumbPrint nor Certificates:Signing:File is set!";
    						Log.Error($"*** {message}!");
    						throw new NotSupportedException(message);
    					}
    					if (!string.IsNullOrEmpty(signingCertFile) && !File.Exists(signingCertFile))
    					{
    						string message = $"Cannot find signing certificate '{signingCertFile}'!";
    						Log.Error($"*** {message}!");
    						throw new NotSupportedException(message);
    					}
    
    					certificate = X509Helper.GetCertificate(signingCertThumbPrint, signingCertFile, signingCertPassword, Log.Logger);
    
    					if (certificate == null)
    					{
    						// throw exception, stop service...
    						string cert = string.IsNullOrEmpty(signingCertThumbPrint) ? signingCertFile : signingCertThumbPrint;
    						throw new NotSupportedException($"Signing Certificate '{cert}' not found!");
    					}
    					else
    					{
    						Log.Debug($"Signing Certificate: Issuer is '{certificate.Issuer}'");
    						builder.AddSigningCertificate(certificate);
    					}
    				}
    
    				builder.Configure(options =>
    				{
    					// adobu TODO
    					// https://documentation.openiddict.com/configuration/token-formats.html#disabling-jwt-access-token-encryption
    					// DisableAccessTokenEncryption is set to true in Volo.Abp.OpenIddict.AbpOpenIddictAspNetCoreModule.AddOpenIddictServer
    					// options.DisableAccessTokenEncryption = false;
    
    					//options.GrantTypes.Add(AbxLoginGrant.ExtensionGrantName);
    					options.GrantTypes.Add(SwitchToTenantGrant.ExtensionGrantName);
    				});
    			});
    
    			PreConfigure&lt;OpenIddictBuilder&gt;(builder =>
    			{
    				builder.AddValidation(options =>
    				{
    					options.AddAudiences("MyApp");
    					options.UseLocalServer();
    					options.UseAspNetCore();
    				});
    			});
    		}
    
    		public override void ConfigureServices(ServiceConfigurationContext context)
    		{
    			var hostingEnvironment = context.Services.GetHostingEnvironment();
    			var configuration = context.Services.GetConfiguration();
    
    			if (!Convert.ToBoolean(configuration["App:DisablePII"]))
    			{
    				Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
    			}
    
    			if (!Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]))
    			{
    				Configure&lt;OpenIddictServerAspNetCoreOptions&gt;(options =>
    				{
    					options.DisableTransportSecurityRequirement = true;
    				});
    			}
    
    			context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
    
    			// This is added for a correct root path in js files
    			Configure&lt;AbpLayoutHookOptions&gt;(options =>
    			{
    				options.Add(LayoutHooks.Head.Last,
    				typeof(AbpApplicationPathViewComponent));
    			});
    
    			Configure&lt;AbpLocalizationOptions&gt;(options =>
    			{
    				options.Resources
    					.Get&lt;MyAppResource&gt;()
    					.AddBaseTypes(
    						typeof(AbpUiResource)
    					);
    			});
    
    			Configure&lt;AbpBundlingOptions&gt;(options =>
    			{
    				options.StyleBundles.Configure(
    					LeptonThemeBundles.Styles.Global,
    					bundle =>
    					{
    						bundle.AddFiles("/global-styles.css");
    					}
    				);
    			});
    
    			Configure&lt;AbpAuditingOptions&gt;(options =>
    			{
    				//options.IsEnabledForGetRequests = true;
    				options.ApplicationName = "AuthServer";
    			});
    
    			if (hostingEnvironment.IsDevelopment())
    			{
    				Configure&lt;AbpVirtualFileSystemOptions&gt;(options =>
    				{
    					options.FileSets.ReplaceEmbeddedByPhysical&lt;MyAppDomainSharedModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}AbxEps.MyApp.Domain.Shared", Path.DirectorySeparatorChar)));
    					options.FileSets.ReplaceEmbeddedByPhysical&lt;MyAppDomainModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}AbxEps.MyApp.Domain", Path.DirectorySeparatorChar)));
    				});
    			}
    
    			Configure&lt;AppUrlOptions&gt;(options =>
    			{
    				options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
    				options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"].Split(','));
    				options.Applications["Angular"].RootUrl = configuration["App:AngularUrl"];
    				options.Applications["Angular"].Urls[AccountUrlNames.PasswordReset] = "account/reset-password";
    				options.Applications["Angular"].Urls[AccountUrlNames.EmailConfirmation] = "account/email-confirmation";
    			});
    
    			Configure&lt;AbpBackgroundJobOptions&gt;(options =>
    			{
    				options.IsJobExecutionEnabled = false;
    			});
    
    			Configure&lt;AbpDistributedCacheOptions&gt;(options =>
    			{
    				options.KeyPrefix = "Abx:";
    			});
    
    			Configure&lt;MvcOptions&gt;(options =>
    			{
    				options.Filters.Add(typeof(TokenExpiredExceptionFilter));
    			});
    
    			var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName("MyApp");
    			if (!hostingEnvironment.IsDevelopment())
    			{
    				var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
    				dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "AuthServer-Protection-Keys");
    			}
    
    			context.Services.AddSingleton&lt;IDistributedLockProvider&gt;(sp =>
    			{
    				//var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
    				//return new RedisDistributedSynchronizationProvider(connection.GetDatabase());
    				return new OracleDistributedSynchronizationProvider(configuration["ConnectionStrings:Default"]);
    			});
    
    			ConfigureCors(context, configuration);
    			ConfigureAuth(context, configuration);
    			ConfigureOpenIdDict(context, configuration);
    			ConfigureStores(context, configuration);
    
    			context.Services.Configure&lt;AbpAccountOptions&gt;(options =>
    			{
    				options.TenantAdminUserName = "admin";
    				options.ImpersonationTenantPermission = SaasHostPermissions.Tenants.Impersonation;
    				options.ImpersonationUserPermission = IdentityPermissions.Users.Impersonation;
    			});
    
    			Configure&lt;PermissionManagementOptions&gt;(options =>
    			{
    				options.IsDynamicPermissionStoreEnabled = true;
    			});
    
    			Configure&lt;FeatureManagementOptions&gt;(options =>
    			{
    				options.IsDynamicFeatureStoreEnabled = true;
    			});
    		}
    
    		private static void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
    		{
    			context.Services.AddCors(options =>
    			{
    				options.AddPolicy(DefaultCorsPolicyName, builder =>
    				{
    					builder
    						.WithOrigins(
    							configuration["App:CorsOrigins"]
    								.Split(",", StringSplitOptions.RemoveEmptyEntries)
    								.Select(o => o.Trim().RemovePostFix("/"))
    								.ToArray()
    						)
    						.WithAbpExposedHeaders()
    						.SetIsOriginAllowedToAllowWildcardSubdomains()
    						.AllowAnyHeader()
    						.AllowAnyMethod()
    						.AllowCredentials();
    				});
    			});
    		}
    
    		private static void ConfigureAuth(ServiceConfigurationContext context, IConfiguration configuration)
    		{
    			context.Services.AddAuthentication();
    		}
    
    		private static void ConfigureStores(ServiceConfigurationContext context, IConfiguration configuration)
    		{
    			context.Services.AddOpenIddict()
    				.AddCore(builder =>
    				{
    					builder
    						.AddApplicationStore&lt;AbxAbpOpenIddictApplicationStore&gt;()
    						.AddAuthorizationStore&lt;AbxAbpOpenIddictAuthorizationStore&gt;()
    						.AddTokenStore&lt;AbxAbpOpenIddictTokenStore&gt;();
    				});
    		}
    
    		private void ConfigureOpenIdDict(ServiceConfigurationContext context, IConfiguration configuration)
    		{
    			// Configure&lt;TokenCleanupOptions&gt;(options => { });
    
    			Configure&lt;AbpOpenIddictExtensionGrantsOptions&gt;(options =>
    			{
    				//options.Grants.Add(AbxLoginGrant.ExtensionGrantName, new AbxLoginGrant());
    				options.Grants.Add(SwitchToTenantGrant.ExtensionGrantName, new SwitchToTenantGrant());
    			});
    
    			// This is required for working of AbxRequestContext
    			context.Services.AddHttpContextAccessor();
    			context.Services.InitLanguageCodeConvertor(configuration);
    			context.Services.InitAbxRequestContext();
    		}
    
    		public override void OnApplicationInitialization(ApplicationInitializationContext context)
    		{
    
    			var app = context.GetApplicationBuilder();
    			var env = context.GetEnvironment();
    
    			if (env.IsDevelopment())
    			{
    				app.UseDeveloperExceptionPage();
    			}
    
    			app.UseAbpRequestLocalization();
    
    			if (!env.IsDevelopment())
    			{
    				app.UseErrorPage();
    			}
    
    			app.UseCorrelationId();
    			app.UseAbpSecurityHeaders();
    			app.UseStaticFiles();
    			app.UseRouting();
    			app.UseCors(DefaultCorsPolicyName);
    			app.UseAuthentication();
    			//app.UseAbpOpenIddictValidation();  // UseIdentityServer
    			app.UseCookieAccessTokenDelete(HeaderNames.Authorization);
    
    			/* https://docs.abp.io/en/abp/7.0/Migration-Guides/IdentityServer_To_OpenIddict
    			app.UseJwtTokenMiddleware();*/
    
    			if (MultiTenancyConsts.IsEnabled)
    			{
    				app.UseMultiTenancy();
    			}
    
    			app.UseUnitOfWork();
    			app.UseMiddleware&lt;SessionEndAuditingMiddleware&gt;();
    			app.UseMiddleware&lt;TenantSwitchMiddleware&gt;();
    
    			app.UseAbpOpenIddictValidation();  // UseIdentityServer
    			app.UseAuthorization();
    
    			app.UseAuditing();
    			app.UseAbpSerilogEnrichers();
    			app.UseConfiguredEndpoints();
    		}
    	}
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Your code is no problem, that strange. Can you share a test project?

  • User Avatar
    0
    alexander.nikonov created

    Your code is no problem, that strange. Can you share a test project?

    Unfortunately I cannot. I only can follow some recommendations. So from what you say I can deduce, that some of the custom store or all of them are not invoked, right? Where should I put the breakpoint in debug?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    My test code

  • User Avatar
    0
    alexander.nikonov created

    I see no problem with this code in the solution where I received the exception - the Store contains correct class:

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    What is the project of this error log? You can try to add your code to Domain module.

    https://abp.io/support/questions/7699/Random-exception-after-switching-from-IdentityServer-to-OpenDict#answer-3a147d57-7267-7eaf-1d74-ba36bdfea929

  • User Avatar
    0
    alexander.nikonov created

    What is the project of this error log? You can try to add your code to Domain module.

    https://abp.io/support/questions/7699/Random-exception-after-switching-from-IdentityServer-to-OpenDict#answer-3a147d57-7267-7eaf-1d74-ba36bdfea929

    Sorry, I am not sure I am following you. The first exception (DI issue) needs to be reproduced yet, I am waiting for my colleague trying to assist me, because I did not manage to get this exception. So I cannot say anything here yet.

    But instead I received another exception related to the transaction level. According to your recommendation, I have overriden all the stores with the code you provided for the older version of ABP - in order to override a transaction level. After adding this code, I can see that the Store property is properly filled with my custom class. All the constructors of all three custom stores did invoke - so the code was applied as expected. Still, I received the same exception again at some point. I cannot see how this may ever happen, if all my front-end applications interact with the same OpenId Server where I made the override and - I expect - there is only one "entry point" to reach out the TokenCleanupBackgroundWorker where the exception happens and this "entry point" is the interaction between front-end applications and OpenId Server?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    I understand your situation. Maybe other projects also execute background jobs, so your code is not applied to all projects.

    You can try to add your code to Domain module.

Made with ❤️ on ABP v9.0.0-preview Updated on September 19, 2024, 10:13