Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty string reading Httpcontext body from x-www-form-urlencoded POST #2072

Closed
1 task done
paolo8417 opened this issue May 13, 2024 · 4 comments
Closed
1 task done
Labels

Comments

@paolo8417
Copy link

Confirm you've already contributed to this project or that you sponsor it

  • I confirm I'm a sponsor or a contributor

Version

4.x

Describe the bug

Hi,

when I try to get the raw body of a x-www-form-urlencoded POST controller anonymous action I get an empty string.

If I comment app.UseAuthentication() from Program.cs I can read the body correctly, so I think this is something related to OpenIddict.

I tried in my project both version 4.x and 5.x. I try also with a simple template app, and the behavior is the same (net 6.0).

Thank you

To reproduce

Controller:

[AllowAnonymous]
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    [HttpPost(Name = "Test")]
    public async Task<string> Test()
    {
        string rawData = null;
        using ( var stream = new StreamReader(Request.Body, Encoding.UTF8,leaveOpen:true))
        {                               
            rawData = await stream.ReadToEndAsync();                
        }  
        return rawData;
    }
}

Program.cs

using OpenIddict.Validation.AspNetCore;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenIddict()
    .AddValidation(options =>
    {
        options.SetIssuer("...");
        options.AddAudiences("...");

        options.UseIntrospection()
               .SetClientId("...")
               .SetClientSecret("...");

        options.UseSystemNetHttp();

        options.UseAspNetCore();
    });

builder.Services.AddAuthentication(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
builder.Services.AddAuthorization();


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

var app = builder.Build();

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

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

app.MapControllers();

app.Run();

Exceptions (if any)

No response

@paolo8417 paolo8417 added the bug label May 13, 2024
@kevinchalet
Copy link
Member

Hey @paolo8417,

If I comment app.UseAuthentication() from Program.cs I can read the body correctly, so I think this is something related to OpenIddict.

It is, indeed: the OpenIddict validation handler natively supports extracting access tokens from the standard access_token parameter when using POST and formURL-encoding (as defined by https://datatracker.ietf.org/doc/html/rfc6750#section-2.2). For that, it uses HttpRequest.ReadFormAsync(), which needs to consume the request stream. Since request streams are not buffered by default in ASP.NET Core, trying to re-read Request.Body a second time cannot work.

Out of curiosity, what are you trying to achieve?

Cheers.

@paolo8417
Copy link
Author

Hi Kevin,

Thank you for your reply.

I need to validate a signature based on raw formURL-encoding post for a controller action.

I wouldn't want to enable buffering by default for all controllers.

What do you think is the best solution to achieve this?

@kevinchalet
Copy link
Member

kevinchalet commented May 13, 2024

One way to solve that would be to write a tiny middleware calling context.EnableBuffering() based on the request path (and registered before app.UseAuthentication()): https://devblogs.microsoft.com/dotnet/re-reading-asp-net-core-request-bodies-with-enablebuffering/ (this way, the request stream could still be rewound from your controller).

Alternatively, if you never send the access token in the request form, you can prevent OpenIddict from calling HttpRequest.ReadFormAsync() by removing the event handler responsible for that:

services.AddOpenIddict()
    .AddValidation(options =>
    {
        options.RemoveEventHandler(OpenIddictValidationAspNetCoreHandlers.ExtractAccessTokenFromBodyForm.Descriptor);
    });

(I'm considering adding new properties in OpenIddictValidationAspNetCoreOptions and OpenIddictValidationOwinOptions to allow controlling that)

@kevinchalet
Copy link
Member

OpenIddict 5.6.0 introduced the ability to disable access token extraction from the Authorization header, the body form or the query string without having to remove the event handler. E.g:

services.AddOpenIddict()
    .AddValidation(options =>
    {
        options.UseAspNetCore()
               .DisableAccessTokenExtractionFromBodyForm();
    });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants