How to I configure Thinktecture IdentityServer to use Unity IOC Container - unity-container

Currently my web app uses unity IoC. I am trying to use Unity to register all my dependencies that the Identityserver needs for my custom userservice.
I am also hosting the identityserver in the same web application.

I was able with ServiceLocator
In Startup.cs
app.Map("/identity", idsrvApp =>
{
var factory = InMemoryFactory.Create(
clients: Clients.Get(),
scopes: StandardScopes.All);
factory.UserService = new Registration<IUserService>(resolver => Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<IUserService>());
And In my Unity config
container.RegisterType<IUserService, LocalRegistrationUserService>();
And In My custom User service
public class LocalRegistrationUserService : IUserService
{
IUser userBusiness;
public LocalRegistrationUserService(IUser userBusiness)
{
this.userBusiness = userBusiness;
}

Related

How to call IdentityServer UserManager method from web API?

I Need to initiate the password reset from my web api. I have identity server application and web api applications separately. I use OIDC client to communicate with identity server. With this client I can only call signin, signout and some standard methods.
What I need is to generate password reset token and get the reset token in API.
I have tried to include 'Microsoft.Extensions.Identity.Core' in my webapi core layer which have all the entities. But I get
Unable to resolve service for type
Microsoft.AspNetCore.Identity.IUserStore1[Application.Core.Entities.User]
while attempting to activate 'Microsoft.AspNetCore.Identity.UserManager
code
private readonly UserManager<User> _userManager;
public AccountController(UserManager<User> userManager)
{
_userManager = userManager;
}
private async Task<string> GeneratePasswordResetLinkAsync(User user)
{
string token = await _userManager.GeneratePasswordResetTokenAsync(user);
return token;
}
I've also tried adding below code in startup Injection
services.AddScoped<UserManager<User>, UserManager<User>>();
What is the proper way of injecting UserManager in my web api ?
You need to configure asp.net core identity in the Startup class of you web api. Unfortunately you can not simply call services.AddIdentity(... in ConfigureServices because behind the scenes a cookie-based authentication scheme is registered and set as the default challenge scheme, as you can see in the code here for asp.net core 2.2
or here for asp.et core 3.1.
Thus the solution I end up with is to copy & update AddIdentity method like this:
For ASP.NET CORE 2.2:
public static IdentityBuilder AddIdentityForWebApi<TUser, TRole>(
this IServiceCollection services,
Action<IdentityOptions> setupAction)
where TUser : class
where TRole : class
{
// Hosting doesn't add IHttpContextAccessor by default
services.AddHttpContextAccessor();
// Identity services
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
services.TryAddScoped<UserManager<TUser>>();
services.TryAddScoped<SignInManager<TUser>>();
services.TryAddScoped<RoleManager<TRole>>();
if (setupAction != null)
{
services.Configure(setupAction);
}
return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
}
For ASP.NET CORE 3.1:
static IdentityBuilder AddIdentityForWebApi<TUser, TRole>(
this IServiceCollection services,
Action<IdentityOptions> setupAction)
where TUser : class
where TRole : class
{
// Hosting doesn't add IHttpContextAccessor by default
services.AddHttpContextAccessor();
// Identity services
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
services.TryAddScoped<IUserConfirmation<TUser>, DefaultUserConfirmation<TUser>>();
services.TryAddScoped<UserManager<TUser>>();
services.TryAddScoped<SignInManager<TUser>>();
services.TryAddScoped<RoleManager<TRole>>();
if (setupAction != null)
{
services.Configure(setupAction);
}
return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
}
Then you should call AddIdentityForWebApi in the Startup of your web api application.
This will register the UserManager and it will now be injected in your controller's constructor.
Then you should configure Data Protection API (DPAPI) properly so that the token generated by your web api (when you call _userManager.GeneratePasswordResetTokenAsync... from your question) could be unprotected by your identity server application.
So I set the "DPAPI application name" across the two applications, in both ConfigureServices methods:
services.AddDataProtection()
.dataProtectionBuilder.SetApplicationName("YOUR_DPAPI_APPLICATION_NAME");
For production, in a web farm environment, you will have to share the DPAPI keys. Depending on your situation you have several options.
Please refer to the official documentation for more details on how to configure DPAPI.
I have tested on Kestrel running Windows, I am not sure about IIS.
The injection code does not look correct. Try changing it to
services.AddScoped<UserManager<Application.Core.Entities.User>>();

Resolving Authentication services in .Net Core 2.0 with AutoFac

I'm in the process of migrating a .Net Core 1.x project to .Net Core 2.0. One of the things that has changed is that Authentication is now configured in ConfigureServices during startup using extensions to IServiceCollection.
I have some custom services which are used in my authentication schemes, however the bulk of the DI registration is built using AutoFac (after this is called):
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//Other .Net Services Registered
services.AddTransient<ITicketStore, DistributedCacheTicketStore>();
services.AddSingleton<AuthenticationEvents>();
var sp = services.BuildServiceProvider();
services.AddAuthentication()
.AddCookie(options =>
{
//Other cookie options
options.SessionStore = sp.GetService<ITicketStore>();
})
.AddOpenIdConnect(options =>
{
//Other OIDC options
options.Events = sp.GetService<AuthenticationEvents>();
});
//Register application services with AutoFac
var builder = new ContainerBuilder();
RegisterAutoFacTypes(builder);
//Include services from .Net DI container
builder.Populate(services);
//Build and return the AutoFac container
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
At the moment, I'm attempting to also register the dependencies of DistributedCacheTicketStore and AuthenticationEvents on the IServiceCollection to allow me to use them in my Authentication config, but this is getting messy and I'd much rather keep it in the AutoFac registration.
Is there a sensible way of refactoring this to keep these registrations in AutoFac, but still use services.AddAuthentication() before the AutoFac container is built?

Access registered object in Nancy Startup class

I'm writing a service in Nancy and I'm using some middleware for monitoring the service:
app.UseOwin(buildFunc =>
{
var log = ConfigureLogger();
buildFunc.UseMonitoringAndLogging(log, HealthCheck);
buildFunc.UseNancy();
});
The middleware is configured to use a HealthCheck() function defined in the Startup class as:
public async Task<bool> HealthCheck()
{
return await SomeRepo.HealthCheck();
}
SomeRepo has a HealthCheck() method that queries the database to confirm it is available/responding. But how to inject SomeRepo into the Startup class, or alternatively access the container to resolve SomeRepo?
At this point you are still in Owin and not in the Nancy pipeline. What host are you running on ? If you are using aspnetcore the you can register your deps in RegisterServices() method and it will handle the injection into your method. You can use Autofac or StructureMap so you can share your container with Nancy as well like this.

ASP.NET 5 (VNext) Autofac Instance per Request

I'm playing around with ASP.NET vNext and I'd like to utilize InstancePerRequest for some of my registrations, e.g MyDbContext would be one example.
I've got Autofac running using InstancePerLifetimeScope for these dependencies. Which works....
But as soon as I change over to use InstancePerRequest I get this common error:
DependencyResolutionException: No scope with a Tag matching
'AutofacWebRequest' is visible from the scope in which the instance
was requested. This generally indicates that a component registered as
per-HTTP request is being requested by a SingleInstance() component
(or a similar scenario.) Under the web integration always request
dependencies from the DependencyResolver.Current or
ILifetimeScopeProvider.RequestLifetime, never from the container
itself.
I've read the Autofac help docs around this.... but I'm not sure how to set up the "request lifetime scope" which is causing this exception.
Has anyone set up an ASP.NET 5 web app integrating Autofac including InstancePerRequest?
You have two options as far as I know and both of them will give you the instance per request.
Assuming you have the below class to register:
public class Foo : IDisposable
{
public Foo()
{
Console.WriteLine("created");
}
public void Dispose()
{
Console.WriteLine("disposed");
}
}
Register with IServiceCollection
You can register the instance as scoped on IServiceCollection and build the Autofac container based on this.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddScoped<Foo, Foo>();
#if DNX451
// Create the autofac container
var builder = new ContainerBuilder();
// Create the container and use the default application services as a fallback
AutofacRegistration.Populate(builder, services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
#endif
return services.BuildServiceProvider();
}
Register on Autofac Builder
You can register the type on Autofac builder as instance per lifetime scope and this will give you the instance per request lifetime:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
#if DNX451
// Create the autofac container
var builder = new ContainerBuilder();
// Create the container and use the default application services as a fallback
AutofacRegistration.Populate(builder, services);
builder.RegisterType<Foo>().As<Foo>().InstancePerLifetimeScope();
var container = builder.Build();
return container.Resolve<IServiceProvider>();
#endif
return services.BuildServiceProvider();
}
As said, the result will be the same for both:
For more info per request instances on ASP.NET 5: Middlewares and Per Request Dependency Injection

Autofac with MVC4: controller does not have a default constructor

I've been working with Autofac in MVC3 and love it. Now I am trying to implement it with MVC4.
I installed the pre-release versions of Autofac MVC4 and Autofac WebApi through the Package Manager Console (Install-Package Autofac.Mvc4 -Pre and Install-Package Autofac.WebApi -Pre)
I adjusted my IoC container as following:
private static void SetAutofacContainer()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerHttpRequest().InstancePerApiRequest();
builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerHttpRequest().InstancePerApiRequest();
builder.RegisterType<RepositoryWrapper>().As<RepositoryWrapper>().InstancePerHttpRequest().InstancePerApiRequest();
builder.RegisterType<ServiceWrapper>().As<ServiceWrapper>().InstancePerHttpRequest().InstancePerApiRequest();
// Repositories
builder.RegisterAssemblyTypes(typeof(UserRepository).Assembly).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces().InstancePerHttpRequest().InstancePerApiRequest();
// Services
builder.RegisterAssemblyTypes(typeof(UserService).Assembly).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerHttpRequest().InstancePerApiRequest();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
When I run the application (by accessing the API controller) I get the exception:
"Controllers.UserController' does not have a default constructor"
The controller looks like this:
namespace Controllers
{
[Authorize]
public class UserController : ApiController
{
private ServiceWrapper _services;
public UserController(ServiceWrapper services)
{
_services = services;
}
// GET api/user/{userrequest}
public IQueryable<User> Get(UserRequest request)
{
if (ModelState.IsValid)
{
'...
}
}
}
Am I missing something? Did I not set it up right? Any help would be greatly appreciated!
Update
My API controller are within a separate project in the same solution. If I place the API controller in my main MVC project, it works. Could someone please enlighten me on how to get Autofac to register the API controllers in my API project?
With the RegisterApiControllers method you tell Autofac where (in which assembly) it should look for your ApiControllers
So the following call:
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
Registers the ApiControllers from the current assembly (project).
If you have ApiControllers also in a different project you need to use it like this:
builder.RegisterApiControllers(typeof(UserController).Assembly);
Which means: register all the ApiController form the assembly (project) where the UserController lives. So you only need one RegisterApiControllers per assembly even if you have multiple ApiController in an assembly (project).

Resources