Skip to content

OpenIdConnectOptions Don't Get Set With DelegateStrategy #1054

@goforebroke

Description

@goforebroke

Andrew,

Until you release a patch for the HttpContextStrategy, I took your advise and used the delegate strategy and I also set the OpenIdConnectOptions per tenant.

      services.AddMultiTenant<AppTenantInfo>()
          .WithClaimStrategy()
          .WithDelegateStrategy<DefaultHttpContext, AppTenantInfo>(httpContext =>
          {
              if (httpContext.Request.Query.TryGetValue("tenant", out StringValues tenantIdentifier) &&
                  !StringValues.IsNullOrEmpty(tenantIdentifier))
              {
                  return Task.FromResult<string?>(tenantIdentifier[0]);
              }

              return Task.FromResult<string?>(null);
          })
          // .WithStaticStrategy(defaultTenantIdentifier)
          .WithHttpRemoteStore(httpRemoteStore, clientBuilder =>
          {
              clientBuilder.AddHttpMessageHandler<TenantRemoteStoreDelegatingHandler>();
          })
         // .WithConfigurationStore()
          .WithPerTenantAuthentication();


           services.ConfigureAllPerTenant<OpenIdConnectOptions, AppTenantInfo>((options, tenant) =>
           {
               options.RequireHttpsMetadata = webHostEnvironment.IsProduction();
               options.Authority = $"http://identity.api:80/{tenant.Identifier}";
               options.Events = OpenIdConnectOptionsExtensions.CreateTenantAwareEvents(webHostEnvironment);
           });

Here is the static method

 public static OpenIdConnectEvents CreateTenantAwareEvents(IWebHostEnvironment env)
 {
     return new OpenIdConnectEvents
     {
         OnRedirectToIdentityProvider = context =>
         {
             var logger = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>()
                 .CreateLogger("OpenIdConnectEvents");

             // Read tenant info from the current HttpContext (Finbuckle)
             var multiTenantContext = context.HttpContext.GetMultiTenantContext<AppTenantInfo>();
             var tenant = multiTenantContext?.TenantInfo;

             logger.LogInformation("OnRedirectToIdentityProvider for tenant: {TenantId}", tenant?.Identifier ?? "null");

             if (tenant is not null)
             {
                 //context.Options.Authority = $"{tenant.JwtAuthority}/{tenant.Identifier}";

                 // Use tenant-specific issuer/authority for the redirect
                 context.ProtocolMessage.IssuerAddress = $"{tenant.JwtAuthority}/{tenant.Identifier}/connect/authorize";
                 context.ProtocolMessage.UiLocales = Thread.CurrentThread.CurrentUICulture.Name;

                 if (env.IsDevelopment())
                 {
                     // discovery metadata for dev environment
                     context.Options.RequireHttpsMetadata = false;
                     context.Options.MetadataAddress = $"http://identity.api:80/{tenant.Identifier}/.well-known/openid-configuration";
                 }
             }

             // carry forward any prompt stored in auth properties
             if (context.Properties.Items.TryGetValue("prompt", out var prompt))
             {
                 context.ProtocolMessage.Prompt = prompt;
             }

             return Task.CompletedTask;
         },

         OnRemoteFailure = context =>
         {
             context.Response.Redirect("/StatusCode?statusCode=500");
             context.HandleResponse();
             return Task.CompletedTask;
         },

         OnAccessDenied = context =>
         {
             if (context.Request.QueryString.Value is not null)
             {
                 var requestQuery = HttpUtility.ParseQueryString(context.Request.QueryString.Value);

                 const string descriptionField = "error_description";
                 const string cancelledCode = "user_canceled_login";

                 var descriptionFieldValue = requestQuery[descriptionField];

                 if (!string.IsNullOrEmpty(descriptionFieldValue) &&
                     descriptionFieldValue.Equals(cancelledCode, StringComparison.OrdinalIgnoreCase))
                 {
                     context.Response.Redirect("/");
                     context.HandleResponse();
                     return Task.CompletedTask;
                 }
             }

             context.Response.Redirect("/StatusCode?statusCode=401");
             context.HandleResponse();
             return Task.CompletedTask;
         }
     };
 }

When a tenant is found and resolved using the DelegateStrategy, the OpenIdConnectOptions are NOT set for the resolved tenant. However, if I use the StaticStrategy and ConfigurationStore the options do get set for the tenant when a challenge is made.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions