MVC Integration Testing with AuthorizeAttribute - c#

On an intranet site using windows authentication, and certain controller methods being marked with the "AuthorizeAttribute" controlling access to certain users/groups and roles, I'm trying to figure out the best way to allow "test users" to access these things.
Since <location> is off the table with MVC (security concerns), what is the best approach here?
My first thought is to implement the following:
A custom config section that essentially mirrors the <authorization> section
A custom attribute that inherits from "AuthorizeAttribute" which checks users against the custom config section
Use config transforms to remove the custom config section for QA and Release environments
Is there an easier/better way???

Update
What I originally wrote used the attribute syntax on a class or method, but if you are using MVC3 you can also use a global action filter in (global.asax.cs) so you only have to do it once.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
#if DEBUG
filters.Add(new AuthorizeAttribute() {Users="YourAccount"});
#endif
//Your other global action filters
}
Original
You could use #if DEBUG to only add the authorization to debug code.
#if DEBUG
[Authorize(Users = "YourAccount")]
#endif
The Authorize attribute allows multiple so you don't have to repeat your production authorized user list or use an #else.

Related

Rewrite URl according to Attribute

We have an ASP.NET Core Web API running on .NET 5. It has got many controllers and routes that are sometimes protected via the Authorize attribute and sometimes they are public.
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase {
[HttpGet("me")]
public IActionResult GetMyPublicInformation()
{
// code...
}
[HttpGet("me")]
[Authorize]
public IActionResult GetMyPrivateInformation()
{
// code...
}
}
Well now I would like to publish these REST routes through different HTTP Routes, depending on the Authorization requirement. For example, the route GetPublicInformation does not require authorization. That route should be available under public/user/me. Whereas the method GetMyPrivateInformation does require authorization and should be published under the route secure/user/me.
Of coure, I am aware that I can define the route manually in the HttpGet attribute (i.e. [HttpGet("public/user/me")), but - besides that I'm lazy - it would be error prone because we have the information available twice: Once with in the manual route definition (HttpGet) and once in the Authorize attribute. So if someone forgets to change one of the two attributes, we get an inconsistency.
Question: What are my options to automate this URL rewriting (I'm thinking of middleware)? Are there any drawbacks you see using this approach? I have been fighting this idea because I don't like extra magic sauce in my codebase. I prefer explicity, that's why I'm going for the manual route naming right now...
By the way: I have to take this on me because of limitations in Microsoft's MSAL library. I believe I shouldn't have to do this because we host an OpenAPI definition on which routes are and which routes aren't authorized. That should be enough in most cases.

ASP.NET Core CORS combining policies; enablecors in controller vs midleware configuration

I'm working on an ASP.NET Core project and I want to enable CORS in my application. I have started with the ASP.NET Core documentation and I'm confused why we cannot combine the two methods as we can read below:
You can apply different policies to controller/page-model/action with the [EnableCors] attribute. When the [EnableCors] attribute is applied to a controllers/page-model/action method, and CORS is enabled in middleware, both policies are applied. We recommend against combining policies. Use the [EnableCors] attribute or middleware, not both in the same app.
Why would you want to?
The result is: CORS is enabled or its not (for one resource).
You can either do this by using the Attribute-Syntax ([EnableCors]) on your controller / your action-method, or make use of the fluent-api-design like in example with
services.AddCors(options => options...);
But you still enable or do not enable the CORS for the specified resource, in one or the other way.
Which one you choose does not matter and depends on your application.
Microsofts recommendation against both approaches at once is because this is redundant and maybe will lead into confusion.

Force MVC RouteConfig Execution?

In my ASP.NET MVC website, I have code in the RouteConfig.cs file to force the URL to include "www":
using Canonicalize;
using System.Configuration;
using System.Web.Routing;
namespace MyWebsite
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
if (ConfigurationManager.AppSettings["Production"] == "true")
{
routes.Canonicalize().Www();
}
}
}
}
I host my website in Azure, which has "deployment slots." I push my code out to a "staging" slot, test, and then "swap" the "staging" slot with the "production" slot.
In the code above, you can see I'm conditionally including routes.Canonicalize().Www(); only for the production slot. This is because the staging slot uses a URL that doesn't allow "www."
The problem is that it seems like the code in the RouteConfig.cs file is only fired on the initial website load. When I load the website, RouteConfig.cs is executed, and routes.Canonicalize().Www(); is correctly excluded. When I swap the slots, the RouteConfig.cs code does not appear to be re-executed, and routes.Canonicalize().Www(); remains excluded, which is not what I want.
Is there a way I can reliably and accurately have routes.Canonicalize().Www(); included only for the production slot?
I would suggest you to use application initialization module in this scenario where you can call you function to add routes.Canonicalize().Www().
The application initialization module has been implemented and is available to use while you swap content between deployment slots. This module has also been implemented regarding all other operations in which a new worker is provisioned (such as auto scale, manual scale or Azure fabric maintenance). Namely, you can proactively perform initialization tasks before your app becomes available.
In order to enable the said module you need to create an applicationInitialization section where you shall define the url to be hit for the initialization task to begin. You have also the option to specify the hostName to be used for the warm up requests, something that may prove really helpful for debugging and monitoring purposes. If not otherwise specified, the “localhost” will be used as host name.
<system.webServer>
<applicationInitialization>
<add initializationPage="/app/initialize" hostName="warmup-requests.domain.com"/>
</applicationInitialization>
<system.webServer>
Following the above, the swap operation between deployment slots will be completed after the code under “app/initialize” url is executed.
Reference:
https://ruslany.net/2015/09/how-to-warm-up-azure-web-app-during-deployment-slots-swap/
https://feedback.azure.com/forums/169385-web-apps/suggestions/6972595-application-initialization-to-warm-up-specific-pag
Hope it helps.

.NET CORE route Api sub domain to Api controller

I have Api Controllers and MVC controllers in my .NET CORE application.
How can I route sub domain api.mysite.com to point only on Api controllers, and dashboard.mysite.com to point on Web Application all in same project?
If you want to implement this in a single ASP.NET Core application, you can do something like this:
Make Api controllers available say at path /Api. You can achieve this using routes, areas or application branches.
Use a reverse proxy which is capable of URL rewriting (e.g. IIS on Win, Nginx on Linux). Configure the reverse proxy so that the requests arriving at api.mysite.com/path are forwarded to your application as /Api/path.
A remark:
If you want to generate URLs in your Api controllers, you should remove the /Api prefix from the path to get correct URLs (and of course you have to configure your reverse proxy to append the necessary headers like X-Forwarded-Host, etc.) For this purpose you can use this simple middleware.
Update
As it was discussed in the comments, an application branch seems the best solution in this case because it enables separate pipelines for the MVC and API application parts.
Actually, it's very easy to define branches. All you need to do is to put a Map call at the beginning of your main pipeline in the Configure method of your Startup class:
public void Configure(IApplicationBuilder app)
{
app.Map("/Api", BuildApiBranch);
// middlewares for the mvc app, e.g.
app.UseStaticFiles();
// some other middlewares maybe...
app.UseMvc(...);
}
private static void BuildApiBranch(IApplicationBuilder app)
{
// middlewares for the web api...
app.UseMvc(...);
}
Now, when a request arrives and its path starts with /Api, the request gets "deflected" and goes through the branch pipeline (defined in BuildApiBranch method) instead of going through the main pipeline (defined in Configure method, following the Map call).
Some things to keep in mind:
When a request is "captured" by the branch, the prefix /Api is removed from the HttpContext.Request.Path property (and appended to HttpContext.Request.PathBase). So you need to define the API routes in the UseMvc method as if the request path had no prefix at all.
Using this code you have two separate pipelines but they share the components registered in Startup.ConfigureServices. If this is undesired, it's possible to create separate DI containers for each of the pipelines. However, this is a somewhat advanced topic.

Route Aliases in ASP.NET Web API 2

I have a Web API that allows users to access/manipulate resources that "belong" to other users. It contains many routes similar to this:
/users/{userId}/resource
I'd like a corresponding set of routes that do the same on behalf of the currently authenticated user:
/resource
Ideally I'd like to get the second set of routes working without doubling the number of actions in my controllers, but I'm struggling to find the right hook. Ideally, I'd like to add a MessageHandler (or something) that intercepts each request, checks if it matches a route, and if it doesn't, prepends "users/" + ID of the authenticated user to the route and checks again. What is the best way to accomplish this?
One constraint: I'm using attribute routing to implement the first set of routes and would ideally like to pull this off without sacraficing that.
The hook is the action selector, as you can see here: Routing and Action Selection in ASP.NET Web API.
You can implement your own action selector to achieve what you want. Here is a sample on how to do that: Magical Web API action selector. From the same page:
We will create a class that implements IActionSelector, as that would allow us to plug into the hook provided by the Web API under GlobalConfiguration.Configuration.Services.

Categories