OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

ASP.NET Core app using Windows authentication, client does not negotiate after OPTIONS request

  • Thread starter Thread starter Mike Nicolino
  • Start date Start date
M

Mike Nicolino

Guest
I'm having an issue with an ASP.NET Core app that is using Windows authentication and CORS. Windows auth works fine for direct API calls. But the client fails to initiate negotiate after an OPTIONS request (the API returns 401 with www-authenticate Negotiate, and the client fails).

I've simplified the app down to a small sample.

Application setup:

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

        builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
        builder.Services.AddAuthorization();

        builder.Services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy", builder => builder
                .AllowAnyMethod()
                .AllowAnyHeader()
                .WithOrigins("https://<my origin>")
                .WithExposedHeaders("WWW-Authenticate")
                .AllowCredentials()
            );
        });

        builder.Services.AddControllers();
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();

        builder.WebHost.ConfigureKestrel(options =>
        {
            options.ListenAnyIP(5001, listenOptions =>
            {
                listenOptions.UseHttps("<my cert>", "<my secret>");
            });
        });
        
        var app = builder.Build();

        if (app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseMiddleware<RequestLoggingMiddleware>();
        app.UseMiddleware<ResponseLoggingMiddleware>();

        app.UseHttpsRedirection();
        app.UseRouting();

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

        app.UseCors("CorsPolicy");
        app.MapControllers();

        app.Run();
    }

Controller:

Code:
[ApiController]
[Route("[controller]")]
public class IwaController : ControllerBase
{
    private readonly ILogger<IwaController> _logger;

    public IwaController(ILogger<IwaController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    [Authorize]
    [Route("[action]")]
    public IActionResult SiteCheck()
    {
        var identity = User?.Identity;

        if (identity == null || !identity.IsAuthenticated)
        {
            _logger.LogWarning("SiteCheck: Unauthorized request: " + identity?.IsAuthenticated.ToString() ?? "Null");
            return Unauthorized();
        }

        _logger.LogInformation("SiteCheck: Authorized request: {name} - {type}", identity?.Name, identity?.AuthenticationType);
        return new JsonResult(new { identity?.Name, identity?.AuthenticationType });
    }
}

Invoking sitecheck directly yields an expected Windows auth via negotiate. Doing a redirect from '' has a success OPTIONS request (204), with apparently appropriate headers:

Code:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: https://<my origin>
Date: Thu, 27 Jun 2024 00:10:42 GMT
Server: Kestrel

But the subsequent GET doesn't do the negotiate, it just fails with 401, even though the negotiate header is present in the response:

Code:
Content-Length: 0
Date: Thu, 27 Jun 2024 00:10:42 GMT
Server: Kestrel
Www-Authenticate: Negotiate

I've tried a number of different approaches with middleware ordering, custom authorization handlers, and CORS policy, as well as a bunch time googling, in Chat GPT, and searching Stackoverflow to no avail.

Would appreciate any suggestions or ideas anyone could provide.
<p>I'm having an issue with an ASP.NET Core app that is using Windows authentication and CORS. Windows auth works fine for direct API calls. But the client fails to initiate negotiate after an <code>OPTIONS</code> request (the API returns 401 with www-authenticate Negotiate, and the client fails).</p>
<p>I've simplified the app down to a small sample.</p>
<p>Application setup:</p>
<pre><code> public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization();

builder.Services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder => builder
.AllowAnyMethod()
.AllowAnyHeader()
.WithOrigins("https://<my origin>")
.WithExposedHeaders("WWW-Authenticate")
.AllowCredentials()
);
});

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.WebHost.ConfigureKestrel(options =>
{
options.ListenAnyIP(5001, listenOptions =>
{
listenOptions.UseHttps("<my cert>", "<my secret>");
});
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseMiddleware<RequestLoggingMiddleware>();
app.UseMiddleware<ResponseLoggingMiddleware>();

app.UseHttpsRedirection();
app.UseRouting();

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

app.UseCors("CorsPolicy");
app.MapControllers();

app.Run();
}
</code></pre>
<p>Controller:</p>
<pre><code>[ApiController]
[Route("[controller]")]
public class IwaController : ControllerBase
{
private readonly ILogger<IwaController> _logger;

public IwaController(ILogger<IwaController> logger)
{
_logger = logger;
}

[HttpGet]
[Authorize]
[Route("[action]")]
public IActionResult SiteCheck()
{
var identity = User?.Identity;

if (identity == null || !identity.IsAuthenticated)
{
_logger.LogWarning("SiteCheck: Unauthorized request: " + identity?.IsAuthenticated.ToString() ?? "Null");
return Unauthorized();
}

_logger.LogInformation("SiteCheck: Authorized request: {name} - {type}", identity?.Name, identity?.AuthenticationType);
return new JsonResult(new { identity?.Name, identity?.AuthenticationType });
}
}
</code></pre>
<p>Invoking <code>sitecheck</code> directly yields an expected Windows auth via negotiate. Doing a redirect from '' has a success <code>OPTIONS</code> request (204), with apparently appropriate headers:</p>
<pre><code>Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: https://<my origin>
Date: Thu, 27 Jun 2024 00:10:42 GMT
Server: Kestrel
</code></pre>
<p>But the subsequent <code>GET</code> doesn't do the negotiate, it just fails with 401, even though the negotiate header is present in the response:</p>
<pre><code>Content-Length: 0
Date: Thu, 27 Jun 2024 00:10:42 GMT
Server: Kestrel
Www-Authenticate: Negotiate
</code></pre>
<p>I've tried a number of different approaches with middleware ordering, custom authorization handlers, and CORS policy, as well as a bunch time googling, in Chat GPT, and searching Stackoverflow to no avail.</p>
<p>Would appreciate any suggestions or ideas anyone could provide.</p>
Continue reading...
 

Latest posts

B
Replies
0
Views
1
Blundering Ecologist
B
Top