Skip to content

Scheme 'azuread' appears to be mandatory #3457

@WenningQiu

Description

@WenningQiu

Microsoft.Identity.Web Library

Microsoft.Identity.Web

Microsoft.Identity.Web version

3.10.0

Web app

Sign-in users

Web API

Protected web APIs (validating tokens)

Token cache serialization

Distributed caches

Description

My application supports multiple tenants, so it registers schemes for those tenants but without registering the default scheme 'azuread'. However, Microsoft.Identity.Web (or its dependencies) appears to be expecting an authentication handler registered under 'azuread' scheme.

The following is an example in which an error triggers "No authentication handler is registered for the scheme 'azuread'" exception:

Image

So my questions are:

  1. Is 'azuread' scheme mandatory?
  2. If that is, how does it fit in my application?

Reproduction steps

  1. Define multiple tenants in appsettings.json file: Image
  2. Use the section names in appsettings.json to construct OIDC scheme name and cookie scheme name as below. For the appsettings.json above, schemes "abc", "abcCookies", "hij", "hijCookies", "xyz" and "xyzCoolies" would be registered.
            services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();

            foreach (var section in _configuration.GetChildren())
            {
                var options = new MicrosoftIdentityOptions();
                section.Bind(options);

                if (options.Instance.IsNullOrEmpty() || options.ClientId.IsNullOrEmpty())
                    continue; // Skip sections that are not defining tenants

                // AuthorizationPolicyProvider determines the scheme for incoming request at runtime that matches the scheme name here.
                var (oidcScheme, oidcCookieScheme) = section.Key.BuildSchemesForTenant();

                services.AddAuthentication()
                    .AddMicrosoftIdentityWebApp(
                        identityOptions => section.Bind(identityOptions),
                        cookieOptions =>
                        {
                            cookieOptions.Cookie.Name = ".AspNetCore.Cookies";
                            cookieOptions.Cookie.MaxAge = TimeSpan.FromHours(4);
                        },
                        oidcScheme, oidcCookieScheme)
                    .EnableTokenAcquisitionToCallDownstreamApi(); // These steps enable "authorization code flow".
            }
  1. When a client makes calls, tenant needs to be provided in the form of query parameters (i.e., https://xxxx?tenant=abc). AuthorizationPolicyProvider then calculates the scheme policy based on the tenant query parameter:
        Task<AuthorizationPolicy> IAuthorizationPolicyProvider.GetDefaultPolicyAsync()
        {
            return Task.FromResult(GetPolicy());
        }

        Task<AuthorizationPolicy> IAuthorizationPolicyProvider.GetFallbackPolicyAsync()
        {
            return Task.FromResult(GetPolicy());
        }

        Task<AuthorizationPolicy> IAuthorizationPolicyProvider.GetPolicyAsync(string policyName)
        {
            throw new NotImplementedException();
        }

        private AuthorizationPolicy GetPolicy()
        {
            var httpContext = _httpContextAccessor.HttpContext;

            var schemeName = httpContext?.Request.GetTenant().ToLower();

            if (httpContext.Request.Path.Value.EndsWith(nameof(AzureController.BearerLogin)))
                schemeName = schemeName.BuildBearScheme();

            return _policyCache.GetOrAdd(schemeName, 
                _ => new AuthorizationPolicyBuilder()
                    .AddRequirements(new AssertionRequirement(_ => true)) // Policy must have at least one requirement
                    .AddAuthenticationSchemes(schemeName)
                    .Build());
        }
    }

Error message

(EventId: Exception)    => SpanId:2fe5c8a02b2ed458, TraceId:9e6f514d3e68d3e78aa9b616b9addcaa, ParentId:0000000000000000 => RequestPath:/AzureSsoService/csgqa-signin-oidc RequestId:80002255-0001-fa00-b63f-84710c7967bb
An exception was thrown attempting to execute the error handler.

System.InvalidOperationException: No authentication handler is registered for the scheme 'azuread'. The registered schemes are: abcCookies, abc, hijCookies, hij, xyzCookies, xyz. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("azuread",...)?
   at async Task<AuthenticateResult> Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, string scheme)
   at async Task<AuthenticateResult> Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator.AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
   at async Task Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at async Task Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at async Task Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.HandleException(HttpContext context, ExceptionDispatchInfo edi)

Id Web logs

No response

Relevant code snippets

See "Reproduction Steps".

Regression

No response

Expected behavior

It should use the appropriate scheme from the schemes that are registered.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions