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

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.

Related

Need to handle Post Authenticate in Asp.Net Core

I'm ready to use Asp.Net core, but here's what I am doing. In MVC 5, I have an Http module that is handling the PostAuthenticate event in order to create the claim where I am doing some stuff to determine roles for the user. I see no way to do this same thing in Core. Note that this is using Windows Authentication so there is no login method to handle.
From the current httpModule that hooks up to the PostAuthenticate because I want to initialize some things for the user.
context.PostAuthenticateRequest += Context_PostAuthenticateRequest;
Note that httpModules no longer exist with Core and that is being moved to middleware.. I don't see how to tap into that event from there though.
I just did this for the first time today. Two basic steps here.
First:
Create a class that implements the IClaimsTransformer interface.
public class MyTransformer : IClaimsTransformer
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context )
{
//don't run if user isn't logged in
if(context.Principal.Identity.IsAuthenticated)
{
((ClaimsIdentity)context.Principal.Identity)?.AddClaims(...);
}
}
return Task.FromResult(context.Principal);
}
Second:
Add this line to Startup.cs in
public void Configure(IApplicationBuilder app, ..., ...)
{
//app.Use...Authentication stuff above, for example
app.UseOpenIdConnectAuthentication( new OpenIdOptions
{
//or however you like to do this.
});
app.UseClaimsTransformation(o => new MyTransformer().TransformAsync(o));
//UseMvc below
app.UseMvc(...);
}
Keep in mind that TransformAsync is going to run on every request, so you might want to look into using sessions or caching if you're hitting a database with it.
Windows Authentication is performed by the hosts (IIS or HttpSys/WebListener) at the start of your application pipeline. The first middleware in your pipeline is the equivalent of PostAuthenticateRequest in this case. Operate on HttpContext.User as you see fit.

Dropwizard Authentication with POST calls failing

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.

ASP Core Add Custom Claim to Auth Token

I'm using openiddict and ASP Identity, and I am trying add a "GroupId" as a claim to the auth token that is returned when logging in (using the /connect/token endpoint - see example I followed below). The GroupId is a property in my AplicationUser class.
I have tried using an IClaimsTransformer but that seems clunky, I can't easily get to the UserManager from the ClaimsTransformationContext.
How would I go about either getting the UserManager through DI in my IClaimsTransformer or just adding the GroupId to the token that is generated at the connect/token endpoint?
I followed this example for setting up my site. This is what I would like to do:
var groupGuid = User.Claims.FirstOrDefault(c => c.Type == "GroupGuid");
There is a couple of ways to achieve it:
First, override CreateUserPrincipalAsync method in your custom SignInManager:
public override async Task<ClaimsPrincipal> CreateUserPrincipalAsync(ApplicationAdmin user)
{
var principal = await base.CreateUserPrincipalAsync(user);
// use this.UserManager if needed
var identity = (ClaimsIdentity)principal.Identity;
identity.AddClaim(new Claim("MyClaimType", "MyClaimValue"));
return principal;
}
The second way is to override CreateAsync method of your custom UserClaimsPrincipalFactory:
public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
var identity = (ClaimsIdentity)principal.Identity;
identity.AddClaim(new Claim("MyClaimType", "MyClaimValue"));
return principal;
}
which is, basically, the same, because base.CreateUserPrincipalAsync method in SignInManager calls this.UserClaimsPrincipalFactory() inside.
Don't forget to add your custom implementations into services:
either
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSignInManager<CustomSignInManager>();
}
or
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, CustomClaimsPrincipalFactory>();
}
ASP Core Add Custom Claim to Auth Token
You can't change a token after it is signed by IdP, so you can't add claim to token.
I have tried using an IClaimsTransformer but that seems clunky, I
can't easily get to the UserManager from the
ClaimsTransformationContext.
I guess your problem is related this github issue. In summary(as far as i understand) if ClaimsTransformer class is registered as singletion and one of the its dependency is scoped or transient, it causes captive dependency. In this case you should use Service Locator pattern to avoid from captive dependency. Your code may be something like this(from #PinpointTownes' comment):
public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
{
var userManager= context.Context.RequestServices.GetRequiredService<UserManager>();
//
}
-- My thoughts about your case --
You have basically two options to achieve your goal:
Add claim to token when token is generated by IdP:
You don't need this method most cases, but if you want to use it:
You should have control over IdP, because this option is possible on the IdP(as far as i understand your IdP and Resource Server is same, so you have control over IdP, but it might not be possible always) .
You should take care of inconsistency when using this option, because the claim is stored in the token and doesn't get each request. So the real value of claim might be different from claim in the token.(I don't prefer it for roles, permissions, groups etc. because these claims can be change anytime).
p.s: i don't know if it is possible to add claims to token with Openiddict.
Claims Transformation
Actually i used HttpContext.Items to store additional claims before i discovered this method and it worked well for me. But i think better way is to use Claims Transformation and it fits into your case.

Invoke a Controller Action from an Interceptor on Asp.Net MVC (Castle Windsor)

Is there any way this. I want to invoke an action with parameter (or parameterless at least) like below.
My situation is;
Interceptor not contains any reference from MVC, Interceptor is located at ApplicationService layer.
This is a service Interceptor.
public class ControllerInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var retVal = (ResponseDTOBase) invocation.ReturnValue;
if (retVal.ResponseCode == UsrNotAuth)
{
//Invoke Controller Action With passsing parameter (retVal)
}
invocation.Proceed();
}
}
Any ideas ? Thanks.
May I offer you another approach for request authorization. MVC is a state machine in its core principle. State machines have actions, triggers and guards. There is already such a 'guard' in MVC for the very purpose of intercepting controller actions and checking for the user privileges. This is the AuthorizeAttribute. This class implements IAuthorizationFilter. Another aspect is that authorization and authentication should happen before they reach your services. What I mean exactly is that there are two types of authorization :
Action Authorization and
Data Authorization.
The first type of authorization you can implement with AuthorizeAttribute or your custom attribute implementation of IAuthorizationFilter + FilterAttribute. Here is an example implementation of such an attribute for a SPA (Single Page Application) that works with ajax requests :
The attribute :
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class LoggedOrAuthorizedAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
CheckIfUserIsAuthenticated(filterContext);
}
private void CheckIfUserIsAuthenticated(AuthorizationContext filterContext)
{
// If Result is null, we’re OK: the user is authenticated and authorized.
if (filterContext.Result == null)
return;
// If here, you’re getting an HTTP 401 status code. In particular,
// filterContext.Result is of HttpUnauthorizedResult type. Check Ajax here.
// User is logged in but this operation is not allowed
if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.HttpContext.Request.IsAjaxRequest())
{
//filterContext.HttpContext.Response.StatusCode = 401;
JsonNetResult jsonNetResult = new JsonNetResult();
jsonNetResult.Data = JsonUtils.CreateJsonResponse(ResponseMessageType.info, "msgOperationForbiddenYouAreNotInRole");
filterContext.Result = jsonNetResult;
//filterContext.HttpContext.Response.End();
}
}
}
If you use pure MVC there is an example implementation here.
The usage :
In your controller
[LoggedOrAuthorized(Roles = Model.Security.Roles.MyEntity.Create)]
public ActionResult CreateMyEntity(MyEntityDto myEntityDto)
{
...
}
You can apply this on every controller action and block the user even before the controller is reached.
You can supply Loggers and other 'plumbing' through Castle Windsor inside your filters in order to record the events.
A very good and important links and comments are available in this answer of a similar question. These links provide very good guide for proper implementation too.
The other type of authorization - Data Access Authorization can be handled in the service or in the controller. I personally prefer to handle all kinds of authorization as soon as possible in the pipeline.
General practice is not to show to the user any data or action that he is not authorize to view or to execute commands upon it. Of course you have to double check this because the user can modify the POST and GET requests.
You can make simple interface with implementation IDataAccessService and control data access by passing user id and entity id to it.
Important thing is that you should not throw exception when the user is not authorized because this is no exception at all. Exception means that your program is in an unexpected state which prohibits its normal execution. When a user is not authorized this is not something unexpected - it is very well expected. That is why in the example implementation a message is returned rather then exception.
Another subtlety is that "exceptions" are handled differently by the .NET framework and they cost a lot more resources. This means that your site will be very vulnerable to easy DDOS outages or even they can perform not as they can. General rule is that if you control your expected program flow through exceptions you are not doing it properly - redesign is the cure.
I hope this guides you to the right implementation in your scenario.
Please provide the type of the authorization you want to achieve and parameters you have at hand so I can suggest a more specific implementation.

ASP.NET MVC 4 Read Persistent Auth Cookie Event?

I'm using WebSecurity for Authentication and a custom ClaimsAuthorizationManager for Authorization.
Mixing Claims based authorization with the built in WebSecurity features for Authentication has provided me with a ton of value. I highly recommend it for anyone who requires complex authorization logic combining from several systems.
Anyways, everything is working great except the RememberMe feature.
When a user logs in, I set my auth cookie (via WebSecurity), new up my ClaimsPrincipal, and write it to my SessionSecurityToken. Bam, it works brilliantly.
However, when a user has previously elected to persist the (Websecurity) auth cookie, she is allowed to bypass my login method, which news up my ClaimsPrincipal and writes my principal to my SessionSecurityToken. My authorization fails because my claims haven't been loaded, because I haven't had a chance to transform my ClaimsPrincipal.
Is there a way to hook into a (Websecurity) "forms authentication cookie read" event? If so, I could handle it, new up my ClaimsPrincipal, and be on my way. Thanks in advance!
You could write a custom AuthorizeAttribute:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (authorized)
{
httpContext.User = new ClaimsPrincipal(...)
}
return authorized;
}
}
Now decorate your protected controller actions with this custom attribute instead of the default built-in:
[MyAUthorize]
public ActionResult Protected()
{
...
}