DuendeSoftware / Support

Support for Duende Software products
20 stars 0 forks source link

No bff:logout_url is received from Duende.BFF #854

Closed acmesoft-arg closed 11 months ago

acmesoft-arg commented 1 year ago

Version: Duende.BFF 2.1.1

Blazor WASM + ASP.NET Core Hosted .NET 7

Issue: No "bff:logout_url" is received from BFF The only one "bff:" claim received from BFF is: "bff:session_expires"

(as I seen no "sid" is received (check below user claims) and no documentation from AWS cognito is mention this data)

To reproduce it use AWS cognito User Pool as Identity Provider. The following code is in Program.cs (Server side)

builder.Services.AddBff(options =>
{
    options.EnforceBffMiddleware = true;
}).AddServerSideSessions();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = "cookie";
    options.DefaultSignOutScheme = "oidc";
    options.DefaultChallengeScheme = "oidc";
})
        .AddCookie("cookie", o =>
        {
            o.Cookie.Name="__Hst-spa";
            o.Cookie.SameSite = SameSiteMode.None; //needs to change
            o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
            o.Cookie.HttpOnly = true;
        })
        .AddOpenIdConnect("oidc", options =>
        {
            options.ResponseType = OpenIdConnectResponseType.Code;
            options.MetadataAddress = builder.Configuration["Authentication:Cognito:MetadataAddress"];
            options.ClientId = builder.Configuration["Authentication:Cognito:ClientId"];
            options.ClientSecret = builder.Configuration["Authentication:Cognito:ClientSecret"];
            options.CallbackPath = builder.Configuration["Authentication:Cognito:CallbackPath"];
            options.SignedOutCallbackPath = builder.Configuration["Authentication:Cognito:SignedOutCallbackPath"];
            options.SaveTokens=true;
            options.MapInboundClaims = false;
            options.Scope.Clear();
            options.Scope.Add("openid");
            options.Scope.Add("profile");
            options.Scope.Add("email");
            options.GetClaimsFromUserInfoEndpoint=true;
        });
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
    app.UseWebAssemblyDebugging();
}
else
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseBlazorFrameworkFiles();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseBff();
app.UseAuthorization();
app.MapBffManagementEndpoints();

app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");

app.Run();

Expected behavior

Receive the logout_url and manage logout.

No output / Error has received.

Additional data: This is the output from:

@foreach (var claim in @context.User.Claims)
{
    <dt>@claim.Type</dt>
    <dd>@claim.Value</dd>
}
sub
f4989468-e081-7050-0c48-8b7e11336d7b

cognito:groups
Group1

gender
male

locale
AR

auth_time
1692904108

jti
3257ef12-1429-46aa-a5f2-d10b746c9ada

email
myemail@invalidemail.com

email_verified
true

address
{"formatted":"my house"}

profile
example_profile

cognito:username
myemail

given_name
Checho

middle_name
M

picture
http://

origin_jti
72eb548e-f3e0-4565-8353-3e276e6cda9d

token_use
id

name
Checho Jones

family_name
Jones

bff:session_expires_in
1209598
josephdecock commented 1 year ago

You're correct, the lack of a sid is the reason why you don't have a logout url. We use the session id to protect the logout endpoint, since without it, an attacker could end sessions by making cross site GET requests to the logout endpoint. Since you don't have a sid, that csrf protection isn't active. Your application can logout by redirecting to the static ~/bff/logout path.

You could create your own csrf protection of the logout endpoint that works basically the same as the sid based protection works. You would need to:

  1. At login time, create some sort of unique value to act as the the logout csrf protection token (a guid would be a great choice),
  2. Save that token as a claim,
  3. Customize the logout endpoint to check that it receives a query parameter that matches that claim, and
  4. Customize the user endpoint to generate a logout url including the query parameter.

One final note - there are a few other places where the BFF uses the sid claim, most notably server side session management. Server side sessions include their sid, and backchannel logout tokens can include a sid to identify which session to end. Just something to watch out for in the future.

josephdecock commented 1 year ago

Is anything further needed on this issue, or should we close it?

josephdecock commented 11 months ago

Closing, but feel free to reopen if necessary.