I am implementing a custom MembershipProvider and I am trying to get the ValidateUser method to validate against my Profiles table in SQL Server. This table has columns called UserName and Password.
public override bool ValidateUser(string username, string password)
{
??? what to do here???
}
FYI, I am using MVC3 & EF 4.1 Code First.
Thanks
Paul
If you're using EF 4.1, you will have some kind of a DbContext object that contains the DbSet for your Profiles table - right?
So in that case, use this:
public override bool ValidateUser(string username, string password)
{
using(DbContext yourCtx = new DbContext())
{
// from your "Profiles" DbSet, retrieve that single entry which
// matches the username/password being passed in
var profile = (from p in yourCtx.Profiles
where p.UserName == username && p.Password == password
select p).SingleOrDefault();
// if that query returns a "Profile" (is != null), then your
// username/password combo is valid - otherwise, it's not valid
return (profile != null);
}
}
Related
I am making a login page and i saved the user's details and hashed password in the CUSTOMERS table, but i cant send the salt and the typed password i get from the database and the user to my method
var UserInput = db.CUSTOMERs.Where(b => b.EMAIL == cUSTOMER.EMAIL && b.PASSWORD == sha256(b.SALT+cUSTOMER.PASSWORD).ToString()).FirstOrDefault() ;
Hash method
static string sha256(string password)
{
System.Security.Cryptography.SHA256Managed crypt = new System.Security.Cryptography.SHA256Managed();
System.Text.StringBuilder hash = new System.Text.StringBuilder();
byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(password), 0, Encoding.UTF8.GetByteCount(password));
foreach (byte theByte in crypto)
{
hash.Append(theByte.ToString("x2"));
}
return hash.ToString();
}
You have the error because Linq To Entities hence Entity Framework can't be used to compose with function that can't be translated into SQL. So your custom method sha256 and ToString.Net method are the main causes.
To make it work you must first get the user by email then check that the user has his password hash equal to the genrated one.
So you need to rewrite your code like this:
var UserInput = db.CUSTOMERs.FirstOrDefault(b => b.EMAIL == cUSTOMER.EMAIL);
if(UserInput != null && UserInput.PASSWORD == sha256(UserInput.SALT+cUSTOMER.PASSWORD))
{
// The user email and password match
}
else
{
// The user not found or the password does not match
}
I am using MVC5, i know that if a user forgets his password, then MVC provides the feature of forgot password and reset password.
My client server is disconnected from internet or mailing, it is behind the firewalls, so i cannot use forgot password, as it might generate a link to reset password, but cannot mail it to the user to facilitate the password reset.
Please suggest if there is any way to decrypt the password(to let user know if he forgets his password) like how it was available in asp.net membership by simply using the GetPassword method of the membership classes.
Thank you
As far I know there is no easy way to do this in MVC5, because Identity (next gen of Membership) is using hash of password rather then encrypted password.
Password is hashed and stored in db as a hash - generally it's one-way operation (it's mean that there is no easy way to get password form hash).
Little bit more about what is hashing and salting you can read here:
How to securely store passwords and beat the hackers
How does hashing work?
This step to Ecrypt and decrypt password in asp.net mvc5.
create class name Hashing, paste this code
private static string GetRandomSalt()
{
return BCrypt.Net.BCrypt.GenerateSalt(12);
}
public static string HashPassword(string password)
{
return BCrypt.Net.BCrypt.HashPassword(password, GetRandomSalt());
}
public static bool ValidatePassword(string password, string correctHash)
{
return BCrypt.Net.BCrypt.Verify(password, correctHash);
}
Create controller login you past this code
using WebBcryptMVC.Models; //
using WebBcryptMVC.Util; // call folder name of Hashing class
namespace WebBcryptMVC.Controllers
{
public class LoginController : Controller
{
private DBLoginEntities db = new DBLoginEntities();
public ActionResult frmLogin()
{
return View("frmLogin", new tblLogin());
}
[HttpPost]
public ActionResult frmLogin(tblLogin account)
{
var currentAccount = db.tblLogins.First(a => a.UserName.Equals(account.UserName));
if ((currentAccount != null))
{
if (Hashing.ValidatePassword(account.Password, currentAccount.Password))
{
Session.Add("UserName", account.UserName);
//return View("~/Views/Home/frmHome.cshtml");
return RedirectToAction("frmHome", "Home");
}
else
{
ViewBag.error = "Invalid";
return View("frmLogin");
}
}
else
{
ViewBag.error = "Invalid";
return View("frmLogin");
}
}
I'm developing a web application in asp.net mvc.
My application uses multiple databases.
The database on which working on depends by the logged user.
I manage login on two levels:
Level1 on a "master" database where I have info about the login username/email and the "specific" database to use.
Level2 on the "specific" database where I manage users and roles with Identity2.
Example:
In the "master" database I have a record in User table with:
- username = user1
- databaseToUse = "specificDb1"
In the "specific" database called specificDb1, for the same user, I have a record in User table with all I need to manage user authentication and more.
What I want to achieve is:
Start the website, click on login, insert username and password, click on login.
Search for the username in the master database, if exist get the specific database name associated to the user.
Set here, DYNAMICALLY, the connection string for the "specific" database and perform Identity 2 login operations.
No problems for points 1 and 2. The problem is in point 3.
I use EntityFramework 6 Code First for both (master and specific) databases.
Regarding the configuration part of Identity I see in Startup.Auth.cs:
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
Should I change something in Identity configuration?
Thanks in advance.
After hours spent in searching here my personal (maybe not the best) working solution.
In the Login action of AccountController, after the first check in "master" database, set the "specific" database informations in Session scope:
//Save the database infos in Session.
Session.Add("SqlServerInstance", masterUser.Company.DatabaseServer);
Session.Add("DbName", masterUser.Company.DatabaseName);
Always in AccountController update the SignInManager and UserManager properties fixing the connection string for the Identity context:
public ApplicationSignInManager SignInManager
{
get
{
//Set manually the right connection string used by the Identity database context.
HttpContext.GetOwinContext().Get<ApplicationDbContext>().Database.Connection.ConnectionString = ApplicationDbContext.GetConnectionString();
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
//Set manually the right connection string used by the Identity database context.
HttpContext.GetOwinContext().Get<ApplicationDbContext>().Database.Connection.ConnectionString = ApplicationDbContext.GetConnectionString();
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
And finally the method that give us the connection string:
/// <summary>
/// Get the connection string getting SqlServerInstance and DbName from Session.
/// </summary>
public static string GetConnectionString()
{
string sqlServerInstance = DEFAULT_SQLSERVERINSTANCE;
if (HttpContext.Current.Session != null && HttpContext.Current.Session["SqlServerInstance"] != null)
sqlServerInstance = Convert.ToString(HttpContext.Current.Session["SqlServerInstance"]);
string dbName = DEFAULT_DBNAME;
if (HttpContext.Current.Session != null && HttpContext.Current.Session["DbName"] != null)
dbName = Convert.ToString(HttpContext.Current.Session["DbName"]);
return "Data Source=" + sqlServerInstance + ";Initial Catalog=" + dbName + ";Integrated Security=True";
}
Hope this can help.
I'm very new to MVC. I'm doing a Custom Membership asp.net MVC4. Above are the Table & data i have created. I try to override isinrole method but its not working.Below is the sample code & i don't know where to edit it.
public override bool IsUserInRole(string userName, string roleName)
{
User user = repository.GetUser(userName);
Role role = repository.GetRole(roleName);
if (!repository.UserExists(user))
return false;
if (!repository.RoleExists(role))
return false;
return user.Name == role.Name;
}
Now i need to get list of roles for a user from UserInRole Table but the this table is not visible.I have to check whether the User role are matching with User.IsInRole("Administrator") .Hope anybody can guide me.Thank u in advance.
It's not working because you're comparing the role name with the user name ("a" != "Administrator"). You need something more like this.
public override bool IsUserInRole(string userName, string roleName)
{
User user = repository.GetUser(userName);
Role role = repository.GetRole(roleName);
if (!repository.UserExists(user))
return false;
if (!repository.RoleExists(role))
return false;
return user.Role.ID == role.ID;
}
It may differ depending on how your entities are setup though.
In my web application registered users can add new content and edit it later. I want only the content's author to be able to edit it. Is there any smart way of doing this other than manually writing code in all the action methods that checks if the logged user is the same as the author? Any attribute that I could use for the whole controller?
Any attribute that I could use for the whole controller?
Yes, you could extend the Authorize attribute with a custom one:
public class AuthorizeAuthorAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
// the user is either not authenticated or
// not in roles => no need to continue any further
return false;
}
// get the currently logged on user
var username = httpContext.User.Identity.Name;
// get the id of the article that he is trying to manipulate
// from the route data (this assumes that the id is passed as a route
// data parameter: /foo/edit/123). If this is not the case and you
// are using query string parameters you could fetch the id using the Request
var id = httpContext.Request.RequestContext.RouteData.Values["id"] as string;
// Now that we have the current user and the id of the article he
// is trying to manipualte all that's left is go ahead and look in
// our database to see if this user is the owner of the article
return IsUserOwnerOfArticle(username, id);
}
private bool IsUserOwnerOfArticle(string username, string articleId)
{
throw new NotImplementedException();
}
}
and then:
[HttpPost]
[AuthorizeAuthor]
public ActionResult Edit(int id)
{
... perform the edit
}
I would:
Save the db.aspnet_Users columm UserId (Guid) against the content record
Write an extension method for your content model which verifies the current users Guid against the saved contents User Guid
I would write some code that overrides this functionality for your Admin logins (I would create an Admin Role).