Question Asp.Net Core Web API - BASIC Authentication Problem?

raysefo

Well-known member
Joined
Feb 22, 2019
Messages
361
Programming Experience
10+
Hello there,

I implemented a basic authentication handler. I debugged it, and even though it enters AuthenticateResult.Fail, I get a response OK from the service. Where is the problem?

Handler:
     public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
         {
             private readonly IUserValidate _userValidate;
             public BasicAuthenticationHandler(
                 IOptionsMonitor<AuthenticationSchemeOptions> options,
                 ILoggerFactory logger,
                 UrlEncoder encoder,
                 ISystemClock clock, IUserValidate userValidate) :
                 base(options, logger, encoder, clock)
             {
                 _userValidate = userValidate;
             }
        
             protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
             {
                 Response.Headers.Add("WWW-Authenticate", "BASIC");
        
                 if (!Request.Headers.ContainsKey("Authorization"))
                 {
                     return await Task.FromResult(AuthenticateResult.Fail("Authorization header missing."));
                 }
        
                 // Get authorization key
                 var authorizationHeader = Request.Headers["Authorization"].ToString();
                 var authHeaderRegex = new Regex(@"BASIC (.*)");
        
                 if (!authHeaderRegex.IsMatch(authorizationHeader))
                 {
                     return await Task.FromResult(AuthenticateResult.Fail("Authorization code not formatted properly."));
                 }
        
                 var authBase64 = Encoding.UTF8.GetString(Convert.FromBase64String(authHeaderRegex.Replace(authorizationHeader, "$1")));
                 var authSplit = authBase64.Split(Convert.ToChar(":"), 2);
                 var authUsername = authSplit[0];
                 var authPassword = authSplit.Length > 1 ? authSplit[1] : throw new Exception("Unable to get password");
        
                 if (!_userValidate.Login(authUsername, authPassword))
                 {
                     return await Task.FromResult(AuthenticateResult.Fail("The username or password is not correct."));
                 }
        
                 var claims = new[] { new Claim("name", authUsername), new Claim(ClaimTypes.Role, "Admin") };
                 var identity = new ClaimsIdentity(claims, "BASIC");
                 var claimsPrincipal = new ClaimsPrincipal(identity);
        
                 return await Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal, Scheme.Name)));
             }
        
         }

Program.cs:
    using Microsoft.AspNetCore.Authentication;
     using Microsoft.EntityFrameworkCore;
     using OyunPalasGame.Data;
     using OyunPalasGame.Services;
     using OyunPalasGame.Services.Handlers;
     using OyunPalasGame.Services.Mapping;
        
     var builder = WebApplication.CreateBuilder(args);
        
     // Add services to the container.
     builder.Services.AddControllers();
     builder.Services.AddDbContext<OyunPalasDbContext>(
         options => options.UseSqlServer("name=ConnectionStrings:OyunPalasDbContext"));
     builder.Services.AddTransient<IOyunPalasServices,OyunPalasServices>().AddTransient<UnitOfWork>();
        
     builder.Services.AddTransient<IUserValidate, UserValidate>();
        
     builder.Services.AddAuthentication("BasicAuthentication").
         AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>
             ("BasicAuthentication", null);
        
     builder.Services.AddAutoMapper(typeof(MappingProfile).Assembly);
     // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
     builder.Services.AddEndpointsApiExplorer();
     builder.Services.AddSwaggerGen();
        
     var app = builder.Build();
        
     // Configure the HTTP request pipeline.
     if (app.Environment.IsDevelopment())
     {
         app.UseSwagger();
         app.UseSwaggerUI();
     }
        
     app.UseRouting();
        
     //app.UseHttpsRedirection();
        
     app.UseAuthentication();
     app.UseAuthorization();
        
     app.MapControllers();
        
     app.Run();

I tried without adding the Authorization header in the Postman and I was supposed to get 401 but the service returned 200 OK. (I put [Authorize] to the controller)
 
C#:
var authHeaderRegex = new Regex(@"BASIC (.*)");

Careful; that will do a case sensitive match for the word BASIC at the start of the string, but auth scheme names are supposed to be case insensitive
 
Back
Top Bottom