Git Product home page Git Product logo

Comments (14)

leastprivilege avatar leastprivilege commented on July 20, 2024 2

I understand this disables the Anti Forgery Check.

As I said - you can decorate your API controller individually with [BffLocalApi].

I will write the sample request down, but since this is a pretty unusual scenario, it will have to go to backlog for now.

from bff.

brockallen avatar brockallen commented on July 20, 2024

Is there anything in the BFF host logs that explains the 401?

from bff.

rahul7720 avatar rahul7720 commented on July 20, 2024

As I mentioned below there is no dedicated IDS4 host or BFF host, but the Blazor Server app host. I have set the Serilog log level to .MinimumLevel.Override("Duende.Bff", LogEventLevel.Verbose) and navigated to the controller from the browser.

Below is the only information is written to the output console:
crbug/1173575, non-JS module files deprecated.

Note: when app.UseBff(); is commented, then the above information is not written to the console.

The Startup Class (Blazor Host) :

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddBff().AddServerSideSessions();
            services.AddControllersWithViews();
            services.AddRazorPages();

            var builder = services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
                options.EmitStaticAudienceClaim = true;
            })
                .AddTestUsers(TestUsers.Users);

            builder.AddInMemoryIdentityResources(Resources.Identity);
            builder.AddInMemoryApiScopes(Resources.ApiScopes);
            builder.AddInMemoryApiResources(Resources.ApiResources);
            builder.AddInMemoryClients(Clients.List);
            builder.AddJwtBearerClientAuthentication();

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "cookie";
                options.DefaultChallengeScheme = "oidc";
                options.DefaultSignOutScheme = "oidc";
            })
            .AddCookie("cookie", options =>
            {
                options.Cookie.Name = "__Host-blazor";
                options.Cookie.SameSite = SameSiteMode.Strict;
            })
             .AddOpenIdConnect("Google", "Sign-in with Google", options =>
             {
                 options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                 options.ForwardSignOut = IdentityServerConstants.DefaultCookieAuthenticationScheme;

                 options.Authority = "https://accounts.google.com/";
                 options.ClientId = "708778530804-rhu8gc4kged3he14tbmonhmhe7a43hlp.apps.googleusercontent.com";
                 options.CallbackPath = "/signin-google";
                 options.Scope.Add("email");
             })
            .AddOpenIdConnect("oidc", options =>
            {
                options.Authority = "https://localhost:44304";
                options.ClientId = "interactive.confidential";
                options.ClientSecret = "secret";
                options.ResponseType = "code";
                options.ResponseMode = "query";

                options.MapInboundClaims = false;
                options.GetClaimsFromUserInfoEndpoint = true;
                options.SaveTokens = true;

                options.Scope.Clear();
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Scope.Add("api");
                options.Scope.Add("offline_access");
            });

        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseSerilogRequestLogging();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseWebAssemblyDebugging();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseBlazorFrameworkFiles();
            app.UseStaticFiles();
            app.UseRouting();


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

            app.UseEndpoints(endpoints =>
            {

                endpoints.MapBffManagementEndpoints();
                endpoints.MapRazorPages();
                endpoints.MapControllers()
                    .RequireAuthorization()
                    .AsLocalBffApiEndpoint();



                endpoints.MapRemoteBffApiEndpoint("/remote", "https://localhost:44304/api/test")
                    .RequireAccessToken();
                endpoints.MapFallbackToFile("index.html");
            });
        }
    }

from bff.

leastprivilege avatar leastprivilege commented on July 20, 2024

Are you sure you want to mix Blazor, BFF and IdentityServer in the same host?

This is def. not how we anticipated how BFF will be used - and we have not tested for it either.

What's the use case?

...also - do you send the antiforgery header when calling the controller?

from bff.

rahul7720 avatar rahul7720 commented on July 20, 2024

I'm upgrading (rebuilding) a Dotnet 4.6 Webapi LOB application to the latest Dotnet Core (6 Preview 4) with small architectural changes.

Legacy App
FrontEnd: WPF Desktop Application
Backend: Asp.Net WebAPI
Authentication: JWT token-based authentication (Owin, OAuth, Thinktecture.IdentityModel on the single host)

New Application
Frontend: Blazor.Client (WASM - Asp.Net Core Hosted)
Backend: Blazor.Server (Resource Server + Identity Server/BFF)
Authentication: IdentityServer 4 BFF (SPA Blazor)

The new application will replace the WPF client with the Blazor WASM. So my plan is to build a Blazor Wasm (Asp.Net Core hosted ) application, where the server app serves as a resource server and the authentication server.

I prefer to combine the resource server and the authentication server into a single host to keep the existing architecture as it is and for maintainability reasons. Is there any drawback to this approach?

Note:
The anti-forgery header is not included in the header, as the call was made from the browser anonymously.
Use case:
To display the login page to users (E.g AccountController/Login) anonymously using [AllowAnonymous] Attribute

from bff.

leastprivilege avatar leastprivilege commented on July 20, 2024

OK - as I said we haven't tested this - but could work. Let us know if you run into problems.

The antiforgery header is required for security reasons - see
https://docs.duendesoftware.com/identityserver/v5/bff/apis/local/

from bff.

rahul7720 avatar rahul7720 commented on July 20, 2024

I tried to access the MVC controller (..Account/Login) using postman with an anti-forgery header and it works.
The Blazor client application also adds an anti-forgery header to the calls made directly from the blazor client.

Problem
The blazor app and the identity server shares the same root address which is https://localhost:44304 since both are hosted in the same server app.
When the Login link is clicked from the client it redirects to the URL https://localhost:44304/Account/Login which is served by the MVC controller, and it returns 401. The AccountController decorated with [AllowAnonymous] attribute and the anti-forgery header is not set since it's a browser redirect.

As per my understanding anti-forgery header is not necessary when redirecting to the AccountController, as it's the same as calling https://demo.duendesoftware.com/Account/Login. It seems adding app.UseBff(); restricts the anonymous access to the AccountController.

I understand this scenario is not tested, but what would be the possible solution to overcome this situation.
Is there any way to disable the anti-forgery header requirement for the AccountController ?

from bff.

leastprivilege avatar leastprivilege commented on July 20, 2024

right - so the AsLocalBffEndpoint extensions makes the assumption that you are decorating API endpoints - but you are also adding this to your UI endpoints. So I would remove this extension to see if that brings you further.

You can then afterwards decorate individual API controllers with the [BffLocalApi] attribute.

The names will change soon - but let me know if this works.

from bff.

rahul7720 avatar rahul7720 commented on July 20, 2024

I have commented on the .AsLocalBffApiEndpoint extension, and now the controllers decorated with [AllowAnonymous] can be accessed without any issues. I understand this disables the Anti Forgery Check.

Highly appreciated it if you could create a sample project for the scenario mention:
A Blazor Asp.net hosted where the server app includes the IdentityServer and the BFF endpoint.

from bff.

leastprivilege avatar leastprivilege commented on July 20, 2024

After discussing this internally - we came to the conclusion that we do not want to encourage this setup.

If there is only a single host in total, you do not need IdentityServer, and if you plan for more clients, IdentityServer should be in a separate host.

from bff.

rahul7720 avatar rahul7720 commented on July 20, 2024

Is there any specific reason to have a separate host for the identity server? Consider single host (Asp.net core Web API) and multiple clients scenario (Blazor Client, WPF Client, Mobile Client), so a single server app fulfils all the needs. This is very common for ERP & Business applications.

Diagram (1)

from bff.

brockallen avatar brockallen commented on July 20, 2024

That's a very simple picture and that would make you think the solution should also be simple, but if you think through the detail of everything that's actually exposed from your IdentityServer+API host, and all the interactions each of those inbound connections expect, and what's needed to secure each of those pieces (authenticate and mitigate against attacks), then you'll start to come to the realization that it's complex, and complexity is the enemy of security. It's far easier to split discrete pieces into their own hosts for separation of concerns and isolation of how each piece needs to be secured. I understand the desire to have a single host for all of these things, but it also doesn't help that ASP.NET Core doesn't allow proper DI/middleware isolation with a single host.

Given what I said above, our BFF library was not designed for this scenario (mainly you'd be missing the anti-forgery feature). What you're asking IS possible, you'd just need to tap into the primitives from ASP.NET Core to juggle the requirements you have. If you're interested in consulting services to help you with this, then let us know.

from bff.

rahul7720 avatar rahul7720 commented on July 20, 2024

Understood from the security perspective. When a business application needs to be hosted in Azure App Service, two different instances need to be run. From a maintenance perspective, this will be a hassle. Is there any way to logically seperate the functionality under the single deployment?

from bff.

github-actions avatar github-actions commented on July 20, 2024

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue.

from bff.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.