I have implemented a custom OAuthAuthorizationServerProvider
to add a domain constraint for the account login. Everything was good. However, I met a problem that, once the user get the token, they can use it for whatever system they want. For example:
They request the TokenEndpointPath
with proper username and password (assume it is the admin account of Tenant 1): http://localhost:40721/api/v1/account/auth and receive the Bearer Token.
Now they use it to access: http://localhost:40720/api/v1/info/admin, which is of Tenant 0. The request is considered Authorized.
I tried changing the CreateProperties
method but it did not help:
public static AuthenticationProperties CreateProperties(string userName)
{
var tenant = DependencyUtils.Resolve<IdentityTenant>();
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName },
{ "tenantId", tenant.Tenant.Id.ToString() },
};
return new AuthenticationProperties(data);
}
I also tried overriding ValidateAuthorizeRequest
, but it is never called in my debug.
Do I need to implement a check anywhere else, so the Token is only valid for a domain/correct tenant?
(NOTE: a tenant may have multiple domains, so it's great if I can manually perform an account check against correct tenant rather than sticking to a domain. However, it's a plus if I could do that, or else, simply limit the token to the domain is ok)
Not a direct answer to my question (since it's not inside ASP.NET Identity workflow), but the simplest fix I applied was to use ActionFilterAttribute
instead.
public class DomainValidationFilter : ActionFilterAttribute
{
public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
// Other Code...
// Validate if the logged in user is from correct tenant
var principal = actionContext.ControllerContext.RequestContext.Principal;
if (principal != null && principal.Identity != null && principal.Identity.IsAuthenticated)
{
var userId = int.Parse(principal.Identity.GetUserId());
// Validate against the tenant Id of your own storage, and use this code to invalidate the request if it is trying to exploit:
actionContext.Response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.Unauthorized, "Invalid Token");
}
return base.OnActionExecutingAsync(actionContext, cancellationToken);
}
}
Then applies the Filter to all actions by registering it in either FilterConfig
or WebApiConfig
:
config.Filters.Add(new DomainValidationFilter());