ASP.Net Identity 2 Using a custom data access layer like Enterprise Library - asp.net

I am new to asp.net identity (ver. 2) and am about to start implementing it one of our MVC projects using the Claims based authorization mechanism instead of role based. I having been going through this link where what I understand from what is written is that I need to inherit Microsoft.AspNet.Identity.UserManager and create a CustomUserManager class and override its methods and then implement Microsoft.AspNet.Identity.EntityFramework.IUserStore to be consumed by my CustomUserManager class at the very least. There are other interfaces that I think were designed to be implemented for certain specific conditions like in my case the IUserClaimStore since I want to go with Claims based authorization. The reason mentioned is that I can change the store at a later date incase I want to change my persistence mechanism.
My questions are:
Since I am never going to change the persistence mechanism, is it really required that I implement all those classes and interfaces?
Going through the sample code the most important methods seem to be the following two code blocks:
Identity Creation and save to session (code in DoLogin Method)
// over simplified user object creation
UserPoco userObject= MyDAL.GetUserDatabyLoginDetails(username,password);
//identity created
var identity = CustomImplementationOfCreateIdentity(userObject, DefaultAuthenticationTypes.ApplicationCookie);
//saved to session
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
CheckAccess
public class AppClaimsAuthManager: ClaimsAuthorizationManager
{
public override bool CheckAccess(AuthorizationContext context)
{
var resource = context.Resource.First().Value;
var action = context.Action.First().Value;
//bool retVal = context.Principal.HasClaim("MyAction", "SampleResource");
bool retVal = context.Principal.HasClaim(action, resource);
bool baseRetVal= base.CheckAccess(context);
return retVal;
}
}
which is then used in controller methods like so
[ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "delete", Resource = "SomeResource")]
public ActionResult ClaimsBasedActionMethod()
{
return View();
}
Does it really matter how my user object is created via the CustomManager and CustomUserstore class implementations? Once the user name and password is verified and claims fetched from DB and my userObject created, I should be good to go right? I want this data to be fetched my service layer using enterprise library which I don't want to clog up with all identity framework related references.
Thoughts?

Related

Need advice of where to put custom user authorization in ASP.NET Core

I need advice of where to put custom user authorization code in ASP.NET Core. I am somewhat a ASP.NET Framework developer and normally I will add code to Global.asax as a session_onstart event to look up a SQL table where users profile are stored that is used to determine what they can view in the rest of the application. With Global.asax this is only cause once per user session, so what I would like to do is the same kind of approach in ASP.NET Core which I am kind of new to but need advice where that check should be done
I would like to do is the same kind of approach in ASP.NET Core which
I am kind of new to but need advice where that check should be done
Well, based on your description, in asp.net core you can achieve that in many ways. For instances, you could set in following places:
program.cs/startup.cs files
Using Middleware file
Using Action Filter
Let's, consider below example using action filter
Role and permissison:
First we are defining the role and the permission.
public enum Role
{
User,
Admin,
SuperAdmin
}
public enum Permission
{
Read,
Create,
Update,
Delete
}
Authorization On Action Filter:
public class AuthorizeActionFilter : IAuthorizationFilter
{
private readonly Role _role;
private readonly Permission _permission;
public AuthorizeActionFilter(Role item, Permission action)
{
_role = item;
_permission = action;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var isAuthorized = context.HttpContext.User.Claims.Any(c => c.Type == _role.ToString() && c.Value == _permission.ToString());
if (!isAuthorized)
{
context.Result = new ForbidResult();
}
}
}
Note: Check your user claim from the HttpContext if that containts either Admin or Read authorization.
Controller:
[Authorize(Role.User, Permission.Read)]
public IActionResult MemberList()
{
var memberList = _context.Members.ToList();
return View(memberList);
}
Output:
You even can implement that using Middleware. Asp.net 6 now providing couple of other mechanism now a days, you could have a look below official implementations as well.
Role-based authorization
Claims-based authorization
Policy-based authorization
Custom Action Filter

Is it possible to use HttpModule to authenticate for SignalR

I am developing an application that uses an HttpModule to perform custom authentication and authorization. My problem is that the user Identity set in the HttpModule is not accessible in the SignalR context objects.
I do the following in my HttpModule BeginRequest handler after custom authentication logic:
var userClaims = new List<Claim>();
userClaims.Add(new Claim(ClaimTypes.NameIdentifier, <some id>));
userClaims.Add(new Claim(ClaimTypes.Name, <some name>));
userClaims.Add(new Claim(ClaimTypes.Email, <da email>));
userClaims.Add(new Claim(ClaimTypes.Authentication, "true"));
var id = new ClaimsIdentity(userClaims);
var principal = new ClaimsPrincipal(new[] { id });
Thread.CurrentPrincipal = principal;
HttpContext.Current.User = principal;
I thought that this would absolutely make everything hereafter behave as though the request was authenticated, however this is not the case.
I have created a SignalR AuthorizeAttribute class to handle the authentication that looks like this:
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class CustomAuthAttribute : AuthorizeAttribute
{
public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
{
if (HttpContext.Current.Request.Path.StartsWith("/signalr/connect"))
{
var test = (ClaimsPrincipal)HttpContext.Current.User;
var test2 = (ClaimsPrincipal)Thread.Current.Principal;
}
return true;
}
public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubContext, bool appliesToMethod)
{
var test = (ClaimsPrincipal)hubContext.Hub.Context.User;
return true;
}
}
So my plan was to access the hubContext.Hub.Context.User var from within the AuthorizeHubMethodInvocation method to do any custom authorization I needed. However this just contains the default WindowsPrincipal.
If I look into the AuthorizeHubConnection call (which is actually a regular HTTP request and not a websocket call), I see that the HttpContext.Current object also does not have the User set as it should.
I do see that I can access the HttpContext.Current.Items collection. I presume I could use this to toss the Principal from the module to the SignalR context, but I'm not sure that is what I'm supposed to do.
Is it best to simply rewrite the HttpModule as OWIN middleware? It looks like I'll have to change stuff anyways when/if we update to ASP.NET 5; there's nothing like MS products to give you job security.
I forgot I posted this question a while ago. I ended up explaining my solution in a comment on the MS article Authentication and Authorization for SignalR Hubs. After trying to implement OWIN middleware for auth I found I would have to do some goofy config to run all modules for all requests, which is inefficient. I couldn't figure out how to run just the Auth OWIN middleware component for all requests so I abandoned that approach and stuck with my HttpModule. Here is a summary of my solution for SignalR auth posted on the page linked above:
1) Create a AuthorizeAttribute class like indicated in the article:
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class CustomAuthAttribute : AuthorizeAttribute
2) Decorate your Hub class with the auth class you created. The naming convention appears to be (SomeName)Attribute for the auth class itself and (SomeName) for the hub decoration.
[CustomAuth]
public class ServerWebSocket : Hub
3) Instead of overriding the "UserAuthorized" method as shown in the docs, override the following methods (I got this from some other SO post, but I can't find it right now):
public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubContext, bool appliesToMethod)
In order to actually authorize users I catch SignalR connection requests in my HttpModule and set an item in the HttpContext Items collection like so:
if (req.Path.StartsWith("/signalr/connect") || req.Path.StartsWith("/signalr/reconnect"))
{
var user_info = doFullAuth(<some token>);
HttpContext.Current.Items.Add("userDat", user_info);
}
This is actually set up so that connect requests will be completely rejected in the HttpModule if the user doesn't have permission. So I actually don't implement the SignalR auth method "AuthorizeHubConnection" at all. But in the "AuthorizeHubMethodInvocation" method I access the user data by calling HttpContext.Current.Items that was set on the original connect request and do custom logic to determine if a method can be accessed by the user.
This is the best way I can figure to get it to work if you want to authenticate every request to protect static files and such.

Get Current Principal as my Custom Application User in ASP.Net Core Identity

In previous versions of ASP.NET, if I wanted to have a custom class as my current logged in user, what I did was: I let the FormsAuthentication module do its work, and then, in the PostAuthenticateRequest event I replaced the current Principal (HttpContext.Current.User) with my custom principal object that I fetched from the database (with some caching for performance).
How can I achieve the same in ASP.NET Identity? I have my own ApplicationUser (not the default that comes with the EntityFramework ASP.NET Identity) and my own UserStore.
In every authenticated request, I have the HttpContext.User as a ClaimsPrincipal object. Is there a way to replace that with my CustomClaimsPrincipal?
Is there another, better way, to retrieve the current ApplicationUser instance based on the current ClaimsPrincipal?
If you have your own IUserStore you can implement IUserClaimStore to customize the claims identity which is passed to the claims principal.
If you need to replace the default claims principal you should implement the IUserClaimsPrincipalFactory and pass your implementation to the SignInManager and register the configured manager to your owin context.
It should look like this along the lines.
(Assuming you are using ASP.NET Core Identity, for Identity v2 the interfaces and constructors may differ!)
class CustomClaimsFactory<TUser> : Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<TUser>
where TUser : class
{
public Task<ClaimsPrincipal> CreateAsync(TUser user)
{
// create and return your custom principal
}
}
class OwinStartup
{
public void Configuration(IAppBuilder app)
{
app.CreatePerOwinContext(CreateSignInManager);
}
Microsoft.AspNetCore.Identity.SignInManager CreateSignInManager()
{
UserManager manager; // the manager that uses your custom IUserStore
IHttpContextAccessor accessor; // I don't know where to get it from...
var factory = new CustomClaimsFactory();
return new SignInManager(manager, accessor, factory, null, null, null);
}
}
For ASP.Net Core the OWIN-like startup configuration is done via dependency injection.

Can asp.net core policies and claims handle resource/activity based authorization?

I'm looking into asp.net core and the new security policies and claims functionality. Having just looked at it I don't see how it is much better than the existing authorize attribute logic in the past where hard-coded roles or users are decorated on controllers, methods etc. To me the issues has just been moved from hard-coding in attributes to hard-coding policies.
Ideally I would like to perform activity/resource based authorization where everything would be database driven. Each activity or resource would be stored in the database and a permission/role would be assigned to the resource.
While researching the topic I found this fantastic article by Stefan Wloch that pretty much covers exactly what I'm looking to do.
http://www.codeproject.com/Articles/1079552/Custom-Roles-Based-Access-Control-RBAC-in-ASP-NE
So my question is with the new core features how does it prevent us from having to hard-code and recompile when the time comes to change what roles/permissions are allowed to access a controller or method in a controller? I understand how claims can be used to store anything but the policy portion seems susceptible to change, which gets us back to square one. Don't get me wrong, loving asp.net core and all the great changes, just looking for more information on how to handle authorization.
There are at least 2 things that need to be consider in implementing what you want. The first one is how to model the Controller-Action access in database, the second one is to apply that setting in asp.net core Identity.
The first one, there are too many possibilities depend on the application itself, so lets create a Service interface named IActivityAccessService that encapsulate. We use that service via dependency injection so that anything that we need can be injected to it.
As for the second one, it can be achieved by customize AuthorizationHandler in a policy-based authorization. The first step is to setup things in Startup.ConfigureServices :
services.AddAuthorization(options =>
{
options.AddPolicy("ActivityAccess", policy => policy.Requirements.Add( new ActivityAccessRequirement() ));
});
services.AddScoped<IAuthorizationHandler, ActivityAccessHandler>();
//inject the service also
services.AddScoped<IActivityAccessService, ActivityAccessService>();
//code below will be explained later
services.AddHttpContextAccessor();
next we create the ActivityAccessHandler:
public class ActivityAccessHandler : AuthorizationHandler<ActivityAccessRequirement>
{
readonly IActivityAccessService _ActivityAccessService;
public ActivityAccessHandler (IActivityAccessService r)
{
_ActivityAccessService = r;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext authHandlerContext, ActivityAccessRequirement requirement)
{
if (context.Resource is AuthorizationFilterContext filterContext)
{
var area = (filterContext.RouteData.Values["area"] as string)?.ToLower();
var controller = (filterContext.RouteData.Values["controller"] as string)?.ToLower();
var action = (filterContext.RouteData.Values["action"] as string)?.ToLower();
var id = (filterContext.RouteData.Values["id"] as string)?.ToLower();
if (_ActivityAccessService.IsAuthorize(area, controller, action, id))
{
context.Succeed(requirement);
}
}
}
}
public class ActivityAccessRequirement : IAuthorizationRequirement
{
//since we handle the authorization in our service, we can leave this empty
}
Since we can use dependency injection in AuthorizationHandler, it is here that we inject the IActivityAccessService.
Now that we have access to what resource is being requested, we need to know who is requesting it. This can be done by injecting IHttpContextAccessor. Thus services.AddHttpContextAccessor() is added in code above, it is for this reason.
And for the IActivityAccessService, you could do something like:
public class ActivityAccessService : IActivityAccessService
{
readonly AppDbContext _context;
readonly IConfiguration _config;
readonly IHttpContextAccessor _accessor;
readonly UserManager<AppUser> _userManager;
public class ActivityAccessService(AppDbContext d, IConfiguration c, IHttpContextAccessor a, UserManager<AppUser> u)
{
_context = d;
_config = c;
_accessor = a;
_userManager = u;
}
public bool IsAuthorize(string area, string controller, string action, string id)
{
//get the user object from the ClaimPrincipals
var appUser = await _userManager.GetUserAsync(_accessor.HttpContext.User);
//get user roles if necessary
var userRoles = await _userManager.GetRolesAsync(appUser);
// all of needed data are available now, do the logic of authorization
return result;
}
}
Please note that the code in IsAuthorize body above is an example. While it will works, people might say it's not a good practice. But since IActivityAccessService is just a common simple service class, we can inject anything that wee need to it and modify the IsAuthorize method signature in any way that we want to. For example, we can just pass the filterContext.RouteData instead.
As for how to apply this to a controller or action:
[Authorize(Policy = "ActivityAccess")]
public ActionResult<IActionResult> GetResource(int resourceId)
{
return Resource;
}
hope this helps

How to Customize ASP.NET Web API AuthorizeAttribute for Unusual Requirements

I am inheriting from System.Web.Http.AuthorizeAttribute to create a custom authorization/authentication routine to meet some unusual requirements for a web application developed using ASP.NET MVC 4. This adds security to the Web API used for Ajax calls from the web client. The requirements are:
The user must logon each time they perform a transaction to verify
someone else has not walked up to the workstation after someone has
logged on and walked away.
Roles cannot be assigned to the web service methods at program time.
They must be assigned at run time so that an administrator can
configure this. This information is stored in the system database.
The web client is a single page application (SPA) so the typical forms authentication does not work so well, but I am trying reuse as much of the ASP.NET security framework as I can to meet the requirements. The customized AuthorizeAttribute works great for requirement 2 on determining what roles are associated with a web service method. I accept three parameters, application name, resource name and operation to determine which roles are associated with a method.
public class DoThisController : ApiController
{
[Authorize(Application = "MyApp", Resource = "DoThis", Operation = "read")]
public string GetData()
{
return "We did this.";
}
}
I override the OnAuthorization method to get the roles and authenticate the user. Since the user has to be authenticated for each transaction I reduce the back and forth chatter by performing authentication and authorization in the same step. I get the users credentials from the web client by using basic authentication which passes the encrypted credentials in the HTTP header. So my OnAuthorization method looks like this:
public override void OnAuthorization(HttpActionContext actionContext)
{
string username;
string password;
if (GetUserNameAndPassword(actionContext, out username, out password))
{
if (Membership.ValidateUser(username, password))
{
FormsAuthentication.SetAuthCookie(username, false);
base.Roles = GetResourceOperationRoles();
}
else
{
FormsAuthentication.SignOut();
base.Roles = "";
}
}
else
{
FormsAuthentication.SignOut();
base.Roles = "";
}
base.OnAuthorization(actionContext);
}
GetUserNameAndPassword retrieves the credentials from the HTTP header. I then use the Membership.ValidateUser to validate the credentials. I have a custom membership provider and role provider plugged in to hit a custom database. If the user is authenticated I then retrieve the roles for the resource and operation. From there I use the base OnAuthorization to complete the authorization process. Here is where it breaks down.
If the user is authenticated I use the standard forms authentication methods to log the user in (FormsAuthentication.SetAuthCookie) and if they fail I log them out (FormsAuthentication.SignOut). But the problem seems to be that base OnAuthorization class does not have access to Principal that is updated so that IsAuthenticated is set to the correct value. It is always one step behind. And my guess is that it is using some cached value that does not get updated until there is a round trip to the web client.
So all of this leads up to my specific question which is, is there another way to set IsAuthenticated to the correct value for the current Principal without using cookies? It seems to me that cookies do not really apply in this specific scenario where I have to authenticate every time. The reason I know IsAuthenticated is not set to the correct value is I also override the HandleUnauthorizedRequest method to this:
protected override void HandleUnauthorizedRequest(HttpActionContext filterContext)
{
if (((System.Web.HttpContext.Current.User).Identity).IsAuthenticated)
{
filterContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
This allows me to return a status code of Forbidden to the web client if the failure was because of authorization instead of authentication and it can respond accordingly.
So what is the proper way to set IsAuthenticated for the current Principle in this scenario?
The best solution for my scenario appears to be bypass the base OnAuthorization completely. Since I have to authenticate each time cookies and caching the principle are not of much use. So here is the solution I came up with:
public override void OnAuthorization(HttpActionContext actionContext)
{
string username;
string password;
if (GetUserNameAndPassword(actionContext, out username, out password))
{
if (Membership.ValidateUser(username, password))
{
if (!isUserAuthorized(username))
actionContext.Response =
new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
else
{
actionContext.Response =
new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
}
else
{
actionContext.Response =
new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest);
}
}
I developed my own method for validating the roles called isUserAuthorized and I am not using the base OnAuthorization any more since it checks the current Principle to see if it isAuthenticated. IsAuthenticated only allows gets so I am not sure how else to set it, and I do not seem to need the current Principle. Tested this out and it works fine.
Still interested if anyone has a better solution or can see any issues with this this one.
To add to the already accepted answer: Checking current sourcecode (aspnetwebstack.codeplex.com) for System.Web.Http.AuthorizeAttribute, it looks like the documentation is out of date. Base OnAuthorization() just calls/checks private static SkipAuthorization() (which just checks if AllowAnonymousAttribute is used in context to bypass the rest of the authentication check). Then, if not skipped, OnAuthorization() calls public IsAuthorized() and if that call fails, it then calls protected virtual HandleUnauthorizedRequest(). And that's all it does...
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw Error.ArgumentNull("actionContext");
}
if (SkipAuthorization(actionContext))
{
return;
}
if (!IsAuthorized(actionContext))
{
HandleUnauthorizedRequest(actionContext);
}
}
Looking inside IsAuthorized(), that's where Principle is checked against roles and users. So, overriding IsAuthorized() with what you have above instead of OnAuthorization() would be the way to go. Then again, you'd still have to probably override either OnAuthorization() or HandleUnauthorizedRequest() anyway to decide when to return a 401 vs a 403 response.
To add to the absolutely correct answer by Kevin, I'd like to say that I may slightly modify it to leverage the existing .NET framework path for the response object to ensure downstream code in the framework (or other consumers) is not adversely affected by some weird idiosyncrasy that can't be predicted.
Specifically this means using this code:
actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, REQUEST_NOT_AUTHORIZED);
rather than:
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
Where REQUEST_NOT_AUTHORIZED is:
private const string REQUEST_NOT_AUTHORIZED = "Authorization has been denied for this request.";
I pulled that string from the SRResources.RequestNotAuthorized definition in the .NET framework.
Great answer Kevin! I implemented mine the very same way because executing OnAuthorization in the base class made no sense because I was verifying an HTTP Header that was custom to our application and didn't actually want to check the Principal at all because there wasn't one.

Resources