Skip to content

[Question] A way to completely disable authentication on a method #39019

@Trokkin

Description

@Trokkin

Summary

I need a way to disable authentication completely so no User would be present in method's context.

I made a solution but I doubt if it is good enough.

Details

I have a method with custom authentication based on request parameters, so I need its context to be free of authenticated users before I call my authentication, or it will break. My application has cookie and JWT authentication method, and user will be authenticated if a token or cookie would be attached to the request if I'm using plain [Authorize] + [AllowAnonymous].

Solution

My solution was to create custom AuthenticationScheme that would fail to authorize anything, then use it as the only one for my method. A custom AuthorizationPolicy was required to do so.

Question is, is there a better way to solve my problem, and does this approach have any critical issues?

    public class AlwaysFailRequirement : IAuthorizationRequirement {}

    public class AlwaysFailAuthorizationHandler : AuthorizationHandler<AlwaysFailRequirement> {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AlwaysFailRequirement requirement) {
            context.Fail();
            return Task.CompletedTask;
        }
    }

    public class AlwaysFailAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions> {
        public AlwaysFailAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) {
        }

        protected override Task<AuthenticateResult> HandleAuthenticateAsync() {
            return Task.FromResult(AuthenticateResult.Fail("Blocking Authentication is called"));
        }
    }

    public static class AlwaysFailAuthExtension {
        public const string AuthenticationScheme = "SchemeAlwaysFail";
        public const string AuthorizationPolicy = "PolicyAlwaysFail";

        // Is called on initialization
        public static IServiceCollection AddAlwaysFailingAuthPolicy(this IServiceCollection services) {
            services.AddAuthentication().AddScheme<AuthenticationSchemeOptions, AlwaysFailAuthenticationHandler>(AuthenticationScheme, null, authenticationScheme => {});
            services.AddAuthorization(options => options.AddPolicy(AuthorizationPolicy,
                    policy => {
                        policy.AuthenticationSchemes = new[] { AuthenticationScheme };
                        policy.AddRequirements(new AlwaysFailRequirement());
                    }));
            services.AddScoped<IAuthorizationHandler, AlwaysFailAuthorizationHandler>();
            return services;
        }
    }

[ApiController]
[Authorize(Policy = AlwaysFailAuthExtension.AuthorizationPolicy)]
public class MyAuthenticationController : ControllerBase {
    // ...
    [AllowAnonymous]
    [HttpPost]
    public IActionResult Authenticate( ... ) {
        //if (this.HttpContext.User != null) throw "User already logged";
        // ...
    }
    // ...
}

Metadata

Metadata

Assignees

Labels

area-authIncludes: Authn, Authz, OAuth, OIDC, Bearerdesign-proposalThis issue represents a design proposal for a different issue, linked in the description

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions