Access HttpServletRequest from an Authenticator using Dropwizard - dependency-injection

Using DropWizard(Jersey Server), Is it possible to access HttpServletRequest from an Authenticator?
I would give it an attribute.
I tried with:
#Context
private HttpServletRequest servletRequest;
But it's not injected.
I registered my Authenticator using:
env.jersey().register(
new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>().setAuthenticator(new FooAuthentificator())
.setRealm("Realm").buildAuthFilter()));

It's possible, but the problem is, the Authenticator never goes through the DI lifecycle, so it never gets a chance to get injected. What we can do though is explicitly inject it ourselves. To do that, we need to get a hold of the ServiceLocator (which is the main IoC container, kind of like ApplicationContext with Spring). Once we have the ServiceLocator, we can call locator.inject(anyObject) to explicitly resolve any injection dependencies.
The easiest place to get the ServiceLocator, when configuring the app, is in a Feature. Here we can also register Jersey components. Calling register on the FeatureContext (seen below) is just like calling env.jersey().register(...) with Dropwizard, it has the same effect. So we can do
public class AuthenticatorFeature implements Feature {
#Override
public boolean configure(FeatureContext ctx) {
ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(ctx);
TestAuthenticator authenticator = new TestAuthenticator();
locator.inject(authenticator);
ctx.register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(authenticator)
.setRealm("SEC REALM")
.buildAuthFilter()));
ctx.register(new AuthValueFactoryProvider.Binder<>(User.class));
return true;
}
}
You can see that explicitly inject the authenticator, with the call to locator.inject(authenticator). Then we register this feature through Dropwizard
env.jersey().register(new AuthenticatorFeature());
Tested, and works fine.
Note, if you are wondering how it's possible to inject the HttpServletRequest, when there is no current request, it's because a proxy is injected. Same thing as if you were to inject the request into a Jersey filter, the same thing happens; a proxy is injected, as there is only a singleton filter, but the request changes from request to request, so a proxy needs to be injected.
See Also:
Injecting Request Scoped Objects into Singleton Scoped Object with HK2 and Jersey

Related

Should I use transient service & repository for user authentication?

My ConfigureServices section of Startup.cs looks like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var builder = services.AddIdentityServer()
.AddInMemoryApiResources(Configurations.ApiResources.GetApiResources())
.AddInMemoryClients(Configurations.Clients.GetClients());
services.AddEntityFrameworkNpgsql();
services.AddDbContext<IdentityDbContext>();
services.BuildServiceProvider();
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
// Login Service and User Repo Injection
services.AddTransient<IUserRepository, UserRepository>();
services.AddTransient<ILoginService, LoginService>();
// Connection String Config
services.Configure<ConnectionStringConfig>(Configuration.GetSection("ConnectionStringConfig"));
if (Environment.IsDevelopment())
{
builder.AddDeveloperSigningCredential();
}
}
I am injecting my loginService into ResourceOwnerPasswordValidator, and I am injecting userRepository into my loginService. ResourceOwnerPasswordValidator is handling the validation of my user's login.
I originally added my repository and loginService as singletons but I got the error
unable to consume scoped instance of DbContext from singleton
userRepository.
As you can see above I changed both my loginService and userRepository instances to transient. Is this a safe way to do it, or is there another way I should choose?
My loginService uses userRepository to talk to the database. However if I add them as singletons,
I get a cannot consume scoped db instance
, so I thought I'd make the whole thing transient.
Is there a better way to do this which would allow me to keep loginService and userRepository as singletons?
Typically you'd only want to use a singleton in a web application if any of the following is true and if the class in question is thread-safe:
Construction of an underlying resource (e.g. a connection to a distributed cache) is expensive
You need to maintain in-memory state for the duration of the application
You need to serialize access to a resource (e.g. an append-only file)
In your case none of these are true so scoped or transient are totally fine.

Configure injected services with information available in runtime

I've been trying to modify injected services with values available from authenticated users.
Using the built-in DI container, I added the required service with Scoped lifetime.
services.AddScoped<ITodoRepository, TodoRepository>();
Then registered a custom middleware between authorization and MVC middlewares to modify the repository with user specific information.
// Configure authorization middleware
app.Use(async (context, next) =>
{
var todoRepository = context.ApplicationServices.GetRequiredService<ITodoRepository>();
todoRepository.UserStoreId = context.User.GetUserStoreId();
await next.Invoke();
});
// Configure MVC middleware
When the program execute a request, the injected repository within my controller does not presist the saved value.
Am i doing something wrong?
From my understanding, scoped objects are saved within request.
Also, is there another way to achieve this?
You can create your own service, i.e. IAuthenticatedUserService/AutheticatedUserService.
Into it, you inject IHttpContextAccessor.
public interface IAuthenticatedUserService
{
ClaimsPrincipal User { get; }
}
Then you inject the IAuthenticatedUserService into your repository, where you can access the logged-in user.
Of course you could also directly inject IHttpContextAccessor into your repository and access httpContextAccessor.HttpContext.User within it, but since repositories are usually defined in their own assembly, you'd also need to reference the Microsoft.AspNetCore.Http.Abstractions package from it which would cause a tight(er) coupling.
But if you don't mind this kind of coupling, just inject the IHttpContextAccessor into your repository, they are supposed to be scoped (=per request) or transient anyways.
P.S. don't forget the Dependency Injection/Inversion of Control mantra: "Don't call us, we call you". You have attempted to call "us" (the repository) to set a value.
Am i doing something wrong? From my understanding, scoped objects are saved within request.
I was able to fix the issue by replacing
context.ApplicationServices.GetRequiredService<ITodoRepository>();
with
context.RequestServices.GetRequiredService<ITodoRepository>();

OWIN Service resolution Using Autofac

I have an WebApi application using OWIN and Autofac. Although controllers and parameters get resolved correctly, I would like to be able to use OwinContext.Get<type> to resolve types registered with Autofac. Is that posible?
Already setapp.UseAutofacMiddleware(container); and config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
By example, I registered builder.Register<IAppConfiguration>(c => new AppConfig()); and I'd like to resolve it using owinContext.Get<IAppConfiguration>().
There is no way to get OwinContext.Get<T> to resolve things from Autofac. If you dive into Microsoft.Owin.OwinContext.Get in Reflector, you'll see it's backed entirely by a dictionary of things you register with an environment. It's not dynamic and there's no way (without creating your own IOwinContext implementation) to get it to resolve things either out of the dictionary or out of dependency resolution.
If you are in a DelegatingHandler or an ApiController you will have a reference to the current HttpRequestMessage. Use message.GetDependencyScope() to get the current request-level dependency scope to resolve services.
public HttpResponseMessage SomeControllerAction()
{
var service = this.Request.GetDependencyScope().GetService(typeof(Service));
}
If you have access to the HttpConfiguration then you can use the HttpConfiguration.DependencyResolver to resolve things. Note that resolver will not have per-request dependencies available. Web API tracks request dependency scope with the inbound HttpRequestMessage so be aware of that limitation. There is an FAQ about per-request lifetime scope that can help you through that.
If you're in a place where there's only an IOwinContext, you may need to make use of a package like CommonServiceLocator and the associated Autofac.Extras.CommonServiceLocator. There really isn't a way to get a reference to the current HttpConfiguration or global container just from an IOwinContext. Again, if you go this route, you won't have per-request dependencies available, so be aware.
The IOwinContext.Get uses the Environment dictionary, resolving objects registered directly with Owin, it does not take into account Autofac container.
I managed to do it by accessing the Autofac OwinLifetimeScope in the Environment property and using the scope to resolve the service.
You can access the LifetimeScope using this code
var scope=OwinContext.Get<Autofac.Core.Lifetime.LifetimeScope>("autofac:OwinLifetimeScope");
and then
scope.GetService(type)
You should check for nulls and write it in a better way, as Extension method maybe.
If you have WebAPI in your project, you can simulate a http request like this
var dependencyScope = new AutofacWebApiDependencyScope(owinContext.GetAutofacLifetimeScope());
var myService = dependencyScope.GetService(typeof(MyService));

Accessing IAuthSession in non-controller classes in ServiceStack/MVC4

I am new to ServiceStack, so this is probably a noob question:
I am working on an ASP.NET MVC4 application that uses ServiceStack and am trying to figure out how I could get a hold of the current IAuthSession from within a class (either a EF context or a PetaPoco Database) used by my MVC4 controllers derived from ServiceStackController.
The class in question is registered with Funq with the ReuseScope.Request scope (i.e. on the per-HTTP request basis), and ideally I'd like every instance of it to be autowired with the current IAuthSession using either a constructor parameter or a public property.
How do I do that?
UPDATE
After some digging I came up with what I think might work.
In my AppHost.Configure I register a lambda that returns a session from the current request:
container.Register<IAuthSession>(c =>
HttpContext.Current.Request.ToRequest().GetSession());
Also:
container.RegisterAutoWired<EFCatalogDb>();
where EFCatalogDb is my EF context that takes IAuthSession as a constructor argument:
public class EFCatalogDb : DbContext
{
public EFCatalogDb(IAuthSession session) : base()
{ }
// ...etc....
}
Unfortunately I am not at the point in my development when I can test this workaround, so have to ask others if it makes sense at all.
My first suggestion would be to try to keep IAuthSession out of your database classes since that creates a dependency on ServiceStack that seems unnecessary.
That being said, I think you could go the route of registering IAuthSession and having the container automatically inject IAuthSession. A better way might be creating your own 'wrapper class' around IAuthSession and injecting that into your database classes. That would then break the dependency on ServiceStack.
If you have no issue keeping a dependency on ServiceStack another possibility would be using the SessionFeature class and doing something like
var key = SessionFeature.GetSessionKey();
authSession = AppHost.Resolve<ICacheClient>().Get<IAuthSession>(key);

does #EJB Annotation work for remote call?

public class Servlet2Stateless extends HttpServlet {
#EJB private HelloUserLocal helloUser;
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println(newSess.getName());
}
will above line of code work when I have EJB and Servlet deployed on different servers? or I need to call it through traditional way????
If the EJB resides on the different server than your client (Servlet) than you cannot use the dependency injection with #EJB annotation.
I guess that you'll need to go with the old JNDI way.
According to EJB 3.1 spec, you can use #EJB annotation in a variety of clients, including servlets which is your case.
The problem is that you are running client and server in different hosts. Depending on the server you are using, you might be able to use the EJB annotation. This post explains how to do it in Weblogic.
Needless to say you have to define the server EJB as #Remote in either case.
If your container also supports CDI, you could write a CDI producer method for the bean whcih does the JNDI lookup. Then you can at least separate the lookup from the injection site.
What about using dependency injection in a standalone client ?

Resources