Build a custom user check password in Asp.Net Identity 2 - c#

I need to build a custom user password check in an application implemented in asp.net MVC 5 and using Asp.Net Identity 2.
I read in a stackoverflow post (Writing a custom IUserPasswordStore and SignInManager.PasswordSignInAsync in Identity 2.1) that I only need to override the CheckPasswordAsync method in UserManager.
I try to override this method in IdentityConfig.cs file. Here is the code that I add to the ApplicationUserManager class just for test this solution:
public override async Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{
return await Task.Run(() => {
return true;
});
}
The problem is that this code is never run in the login process, and the login always fail. To sign in the user I’m using the SignInManager.PasswordSignInAsync to log in the user, this is the default when creating a new web application in asp.net MVC 5. Shouldn’t this method call the ApplicationUserManager. CheckPasswordAsync? Or there is another configuration needed to this work?

It should work. I've just used the standard ASP.NET MVC template, updated all the libraries involved through NuGet, and it must work.
I guess the problems is the way you are overriding the method.
In your ApplicationUserManager try to change your code like this:
public override Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{
return Task.FromResult<bool>(true);
}
or:
public override Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{
return Task.Run(() => MyCheckPasswordAsync());
}
private bool MyCheckPasswordAsync()
{
return true;
}
and you will see it goes through:

The problem was that I was trying to login with a user that do not exists in the system.
The SignInManager.PasswordSignInAsync never invoke the ApplicationUserManager. CheckPasswordAsync if the user not exists in the user store repository.
In conclusion, I have to store the users in my application or implement a custom user store mechanism.

This may not be a direct answer however it provides a full solution to the problem. He implements a custom authorisation filter which you can then customise to do what you want.
https://weblog.west-wind.com/posts/2013/Apr/18/A-WebAPI-Basic-Authentication-Authorization-Filter
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class BasicAuthenticationFilter : AuthorizationFilterAttribute
It can then be used like this instead of the [Authorize] attribute
[MyBasicAuthenticationFilter]
public class QueueController : ApiController

Related

How should the restriction be done when the subscription period expires?

In a Rest Api SaaS project developed with .Net Core 3.1.
When the user's subscription expires (needs to pay), what kind of a method would be better to follow.
There are 2 methods that I think of but I think there will be some problems in both of them.
Method 1) Checking the subscription status during JWT generate and not generating JWT if the subscription period has expired:
If I use this method;
Advantage: Since a token is not given to a user whose subscription expires,
they will not be able to access other endpoints.
I think this will work extremely safe without doing any other coding work.
Disadvantage: When I need to redirect the user to the payment page,
I will have to do a special work for the payment endpoints since there are no tokens.(Example: Password Reset Methods)
I will get it with query string, I think I can create a special token for this method.
But I think there might be a security bug because I couldn't protect this process with my standard authorization method?
Method 2) Even if the subscription expires, jwt will be generated, but membership will be restricted:
If I use this method;
Advantage: I can use my standard authorization method without any problems
when I need to direct the user to the payment endpoints or to another endpoints.
I will use with jwt and security bugs will be considerably reduced.
Disadvantage: I need to determine endpoints that cannot be accessed on the application for user whose subscription period expired
and I will need to code a working service in middleware that will make them inaccessible. (Like to permission methods)
This will both do extra coding work and each endpoint will require extra work.
These are my thoughts....
Or other solutions...
How should we restrict a user whose subscription expires and how should we act?
Thank you very much for your information sharing.
I solved the question I asked above using Method 2.
I wanted to explain how I did it, as I thought it might help those who investigate this question in the future.
I said in method 2, jwt has generated but membership restricted.
First of all, when generating tokens, I set claims whether they have a subscription or not.
....
new Claim(JwtClaimIdentifier.HasSubscription, hasSubscription)
I do not explain here in detail. Standard claims.
Subscription Control
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public sealed class SubscriptionRequiredAttribute : TypeFilterAttribute
{
public SubscriptionRequiredAttribute()
: base(typeof(SubscriptionFilter)) { }
}
--
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public sealed class AllowWithoutSubscriptionAttribute : Attribute
{
public AllowWithoutSubscriptionAttribute() { }
}
--
public class SubscriptionFilter : IAuthorizationFilter
{
private bool AllowWithoutSubscription(AuthorizationFilterContext context)
{
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
bool allowWithoutSubscriptionForMethod = controllerActionDescriptor.MethodInfo.CustomAttributes.Any(x => x.AttributeType == typeof(AllowWithoutSubscriptionAttribute));
if (allowWithoutSubscriptionForMethod)
return true;
bool allowWithoutSubscriptionForController = controllerActionDescriptor.ControllerTypeInfo.CustomAttributes.Any(x => x.AttributeType == typeof(AllowWithoutSubscriptionAttribute));
if (allowWithoutSubscriptionForController)
return true;
return false;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
if (AllowWithoutSubscription(context))
return;
var hasSubscription = context.HttpContext.User.Claims.First(x => x.Type == JwtClaimIdentifier.HasSubscription).Value.ToLower() == "true";
if (!hasSubscription)
context.Result = new BadRequestObjectResult(**ErrorCode**);
}
}
I added, an attribute that override subscription control.
For example; To use it in a controller or method that I need to override when checking subscriptions on base.
Use Controller
[SubscriptionRequired]
public class FooController
{
public async Task<IActionResult> FooMethodOne(){...}
public async Task<IActionResult> FooMethodTwo(){...}
[AllowWithoutSubscription]
public async Task<IActionResult> FooMethodThree(){...}
}
While FooMethodOne and FooMethodTwo above require subscription, FooMethodThree will work without subscription.
Likewise, all controls are called "AllowWithoutSubscription".
It can also be called "SubscriptionRequired" in methods.
Hopefully it benefits your business...

Asp.Net Identity connecting to DB via Web Api

I am working on a legacy MVC application which initially had forms authentication via a custom class and implementation. I have modified it and utilised Asp.Net Identity which is working as expected.
My requirement now is that this MVC application no longer should have direct access to the database. So I have removed the connection string from the web.config and have been looking at making all database calls via calls to my web service (Asp.Net Web Api).
I have custom classes for:
UserStore
RoleStore
etc
Please note I have a custom user class as it is a custom user table.
Questions
1) Is the correct way to achieve my goal? It's likely I will be overriding many methods which had previously used the IdentityDBContext such as:
public override Task<CustomUser> FindByIdAsync(int usrID)
public override Task<Customer> FindByNameAsync(string userName)
2) I am finding that
FindByNameAsync()
is working as expected and the user is being passed to the method however FindByIdAsync() is passing userid as 0. Why would FindByIdAsync() not be passing my actual userid?
To call FindByIdAsync() I am implementing a UserStore:
public class CustomUserStore : UserStore
<
CustomUser,
CustomRole,
int,
CustomUserLogin,
CustomUserRole,
CustomUserClaim
>
{
and then overriding FindByIdAsync():
public override Task<CustomUser> FindByIdAsync(int usrID)
{
var response = client.GetAsync("api/user/" + usrID).Result.Content;
return response.ReadAsAsync<CustomUser>(
new List<MediaTypeFormatter> {
new XmlMediaTypeFormatter(),
new JsonMediaTypeFormatter()
});
//return base.FindByIdAsync(userId);
}
The issue is that usrID is 0.
I now have this working, so my mvc application is using AspNet.Identity but for all the database calls it is calling my api. The solution was indeed to implement IUserStore (and other interfaces as required) and there are a lot of answers and guides on the Internet for this. A good starting point is:
https://learn.microsoft.com/en-us/aspnet/identity/overview/extensibility/overview-of-custom-storage-providers-for-aspnet-identity

Best practise for optional injecting of current user

In our ASP.NET MVC project we are using Ninject to resolve our dependencies needed by the controllers.
One of these dependencies is the current user HttpContext.Current.User.Identity. If the user is authenticated we would like to instantiate a user object and several services which relies on it. But we would like to do this not manually but let ninject inject these instances to the controller.
So we get into trouble now, since a url can be located without being authenticated of course. Then ninject tries to resolve the instances before asp.net can redirect to the login page.
I can think of the solution, that we configure ninject do just inject when user is authenticated:
kernel.Bind<User>().ToMethod(GetUser).When(context => HttpContext.Current.User.Identity.IsAuthenticated).InRequestScope();
The problem here is that even if the user is not authenticated ninject instantiates a default object, so my services crashes or needs to check the instance anyhow.
Null checks would me much more acceptable but I wouldn't like to activate AllowNullInjection setting of Ninject.
So my question is whats the best practise for doing such conditional things?
Are there Ninject features I could use in these cases or shouldn't I inject these dependencies anyway?
I assume you are talking about a situation where a non-authenticated user could try to navigate to a page that normally requires authentication, but without first going through the login process. Ninject would then be unable to inject the current user object into the controller because it's not yet known and will throw an exception.
I can see 2 options:
The first option is instead of injecting the current user, create a factory or provider that retrieves the current user details and inject this instead. The controller can then call the provider to get the current user and if the user is unavailable you can redirect to the login page.
public OrdersController(IUserProvider userProvider)
{
this.userProvider = userProvider
}
public void DoSomething()
{
var user = this.userProvider.GetCurrentUser();
if (user == null)
RedirectToLogin();
// continue doing something
}
public class UserProvider : IUserProvider
{
public User GetCurrentUser() { ... }
}
The problem with this option is that you'll need to do this potentially in many controllers (it's a "cross cutting concern") and you don't want to have to repeat the code that does the redirect over and over. Instead, a second option would be to use the Decorator design pattern to create an interceptor that checks for logged in users before forwarding on to the real controller.
The way I've done something similar in the past is using the Ninject Interception Extension to create an attribute that marks which controllers require authentication, like this (bit psuedo-codey):
public class AuthenticationInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
bool authenticated = // ... get the current user ...
if (authenticated)
invocation.Proceed();
else
RedirectToLoginPage(); // however you want to do this
}
}
public class RequiresAuthenticationAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Context.Kernel.Get<AuthenticationInterceptor>();
}
}
[RequiresAuthentication]
public class OrdersController : IOrdersController
{
// assume you've already been authenticated
}
The interceptor will automatically be created whenever a class that's decorated with RequiresAuthentication is created and the current user credentials will be checked. If they are invalid, the request will be forwarded to the login page, otherwise it will continue as normal. This one interceptor can then be written and tested once whilst being used in many places without duplicating code.
Just as a simple auth and non auth answer that some may find useful.
kernel.Bind<ICustomUser>()
.To<User>()
.When(ctx => HttpContext.Current.User.Identity.IsAuthenticated)
.InRequestScope();
kernel.Bind<ICustomUser>()
.To<Guest>()
.When(ctx => !HttpContext.Current.User.Identity.IsAuthenticated)
.InRequestScope();
Otherwise anything more complex Adam Rodgers awnser is better :)

Controlling access to methods

Is there a way to control access to methods to certain roles in .net. Like
class A
{
//should only be called by Admins**
public void Method1() { }
//should only be called by Admins and PM's**
public void Method2() { }
}
I'm using windows authentication only for retrieving user names and nothing more.User roles are maintained in a different application. I think it's possible through attributes but I'm not really sure how
It it possible, I have used it on an web project that used asp.net and AzMan as the authentication.
Take a look at Code Access Security
From memory all of our methods looked something like
[Permission(SecurityAction.Demand, "Permission")]
public void Method1
It's been a while though so that might not be actually 100% correct.
I'd also highly suggest if you are going to put protection down to this level to look at a task orientated permission approach as this is much more flexible than role based permissions
You can do this as follows:
class A
{
//should only be called by Admins**
[PrincipalPermission(SecurityAction.Demand, Role="Admin")]
public void Method1()
{
}
//should only be called by Admins and PM's**
[PrincipalPermission(SecurityAction.Demand, Role="Admin")]
[PrincipalPermission(SecurityAction.Demand, Role="PM")]
public void Method2()
{
}
}
To do this Thread.CurrentPrincipal must be set to a principal that has the required roles. For example, if you enable roleManager in an ASP.NET application, Thread.CurrentPrincipal will be set to a RolePrincipal with roles from your configured RoleProvider. See this MSDN article for more info.
You can do it using custom validation.
1- Make a method in another public class which take login id as parameter and return roles in form of bits.
2- Call this method on the page_Load event of the required class and save returned bits in the view state.
3- Now validate required method on the basis of roles bits.

Roles/Permissions - can caching affect it?

Once authenticatated I use HttpContext.Current.User.Identity.Name; to ensure user is authorized to view a part of my site.
When I access certain parts of my site I need to get the User and get which context (organization they are logged into), url would be something like settings/supercompany/profile. where supercompany is the current context.
For each user I would need to check if they are admin in that company or a general user, if a general user then they cannot see certain things.
public class SettingsApi
{
private readonly string _userId;
private readonly string _contextId;
public SettingsApi(string userId, string contextId)
{
_userId = userId;
_contextId = contextId;
}
}
If I instantiate the class above from a controller (post or get), would caching somehow mess things up? Users role changed and I don't pick it up? Would something like the below work well?
var settings = new SettingsApi(HttpContext.Current.User.Identity.Name, currentContextId);
settings.IsAdmin();
Note: I would have used attributes to authorize but my requirements are I need to pick out the currentContext from the URL plus I need to use the class above elsewhere in my code.
Update
AuthorizeAttribute works well with caching, but the method used to authorize i.e.
protected override bool AuthorizeCore(HttpContextBase httpContext)
Will not hand me back an instance of the class I need...
Update 2 I don't want this class or an instance of this class to be cached in anyway, everytime I ask for a new instance I don't mind fetching one from the DB...
My Question - is the way I am coding ok? Will my user and his permissions NOT be cached?
It is possible, if you're not careful, to let MVC cache the output of the first request by an authenticated user. I use VaryByCustom and the current identity's name.
[OutputCache(VaryByCustom="user")]
public class SomeController : Controller
{
// etc.
}
In my Global.asax.cs I define:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (custom.Equals("user", StringComparison.OrdinalIgnoreCase))
{
return context.User.Identity.IsAuthenticated ? context.User.Identity.Name : string.Empty;
}
return base.GetVaryByCustomString(context, custom);
}
If you are proposing to add instances of the SettingsApi to the cache then it definitely will not work as caching is app wide and so all users will end up sharing the same SettingsApi. Using the OutputCache should be fine (as long as you dont do something like put userid in a hidden field and use [OutputCache(VaryByCustom="user")] or similar).
If you are looking to cache the SettingsApi you should do so through SessionState which is per user/session and wont affect the authentication.

Categories