How to implement Asp.net membership in my developed web application - asp.net

I am working on a web application. I already completed it. But when I gone through security audit, I came to know that I should use asp.net membership for, login, password change, creating user, reset password etc.
So I stared using asp.net membership. I created a login page and it's working fine. I also got a database in my App_Data folder.
The problem is that I already have a database for my application where I have a user table which is having more fields than the table aspnet_Users. see the image below.
So please suggest me how to implement asp.net membership in my web application, as I need more fields in user table,
how to insert data along with my fields with the fields above mentioned in the above image, because I didn't fine any code through using asp.net membership. If I could got, I would surely make changes accordingly.
I mean how to merge this database and mine without any code.

I would also recommend that you use ASP.Net Identity as it is the framework for handling security.
However, if you are going to use simple membership, here is some code to help you "add fields" to your user table.
First, create your user model with all needed properties like so:
[Table("User")]
public class User
{
public int UserId { get; set; }
[Display(Name = "User name")]
[Required(ErrorMessage = "Usernname is required.")]
[StringLength(80, ErrorMessage = "Please enter a value no more than 80 characters.")]
public string UserName { get; set; }
[Display(Name = "First Name")]
[Required(ErrorMessage = "First name is required.")]
[StringLength(80, ErrorMessage = "Please enter a value no more than 80 characters.")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
[Required(ErrorMessage = "Last name is required.")]
[StringLength(80, ErrorMessage = "Please enter a value no more than 80 characters.")]
public string LastName { get; set; }
[Required]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
[StringLength(254, ErrorMessage = "Please enter a value no more than 254 characters.")]
public string Email { get; set; }
//Add other properties... etc
}
Next, write the code to initialize your database. You probably have this code somewhere in the InitializeSimpleMembershipAttribute.cs file. Or, you can take it out from there and put in on your Application Start method. Here is the piece you need to modify:
WebSecurity.InitializeDatabaseConnection("YourDBConnectionName", "User", "UserId", "UserName", autoCreateTables: true);
//Modify the above properties if you change your user model to be a different table name
See reference to InitializeDatabaseConnection.
Now, when you want to create a user, call the following method:
WebSecurity.CreateUserAndAccount(user.UserName, user.Password, new { user.Email, user.FirstName, user.LastName });
//user is the User object that has all your data populated from some type of input
Reference to create user account: CreateUserAndAccount

The one you are trying to implement is legacy ASP.Net Membership Provider created using aspnet_regsql.exe. Do not use it, because it has been deprecated long time ago.
Currently, Microsoft offers 3 types of Memberships -
ASP.NET Universal Providers
Simple Membership Provider
ASP.NET Identity
Since your application is new and doesn't have existing users, you want to use -
ASP.NET Identity 2
The problem is that I already have a database for my application where
I have a user table which is having more fields than the table
aspnet_Users.
ASP.Net Identity lets you create custom fields in User table.
FYI: Make sure you use Version 2.

Related

Remove User from Directory Role using Graph API

I am trying to add and remove users from a directory role (Guest Inviter) based on a user's ID. My client ID has Directory.AccessAsUserAll for the Microsoft Graph application. I am using the ID for the directory role and the ID for the user. Using an HTTP Client call (verb is DELETE) I use the format suggested by Microsoft and get an "Insufficient privileges to complete the operation." error. I can perform other functions successfully
It seems clear to me that I am missing something. I would think that you still log in with the Client ID and Client Secret then do something with an admin type id and password rather than just create a new token based these credentials (because then why would you link them) similar to impersonation code but I don't know how and cannot seem to find an example of how.
Using HTTPClient
Verb DELETE
following this pattern
DELETE /directoryRoles/{id}/members/{id}/$ref
https://learn.microsoft.com/en-us/graph/api/directoryrole-delete-member?view=graph-rest-1.0&tabs=cs
Using C# creating bearer token (with client id and client secret) then using an HTTPCLient I call DeleteAsync using a url string based on the recommended pattern.
I see references to needing to pass user credential for a user in an admin role.
I think the issue is the absence of something important. This is called once the bearer token is obtained using client id and client secret for out tenant.
string delURL = $"{settings.RestUrl.value}{settings.RestVersion.value}/directoryRoles/{settings.GuestInviterRoleObjectID.value}/members/{user.id}/$ref";
HttpResponseMessage payload = await client.DeleteAsync(delURL);
Task<string> json = payload.Content.ReadAsStringAsync();
JObject o = new JObject();
if (json.Result.Length > 0)
{
o = JObject.Parse(json.Result);
}
I would like to remove the user from the Guest Inviter directory role. I get however
error: code:"authorization_requestDenied",
messsage: "Insufficient privileges to complete the operation" ....
Update: I was following this example https://dzone.com/articles/getting-access-token-for-microsoft-graph-using-oau-2
I built a class to contain the properties so after getting my original token using Client ID and Client secret then feeding in what I was told was a global admin credentials and now I get a 401 unauthorized error.
string tURL = $"https://login.microsoftonline.com/{settings.TenantID.value}/oauth2/token";
using (System.Net.WebClient c = new System.Net.WebClient())
{
c.Headers["Authorization"] = $"Bearer {token}";
c.Headers["Content-Type"] = "application/x-www-form-urlencoded";
System.Collections.Specialized.NameValueCollection data = new System.Collections.Specialized.NameValueCollection();
body.GetType().GetProperties().ToList().ForEach(delegate (System.Reflection.PropertyInfo item)
{
data.Add(item.Name, item.GetValue(body) == null ? string.Empty : item.GetValue(body).ToString());
});
var res = await Task.Run(() => c.UploadValues(tURL, data));
Task.WaitAll();
if(res != null)
{
string response = System.Text.Encoding.UTF8.GetString(res);
}
}
Data object
public class JSONBody
{
public string grant_type { get; set; }
public string client_id { get; set; }
public string client_secret { get; set; }
public string resource { get; set; }
public string username { get; set; }
public string password { get; set; }
public JSONBody()
{
this.grant_type = "password";
this.resource = "https://graph.microsoft.com";
}
}
I cannot prove or disprove the 401 error because I cannot prove my code works (or doesn't).
According to the documentation https://learn.microsoft.com/en-us/graph/api/directoryrole-delete-member
You’ll need an application with the delegated Directory.AccessAsUser.All permission. The you’ll need an admin to login to that application (with the correct permissions).
The application credentials (or client credentials flow) is unsupported, by design.
This could result in privilege elevation, if some admin would create an application with these permissions. If that admin would then be removed from the admin role he would be able to use his application to make himself admin again

Plain password in .net core SignInManager Identity

I have user table with plain passwords. I need connect the table into .net core web's AspNetUsers table.How to hash my user table's plain passwords like AspNetUsers's PasswordHash.
How can login with SignInManger plain-text password?
I recently did something like this. Our legacy system had its own password hashing method. I needed to covert everything over to asp.net users.
First thing I did was add two new columns to the Application user. These contain my legacy user password and that hash that was used to create it.
public string LegacyPasswordHash { get; set; }
public string LegacyPasswordSalt { get; set; }
Then i ran my sql script that copied all of the users in including their legacy password hash and salt.
Then i created a custom SignInManager.
public class ApplicationSignInManager : SignInManager<ApplicationUser> {}
In the password check method I test if its a legacy password user and if it is i covert the password that they just sent me over to a asp.net users password and delete their legacy password. Tip: is to remember to set the user security token on the user table as well this can not be null. You will have major issues with resting password if it is. As there is a bug in the token validation 2022
This is the section of the code i use for testing and resetting the password.
if (_password.EncodePassword(_user.LegacyPasswordSalt) == _user.LegacyPasswordHash)
{
_logger.LogInformation(LoggingEvents.LegacyUserCommand, "Legacy User {_user.Id} migrating password.", _user.Id);
await _userManager.AddPasswordAsync(_user, _password);
_user.SecurityStamp = Guid.NewGuid().ToString();
_user.LegacyPasswordHash = null;
_user.LegacyPasswordSalt = null;
await _userManager.UpdateAsync(_user);
return await new CheckTwoFactorCommand(_logger, _userManager, _user).Execute();
}
if (_shouldLockout)
{
_user.SecurityStamp = Guid.NewGuid().ToString();
await _userManager.UpdateAsync(_user);
_logger.LogInformation(LoggingEvents.LegacyUserCommand, "Login failed for Legacy user {_user.Id} invalid password. (LockoutEnabled)", _user.Id);
await _userManager.AccessFailedAsync(_user);
if (await _userManager.IsLockedOutAsync(_user))
return SignInResult.LockedOut;
}
_logger.LogInformation(LoggingEvents.LegacyUserCommand, "Login failed for Legacy user {_user.Id} invalid password", _user.Id);
return SignInResult.Failed;

ASP.NET MVC password validation with hash

So I want to add my Custom Hash into my password, but it got stuck because my own validation
My Model:
public class ms_user
{
[Required(ErrorMessage = "Please Input your Login Email")]
[DataType(DataType.EmailAddress)]
public object user_id { get; set; }
[Required(ErrorMessage = "Please Input your Password")]
// Validation at least 1 uppercase & 1 number, password lenght must be greater then 6 and lower then 12, with no Special Character
[RegularExpression(#"^(?=.*\d)(?=.*[A-Z])[a-zA-Z0-9](.{6,12})$", ErrorMessage = "Error, Wrong Password Format")]
public object password { get; set; }
}
Sample:
Password Inputed : Admin123 // Pass Validation
HashedPassword Output: l92Vi3c2Af7Oftgy7JqYJKR8isYXef8pIOqvMzjrN6rnRct6W6UuDzv0YRCOudPPXnC69Gj2J4igXZWH1WRz9C19abN4UWKSqX8d0TxA+0IvXJAvzoksaEWPQm56gy/l:9KZQeh3nB9apjy81V/FvfU // After i hashed my password,
My Project pass the Password Validation, but on the db.SaveChanges(); it return error, because the Password validation
is there any solution?? i prefer not to add javascript validation...
Thx
Change the Datatype of Password column to nvarchar(MAX) in your User table to accomodate the Hashed Password.
I faced this exact same problem, because I updated the password length in database to nvarchar(max) but didn't update the model in visual studio after that. So Update the Model and it should fix that.

OAuth and SimpleMembership - how to retrieve ProviderUserId from webpages_OAuthMembership table

I've created an ASP.Net MVC4 web application and it includes the templated functionality that allows users to register with external providers such as Facebook and Twitter. This uses OAuth and SimpleMembership. I'm using Entity Framework code-first, which I'm new to, so I'm finding it difficult to do something really simple.
Once the user has registered with the external provider, a record is created in webpages_OAuthMembership with fields Provider, ProviderUserId and UserId. UserId maps to UserId in the UserProfile table. How do I read the ProviderUserId for the authenticated user? I need it to for use with the FB.api and for other things like retrieving the user photo using https://graph.facebook.com/[ProviderUserId]/picture?type=small.
I have tried this:
SimpleMembershipProvider provider = (SimpleMembershipProvider)Membership.Provider;
string providerUserId = provider.GetUser("[username]", true).ProviderUserKey.ToString();
but ProviderUserKey just returns the UserId rather than ProviderUserId.
There must be a simple way to do this that I'm missing?
This answer assumes using Entity Framework 6 Code First approach (although all the code should work with earlier versions of EF).
I was having issues with accessing Provider and ProviderUserId too. I was attempting to delete a user accounts that authenticated with OAuth. I was able to delete the actual user account from the database with the code:
((SimpleMembershipProvider)Membership.Provider).DeleteAccount(selectedUser); // deletes record from webpages_Membership table
((SimpleMembershipProvider)Membership.Provider).DeleteUser(selectedUser, true); // deletes record from UserProfile table
However, this left the entry in the webpages_OAuthMembership table (which I wanted to delete!).
To solve this, I made a class with the same name as the db table:
public class webpages_OAuthMembership
{
[Key, Column(Order=0)]
public string Provider { get; set; }
[Key, Column(Order = 1)]
public string ProviderUserId { get; set; }
public int UserId { get; set; }
}
The Key and Column data annotations let EF know that Provider and ProviderUserId form a composite key (I think SQL Server calls it a clustered PK). Anyways, in the DbContext class that initializes the database, I did a DbSet on that class:
public DbSet<webpages_OAuthMembership> webpages_OAuthMembership { get; set; }
This now allows you to access the OAuth table in the database in your code
var db = new DbContext(); db.webpages_OAuthMembership.ToList();
// this would give you all entries in the OAuth table
For your case, to get the ProviderUserId, you could use the following code
var OAuthAccount = db.webpages_OAuthMembership.Where(u => u.UserId == userIdOfUserYouAreSearchingFor).FirstOrDefault;
// ProviderUserId would be OAuthAccount.ProviderUserId
where 'userIdOfUserYouAreSearchingFor' is the UserId (from UserProfile table). Make sure to have the FirstOrDefault on the end. That way, if there is no entry in the database for that particular UserId, it will receive null and you can check again that.
Now in my case, I wanted to delete entries from said table. Just in case anyone else comes across this, I will include that info too.
I used this code
var OAuthAcct = ((SimpleMembershipProvider)Membership.Provider).GetAccountsForUser(selectedUser).ToList();
var provider = OAuthAcct[0].Provider;
var providerUserId = OAuthAcct[0].ProviderUserId;
((SimpleMembershipProvider)Membership.Provider).DeleteOAuthAccount(provider, providerUserId);
to delete entries from the webpages_OAuthMembership table.
Hope that helps!

How to securely store service passwords with ASP.NET Membership?

I am using ASP.NET MVC 3 membership for my site with defaults. Thus the membership password for the user is stored securely.
My service requires the user to enter username/passwords for other web services they use. I access those services from my service. If I save the users' service passwords I need to ensure that those usernames/passwords are stored securely as well so that if someone hacks my server they will not be exposed.
I understand the general concepts of how this might be done (encrypt the username/pw using the hash of the ASP.NET membership pw they've provided as the key). But I don't know the specific APIs or correct patterns.
I also think it's basically impossible to really do this because if someone hacks my service they could simply use the hash themselves to decrypt the passwords. Am I right about that.
Assuming i'm wrong, and it is possible to do what I want, assume my model contains something like this:
public class MSExchangeSettings
{
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address for your Exchange account")]
public string EmailAddress { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password for your Exchange account")]
public string Password { get; set; }
...
}
Can someone please provide an example of how to do this correctly?
If, this is not possible I'll have to resort to asking the user for the PW every every time which I want to avoid. Of course, for the services I use that support OpenID or OAuth I have other alternatives, but for this specific example (Exchange) I need a username/pw.
Take a look at this
private static string GetPasswordHashed(string password) {
var saltBytes = new byte[0x10];
using (var random = new RNGCryptoServiceProvider()) {
random.GetBytes(saltBytes);
}
var passwordBytes = Encoding.Unicode.GetBytes(password);
var combinedBytes = saltBytes.Concat(passwordBytes).ToArray();
byte[] hashBytes;
using (var hashAlgorithm = HashAlgorithm.Create("HashAlgorithm")) {
hashBytes = hashAlgorithm.ComputeHash(combinedBytes);
}
var PasswordHashed = Convert.ToBase64String(hashBytes);
return PasswordHashed;
}

Resources