SignalR Custom Authorize Attribute - signalr

I am trying to implement custom Authorize attribute for .net 5 SignalR component. When I use the attribute, It is being ignored and doesn't get into the custom Authorize class.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class IdentitySignalRAuthorizeAttribute : Microsoft.AspNet.SignalR.AuthorizeAttribute
{
private Role[] _roles;
public IdentitySignalRAuthorizeAttribute(params Role[] roles)
{
_roles = roles;
}
public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
{
return base.AuthorizeHubConnection(hubDescriptor, request);
}
public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod)
{
return base.AuthorizeHubMethodInvocation(hubIncomingInvokerContext, appliesToMethod);
}
}
public enum Role
{
Admin,
User
}
Usage:
[IdentitySignalRAuthorize(Role.User)]
public async Task InitConnectionAsync(...)

Related

Generic Authorize Attribute multiple Roles ASP.NET Core

I am trying to implement a generic multiple Authorize attribute which understand that every method is authorized by role that i specify OR role named "SysAdmin" that will be in all methods, Example :
[Authorize(Roles = "Role_A,SysAdmin")]
public Method1
{
//actions
}
[Authorize(Roles = "Role_B,SysAdmin")]
public Method2
{
//actions
}
[Authorize(Roles = "Role_C,SysAdmin")]
public Method3
{
//actions
}
I think it is not a good idea to repeat SysAdmin in all methods, is there any solution to pass it generic?
Since you always need to check for SysAdmin role we can keep it as a constant inside the attribute.
[AuthorizeUser(Role = "Role_A")]
public Method1
{
//actions
}
using System.Linq;
public class AuthorizeUserAttribute : AuthorizeAttribute
{
public string Role{ get; set; }
private readonly string SysAdmin = "SysAdmin";
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
return false;
}
// method to get roles array by user name from db or claims
string roles = GetUserRoles(httpContext.User.Identity.Name.ToString());
var splittedRoles = Role.split(",");
return roles.Any(x => splittedRoles.Any(y => y == x || y == SysAdmin))
}
}
Override the following method to return the unauthorized users
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)

How to custom/override User.IsInRole in ASP.NET Core

I'm a newbine in ASP.NET Core, I see in the User property (in ClaimsPrincipal class) in my controller, it has User.IsInRole method, so how can I override it to call my service dependency and register in my application (I don't want to use extension method).
You can use ClaimsTransformation:
public class Startup
{
public void ConfigureServices(ServiceCollection services)
{
// ...
services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
}
}
public class CustomClaimsPrincipal : ClaimsPrincipal
{
public CustomClaimsPrincipal(IPrincipal principal): base(principal)
{}
public override bool IsInRole(string role)
{
// ...
return base.IsInRole(role);
}
}
public class ClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var customPrincipal = new CustomClaimsPrincipal(principal) as ClaimsPrincipal;
return Task.FromResult(customPrincipal);
}
}
Controller method:
[Authorize(Roles = "Administrator")]
public IActionResult Get()
{
// ...
}
Role checking by Authorize attribute will use your overrided IsInRole method
For User.IsInRole, it is ClaimsPrincipal which is not registered as service, so, you could not replace ClaimsPrincipal, and you could not override IsInRole.
For a workaround, if you would not use extension method, you could try to implement your own ClaimsPrincipal and Controller.
CustomClaimsPrincipal which is inherited from ClaimsPrincipal
public class CustomClaimsPrincipal: ClaimsPrincipal
{
public CustomClaimsPrincipal(IPrincipal principal):base(principal)
{
}
public override bool IsInRole(string role)
{
return base.IsInRole(role);
}
}
ControllerBase to change ClaimsPrincipal User to CustomClaimsPrincipal User
public class ControllerBase: Controller
{
public new CustomClaimsPrincipal User => new CustomClaimsPrincipal(base.User);
}
Change the Controller from inheriting ControllerBase.
public class HomeController : ControllerBase
{
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
var result = User.IsInRole("Admin");
return View();
}
Change the logic in public override bool IsInRole(string role) based on your requirement

Asp Mvc 6 Model Validation with a service in custom ValidationAttribute

TLDR: In Asp Mvc 6 how do I perform model validation with a service using data annotations? What are the alternatives?
I have a very simple model
public class MyModel
{
[Required]
public string Name { get; set; }
}
I also have a service that exposes some simple validation methods
public interface IMyService
{
string[] ReservedWords { get; }
bool IsValidName(string name);
// Internally calls IsValidName and throws an Exception if the name is invalid
void Save(MyModel myModel);
// ... snip
}
And I have wired up my controller like so
public class MyController : Controller
{
private readonly IMyService _service;
public MyController(IMyService service)
{
_service = service;
}
// ... snip
public IActionResult Post(MyModel myModel)
{
if (!_service.IsValidName(input?.Name))
{
ModelState.AddModelError(nameof(MyModel.Name), "Invalid Name");
}
if (!ModelState.IsValid)
{
return View(myModel);
}
_service.Save(myModel);
return RedirectToAction(nameof(Index));
}
}
It feels a bit clucky to have 2 stages of validation - automatic model validation then manually performing service validation. I was hoping that something simialr to this would work
public class MyModel
{
[ServiceValidation(nameof(IMyService), nameof(IMyService.IsValidName)]
[Required]
public string Name { get; set; }
}
public ServiceValidationAttribute : ValidationAttribute
{
private readonly Type _interfaceOrClass;
private readonly string _methodOrProperty;
public ServiceValidationAttribute(Type interfaceOrClass, string methodOrProperty)
{
_interfaceOrClass = interfaceOrClass;
_methodOrProperty = methodOrProperty;
}
public override bool RequiresValidationContext => true;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var service = validationContext.GetService(_interfaceOrClass);
// Extension method in shared library to assist with reflection
bool isValid = _interfaceOrClass.ValueForMethodOrPropertyNamed<bool>(service, _methodOrProperty, value);
return isValid
? ValidationResult.Success
: new ValidationResult(ErrorMessage);
}
}
However var serivce is always null, is there any way around this? I have wired up the IMyService to an implementation in the Startup.cs as it is available in the Controller.
Alternatively is there a better way of adding to the ModelState with a service?

Dependency injection inside a FilterAttribute in ASP.NET MVC 6

I'm struggling with ASP.NET MVC 6 (beta 4 release) trying to inject a service within a controller filter attribute of type AuthorizationFilterAttribute.
This is the service (it has another service injected)
public class UsersTableRepository
{
private readonly NeurosgarContext _dbContext;
public UsersTableRepository(NeurosgarContext DbContext)
{
_dbContext = DbContext;
}
public ICollection<User> AllUsers
{
get
{
return _dbContext.Users.ToList();
}
}
//other stuff...
}
This is the ConfigureServices method in Startup class for services enabling
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddSingleton<NeurosgarContext>(a => NeurosgarContextFactory.GetContext());
services.AddSingleton<UifTableRepository<Nazione>>();
services.AddSingleton<UsersTableRepository>();
}
A simple "dummy" controller with two filters defined on it. You can notice that I already done DI inside this controller by decorating the property with [FromServices]and it works.
[Route("[controller]")]
[BasicAuthenticationFilter(Order = 0)]
[BasicAuthorizationFilter("Admin", Order = 1)]
public class DummyController : Controller
{
[FromServices]
public UsersTableRepository UsersRepository { get; set; }
// GET: /<controller>/
[Route("[action]")]
public IActionResult Index()
{
return View();
}
}
Doing the same DI within BasicAuthenticationFilterdoes not work and at runtime UserRepository property is a null reference.
public class BasicAuthenticationFilterAttribute : AuthorizationFilterAttribute
{
[FromServices]
public UsersTableRepository UsersRepository { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!Authenticate(filterContext.HttpContext))
{
// 401 Response
var result = new HttpUnauthorizedResult();
// Add the header for Basic authentication require
filterContext.HttpContext.Response.Headers.Append("WWW-Authenticate", "Basic");
filterContext.Result = result;
//if (!HasAllowAnonymous(context))
//{
// base.Fail(context);
//}
}
}
// ...
}
Any idea about how solve this?
Refrain from injecting dependencies into your attributes as explained here. Make your attributes passive, or make your attribute a humble object as described here.
var dependencyScope = context.HttpContext.RequestServices;
var usersRepository = dependencyScope.GetService(typeof(UsersTableRepository)) as UsersTableRepository;
// usersRepository is now ready to be used
So your BasicAuthenticationFilter will look like this:
public class BasicAuthenticationFilterAttribute : AuthorizationFilterAttribute
{
public UsersTableRepository UsersRepository { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
var dependencyScope = context.HttpContext.RequestServices;
UsersRepository = dependencyScope.GetService(typeof(UsersTableRepository)) as UsersTableRepository;
if (!Authenticate(filterContext.HttpContext))
{
// 401 Response
var result = new HttpUnauthorizedResult();
// Add the header for Basic authentication require
filterContext.HttpContext.Response.Headers.Append("WWW-Authenticate", "Basic");
filterContext.Result = result;
//if (!HasAllowAnonymous(context))
//{
// base.Fail(context);
//}
}
}
// ...
}

Cast User object in ASP.NET Identity 2.0

I want to get a custom ApplicationUser instance in the controller. Can I get it from User object inside the controller? How should I do that?
I tried this but it didn't worked:
ApplicationUser u = (ApplicationUser)User;
ApplicationUser u2 = (ApplicationUser)User.Identity;
My custom Identity models are like that:
public class ApplicationUser : IdentityUser<long, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public virtual UserInfo UserInfo { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager)
{
// Note the authenticationType must match the one
// defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity =
await manager.CreateIdentityAsync(this,
DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationRole : IdentityRole<long, ApplicationUserRole>
{
public ApplicationRole() : base() { }
public ApplicationRole(string name, string description)
{
this.Name = name;
this.Description = description;
}
public virtual string Description { get; set; }
}
public class ApplicationUserRole : IdentityUserRole<long> { }
public class ApplicationUserClaim : IdentityUserClaim<long> { }
public class ApplicationUserLogin : IdentityUserLogin<long> { }
No. The User property of the controller returns an IPrincipal object, not an ApplicationUser object. These are two entirely different things. IPrincipal is used by ASP.NET to control authentication and authorization, while ApplicationUser is merely an entity used in your database.
If you want ApplicationUser, you have to get it from UserManager.

Resources