I am moving all of the Authentication and Security concerns into my Data Access Layer on an ASP.NET MVC4 Internet Application. Everything is fine for logging in, logging out, creating users etc but I am hitting a stumbling block with adding users to roles.
After Creating a user account I want to add them to some default roles. The method for doing so looks like this
public static string CreateUserAccount(string username, string password)
{
WebSecurity.CreateUserAndAccount(username, password);
var roleProvider = new SimpleRoleProvider();
roleProvider.AddUsersToRoles(new[] {username}, new[] {"MeterInfo", "SiteInfo", "AMRInfo", "InstallImages"});
return username + " Account Created";
}
The call to WebSecurity for creating the account is OK, but my use of SimpleRoleProvider causes this error
You must call the "WebSecurity.InitializeDatabaseConnection" method before you call any other method of the "WebSecurity" class. This call should be placed in an _AppStart.cshtml file in the root of your site.
The InitializeDatabaseConnection is already handled in the AuthConfig which is called on startup by global.asax.
AssetRegisterDataLayer.DataAccess.Security.InitializeSecurity();
The method being called on my DataAccess layer looks like this
public static void InitializeSecurity()
{
WebSecurity.InitializeDatabaseConnection("AssetRegisterDb","UserProfile","UserId","UserName", false);
}
I have seen this issue happen when people use the out of the box config for MVC4 where the Accounts controller is decorated with the [InitializeSimpleMembership] attribute instead of calling the WebSecurity initializer at application start, but that is not the case here. Anyone know why all the WebSecurity works except roles?
Thanks very much
I have found my mistake, I will answer my own question in case someone else has a similar issue.
The error in the code shown in my question was instantiating a new SimpleRoleProvider. I should have done this
public static string CreateUserAccount(string username, string password)
{
WebSecurity.CreateUserAndAccount(username, password);
var roleProvider = (SimpleRoleProvider)Roles.Provider;
roleProvider.AddUsersToRoles(new[] {username}, new[] {"MeterInfo", "SiteInfo", "AMRInfo", "InstallImages"});
return username + " Account Created";
}
Related
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
By default, MVC 5 Single Page Application uses EntityFramework to store users and passwords for authentication.
In my scenario, I must use an existing homemade AuthenticationService.
I decided to create a custom IUserStore. I then must implement the GetPasswordHashASync to validate credentials.
Our architect considers this as a security breach but I do not agree with this. I then would like to get your opinion about this.
What is the difference between getting the PasswordHash for the database of another service on the same server node. In my opinion, I dont this it is a security breach...
Here's some code to demonstrate how it works.
The user logs in with his credentials so it calls the Login Method of my AccountController. Then, it calls the UserManager FindUserAsync:
var user = await UserManager.FindAsync(model.Email, model.Password);
Since I create my own IUserStore, I call our service (WFC) like this:
if (client.IsUsernameExists(userName, remoteInfo, out messages))
{
user = new ApplicationUser() { Email = userName, Username = userName};
}
Under the hood it then calls the GetPasswordHashAsync. My implementation then call our service again:
passwordHash = client.GetPasswordHash(user.Username, RemoteInfo, out messages);
Any thoughts?
The interface you are looking to implement is the IUserPasswordStore. Nothing wrong with that.
This is the correct way of implementing the IdentityStores of OWIN (and probably other authentication frameworks).
I've implemented my own UserStore for a MongoDB implementation of OWIN. Here is my implementation of the IUserPasswordStore
public Task SetPasswordHashAsync(TUser user, string passwordHash)
{
user.PasswordHash = passwordHash;
return Task.FromResult(0);
}
public Task<string> GetPasswordHashAsync(TUser user)
{
return Task.FromResult(user.PasswordHash);
}
The password hash is stored in the DB, so when you pull the user from the DB, it has a property which is the hash. So the appropriate implementation for GetPasswordHashAsync, is to return the hash from the user object.
I have a site (MVC5) that require a user to login. However I have no control over the user database, instead I have a web services with a method of something like this.
public bool LogIn(string username, string password);
I need to login the user if it returns true, any idea how to achieve this?
I've read this article
http://www.asp.net/identity/overview/extensibility/overview-of-custom-storage-providers-for-aspnet-identity but have no idea how to create my own context, stuck in this part since the author doesn't provide downloadable solution example.
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ExampleStorageContext.Create);
app.CreatePerOwinContext(ApplicationUserManager.Create);
...
Any help will be appreciated and sorry for bad english.
In this case you can simply use Session to save state of user.
I am creating an application where I first login with my user account. This user account could be windows or self managed account in my own application database.
Now I want to authorize the logged in user before accessing any business objects of my application. Objects are mapped with database tables so eventually I want to authorize user first, whether to give data back to user or not.
After logging in I store user credentials globally as an object of UserCredential class. But I don't want to pass this credentials to each object when I am creating it.
Is there any way to check/reach the application context (including UserCredential object I stored globally) for each business objects automatically which I am creating further?
I want to achieve this in C#. Code example is much appreciated.
You should take a look at the PrincipalPermissionAttribute class, here is the MSDN documentation:
PrincipalPermissionAttribute class MSDN documentation
The PrincipalPermissionAttribute throws a SecurityException when the Thread.CurrentPrincipal does not match the security assertion.
Examples:
User's name is GDroid:
[PrincipalPermission(SecurityAction.Demand, Name = "GDroid")]
public void YourBusinessMethod()
{
// Do something
}
User belongs to Admin role:
[PrincipalPermission(SecurityAction.Demand, Role = "Admin")]
public void YourBusinessMethod()
{
// Do something
}
User is authenticated:
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
public void YourBusinessMethod()
{
// Do something
}
I have a WPF application that connects to a WCF service. I need users to be authenticated to call any method of my service but I also need users to be able to register if thy don't have an account.
I first thought about using a usernamePasswordvaldator but I couldn't find a way to create a register method that doesn't go through the validate method of my validator class.
I then saw MembershipPorvider but didn't find any example that matches my case.
You can create a special user in the database. Add this user to a special membership role.
This special user can only create new users, it doesn't have any other permissions to the service methods.
You should add a PriciplePermission attirbute on all of your methods, and allow your new role (CreateUserRole) to access just the CreateUser method.
[PrincipalPermission(SecurityAction.Demand, Role = "CreateUserRole")]
public void CreateUser(string username, string password)
All other methods should have different roles:
[PrincipalPermission(SecurityAction.Demand, Role = "ADMINISTRATORS")]
public bool DeleteUser(string username)
so that this special user can only access the CreateUser method.