Dropwizard Authentication with POST calls failing - authentication

I was trying out Dropwizard authentication in my code but facing some issue in POST call at runtime, although its working fine with GET. this is how I am using this in the GET call:
#Override
#GET
#Path("/auth")
public Response doAuth(#Auth User user) {
//do something
}
And then in Post call which is not working:
#Override
#POST
#Path("/")
public Response createLegalEntity(#Auth User user, LegalEntity createLegalEntity) {
// do something
}
While running it is throwing following error:
SEVERE: Missing dependency for method public javax.ws.rs.core.Response org.flipkart.api.LegalEntityResource.createLegalEntity(com.yammer.dropwizard.authenticator.User,org.flipkart.model.LegalEntity) at parameter at index 0
I am new to Dropwizard and not able to figure out the cause of the problem.
UPDATE
Here is how I have registered my ldap authentication configs:
final LdapConfiguration ldapConfiguration = configuration.getLdapConfiguration();
Authenticator<BasicCredentials, User> ldapAuthenticator = new CachingAuthenticator<>(
environment.metrics(),
new ResourceAuthenticator(new LdapAuthenticator(ldapConfiguration)),
ldapConfiguration.getCachePolicy());
environment.jersey().register(new AuthDynamicFeature(
new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(ldapAuthenticator)
.setRealm("LDAP")
.buildAuthFilter()));
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));

The most likely reason is that you have not configured that auth feature correctly. The one thing that most people forget about is the AuthValueFactoryProvider.Binder. An instance of this class also needs to be registed. This would definitely cause the error you are seeing, if unregistered.
// If you want to use #Auth to inject a custom Principal type into your resource
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));
From Basic Authentication docs
See also:
My comment for Dropwizard issue regarding the same problem. You will get a good explanation of the what causes the problem.

Related

Register dependent services on every request

I am working in Multi-tenant solution primarily there are 2 type of applications
WebAPI
Console app to process message from queue
I have implemented dependency injection to inject all services. I have crated TenantContext class where I am resolving tenant information from HTTP header and it's working fine for API, but console application getting tenant information with every message (tenant info is part of queue message) so I am calling dependency injection register method on every incoming message which is not correct, do you have any suggestion/solution here?
The way I am resolving ITenantContext in API
services.AddScoped<ITenantContext>(serviceProvider =>
{
//Get Tenant from JWT token
if (string.IsNullOrWhiteSpace(tenantId))
{
//1. Get HttpAccessor and processor settings
var httpContextAccessor =
serviceProvider.GetRequiredService<IHttpContextAccessor>();
//2. Get tenant information (temporary code, we will get token from JWT)
tenantId = httpContextAccessor?.HttpContext?.Request.Headers["tenant"]
.FirstOrDefault();
if (string.IsNullOrWhiteSpace(tenantId))
//throw bad request for api
throw new Exception($"Request header tenant is missing");
}
var tenantSettings =
serviceProvider.GetRequiredService<IOptionsMonitor<TenantSettings>>();
return new TenantContext(tenantId, tenantSettings );
});
Create two different ITenantContext implementations. One for your Web API, and one for your Console application.
Your Web API implementation than might look as follows:
public class WebApiTenantContext : ITenantContext
{
private readonly IHttpContextAccessor accessor;
private readonly IOptionsMonitor<TenantSettings> settings;
public WebApiTenantContext(
IHttpContextAccessor accessor,
IOptionsMonitor<TenantSettings> settings)
{
// Notice how the dependencies are not used in this ctor; this is a best
// practice. For more information about this, see Mark's blog:
// https://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple/
this.accessor = accessor;
this.settings = settings;
}
// This property searches for the header each time its called. If needed,
// it can be optimized by using some caching, e.g. using Lazy<string>.
public string TenantId =>
this.accessor.HttpContext?.Request.Headers["tenant"].FirstOrDefault()
?? throw new Exception($"Request header tenant is missing");
}
Notice that this implementation might be a bit naive for your purposes, but hopefully you'll get the idea.
This class can be registered in the Composition Root of the Web API project as follows:
services.AddScoped<ITenantContext, WebApiTenantContext>();
Because the WebApiTenantContext has all its dependencies defined in the constructor, you can do a simple mapping between the ITenantContext abstraction and the WebApiTenantContext implementation.
For the Console application, however, you need a very different approach. The WebApiTenantContext, as shown above, is currently stateless. It is able to pull in the required data (i.e. TenantId) from its dependencies. This probably won't work for your Console application. In that case, you will likely need to manually wrap the execution of each message from the queue in a IServiceScope and initialize the ConsoleTenantContext at the beginning of that request. In that case, the ConsoleTenantContext would look merely as follows:
public class ConsoleTenantContext : ITentantContext
{
public string TenantId { get; set; }
}
Somewhere in the Console application's Composition Root, you will have to pull messages from the queue (logic that you likely already have), and that's the point where you do something as follows:
var envelope = PullInFromQueue();
using (var scope = this.serviceProvider.CreateScope())
{
// Initialize the tenant context
var context = scope.ServiceProvider.GetRequiredService<ConsoleTenantContext>();
content.TenantId = envelope.TenantId;
// Forward the call to the message handler
var handler = scope.ServiceProvider.GetRequiredService<IMessageHandler>();
handler.Handle(envelope.Message);
}
The Console application's Composition Root will how have the following registrations:
services.AddScoped<ConsoleTenantContext>();
services.AddScoped<ITenentContext>(
c => c.GetRequiredServices<ConsoleTenantContext>());
With the registrations above, you register the ConsoleTenantContext as scoped. This is needed, because the previous message infrastructure needs to pull in ConsoleTenantContext explicitly to configure it. But the rest of the application will depend instead on ITenantContext, which is why it needs to be registered as well. That registration just forwards itself to the registered ConsoleTenantContext to ensure that both registrations lead to the same instance within a single scope. This wouldn't work when there would be two instances.
Note that you could use the same approach for Web API as demonstrated here for the Console application, but in practice it's harder to intervene in the request lifecycle of Web API compared to doing that with your Console application, where you are in full control. That's why using an ITenantContext implementation that is itself responsible of retrieving the right values is in this case an easier solution for a Web API, compared to the ITenantContext that is initialized from the outside.
What you saw here was a demonstration of different composition models that you can use while configuring your application. I wrote extensively about this in my series on DI Composition Models on my blog.

Can I add a service info / health check endpoint to my Identity Server 3-based service?

I have a set of AspNet WebApi-based web services and an IdentityServer3-based authentication service. All of the web services support a simple service info endpoint that we use for monitoring and diagnosis. It reports the service version and the server name. The only service that currently does not support the service info endpoint is the IdentityServer3-based authentication service.
Is there a way to add a simple endpoint to an IdentityServer3-based service? In GitHub issue 812 Brock Allen says "We have a way to add custom controllers, but it's undocumented, current unsupported, and not really done." I'd rather not take that indocumented, unsupported route.
Is there a way to modify/extend the discovery endpoint to include additional information?
Here's how I ended up coding this up. At a high level, basically I added a Controllers folder, created a AuthenticationServiceInfoController class with a single GET action method and then registered that controller during Startup. As noted in comment above, my solution had some extra complexity because my AuthenticationServiceInfoController inherited from a base ServiceInfoController defined elsewhere, but I've tried to eliminate that from this sample. So, the controller code looks like this:
[RoutePrefix("api/v1/serviceinfo")]
public class AuthencticationServiceInfoController : IServiceInfoController
{
[Route("")]
[Route("~/api/serviceinfo")]
public IHttpActionResult Get()
{
try
{
ServiceInformation serviceInfo = new ServiceInformation();
serviceInfo.ServiceVersion = Global.serviceVersion;
return Ok(serviceInfo);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
}
It implements a simple interface:
public interface IServiceInfoController
{
IHttpActionResult Get();
}
And in my Startup.Configuration method where I configure Identity Server, I've got:
var idSrvFactory = new IdentityServerServiceFactory();
idSrvFactory.Register(new Registration<IServiceInfoController, Controllers.AuthencticationServiceInfoController>());
I think that's all that it took. It's in place and working in my Identity Server 3-based service.

Custom authentication scheme with AbpMvcAuthorize

I'm having trouble making AbpMvcAuthorize attribute working in my special case.
I have some custom authentication mechanism (with a custom AuthenticationScheme), that sign-in my user.
To do that, I implemented a AuthenticationHandler<MyCustomAuthenticationOptions> and overrode the HandleAuthenticateAsync method and registered it inside the AuthConfigurer.Configure method from the Module-zero :
services.AddAuthentication(o => o.AddScheme("amx", b => b.HandlerType = typeof (MyCustomAuthenticationHandler)));
Now if I have this:
[Authorize(AuthenticationSchemes = "amx")]
public string GetTest()
{
return "OK";
}
And make a request with my special amx header, it's working and I can only access the method when I'm specifying it.
If I'm doing the same thing with:
[AbpMvcAuthorize(AuthenticationSchemes = "amx")]
public string GetTest()
{
return "OK";
}
It's not working anymore and I have a 401 Unauthorized result and in debug mode, I never enter my custom AuthenticationHandler.
It seems like either the AbpMvcAuthorize attribute was executed BEFORE my custom AuthenticationHandler or maybe it didn't read the AuthenticationScheme property?
Have any idea if I'm doing something wrong?
Thanks
I asked on their Github: https://github.com/aspnetboilerplate/aspnetboilerplate/issues/3778
And was told that this is not possible right now because the AbpMvcAuthorize doesn't read the AuthenticationScheme property.
I'll try to implement it with some Policy

RestEasy #ValidateRequest is not working

I am having below configuration for a RestEasy Rest WS
jaxrs-api-2.3.5.Final.jar,
resteasy-jaxrs-2.3.5.Final.jar,
resteasy-hibernatevalidator-provider-2.3.5.Final.jar,
hibernate-validator-4.3.2.Final.jar,
validation-api-1.0.0.GA.jar
I have added #ValidateRequest on class(tried on method as well) to validate any request input data before processing the request but i dont know why validation in not being invoked.
#Path(value = "/events")
#ValidateRequest
public class EventRestController {
#GET
#Produces({ MediaType.APPLICATION_XML, ACCEPT_HEADER })
public Response get(#QueryParam("componentSerialNumber") #NotNull String componentSerialNumber) {
System.out.println("powerChangeEvevnt.getComponentSerialNumber() " + componentSerialNumber);
return Response.ok().build();
}
}
i dont know what i am missing.
please suggest.
Turning on auto scanning of Rest resources and providers solved the issue, validation started working.
just set resteasy.scan parameter value to true in web.xml
i had explicitly registered all resources in a subclass extending javax.ws.rs.Application class but it was not considering HibernateValidator as a validator for validation. i found registering HibernateValidator as a validator quite complex, so just removed this explicitly registered configuration class and enabled Automatically scan.

Why does my ServiceStack AuthProvider never call Authenticate(), even when IsAuthorized() returns false?

I'm writing an AuthProvider for ServiceStack to authenticate against our own OAuth2 server, and having problems with the way ServiceStack interacts with my provider.
According to https://groups.google.com/d/msg/servicestack/e3kkh-qRDYs/DF9Y05ibl-MJ
There are generally 2 ways for extending, if you want to provide your own OAuth implementation you would sub class AuthProvider (or implement IAuthProvider) and override the Authenticate() method which holds the entire implementation of your service. The AuthService now has no real implementation of its own, it just checks the Auth Provider .IsAuthorized() method to see if the user is already authenticated, if not it calls the Authenticate() method. [my emphasis]
My entire auth provider right now looks like this:
using System;
using ServiceStack.ServiceInterface;
using ServiceStack.ServiceInterface.Auth;
namespace SpotAuth.ResourceServer.Services {
public class SpotlightOAUthProvider : AuthProvider {
public override bool IsAuthorized(IAuthSession session, IOAuthTokens tokens, Auth request = null) {
return (false);
}
public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request) {
// A breakpoint on this line is never reached; the service just returns Unauthorized.
throw new NotImplementedException();
}
}
}
Why is the Authenticate method never being called? The forum post linked above is nearly a year old but I can't find anything suggesting this behaviour has been deprecated.
This answer probably comes a bit late, but I just stumbled upon your question now.
A few weeks before you asked your question, I tried to implement my own AuthProvider and had a similar problem:
How to get ServiceStack authentication to work? (with iPhone clients)
(near the bottom of the question, there's my MyBasicAuthProvider)
In the end I found out what I did wrong, and I think you made the same mistake as I did:
I needed to override TryAuthenticate instead of Authenticate.
As soon as I changed that, my provider worked.