AuthorizeAttribute unit testing dependency injection - c#

I am aiming to create a custom implementation of MVC's IAuthorizationFilter by subclassing AuthorizeAttribute and overriding bool AuthorizeCore(HttpContextBase httpContext);
Being the hipster I am, I want to do this TDD style.
(Just because I said I'm a hipster doesn't mean you can navigate back. Yes, I saw that.)
Additionally, I want to inject into certain parameters of the constructor, using ninject like so.
So, my question is how do I unit test such a setup?
Here is my Attribute setup:
public class MyAuthorize : FilterAttribute {
public MyAuthorize(params string[] Activities)
{
this.RequestedActivities = Activities.ToList();
}
public IEnumerable<string> RequestedActivities { get; set; }
}
public class MyAuthorizeFilter : AuthorizeAttribute
{
private readonly IEnumerable<string> _RequestingActivities;
private readonly IUserService _UserService;
public MyAuthorizeFilter(IUserService UserService, IEnumerable<string> Activities)
{
this._RequestingActivities = Activities;
_UserService = UserService;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return (_RequestingActivities.All(c=>c == "Permitted"));
}
}
I attempted to test the void OnAuthorization(AuthorizationContext filterContext); method exposed by AuthorizeAttribute but there wasn't anything to assert against. filterContext was not altered in any noticeable way.
My next step was to create a mock class with [MyAuthorize("APermission")] on an action, then invoke that like so:
controller.ActionInvoker.InvokeAction(controller.ControllerContext, "Permitted");
But since I'm not actually using MyAuthorizeFilter it's not calling the code that actually does the authorization checks.
I honestly have no idea how to proceed.

Remember, when you unit test, you're not testing the implementation of things like attributes being hooked up and being called. You're testing the actual attribute's functionality.
So all you need to do is instantiate you MyAuthorize class, probably passing in mocked services and activities. Then you simply call the methods that will get called by the framework, and verify that the proper results are achieved.
In this case, you would probably just call MyAuthorize.OnAuthorization() passing in a mocked authorization context, and check the state of the filterContext.Response object, which will be unchanged if it succeeds and will contain an Unauthorized (401) if it fails.
It may also throw exceptions if the filterContext is null or not configured correctly.
You can look at the source code to the AuthorizeAttribute to see what it's doing.. so you know what to assert against.
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/AuthorizeAttribute.cs

Related

C# pattern to extend NuGet interface

We have a common architecture for many of our projects, and this architecture requires some amount of boilerplate that is generic for every project. I'm trying to tie all this boilerplate into a single reusable NuGet package to make maintenance easier, but am running into issues with getting the DI to work with me.
Specifically, I'm struggling with the concept of services. In the NuGet, I'll have to define basic service interfaces so I can hook some pipelines to use these services. However, every application that will be using this NuGet will need to be able to extend these services with application specific methods.
Let's go over an example with the "User authentication pipeline", which should answer common questions like "Is this user in role x" and application specific questions like "Can this user modify z based on its owner y".
First, our application layer is structured based on CQRS using a common interface, which is implemented by every Query and Command:
public interface IApplicationRequestBase<TRet> : IRequest<TRet> { //IRequest from MediatR
Task<bool> Authorize(IUserServiceBase service, IPersistenceContextBase ctx);
void Validate();
}
IUserServiceBase is an interface providing access to the current user (I'm skipping the IPersistenceContextBase, which is just an empty interface):
public interface IUserServiceBase {
string? CurrentUserExternalId { get; }
bool IsUserInRole(params string[] roleNames);
...
And in the authentication pipeline
public class RequestAuthorizationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IApplicationRequestBase<TResponse> { //MediatR IPipelineBehavior
private readonly IUserServiceBase _userService;
private readonly IPersistenceContextBase _ctx;
public RequestAuthorizationBehaviour(IUserServiceBase userService, IPersistenceContextBase ctx) {
_userService = userService;
_ctx = ctx;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) {
if (await request.Authorize(_userService, _ctx)) {
return await next();
}
throw new UnauthorizedAccessException();
}
}
}
And finally the NuGet DI definition:
public static class DependencyInjection {
public static IServiceCollection AddApplicationInfra(this IServiceCollection services) {
...
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestAuthorizationBehaviour<,>));
return services;
}
}
All well and good in the NuGet side, now the application. This approach has me trying to extend the interfaces directly, and this is the easiest way to visualize what I wish to accomplish.
The application has a bunch of app-specific authorization checks, so we have a custom interface for that:
public interface IUserService : IUserServiceBase {
public string LocalUserIdClaimKey { get; }
Guid CurrentUserLocalId { get; }
/// <summary>
/// Shortcut for checking if the user has any role allowing read access to notifications
/// </summary>
bool CurrentUserCanReadNotifications { get; }
...
The UserService class implements all the functionality required in the IUserService interface, meaning the IUserServiceBase methods as well. It is defined in a different project (Infrastructure) than the interface (Application).
public class UserService : IUserService {
private readonly IHttpContextAccessor _contextAccessor;
public UserService(IHttpContextAccessor contextAccessor) {
_contextAccessor = contextAccessor;
}
public string? CurrentUserExternalId {
get {
var user = _contextAccessor.HttpContext.User;
if (user != null) {
return user.FindFirst(JwtClaimTypes.Subject)?.Value;
}
return null;
}
}
...
And finally, in our Command, where it all should come together:
public class UpdateSubsequentTreatmentFacilitiesCommand : IApplicationRequestBase<int> {
public async Task<bool> Authorize(IUserService service, IPersistenceContext ctx) {
//Application specific authorization check
}
public void Validate() {
}
Now, here we get a build error, stating that 'UpdateSubsequentTreatmentFacilitiesCommand' does not implement interface member 'IApplicationRequestBase<int>.Authorize(IUserServiceBase, IPersistenceContextBase)'. This is probably what I'm encountering here (though I still can't figure out why exactly...).
So, to reiterate:
Goal is to package common project boilerplate to a single NuGet
We need to be able to extend the services defined in the NuGet with application specific functionality
IApplicationRequestBase defines the type of the service parameter as IUserServiceBase, but UpdateSubsequentTreatmentFacilitiesCommand tried to use IUserService. OO programming and inheritance doesn't let you change method signatures.
If you can change IApplicationRequestBase, adding a TService generic parameter will let you get around it:
public interface IApplicationRequestBase<TRet, TService> : IRequest<TRet>
where TService is IUserServiceBase
{
Task<bool> Authorize(TService service, IPersistenceContextBase ctx);
void Validate();
}
public class UpdateSubsequentTreatmentFacilitiesCommand : IApplicationRequestBase<int, IUserService>
{
public async Task<bool> Authorize(IUserService service, IPersistenceContext ctx)
{
// method body
}
// rest of class
}
However, given that IUserService is an interface, if it is the only thing that extends/implements IUserServiceBase, then it sounds like a case of overengineering. There's a saying that perfection is the enemy of good. In other words, attempting to be too generic, too reusable, where it's not actually needed, is just slowing down progress. By all means, strive to have a high quality codebase, but you also need to be pragmatic.
If other apps that use IApplicationRequestBase have their own user service, not the same IUserService as your app, then you'll need to find another approach, given that C# is a strongly typed language. You could just typecast the IUserServiceBase into an IUserService in the method body. Rather than extending the interface, you could have an extension method. If you're creative, you might think of other approaches as well.
However, looking at IUserService, my guess is that it exists only to improve performance of checking certain commonly used roles. If I'm wrong and it's about convenience and not performance, then an extension method should be sufficient. If the concern is performance, then make sure that the implementation of IsUserInRole does caching. Looking up a string still won't be as fast as returning a property's backing field. But changing your software architecture to improve performance for something you haven't profiled to confirm that it is a performance bottleneck is the definition of premature optimization. If IsUserInRole does basic caching, you'll probably find the the performance is good enough, and helper/extension methods solve whatever readability/code quality issue you're trying to solve.

How to use the same generic method for validation of different types

I am having an interface IValidator which has a generic method Validate and is intended to validate different objects across the application. For now I am validating User's profile and Login credentials. The problem is, when I try to validate profile or Login class, it always calls the method for the profile even when I try to validate Login details. Here's the code:
IValidator
public interface IValidator
{
List<Error> Validate<T>(T request);
}
UserProfileValidator
public class UserProfileValidator : IValidator
{
public List<Error> Validate<T>(T request)
{
//Code for profile validation
}
}
UserLoginValidator
public class UserLoginValidator: IValidator
{
public List<Error> Validate<T>(T request)
{
//Code for login validation
}
}
UserService
private readonly IValidator _validator;
public UserService(IValidator validator)
{
_validator = validator;
}
public async Task<Response> Login(UserDetail userDetail)
{
//this is supposed to validate login details, but validates profile instead
var errors = _validator.Validate(userDetail);
}
public async Task<Response> UpdateProfile(Profile profile)
{
var errors = _validator.Validate(profile);
}
Please guide. Thanks
I'm posting this though it may not be the solution to OP's problem.
Based on what you said you are using AutoFac.
Service:
builder.RegisterType<UserService>().As<IUserService>();
Validators:
builder.RegisterAssemblyTypes(typeof(DependencyBuilder).Assembly).Where(t => t.Name.EndsWith("Validator")).AsImplementedInterfaces().InstancePerLifetimeScope();
Looking at how you register your UserService you are not supplying a specific IValidator parameter to its constructor which I think is the reason why AutoFac keeps using the UserProfileValidator. Logically speaking how will UserService know what implementation of IValidator to use on run-time?
I often use the following to specify parameters to my constructors.
builder
.Register(r => new UserService(r.Resolve<IValidator>()))
.As<IUserService>()
.InstancePerRequest();
But the problem with this is if the DI will resolve for the IValidator it is still not specific.
I would suggest redesigning your code since I don't think your current design allows the UserService to use both UserProfileValidator and UserLoginValidator.
Probably assigning the IValidator per view model would be a better approach so that each view model has their own implementation of IValidator then you could do something like var errors = viewModel.Validate();.
You should change your interface to be:
public interface IValidator<T>
{
List<Error> Validate(T request);
}
You must be using some dependency injection registration with the default DI container or Autofac. Please provide details of how you're doing so.
Your interface is not generic, which means that your dependency injection container is registering several implementations for the same interface and when you inject it it is taking the last implementation.
Change the interface to
public interface IValidator<T>
{
List<Error> Validate(T request);
}
and inject a service IValidator<UserDetail> and another IValidator<Profile> so in essence there are different validators that use the same interface.
Using generics is ok when the implementation is generic, but in your case each validator is different therefore the DI needs to know exactly which one to use.
In autofac you should have something like
builder.RegisterType<UserLoginValidator>().As<IValidator<UserDetails>>();
builder.RegisterType<ProfileValidator>().As<IValidator<Profile>>();
Thanks all of you for the help, it did help me to solve this problem. I used Autofac's keyed services to Register both the validators as IValidator, then resolved by index as needed.
see this:
https://autofaccn.readthedocs.io/en/latest/advanced/keyed-services.html

How do you avoid lots of [FromService] parameters with ASP.NET Core dependency injection?

I have an ASP.NET Core project that uses lots of dependency injection.
The problem is that these start to stack up on my controller actions:
public async Task LoginAsync(
[FromBody] LoginModel login,
[FromServices] IConnectionMultiplexer redis,
[FromServices] ISerialiserFactory serialiser,
[FromServices] IDataService dataService,
[FromServices] ILookupNormalizer normaliser,
[FromServices] IPasswordHasher hasher,
...
I can put these in the constructor, but most methods don't use them and those that do don't always use all of them.
I can directly instantiate them, but then I lose the ability to inject them in the startup.
Is there an easier way to get at these injected services? Ideally I want to call something like:
// It turns out I need the injected serialiser
var serialiser = services.Get<ISerialiserFactory>();
Is there a way to do this already in ASP.NET Core?
As pointed in the comments, if you have so many dependencies in a single controller action it, its a very good sigh of badly abstracted code: Your controller is doing more than it should.
Ideally, the controller action should be just a few lines of code per action (rule of thumb, 10-15 lines of code). If you have more, you are probably doing to much inside it.
A controller action should only accept the input from user (form or WebApi-esque), validate it and delegate it to a service as well as handling http status codes.
i.e.
public class LoginService : ILoginService
{
public IConnectionMultiplexer redis,
public ISerialiserFactory serialiser,
public IDataService dataService,
public ILookupNormalizer normaliser,
public IPasswordHasher hasher
public LoginService(/* inject your services here */)
{
}
public async Task<bool> Login(LoginModel login)
{
// Do your logic here and perform the login
return /*true or false*/;
}
}
Then inject this into your controller or your action:
[HttpPost]
public async Task<IActionResult> LoginAsync([FromBody]LoginModel login, [FromServices]ILoginService loginService)
{
// Validate input, only rough validation. No business validation here
if(!Model.IsValid)
{
return BadRequest(Model);
}
bool success = await loginService.Login(model);
if(success)
{
return RedirectTo("Login");
}
return Unauthorized();
}
If you get more code than that, it's a code smell. Especially if you do some logic etc. Your controllers should be as thin as possible. Controllers are rather hard to test (compared to ILoginService in my example).
You should never have to call new LoginService(...) at any time (except, if you create an abstract factory).
Also you should always prefer to use constructor injection. Use [FromServices] only, when the services is required in one single action. If its required in multiple actions, always use constructor injection
public LoginController : Controller
{
public ILoginService loginService;
public LoginController(ILoginService loginService)
{
if(loginService==null)
throw new ArgumentNullException(nameof(loginService));
this.loginService = loginService
}
public async Task<IActionResult> LoginAsync([FromBody]LoginModel login)
{
// Do your stuff from above
...
bool success = await loginService.Login(login);
...
}
}
It's also no problem, if the dependencies have different lifetimes, as long as the lifetime of the main object is shorter than of it's dependencies.
i.e. if your one of the above dependencies is scoped, then your ILoginService must be scoped too. It will be disposed at the end of the request.
services.AddSingleton<ISerialiserFactory, ...>();
services.AddSingleton<IConnectionMultiplexer, ...>();
services.AddScoped<IDataService, ...>();
services.AddScoped<ILookupNormalizer, ...>();
services.AddScoped<IPasswordHasher, ...>();
services.AddScoped<ILoginService, LoginService>();
That will work fine.
services.AddSingleton<ISerialiserFactory, ...>();
services.AddSingleton<IConnectionMultiplexer, ...>();
services.AddScoped<IDataService, ...>();
services.AddScoped<ILookupNormalizer, ...>();
services.AddScoped<IPasswordHasher, ...>();
// This will create trouble
services.AddSingleton<ILoginService, LoginService>();
But this won't. Now, ILoginService will be singleton, but it's dependencies will get disposed after the first request. Subsequent request will triggern an exception when calling IDataService or IPasswordHasher... "xyz has been disposed.".

How do I apply AutoFixture customizations to anything inheriting from a base class?

In an attempt to DRY up my unit tests, I'm trying to use AutoFixture as an IoC container to instantiate my system under test (SUT), which in this particular case are ASP.NET MVC Controllers. Therefore, I want to customize AutoFixture to create controllers without auto-properties.
I tried adding a customization for ControllerBase, but it doesn't seem to work for subclasses of ControllerBase.
fixture.Customize<ControllerBase>(c => c.OmitAutoProperties());
Here's an example of the test I want to be able to write:
[Theory, AutoFixtureData]
public void ControllerTest(AccountController controller) {
Assert.Equal(default(UrlHelper), controller.Url);
}
Naturally, it works if I manually add one customization for each specific controller in my project, but who wants to do that? Is there a better way?
The following Customization passes the above test, and does what you seem to ask
public class MvcCostumization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new FilteringSpecimenBuilder(
new MethodInvoker(new ModestConstructorQuery()),
new ControllerSpecification()));
}
private class ControllerSpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
var t = request as Type;
if (t == null)
return false;
return typeof(ControllerBase).IsAssignableFrom(t);
}
}
}
However, that disables all properties of all MVC Controllers, including User, HttpContext, ModelState, Request, Response, etc. You might need those in unit tests, so are you sure you want to do that?
I'll be the first person to agree that the MVC Controller base class is one huge SRP violation, but it's a class which is given to us, so there's nothing we can do about except trying to make the best of it.
Usually, you only need to twist it a little to make AutoFixture fill most of the properties automatically.
In MVC 3 projects, this, combined with the AutoMoq extension, is sufficient to create Controller instances:
fixture.Customize<ModelBindingContext>(c => c
.Without(x => x.Model)
.Without(x => x.ModelType));
fixture.Inject(CultureInfo.CurrentCulture);

Why is User (as in User.Identity.Name) null in my abstract base controller?

I was asking a related question but messed the title up and no-one would understand it. Since I am able now to ask the question more precisely, I decided to reformulate it in a new question and close the old one. Sorry for that.
So what I want to do is passing data (my custom user's nickname as stored in the db) to the LoginUserControl. This login gets rendered from the master page via Html.RenderPartial(), so what I really need to do is making sure that, say ViewData["UserNickname"] is present on every call. But I don't want to populate ViewData["UserNickname"] in each and every action of every controller, so I decided to use this approach and create an abstract base controller which will do the work for me, like so:
public abstract class ApplicationController : Controller
{
private IUserRepository _repUser;
public ApplicationController()
{
_repUser = RepositoryFactory.getUserRepository();
var loggedInUser = _repUser.FindById(User.Identity.Name); //Problem!
ViewData["LoggedInUser"] = loggedInUser;
}
}
This way, whatever my deriving Controller does, the user information will already be present.
So far, so good. Now for the problem:
I can't call User.Identity.Name because User is already null. This is not the case in all of my deriving controllers, so this is specific for the abstract base controller.
I am setting the User.Identity.Name via FormsAuthentication at another place in the code, but I think this can't be the problem - afaik User.Identity.Name can be null, but not User itself.
It looks to me like the HttpContext is not available (since also null ;-) and that I am missing a simple yet important point here. Can anyone give me some hints? I would really appreciate it.
The answer to this problem is actually quite simple. I can't execute the code from within the constructor for reasons pointed out by Raimond, but I can do it outside the constructor.
So what I did was overriding onActionExecuting() in the base controller class (I created a custom Attribute for it, but just overriding the method should also work) and then do my user lookup from there.
Now it works as expected and I have no repeated code.
The User property is not assigned until after the Controller has been instantiated, but you can gain early access from your constructor with:
System.Web.HttpContext.Current.User
My guess would be that the Controller's base constructor is not filling in the User, but that it is only known later when the ControllerContext is set for the Controller. You should check this in the documentation about the lifecycle of an MVC application, (the one here will probably do, although it might be a bit out of date since it's for the preview version), or just check the source code of MVC.
from the code that I have of MVC (also a preview version, but that should be fine):
(In Controller)
public IPrincipal User {
get {
return HttpContext == null ? null : HttpContext.User;
}
}
...
public HttpContextBase HttpContext {
get {
return ControllerContext == null ? null : ControllerContext.HttpContext;
}
}
I don't see en an implementation of a default constructor in the code.
That would prove that the ControllerContext is null at the time of construction.
So you should execute your code somewhere else.
Can you grab this using something like:
HttpContext currentContext = HttpContext.Current;
string userName = currentContext.User.Identity.Name;
Or is the HttpContext always empty??
Could you set the httpContext through the constructor of the abstract class? and use it this way?
Thanks Raimond. I was too tired to see the obvious.
#Keeney: Yes the context is always null. Raimond pointed out why. Thanks anyway, I didn't see why too :-)
My current working solution (albeit not what I wanted) is a Attribute that I use to decorate all my controller actions. Here is the implementation:
public class MasterPageDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
IUserRepository _repUser = RepositoryFactory.getUserRepository();
IPrincipal siteUser = filterContext.Controller.ControllerContext.HttpContext.User;
User loggedInUser = null;
if (siteUser == null || siteUser.Identity.Name == null)
{
//do nothing
}
else
{
loggedInUser = _repUser.findUserById(siteUser.Identity.Name);
}
filterContext.Controller.ViewData["LoggedInUser"] = loggedInUser ?? new User { Nickname = "Guest" };
}
}
I will be looking into how to get that code executed in a way that follows the DRY principle, since using attributes for that definitely means repeating oneself. Maybe some sort of interceptor (interesting idea) or hook might help.
Cheers for that.
I am doing this in a basecontroller implementation and it works as expected.
public abstract class BaseController : Controller
{
public bool LoggedOn
{
get { return User.Identity.IsAuthenticated; }
}
}
This always returns true or false for me so User != null
to Masterfu:
I did something similiar with your help, wish that can help latter visitors.
In my case, i need to create reposiotry of controllers for different users, yet in the constructor of controllers, (principal)User is not ready. So i created a attribute for controllers:
[CreateRepositoryByUser]
public class MFCController : Controller
{
protected MFCRepository _repository
{
get { return ViewData["repository"] as MFCRepository; }
}
...
the _repository, indeed, is not a private variable of controller, but somethign create by the attribute:
public class CreateRepositoryByUser : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
CreateRepository(filterContext);
}
public static void CreateRepository(ActionExecutingContext filterContext)
{
if (filterContext.Controller.ViewData["repository"] == null)
{
filterContext.Controller.ViewData["repository"] =
MFCRepository.CreateMFCRepository(filterContext.Controller.ControllerContext.HttpContext.User);
}
}
}
I put codes of creating the repository in a seperate method, in case of that other attributes may want to use (principal)User before this attribute being triggered.
Calling from a constructor is too soon in the MVC pipeline.
Moving code to OnAuthorization, you get authorized user in a parameter. Worked for me!
From your example I would do something like this:
public abstract class ApplicationController : Controller {
private IUserRepository _repUser;
protected override void OnAuthorization(AuthorizationContext filterContext)
{
_repUser = RepositoryFactory.getUserRepository();
var loggedInUser = _repUser.FindById(filterContext.HttpContext.User.Identity.Name); //Problem!
ViewData["LoggedInUser"] = loggedInUser;
}
}
Inject IPrincipal if you need User in the constructor.
// startup.cs
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Then add as IPrincipal in your constructor. Note that it is guaranteed to be ClaimsPrincipal with ASPNET - because that's what HttpContext.User is.
Similar question
Select Project -> press F4 -> anonymous login -> false | windows authentication - > True

Categories

Resources