0
votes

I wrote a custom auth handler for a web API in .net core 3.0 following this tutorial by Jason Watmore. The Authorize attribute works great IIS express. However, when I publish the code to Azure Web App the Authorize attribute does not fire. There is no authentication challenge and data is returned without authentication.

Azure Authentication Authorization Settings enter image description here

Here is the custom BasicAuthenticationHandler

public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
    {
        private readonly IAPIRepo _apiRepo;

        public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
                                            ILoggerFactory logger, UrlEncoder encoder, 
                                             ISystemClock clock,
                                              IAPIRepo apiRepo): base(options, logger, encoder, clock)
        {
            _apiRepo = apiRepo;
        }
        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            //throw new NotImplementedException();
            if (!Request.Headers.ContainsKey("Authorization"))
                return AuthenticateResult.Fail("Missing Authorization Header");
            User user = null;
            try
            {
                var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
                var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
                var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
                var username = credentials[0];
                var password = credentials[1];
                user = _apiRepo.Authenticate(username, password);
            }
            catch
            {
                return AuthenticateResult.Fail("Invalid Authorization Header");
            }

            if (user == null)
                return AuthenticateResult.Fail("Invalid Username or Password");

            var claims = new[] {
                new Claim(ClaimTypes.NameIdentifier, user.User_Id.ToString()),
                new Claim(ClaimTypes.Name, user.UserName),
            };
            var identity = new ClaimsIdentity(claims, Scheme.Name);
            var principal = new ClaimsPrincipal(identity);
            var ticket = new AuthenticationTicket(principal, Scheme.Name);

            return AuthenticateResult.Success(ticket);
        }
    }

Startup.cs

  services.AddScoped<IAPIRepo, APIRepo>();

            services.AddAuthentication("BasicAuthentication")
                .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {

        app.UseRouting();

        app.UseAuthentication();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }

Edit: Difference between .net core 2.2 and 3.1. Changing the run time to 3.1 fixed the issue

enter image description here

1
Did you try turning off the app service auth?David C
@DavidC799 Thanks for your response. Yes, I have tried and restarted the app. No luck.salli
I'm putting together a test harness of a basic REST API and using that tutorial. One thing I notice though is that the tutorial is for 3.1 and you say you're using 3.0. Is it possible that something in the article is newer than what you're using?David C
I think you are right. That fixed it!! I would like to know what it was. I compared the BasicAuthenticationHandler code between 2.2 and 3.1 and it is exactly the same. The only real changes are in the statup.cs. I updated the original question. I would still like to know which part broke the authorization. @DavidC799 please post it as answer so i can accept it.salli
I deployed it using FTP. Make sure you are publishing release code only. When you first create the site you have to create the .Net Core 3.0 (Current). Later, you can change it to 3.1 under configuration > general settings.salli

1 Answers

1
votes

It looks like you are using the Startup.cs of .NET Core 3.0 instead of 3.1 like the article is using.