Geborren
Geborren

Reputation: 13

Custom HandleRequirement method does not trigger

I am attempting to create a custom authorization policy for ASP.NET Core 6 MVC, but I cannot seem to get the requirement to evaluate. Here is the auth handler along with the requirement and the HandleRequirementAsync method.

The log message in

HandleRequirementAsync ("Reached this point, evaluating requirements") 

is never printed.

public class DpAuthRequirement : IAuthorizationRequirement { }

public class DpAuthHandler : AuthorizationHandler<DpAuthRequirement>
{
    private readonly ILogger<DpAuthHandler> _logger;
    private readonly site_masterContext _context;

    public DpAuthHandler(site_masterContext context, ILogger<DpAuthHandler> logger)
    {
        _context = context;
        _logger = logger;
          
        _logger.LogInformation("Created auth handler"); //this is printed in the log
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, DpAuthRequirement requirement)
    {
        _logger.LogInformation("Reached this point, evaluating requirements"); //this is NOT printed
          
        context.Fail();

        return Task.CompletedTask;
    }
}

Here is the Program.cs:

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.Services.AddAuthorization(options =>
            {
                options.AddPolicy("DpAuthRequirement", policy =>
                {
                    policy.Requirements.Add(new DpAuthRequirement());
                });
            });

        // cookies and session data
        builder.Services.AddDistributedMemoryCache();
 
        builder.Services.AddSession(options =>
            {
                //timeout currently set to 9 minutes
                options.IdleTimeout = TimeSpan.FromSeconds(520);
                options.Cookie.HttpOnly = true;
                options.Cookie.IsEssential = true;
            });

        var logger = LoggerFactory.Create(config =>
            {
                config.AddConsole();
                config.AddDebug();
                config.AddAzureWebAppDiagnostics();
            }).CreateLogger<Program>();

        builder.Services.AddDbContext<site_masterContext>(options => options.UseSqlServer(Environment.GetEnvironmentVariable("SQLCONNSTR_MASTER_DB")));

        builder.Services.AddScoped<site_masterContext>();
        builder.Services.AddScoped<IAuthorizationHandler, DpAuthHandler>();
        builder.Services.AddHttpContextAccessor();

        // logging
        #region LOGS
        if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != "Production")
        {
            builder.Logging.ClearProviders();
            builder.Logging.AddConsole();
            builder.Logging.AddDebug();
            builder.Logging.AddAzureWebAppDiagnostics();
        }
        #endregion

        JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

        builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(builder.Configuration)
            .EnableTokenAcquisitionToCallDownstreamApi()
            .AddInMemoryTokenCaches();

        builder.Services.AddControllersWithViews(options =>
            {
                var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
                options.Filters.Add(new AuthorizeFilter(policy));
            }).AddMicrosoftIdentityUI();

        var app = builder.Build();

        app.UseSession();

        string pattern = "{controller=Home}/{action=Index}/{id?}";
          
        if (!app.Environment.IsDevelopment())
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();

            app.MapControllerRoute(
              name: "default",
              pattern: pattern);
        }
        else
        {
            app.MapControllerRoute(
                   name: "default",
                   pattern: pattern).AllowAnonymous();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.Run();
    }
}

And finally, the controller has this:

[Authorize(Policy = "DpAuthRequirement")]
public class HomeController : Controller
{
    // ....
}

I am expecting the requirement to evaluate and fail. But the code is never reached and the requirement always succeeds, loading the page just fine regardless of what I try. What am I missing?

Upvotes: 0

Views: 57

Answers (1)

Md Farid Uddin Kiron
Md Farid Uddin Kiron

Reputation: 22409

I am expecting the requirement to evaluate and fail. But the code is never reached and the requirement always succeeds, loading the page just fine regardless of what I try. What am I missing?

Based on your shared code snippet and scenario I have tried to troubleshoot your implementation.

According to my investigation, it looks like you've set up most of the components correctly.

I have tried your code and it seems HandleRequirementAsync has been executed as expected.

So I have noticed you have used OpenIdConnectDefaults.AuthenticationScheme, I am not sure if your configuration is correct. I don't have the environment to verify OpenIdConnectDefaults.

Therefore, I have used builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) which is the default authentication schema.

And rest of the code I have used as as yours and I was able to execute DpAuthRequirement policy handler.

Here is my program.cs:

builder.Services.AddScoped<IAuthorizationHandler, DpAuthHandler>(); builder.Services.AddHttpContextAccessor()

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("DpAuthRequirement", policy =>
    {
        policy.Requirements.Add(new DpAuthRequirement());
    });
});

//My DbConnection

/* 
 
  My Service reference DI
 
 */



builder.Services.AddScoped<IAuthorizationHandler, DpAuthHandler>();
builder.Services.AddHttpContextAccessor();

// Setting my default authentication scheme
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(options =>
            {
                options.LoginPath = "/Account/Login";
                options.AccessDeniedPath = "/Account/AccessDenied";
            });
builder.Services.AddControllersWithViews(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
});
var app = builder.Build();

Output:

enter image description here

enter image description here

Note: I think, DpAuthRequirement has no issue, your program.cs is correct, so my concern is if you have configured your OpenIdConnectDefaults stuff accordingly. Apart from that your environment conditional (!app.Environment.IsDevelopment()) which I have get rid while I was testing might also cuase the issue . I would recommend, you to check this official document.

Upvotes: 0

Related Questions