I am creating a simple application, i have created the hash for the password at register, but can not apply the hash at login. Currently i can not login with new users who have hashed passwords. Any help would be much appreciated. Currently i have: (Register)
public String HashPassword(String password)
{
var combinedPassword = String.Concat(password);
var sha256 = new SHA256Managed();
var bytes = UTF8Encoding.UTF8.GetBytes(combinedPassword);
var hash = sha256.ComputeHash(bytes);
return Convert.ToBase64String(hash);
}
public void AddUserAccount(UserSignUpView user)
{
using (DemoDBEntities db = new DemoDBEntities())
{
SYSUser SU = new SYSUser();
SU.PasswordEncryptedText = HashPassword(user.Password);
SU.LoginName = user.LoginName;
SU.RowCreatedSYSUserID = user.SYSUserID > 0 ?
user.SYSUserID : 1;
SU.RowModifiedSYSUserID = user.SYSUserID > 0 ?
user.SYSUserID : 1; ;
SU.RowCreatedDateTime = DateTime.Now;
SU.RowMOdifiedDateTime = DateTime.Now;
db.SYSUsers.Add(SU);
db.SaveChanges();
This all works fine to register and hash. This is what i have for login:
public Boolean ValidatePassword(String enteredPassword, String storedHash)
{
var hasher = HashPassword(enteredPassword);
return String.Equals(storedHash, hasher);
}
public string GetUserPassword(string enteredPassword)
{
using (DemoDBEntities db = new DemoDBEntities())
{
var hash = HashPassword(enteredPassword);
var user = db.SYSUsers.Where(o =>
o.PasswordEncryptedText.Equals(enteredPassword));
if (user.Any())
return user.FirstOrDefault().PasswordEncryptedText;
else
return string.Empty;
}
}
In the controller i have:
public ActionResult LogIn(UserLoginView ULV, string returnUrl)
{
if (ModelState.IsValid)
{
UserManager UM = new UserManager();
string password = UM.GetUserName(ULV.LoginName);
string hash = UM.GetUserPassword(ULV.Password);
//var password = ComputeHash(password, new SHA256CryptoServiceProvider());
if (string.IsNullOrEmpty(hash))
ModelState.AddModelError("", "The user login or password provided is incorrect.");
else {
if (ULV.Password.Equals(hash)&&(ULV.LoginName.Equals(password)))
{
FormsAuthentication.SetAuthCookie(ULV.LoginName, false);
return RedirectToAction("Welcome", "Home");
}
else {
ModelState.AddModelError("", "The password provided is incorrect.");
}
}
}
It looks like you are getting the hashed password from the database with the line string hash = UM.GetUserPassword(ULV.Password); and then comparing it to the value that was entered with this line ULV.Password.Equals(hash). Since one is hashed and the other is not, they will never be equal.
This worked:
string password = UM.GetUserName(ULV.LoginName);
string hash = UM.GetUserPassword(ULV.Password);
string hashit = HashPassword(ULV.Password);
public string GetUserPassword(string enteredPassword)
{
using (DemoDBEntities db = new DemoDBEntities())
{
var hash = HashPassword(enteredPassword);
var user = db.SYSUsers.Where(o => o.PasswordEncryptedText.Equals(hash));
if (user.Any())
return user.FirstOrDefault().PasswordEncryptedText;
else
return string.Empty;
}
}
Related
I faced problem with hashing, salting and verifying password in ASP.NET.
I am creating a new User and then using hashing method.
But when I try to get some resources which requires Authorization and I
enter the same username and password as I saved in database the result is failed.
Here is my password hasher class:
using Microsoft.AspNetCore.Identity;
namespace FlowerShop.ApplicationServices.Components.PasswordHasher
{
public class BCryptPasswordHasher<User> : IPasswordHasher<User> where User : class
{
public string HashPassword(User user, string password)
{
return BCrypt.Net.BCrypt.HashPassword(password, 12);
}
public PasswordVerificationResult VerifyHashedPassword(User user, string hashedPassword, string providedPassword)
{
var isValid = BCrypt.Net.BCrypt.Verify(providedPassword, hashedPassword);
if (isValid && BCrypt.Net.BCrypt.PasswordNeedsRehash(hashedPassword, 12))
{
return PasswordVerificationResult.SuccessRehashNeeded;
}
return isValid ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
}
}
This is my authentication class:
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly IQueryExecutor queryExecutor;
private readonly IPasswordHasher<User> passwordHasher;
public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock,
IQueryExecutor queryExecutor, IPasswordHasher<User> passwordHasher)
: base(options, logger, encoder, clock)
{
this.queryExecutor = queryExecutor;
this.passwordHasher = passwordHasher;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var endpoint = Context.GetEndpoint();
if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
{
return AuthenticateResult.NoResult();
}
if (!Request.Headers.ContainsKey("Authorization"))
{
return AuthenticateResult.Fail("Missing Authorization Header");
}
User user = null;
try
{
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
var username = credentials[0];
var providedPassword = passwordHasher.HashPassword(user, credentials[1]);
var query = new GetUserQuery()
{
UserName = username
};
user = await this.queryExecutor.Execute(query);
if (user == null || passwordHasher.VerifyHashedPassword(user, user.PasswordHash, providedPassword)
== PasswordVerificationResult.Failed)
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Role, user.Role.ToString()),
new Claim(ClaimTypes.Email, user.Email),
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
And in this place I am creating a new User:
using MediatR;
using Microsoft.AspNetCore.Identity;
using System.Threading;
using System.Threading.Tasks;
public class AddUserHandler : IRequestHandler<AddUserRequest,
AddUserResponse>
{
private readonly ICommandExecutor commandExecutor;
private readonly IQueryExecutor queryExecutor;
private readonly IMapper mapper;
private readonly IPasswordHasher<User> passwordHasher;
public AddUserHandler(ICommandExecutor commandExecutor,
IQueryExecutor queryExecutor,
IMapper mapper, IPasswordHasher<User> passwordHasher)
{
this.commandExecutor = commandExecutor;
this.queryExecutor = queryExecutor;
this.mapper = mapper;
this.passwordHasher = passwordHasher;
}
public async Task<AddUserResponse> Handle(AddUserRequest
request, CancellationToken cancellationToken)
{
var query = new GetUserQuery()
{
UserName = request.UserName,
Email = request.Email
};
var getUser = await this.queryExecutor.Execute(query);
if (getUser != null)
{
if (getUser.UserName == request.UserName)
{
return new AddUserResponse()
{
Error = new ErrorModel(ErrorType.ValidationError +
"! The name is already taken.")
};
}
if (getUser.Email == request.Email)
{
return new AddUserResponse()
{
Error = new ErrorModel(ErrorType.ValidationError +
"! Email address is in use.")
};
}
return new AddUserResponse()
{
Error = new ErrorModel(ErrorType.Conflict)
};
}
request.PasswordHash = passwordHasher.HashPassword(getUser,
request.Password);
var user = this.mapper.Map<User>(request);
var command = new AddUserCommand()
{
Parameter = user
};
var addedUser = await this.commandExecutor.Execute(command);
var response = new AddUserResponse()
{
Data =
this.mapper.Map<Domain.Models.UserDTO>(addedUser)
};
return response;
}
}
This is my Startup.cs :
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions,
BasicAuthenticationHandler>("BasicAuthentication", null);
services.AddScoped<IPasswordHasher<User>,
BCryptPasswordHasher<User>>();
}
Maybe first of all, is it all correct implemented?
Is hash in AddUserHandler correct assigned to request.PasswordHash?
How to retrieve salt and assign to request.PasswordSalt?
Sorry for any unclear things if they occur.
Any feedback and help will be appreciated.
Thanks in advance :)
Edit:
for example if I add user with password "pass123" and it is stored in database as 'user.PasswordHash = "$2a$12$Iqpy7FyQh/pt2O8upTtG5eOQKzo1V395wRNdAXPpp5Qf.NQ.KxUyy"' and provided password after hashing is 'providedPassword = "$2a$12$9vSz8Sw/WtmqGY6jyDiTleN/btZ0wXJkXdoB3sDpANVIIDGBpaqT."'
I fixed the bug if anyone needs to use it in thee future.
The problem was in my authentication class.
In place of:
var username = credentials[0];
var providedPassword = passwordHasher.HashPassword(user, credentials[1]);
Should be:
var username = credentials[0];
var providedPassword = credentials[1];
I am sure that I have checked it a few times but somehow didn't work then. Anyway, it finally works properly.
I'm building a Restful API with asp.net core. I have an endpoint that are used to authenticate users. I have two kinds of Users where one is an Admin and one is "FilmStudio". I succesfully managed to authenticte the User (Admin) but i also need to be able to authenticate the FilmStudio with username and password. Is there anyway I can do this with a single endpoint?
This is my endpoint form the UsersController:
[AllowAnonymous]
[HttpPost("Authenticate")]
public IActionResult Authenticate([FromBody] UserDto model)
{
var user = _userRepo.Authenticate(model.UserName, model.Password);
if (user !=null)
{
if (user == null)
{
return BadRequest("The username or password is incorrect.");
}
return Ok(new
{
Id = user.UserId,
Username = user.UserName,
Role = user.Role,
Token = user.Token
});
}
else
{
var filmStudioDto = new FilmStudioDto();
var studio = _studioRepo.Authenticate(model.Name, model.Password);
if (studio == null)
{
return BadRequest("The username or password is incorrect.");
}
return Ok(new
{
Id = studio.StudioId,
Username = studio.Name,
City = studio.City,
Role = studio.Role,
Token = studio.Token
});
}
}
}
When im giving the username and password for the admin user it works. However when im trying to enter the username and passwod for FilmStudio I allways get the error messsage that says: "The username or password is incorrect."
[AllowAnonymous]
[HttpPost("Authenticate")]
public IActionResult Authenticate([FromBody] UserDto model)
{
if (model.UserName != null) // Check if UserName is null or not
{
var user = _userRepo.Authenticate(model.UserName, model.Password);
if (user == null)
{
return BadRequest("The username or password is incorrect.");
}
return Ok(new
{
Id = user.UserId,
Username = user.UserName,
Role = user.Role,
Token = user.Token
});
}
else
{
var studio = _studioRepo.Authenticate(model.StudioName, model.StudioPassword);
if (studio == null)
{
return BadRequest("The username or password is incorrect.");
}
return Ok(new
{
Id = studio.StudioId,
Username = studio.Name,
City = studio.City,
Role = studio.Role,
Token = studio.Token
});
}
}
}
you can try to use instead of model.Name model.UserName for studio too
else
{
var studio = _studioRepo.Authenticate(model.UserName, model.Password);
if (studio == null)
return BadRequest("The username or password is incorrect.");
return Ok( new FilmStudioDto
{
Id = studio.StudioId,
Username = studio.Name,
City = studio.City,
Role = studio.Role,
Token = studio.Token
});
}
and IMHO you can fix user part too
if (user !=null)
return Ok(new UserDto
{
Id = user.UserId,
Username = user.UserName,
Role = user.Role,
Token = user.Token
});
A system need single user login at a time. If tried for multiple login simultaneously the user get blocked. I have used Cookie Authentication which will manage from client browser.
Login Code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel oLoginViewModel)
{
try
{
bool Result = new UserBL().ValidateUser(oLoginViewModel.UserName, oLoginViewModel.Password);
if (Result == true)
{
FormsService.SignIn(oLoginViewModel.UserName, oLoginViewModel.RememberMe);
CreateAuthenticationTicket(oLoginViewModel.UserName);
return RedirectToLocal(Request.Form["returnUrl"]);
}
else
ViewBag.Error = "Invalid Username or Password / Due to simultaneous login you get blocked.";
return View();
}
catch (Exception ex)
{
throw ex;
}
}
public void CreateAuthenticationTicket(string username)
{
Users oUsers = new Users();
oUsers.Email = username;
oUsers.Role = "User";
int sessionid = new UserBL().GetByUserName(username).UserId;
string userData = JsonConvert.SerializeObject(oUsers);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,
username,
DateTime.Now,
DateTime.Now.AddYears(1), // value of time out property
false, //pass here true, if you want to implement remember me functionality
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
var isSsl = Request.IsSecureConnection; // if we are running in SSL mode then make the cookie secure only
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
{
HttpOnly = false,
Secure = isSsl,
};
faCookie.Expires = DateTime.Now.AddYears(1);
Response.Cookies.Add(faCookie);
//Login Repository Entry
LoginsRepository oLogin = new LoginsRepository();
oLogin.UserName = username;
oLogin.SessionId = sessionid.ToString();
oLogin.LoggedIn = true;
oLogin.CreatedOn = Utility.CommonFunction.DateTime_Now();
oLogin.IPAddress = HttpContext.Request.RequestContext.HttpContext.Request.ServerVariables["REMOTE_ADDR"];
oLogin.Status = En_LoginStatus.SingleUser.ToString();
new LoginRepositoryBL().Add(oLogin);
}
I'm saving every user login with their IP Address to check the user multiple login.
After login it redirects to home controller and their I checked the multiple logins logic from database table Loginsrepository which is mentioned above :
public class HomeController : CustomerBaseController
{
public ActionResult Index()
{
Users oUser = new Users();
oUser = new UserBL().getActiveUser();
// check to see if your ID in the Logins table has
// LoggedIn = true - if so, continue, otherwise, redirect to Login page.
if (new LoginRepositoryBL().IsYourLoginStillTrue(System.Web.HttpContext.Current.User.Identity.Name, oUser.UserId.ToString()))
{
// check to see if your user ID is being used elsewhere under a different session ID
if (!new LoginRepositoryBL().IsUserLoggedOnElsewhere(System.Web.HttpContext.Current.User.Identity.Name, oUser.UserId.ToString()))
{
Answers oAnswer = new Answers();
return View(oAnswer);
}
else
{
// if it is being used elsewhere, update all their
// Logins records to LoggedIn = false, except for your session ID
new LoginRepositoryBL().LogEveryoneElseOut(System.Web.HttpContext.Current.User.Identity.Name, oUser.UserId.ToString());
Answers oAnswer = new Answers();
return View(oAnswer);
}
}
else
{
oUser = new UserBL().GetByUserName(System.Web.HttpContext.Current.User.Identity.Name);
oUser.Status = En_Status.Inactive.ToString();
new UserBL().update(oUser);
FormsService.SignOut();
FormsAuthentication.SignOut();
return RedirectToAction("Login", "Account");
}
}
}
Above methods :
public bool IsYourLoginStillTrue(string userId, string sid)
{
try
{
using (var ctx = new CnSiteEntities())
{
IEnumerable<LoginsRepository> logins = (from i in ctx.LoginsRepository
where i.LoggedIn == true &&
i.UserName == userId && i.SessionId == sid
select i).AsEnumerable();
return logins.Any();
}
}
catch (Exception)
{
throw;
}
}
public bool IsUserLoggedOnElsewhere(string userId, string sid)
{
try
{
using (var ctx = new CnSiteEntities())
{
IEnumerable<LoginsRepository> logins = (from i in ctx.LoginsRepository
where i.LoggedIn == true &&
i.UserName == userId && i.SessionId != sid
select i).AsEnumerable();
return logins.Any();
}
}
catch (Exception)
{
throw;
}
}
public void LogEveryoneElseOut(string userId, string sid)
{
try
{
using (var ctx = new CnSiteEntities())
{
IEnumerable<LoginsRepository> logins = (from i in ctx.LoginsRepository
where i.LoggedIn == true &&
i.UserName == userId &&
i.SessionId != sid // need to filter by user ID
select i).AsEnumerable();
foreach (LoginsRepository item in logins)
{
item.LoggedIn = false;
}
ctx.SaveChanges();
}
}
catch (Exception)
{
throw;
}
}
It's not working properly. It keeps it true after login even if multiple simultaneous logins. I have googled it and tried it much but I didn't get any solution.
After ChangePasswordAsync, the user is signed out automatically and needs to sign in again. How can I keep the user signed in?
private UserManager<ApplicationUser> _userManager
{
get
{
var userStore = new UserStore<ApplicationUser>(Db);
return new UserManager<ApplicationUser>(userStore);
}
}
public bool ChangePassword(string oldPassword,string password)
{
var userId = HttpContext.Current.User.Identity.GetUserId();
var user = _userManager.ChangePasswordAsync(userId, oldPassword, password);
if(!user.Result.Succeeded) return false;
return true;
}
Instead of calling _userManager.ChangePasswordAsync, modify directly PasswordHash:
var userName = HttpContext.Current.User.Identity.Name;
var user = _userManager.Find(userName, oldPassword);
user.PasswordHash = UserManager.PasswordHasher.HashPassword(password);
IdentityResult result = await UserManager.UpdateAsync(user);
I have an intranet that gets the current logged in user through active directory. When a user is locked out they get a windows prompt to enter their username and password. Is there a way for me to catch this and redirect them to a page where they are asked to enter their credentials again or tell them that their account might be locked out and to contact the help desk?
On your application once you grab the user that is logged in do the IsAccountLocked method below
public bool IsAccountLocked(string sUserName)
{
UserPrincipal oUserPrincipal = GetUser(sUserName);
return oUserPrincipal.IsAccountLockedOut();
}
public UserPrincipal GetUser(string sUserName)
{
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal = UserPrincipal.FindByIdentity(oPrincipalContext, sUserName);
return oUserPrincipal;
}
public PrincipalContext GetPrincipalContext()
{
PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Domain, sDomain, sDefaultOU, ContextOptions.SimpleBind, sServiceUser, sServicePassword);
return oPrincipalContext;
}
This is using System.DirectoryServices.AccountManagement for using only System.DirectoryServices you can do this
public bool IsAccountLocked(DirectoryEntry oDE)
{
return Convert.ToBoolean(oDE.InvokeGet("IsAccountLocked"));
}
public DirectoryEntry GetUser(string sUserName)
{
//Create an Instance of the DirectoryEntry
oDE = GetDirectoryObject();
//Create Instance fo the Direcory Searcher
oDS = new DirectorySearcher();
oDS.SearchRoot = oDE;
//Set the Search Filter
oDS.Filter = "(&(objectClass=user)(sAMAccountName=" + sUserName + "))";
oDS.SearchScope = SearchScope.Subtree;
oDS.PageSize = 10000;
//Find the First Instance
SearchResult oResults = oDS.FindOne();
//If found then Return Directory Object, otherwise return Null
if (oResults != null)
{
oDE = new DirectoryEntry(oResults.Path, sADUser, sADPassword, AuthenticationTypes.Secure);
return oDE;
}
else
{
return null;
}
}
private DirectoryEntry GetDirectoryObject()
{
oDE = new DirectoryEntry(sADPath, sADUser, sADPassword, AuthenticationTypes.Secure);
return oDE;
}
for a full implementation you can go to
http://anyrest.wordpress.com/2010/06/28/active-directory-c/
or
http://anyrest.wordpress.com/2010/02/01/active-directory-objects-and-c/