Asp.Net Web Api and Autofac with Custom Authorisation attribute issue (property injection) - asp.net-web-api2

I am using Autofac to inject all my project dependencies which is working great. Now I have added a Custom Authorization attribute (I don't need very complex functionality like OWIN and Identity stuff). The custom authorization attribute has dependency to data layer and therefore I am trying to inject it as a property injection. However the property is always Null. The code is below:
public class CustomAuthorizationFilterAttribute : AuthorizeAttribute, IAutofacAuthorizationFilter
{
public IAuthorisationHelper AuthorisationHelper { get; set; }
public override void OnAuthorization(HttpActionContext actionContext)
{
**... removed for brevity**
**// TODO: this should be injected by autofac and is always null??**
if (AuthorisationHelper.IsValidUser(username, password, out roleOfUser))
{
var principal =
new GenericPrincipal((new GenericIdentity(username)),
(new[] { roleOfUser }));
Thread.CurrentPrincipal = principal;
return;
}
... removed for brevity
}
}
Code that injects the AuthorizationHelper:
public static IContainer Container()
{
var builder = new ContainerBuilder();
var assemblies = new List<Assembly>();
assemblies.Add(Assembly.Load("Kids.Math.Interfaces"));
assemblies.Add(Assembly.Load("Kids.Math.Data"));
assemblies.Add(Assembly.Load("Kids.Math.Business"));
assemblies.Add(Assembly.Load("Kids.Math.ImportExport"));
assemblies.Add(Assembly.Load("Kids.Math.Common"));
assemblies.Add(Assembly.Load("Kids.Math.Api"));
builder.RegisterAssemblyTypes(assemblies.ToArray()).
AsImplementedInterfaces();
builder.RegisterType(typeof(MathContext)).As(typeof (DbContext)).InstancePerRequest();
// Register web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// TODO: this is not working, also this should be generic to register it for all controllers
// inject the authorisation filter
builder.RegisterType<AuthorisationHelper>().As<IAuthorisationHelper>();
builder.Register(c => new CustomAuthorizationFilterAttribute()).PropertiesAutowired()
.AsWebApiAuthorizationFilterFor<QuestionsImportController>()
.InstancePerRequest();
// Set the dependency resolver to be Autofac.
var container = builder.Build();
return container;
}
Attribute is registered in FilterConfig as
filters.Add(new CustomAuthorizationFilterAttribute());
All the wiring up works but AuthorisationHelper is always null.
Any comments will be appreciated.

Aren't you missing some key registration steps here? Refer to the Autofac doco
// OPTIONAL: Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
// Set the dependency resolver to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
EDIT: After being told that the configuration has been setup correctly, have you tried registering your filter like this?
builder.RegisterType<CustomAuthorizationFilterAttribute>().PropertiesAutowired()
.AsWebApiAuthorizationFilterFor<QuestionsImportController>()
.InstancePerRequest();

seems like this is a known bug in autofac:
https://code.google.com/p/autofac/issues/detail?id=289

Related

How to conditionally disable Application Insights in ASP.NET Core?

I'm trying to avoid the service locator pattern in ASP.NET Core when conditionally including Application Insights in my ASP.NET Core application, the reason for this is I want to completely disable Applications Insights during development.
Service locator pattern (not recommended)
The most basic way of doing this is to service locate a IOptions setting in ConfigureServices() after building a service provider using the BuildServiceProvider() method on the IServiceCollection
Example of (not recommended!) service locator pattern:
public void ConfigureService(IServiceCollection services)
{
// Configure the services
services.Configure<AppSettings>(configuration.GetSection(nameof(AppSettings)));
// Build an intermediate service provider
var sp = services.BuildServiceProvider();
// Resolve the settings from the service provider;
var appSettings = sp.GetRequiredService<AppSettings>();
// Conditionally include the service using the settings
if (appSettings.EnableApplicationInsights) {
services.AddApplicationInsightsTelemetry();
}
}
This is not a recommended pattern as it results in an additional copy of singleton services being created. But we can be sure Application Insights is completely disabled in the application, in fact it's not even included in the DI container.
Better pattern #1
A much better way of resolving classes that are dependent on other services is to use the AddXXX overload that provides you with the IServiceProvider. This way you do not need to instantiate an intermediate service provider.
The following samples show how you can use this overload in AddSingleton/AddTransient methods.
services.AddSingleton(serviceProvider =>
{
var settings = serviceProvider.GetRequiredService<AppSettings>();
var fooService = new FooService();
fooService.Enable = settings.EnableFooService
return fooService;
});
services.AddTransient(serviceProvider =>
{
var settings = serviceProvider.GetRequiredService<AppSettings>();
var barService = new BarService();
barService.Enable = settings.EnableBarService
return barService;
});
The overload with IServiceProvider is available for i.e. AddSingleton, AddScoped, AddTransient. This pattern works great and is simple to implement, but often services have AddFoo() methods that do not provide this overload, i.e. AddApplicationInsightsTelemetry, AddCors, AddAuthentication, AddAuthorization...
I got inspiration from Ehsan Mirsaeedi answer:
https://stackoverflow.com/a/56278027/294242
Better pattern #2
We can implement the IConfigureOptions<TOptions> interface, register our configuration class in the
ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<ApplicationInsightsServiceOptions>, ConfigureApplicationInsightsServiceOptions>();
services.AddApplicationInsightsTelemetry();
}
public class ConfigureApplicationInsightsServiceOptions : IConfigureOptions<ApplicationInsightsServiceOptions>
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public ConfigureApplicationInsightsServiceOptions(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
public void Configure(ApplicationInsightsServiceOptions options)
{
using var scope = _serviceScopeFactory.CreateScope();
var provider = scope.ServiceProvider;
var settings = provider.GetRequiredService<AppSettings>();
if (!settings.EnableTracking)
{
options.EnableQuickPulseMetricStream = false;
options.EnablePerformanceCounterCollectionModule = false;
options.EnableAppServicesHeartbeatTelemetryModule = false;
options.EnableAzureInstanceMetadataTelemetryModule = false;
options.EnableDependencyTrackingTelemetryModule = false;
options.EnableEventCounterCollectionModule = false;
options.EnableAdaptiveSampling = false;
options.EnableDebugLogger = false;
options.EnableHeartbeat = false;
options.EnableRequestTrackingTelemetryModule = false;
options.EnableAuthenticationTrackingJavaScript = false;
options.EnableDiagnosticsTelemetryModule = false;
}
}
}
I'm currently evaluating this pattern but i'm not sure Application Insights is completely disabled in my application.
I got inspiration from:
https://andrewlock.net/access-services-inside-options-and-startup-using-configureoptions/#the-new-improved-answer
In the basic example, there is no need to build a service provider. It is even advised against in most documentation. The desired settings can be extracted directly from configuration.
public void ConfigureService(IServiceCollection services) {
var section = configuration.GetSection(nameof(AppSettings));
// Configure the services for IOptions injection
services.Configure<AppSettings>(section);
// Extract the settings from configuration explicitly as needed
AppSettings appSettings = section.Get<AppSettings>();
// Conditionally include the service using the settings
if (appSettings.EnableApplicationInsights) {
services.AddApplicationInsightsTelemetry();
}
//...
}
There really is no need to involve dependent classes or use a custom IConfigureOptions<TOptions> to satisfy the desired conditional in Startup
Reference: Configuration in ASP.NET Core - Bind to an object graph

How to correctly get dependent scoped services from ISecurityTokenValidator

In my asp.net core 2.0 web app, I've got a custom ISecurityTokenValidator which validates tokens.
It depends on a repository to do a db lookup - the repository itself is setup as a scoped dependency:
services.AddScoped<IMyRepository>(MyRepository);
Now the funkiness comes about because of the way the ISecurityTokenValidator is setup.
It's added in ConfigureServices:
.AddJwtBearer(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new MyTokenValidator(services.BuildServiceProvider()));
})
This is how it looks:
public class MyTokenValidator : ISecurityTokenValidator
{
private readonly IServiceProvider _serviceProvider;
public MyTokenValidator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public bool CanReadToken(string securityToken) => true;
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters,
out SecurityToken validatedToken)
{
var serviceScopeFactory = _serviceProvider.GetRequiredService<IServiceScopeFactory>();
using (var scope = serviceScopeFactory.CreateScope())
{
var myRepository = scope.ServiceProvider.GetService<IMyRepository>();
var principalFactory = scope.ServiceProvider.GetService<IUserClaimsPrincipalFactory<User>>();
// Use the repo....
}
}
}
Now, because the IsecurityTokenProvider is only instantiated once, it's effectively a singleton. When I use the service provider to ask for a IMyRepository I was finding that I was always received the same object - there is no new scope as far as it was concerned, because it's in a singleton class.
To get round that, you'll see in the code above Ive had to manually force a new scope every time the token validator is called. Is this really the only way to resolve this, it seems like I'm hacking around to make it work here...
Old question but the best way I have found to solve this problem is to use IPostConfigureOptions<JwtBearerOptions> to configure SecurityTokenValidators.
First register the JWT bearer and options
services.AddAuthentication(options =>
{
...
}).AddJwtBearer(AuthenticateScheme, options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
...
};
});
Then register a custom implementation of IPostConfigureOptions<JwtBearerOptions>
services.AddSingleton<IPostConfigureOptions<JwtBearerOptions>, CustomJwtBearerOptionsPostConfigureOptions>();
And register a custom implementation of ISecurityTokenValidator
services.AddSingleton<MyCustomSecurityTokenValidator>();
CustomJwtBearerOptionsPostConfigureOptions could look something like:
public class CustomJwtBearerOptionsPostConfigureOptions : IPostConfigureOptions<JwtBearerOptions>
{
private readonly MyCustomSecurityTokenValidator _tokenValidator; //example dependancy
public CustomJwtBearerOptionsPostConfigureOptions(MyCustomSecurityTokenValidator tokenValidator)
{
_tokenValidator = tokenValidator;
}
public void PostConfigure(string name, JwtBearerOptions options)
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(_tokenValidator);
}
}
Now options.SecurityTokenValidators is configured by CustomJwtBearerOptionsPostConfigureOptions which is instantiated by dependency injection and can pass on the relevant decencies.

Autofac inject into ValidationAttribute on WebApi and OWIN

There's a few posts on SO relating to the work around for allowing autofac injections with ValidationAttribute 's (Asp.Net MVC3: Set custom IServiceProvider in ValidationContext so validators can resolve services) but I'm using OWIN and WebApi so I'm not sure if this is possible?
All other dependency injection is working fine.
DependencyResolver isn't populated in OWIN and I remember reading a difference in how OWIN handles injections for the validation requests. Does anyone know if Autofac, OWIN, WebApi and ValidationAttribute 's are possible? And, with specific examples?
You need to register the Autofac middleware and then you need to extend it to the WebApi. Now you can use the Autofac resolution inside the OWIN middleware.
// Register the Autofac middleware FIRST.
app.UseAutofacMiddleware(container);
// extend the autofac scope to the web api
app.UseAutofacWebApi(HttpConfiguration);
After this, WebApi and OWIN middleware will share the same resolution context, and you can do whatever you want.
For the ValidationAttribute thing you can, for example, do something like this:
public class AppStartup
{
public void Configuration(IAppBuilder app)
{
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
//Set builder
var builder = new ContainerBuilder();
//IoC container build
var container = builder.Build();
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(HttpConfiguration);
WebApiConfig.Register(HttpConfiguration);
app.UseWebApi(HttpConfiguration);
}
}
and then
public override bool IsValid(object value)
{
var dependencyResolver = (AutofacWebApiDependencyResolver)GlobalConfiguration.Configuration.DependencyResolver;
using (var lifetimeScope= dependencyResolver.BeginScope())
{
var foo = lifetimeScope.Resolve<Foo>();
// use foo
}
}

Nservicebus 5 and later Web Api Depenedency Injection settings

How can I configure Web api dependency settings for NserviceBus 5 and later version.
Version 3 or 4 is like this:
public static class ConfigureWebApi
{
public static Configure ForWebApi(this Configure configure)
{
// Register our http controller activator with NSB
configure.Configurer.RegisterSingleton(typeof(IHttpControllerActivator),
new NSBHttpControllerActivator());
// Find every http controller class so that we can register it
var controllers = Configure.TypesToScan
.Where(t => typeof(IHttpController).IsAssignableFrom(t));
// Register each http controller class with the NServiceBus container
foreach (Type type in controllers)
configure.Configurer.ConfigureComponent(type, ComponentCallModelEnum.Singlecall);
// Set the WebApi dependency resolver to use our resolver
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NServiceBusResolverAdapter(configure.Builder));
// Required by the fluent configuration semantics
return configure;
}
}
But Version 5 does not use Configure class, that use BusConfiguration
I try this but can not scan assemblies:
public static class ConfigureWebApi
{
public static BusConfiguration ForWebApi(this BusConfiguration configuration)
{
configuration.RegisterComponents(c => c.RegisterSingleton(typeof(IHttpControllerActivator),
new NServiceBusHttpControllerActivator()));
????
}
}
I'm not sure which way you're thinking. I'm asking, because I might be wrong with my answer. If so, let me know and I'll try to update it.
The way I go about this issue is setting up the container first and then have NServiceBus use that container. I'm using AutoFac and create a special class to set it up.
Disclaimer : I'm copying this from an existing app and didn't try nor compile it. I'm 100% sure this is working though, although I might've forgotten a line or added one too much! :)
public class DependenciesConfig
{
public static IContainer RegisterDependencies()
{
ContainerBuilder builder = new ContainerBuilder();
// MVC Controllers
builder.RegisterModule(new AutofacWebTypesModule());
builder.RegisterControllers(Assembly.GetExecutingAssembly())
// WebAPI controllers
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);
// Way more registrations
// Next line is AutoFac specific for WebAPI
builder.RegisterFilterProvider();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
return container;
}
}
Then I have an additional class for registering NServiceBus. I don't have handlers in my web app, nor do I publish messages, so I use a SendOnly endpoint.
public class ServiceBus
{
public static ISendOnlyBus Bus { get; private set; }
private static readonly object padlock = new object();
public static void Init(ILifetimeScope container)
{
if (Bus != null) return;
NServiceBus.Logging.LogManager.Use<CommonLoggingFactory>();
lock (padlock)
{
if (Bus != null) return;
var configuration = new BusConfiguration();
configuration.UseSerialization<JsonSerializer>();
configuration.UseContainer<AutofacBuilder>(x => x.ExistingLifetimeScope(container));
configuration.UseTransport<AzureStorageQueueTransport>();
ConventionsBuilder conventions = configuration.Conventions();
conventions.DefiningCommandsAs(t => t.Namespace != null && t.Namespace.StartsWith("Messages") && t.Namespace.EndsWith("Commands"));
Bus = NServiceBus.Bus.CreateSendOnly(configuration);
}
}
}
Is this what you're looking for?

OAuth: ASP.NET Web API User.Identity doesn't load claims set by authentication token provider

I am using OAuth bearer authentication, configured like this in Startup.cs:
OAuthBearerAuthenticationOptions oAuthBearerOptions =
new OAuthBearerAuthenticationOptions
{
AccessTokenProvider = new AccessTokenProvider(),
AuthenticationMode = AuthenticationMode.Active
};
app.UseOAuthBearerAuthentication(oAuthBearerOptions);
... where AccessTokenProvider is implemented as:
public class AccessTokenProvider : AuthenticationTokenProvider
{
public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
// Internal logic to get data needed for building identity...
// Create claims identity
ClaimsIdentity identity = new ClaimsIdentity(identityName);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, nameIdentifier));
// Add other claims
// Set claims identity
context.SetTicket(new AuthenticationTicket(identity, new AuthenticationProperties()));
}
}
If I set a breakpoint at the end of ReceiveAsync, I can verify that the identity is built correctly (has claims) and that SetTicket is reached.
But when I try to access the identity from a Web API controller:
public abstract class BaseStorageController : ApiController
{
protected IStorageService StorageService;
protected BaseStorageController(IStorageServiceFactory storageServiceFactory)
{
StorageService = storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
}
}
... the list of claims on the identity is empty!
What can be causing this?
Side note: I don't know if this is related, but I am using Castle Windsor as an IOC container to inject dependencies into my controllers (in the above case, IStorageServiceFactory). The above seemed to work (claims were not empty) before I added that. However, I'm not using CW to manage anything related to authentication. Here is my CW installer for api controllers:
public class ApiControllerInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestylePerWebRequest());
}
}
I found the answer. It was not related to dependency injection/inversion of control. I'm not sure how I thought it was working prior to adding that.
The issue is similar to what is described here (but in my case the solution is different): User (IPrincipal) not avaliable on ApiController's constructor using Web Api 2.1 and Owin
Basically IPrincipal is not accessible from the constructor of the api controller, which is why there are no claims (the user is not yet authenticated). User.Identity is only accessible from the controller's actions, not the constructor. I changed my base controller implementation to the following to get around this issue:
public abstract class BaseStorageController : ApiController
{
private readonly IStorageServiceFactory _storageServiceFactory;
private IStorageService _storageService;
protected BaseStorageController(IStorageServiceFactory storageServiceFactory)
{
_storageServiceFactory = storageServiceFactory;
}
protected IStorageService StorageService
{
get
{
if (_storageService == null)
{
_storageService = _storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
}
return _storageService;
}
}
}
Since StorageService is only accessed from controller actions, User.Identity is authenticated and has claims populated by the time that the StorageService getter gets called.
Hope this helps someone!
protected IStorageService StorageService
{
get
{
if (_storageService == null)
{
_storageService = _storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
}
return _storageService;
}
}
this is not the best approach for implementing DI
It's much better to use constructor injection.
Check Constructor Injection in C#/Unity?
if you are not familliar with Unity, follow this link, very useful:
https://msdn.microsoft.com/en-us/library/dn223671(v=pandp.30).aspx
Regards