Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a 404 when accessing an [Authorize] controller when authenticated

I'm trying to implement authentication and access control with IdentityServer4 on an ASP.NET MVC Core app (.NetCore 2). While it's not the first time I implement a backend, it's the first time with .net, and I'm struggling with some things.

I've followed the instructions at https://identityserver4.readthedocs.io/en/release/quickstarts/1_client_credentials.html as well as the page before that.

I have also added the sample IdentityController as they show:

using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace leafserver.Controllers
{
    [Route("/api/identity")]
    [Authorize]
    public class IdentityController : Controller
    {
        [HttpGet]
        public IActionResult Get()
        {
            return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
        }
    }
}

There are a few differences between my implementation and their example. As far as I can see:

  • I'm serving on my local network address (192.168.1.x) instead of localhost
  • They're using a "Web Application", where I'm using a "Web Api"
  • They seem to use ControllerBase instead of Controller as a superclass
  • I'm not sure whether there's a difference between the ASP.NET MVC they use and the one I use (I'm using core, they don't seem to, but normally it should still work...)

What I noticed is the following:

  • as long as I don't put a [Authorize], all is well. I get a 200 OK with the expected result
  • when the [Authorize] annotation is there, but I use no authentication bearer token, I am redirected to the login page (which doesn't work since this is a web api, but that's a problem for later)
  • when the [Authorize] annotation is there, and I use (what I think is) a correct authentication token, I get a 404 response.

I was expecting to have a 401 response instead. Why would my routing not work because I'm using an authentication token?

Also, I'm not getting any log from the server, which doesn't help...

like image 785
aspyct Avatar asked Jan 29 '23 14:01

aspyct


2 Answers

For me the answer was setting the Authorize attribute on my controller like this

[Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]

which is outlined in the docs that leastprivilege has pointed to. https://identityserver4.readthedocs.io/en/release/topics/add_apis.html

If I just had [Authorize] then it would produce 404's

like image 70
Ryan Dobbs Avatar answered Feb 13 '23 06:02

Ryan Dobbs


Alright, I've found the problem.

In my Startup.ConfigureServices, I modified the order in which I add the services.

    // https://identityserver4.readthedocs.io/en/release/quickstarts/1_client_credentials.html
    services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddTestUsers(Config.GetTestUsers()); // TODO Remove for PROD

    // This MUST stay below the AddIdentityServer, otherwise [Authorize] will cause 404s
    services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(o =>
            {
                o.Authority = "http://localhost:5000";
                o.RequireHttpsMetadata = false; // TODO Remove for PROD
                o.ApiName = "leaf_api";
            });

If you add authentication before the identity server, then you'll get the 404s. In this order, it works just fine.

Here's the full Startup.cs file for reference:

using leafserver.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

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

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<LeafContext>(options => options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));

            services.AddMvcCore()
                    .AddAuthorization()
                    .AddJsonFormatters();

            // https://identityserver4.readthedocs.io/en/release/quickstarts/1_client_credentials.html
            services.AddIdentityServer()
                    .AddDeveloperSigningCredential()
                    .AddInMemoryApiResources(Config.GetApiResources())
                    .AddInMemoryClients(Config.GetClients())
                    .AddTestUsers(Config.GetTestUsers()); // TODO Remove for PROD

            // This MUST stay below the AddIdentityServer, otherwise [Authorize] will cause 404s
            services.AddAuthentication("Bearer")
                    .AddIdentityServerAuthentication(o =>
                    {
                        o.Authority = "http://localhost:5000";
                        o.RequireHttpsMetadata = false; // TODO Remove for PROD
                        o.ApiName = "leaf_api";
                    });

            // https://dotnetcoretutorials.com/2017/01/17/api-versioning-asp-net-core/
            services.AddApiVersioning(o =>
            {
                o.ReportApiVersions = true;
                o.AssumeDefaultVersionWhenUnspecified = true;
                o.DefaultApiVersion = new ApiVersion(1, 0);
                o.ApiVersionReader = new HeaderApiVersionReader("x-api-version");
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
                app.UseStatusCodePages();
            }

            app.UseIdentityServer();
            app.UseAuthentication();

            app.UseMvc();
        }
    }
}
like image 36
aspyct Avatar answered Feb 13 '23 06:02

aspyct