Exception Handling in N-Tier application - c#

I am writing a N-Tier application using ASP.Net Core.
In my service layer in logic tier I have an API which update the user's password. Here is the code from the service layer.
public IActionResult UpdatePassword([Required][EmailAddress] string email, [Required][DataType(DataType.Password)] string oldPassword, [Required][DataType(DataType.Password)] string newPassword)
{
try
{
_userLogic.UpdatePasswordLogic(oldPassword, email, newPassword);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
return Ok($"Password updated successfully. The new password is: { newPassword }");
}
basically it just gets the email, the current password, and the new given password by user and pass it to the "UpdatePasswordLogic" method in business layer. The "UpdatePasswordLogic" works as following:
public void UpdatePasswordLogic(string oldPassword, string email, string newPassword)
{
// Take the user's password from the database
string savedPassword = _context.Users
.Where(x => x.Email == email)
.Select(x => x.Password);
if (!string.IsNullOrEmpty(savedPassword))
{
// Check if the oldPassword is equal to the password saved in the databank
if (ComparePasswords(savedPassword, oldPassword))
{
// TODO: Set the new password
}
else
// Throw exception when password is not correct
throw new Exception("password does not match the one saved in the database");
}
else
// If user does not exist, throw an exception
throw new Exception("User does not exist in databank");
}
The "ComparePasswords" method check if the given password by user match the one that saved in the databank. If the password is not correct then it suppose to throw an exception. When I enter a wrong password the UpdatePasswordLogic does throw an exception but my API in service layer does not catch this exception and it returns the OKObjectResult. Does anyone know why it does not catch the exception?

Related

Firebase Realtime Database Rules Denied Permission

I am registering user using Email/Password Sign-In-Method. So after successfully registration and loge in, I can't read and write my data in Firebase Real Time.
I'm new to Firebase so I can't really figure out what the main problem is or which steps I have missed.
This rule is obviously working fine:
{
"rules": {
".read": "auth == null",
".write": "auth == null"
}
}
However, this rule is not working, although my user is already registered and has got a UID.
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
It always shows the following error:
Exception occured while processing the request.
Url: https://App-Name-6ssd2.firebaseio.com/Appointments/-MUAG-CHWBFSv-Vrtsoc/.json?print=silent
Response: {
"error" : "Permission denied"
}
What I currently want is to allow ANY registered user to read/write everybody's information, but it always denied the permission.
Screenshots:
My implementation for getting Firebase Data.
The error is also pointing to the this method.
public async Task<List<Appointment>> GetUserAppointment(string userId)
{
var appointments = (await Firebase.Child("Appointments")
.OnceAsync<Appointment>()).Where(a => a.Object.UID == userId).Select(item =>
new Appointment
{
UID = item.Object.UID,
AppointmentID = item.Object.AppointmentID,
Title = item.Object.Title,
Date = item.Object.Date,
Time = item.Object.Time,
Status = item.Object.Status,
ReasonText = item.Object.ReasonText
}).ToList();
return appointments;
My implementation when a user SinUp for the first time.
public async Task<string> SignUpWithEmailAndPassword(string email, string password)
{
try
{
var signUpTask = await auth.CreateUserWithEmailAndPasswordAsync(email, password);
var user = signUpTask.User;
var token = await auth.CurrentUser.GetIdToken(false).AsAsync<GetTokenResult>();
await SendEmailVerification();
return token.Token;
}
catch (FirebaseAuthInvalidUserException e)
{
e.PrintStackTrace();
return string.Empty;
}
catch (FirebaseAuthInvalidCredentialsException e)
{
e.PrintStackTrace();
return string.Empty;
}
catch (FirebaseAuthUserCollisionException existEmail)
{
existEmail.PrintStackTrace();
return string.Empty;
}
}
In order to check whether a user is authenticated/verified or not, i did the debugging and as a result... I can see the same UID in my console as it is in Firebase -> Authentication -> Users.
Here is the screenshot.
Debugging GetUserAppointment(string userID) to check whether the current user is set.
It's because you are not authorized to the Database, check the Rules Tab in the Realtime database.
Open firebase, select database on the left hand side.
Now on the right hand side, select Realtime database from the dropdown and change the rules to allow anyone to write the Database
{
"rules": {
".read": true,
".write": true
}
}
Your rule is:
{
"rules": {
".read": "auth != null",
".write":"auth != null"
}
}
This means only authorized user's can write and read the Data.

Getting Invalid token reset password time in web api and identity c#?

I am creating a small demo for reset password in web API and identity using in .net MVC c#.and I am clicking on forgot password send one code in the mail using a query string. In the mail code is correct getting. now I am going for the change password and getting the code from the URL not getting propare in the token '==' last end not getting and get error invalid token how can do fix it this error anyone knows?
this my ForgotPassword method in Account Controller :
public async Task<IHttpActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
try
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null)
{
return Ok();
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
await UserManager.SendEmailAsync(user.Id, "Reset Password",Request.RequestUri.GetLeftPart(UriPartial.Authority) + "/home/ChangePassword?Code=" + code);
return Ok("Ok");
}
catch (Exception ex)
{
ExceptionsLogging.SendExcepToDB(ex);
throw new HttpException(500, ex.Message);
}
}
this is my ResetPasswordMethod :
public async Task<IHttpActionResult> ResetPassword(ChangePasswordBindingModel model)
{
try
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return Ok();
}
var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.NewPassword); // here not getting code propare
if (result.Succeeded)
{
return Ok("Done");
}
return Ok();
}
catch (Exception ex)
{
ExceptionsLogging.SendExcepToDB(ex);
throw new HttpException(500, ex.Message);
}
}
any one know how can fix it i am try encode/decode but now getting propare
You must encode the generated token before sending the email
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var encodedCode = HttpUtility.UrlEncode(code);
await UserManager.SendEmailAsync(user.Id, "Reset Password",Request.RequestUri.GetLeftPart(UriPartial.Authority) + "/home/ChangePassword?Code=" + encodedCode);
return Ok("Ok");

Identity - VerifyHashedPassword method does not work well

I have really strange problem with ASP.NET Identity and EntityFramework.
I have a login form, from which I receive username and password.
Then I check if the user exist in the database.
After that I call the UserManager's method VerifyHashedPassword to verify that the user password from database and that from the form are the same. Everything is OK, but for some of the users in the database, the method give me result that the given password and the hashed password are not the same (but they actually are). I just can't figure out why for some of the users password verification fails.
Here's my code.
public async Task<User> FindUserAsync(string userName, string password)
{
User user;
if (password != null)
{
user = await _userManager.FindByNameAsync(userName);
if (user == null)
{
user = await _userManager.FindByEmailAsync(userName);
}
var result = _userManager.PasswordHasher.VerifyHashedPassword(user.PasswordHash, password);
if (!(result == PasswordVerificationResult.Success))
{
return null;
}
}
return user;
}
Well, the problem was on my side.
The problem came when some user decide to change their password.
If user change their password, I first delete the password and then I add the new password to the database. Which was very dumb, because the transaction to the database with which I delete the password is committed successfully, but the transaction (for some reason) with which I add the new password was never done successfully.
Actually I used these two methods when a password is changed:
await _userManager.RemovePasswordAsync(appUser.Id);
await _userManager.AddPasswordAsync(appUser.Id, fbUser.Password);
Now I do that manually:
String hashedNewPassword = _userManager.PasswordHasher.HashPassword(fbUser.Password);
if (hashedNewPassword != null)
{
appUser.PasswordHash = hashedNewPassword;
_context.Entry(appUser).State = EntityState.Modified;
await _context.SaveChangesAsync();
}
And this works for me.
You can do this using the UserManager as long as you are able to do it async, the non-async extension method was broken for me at least, sending a null to the hashedPassword argument in the PasswordHasher. To do it async:
await _userManager.ChangePasswordAsync(userId, oldPassword, newPassword);

How to find OldPassword to let the user change it

I'm working on an intranet, I've just added a feature on the user's profile to change his password.
As you can see with the following controller :
[HttpPost]
public ActionResult ChangePassword(Employee objToEdit, FormCollection form, LocalPasswordModel model) // Find how to obtain "OldPassword" from AccountModel
{
objToEdit.Login = User.Identity.Name;
string name = objToEdit.FirstName;
string pwd = form["NewPassword"];
string confirm = form["ConfirmPassword"];
if (_service.Edit_password(objToEdit, pwd, confirm)) // Checks if NewPassword and ConfirmPassword are the same, and does some syntax checking
{
bool changePasswordSucceeded;
try
{
changePasswordSucceeded = WebSecurity.ResetPassword(WebSecurity.GeneratePasswordResetToken(objToEdit.Login), pwd); // Seems to work
}
catch (Exception)
{
changePasswordSucceeded = false;
}
if (changePasswordSucceeded)
{
return RedirectToAction("Index", new { Message = CRAWebSiteMVC.Controllers.AccountController.ManageMessageId.ChangePasswordSuccess });
}
else
{
ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
}
return new RedirectResult(Url.Action("Index"));
}
return View();
}
So far, the user just needs to input a New password and a confirmation password. I wish to add a "Enter your current Password" feature but I can't find a way to retrieve the user's current password !
The user profile DB does not contain a Password column anymore and I use Form authentication if that's of any help.
EDIT: Thank you for your help, to solve my problem I simply replaced the ResetPassword line by the following :
changePasswordSucceeded = WebSecurity.ChangePassword(objToEdit.Login, current, pwd);
If it fails, it directly displays the error message that the current password is wrong.
You can't !
That's actually a security feature. You should never store a password in plain text.
The good thing is, you don't need to do the comparison yourself:
Instead, use something like ValidateUser to let the Membership Provider validate the provided password. Behind the scenes, this method will hash the password and compare it with the hashed version contained in the database.
EDIT:
Also, note that since you are using the WebSecurity class, there is a method, ChangePassword that accepts the current password. It seems that method will check the current password matches the specified currentPassword parameter. Maybe you should use this one instead of ResetPassword

Testing Password format

Ok I am writeing a test for a membership password change. The code below is what I have so far. I need some assistance to check the password format. Min char length is 7 and max length is 8.
Also the I can test if the password format is clear, but how do I test an encrypted format?
Can anyone assist?
[TestMethod]
public void TestChangePassword()
{
try
{
AsaMembershipProvider prov = this.GetMembershipProvider();
MembershipCreateStatus status;
//creates user
MembershipUser user = prov.CreateUser("testUserX", "12345", "test.UserX#abc.com", "", "", true, null, out status);
//gets user
user = prov.GetUser("testUserX", false);
Assert.AreEqual(user.UserName, "testUserX");
//Authenticates username and password
var isAuthenticated = prov.ValidateUser(user.UserName, "12345");
Assert.IsTrue(isAuthenticated);
//changes password
prov.ChangePassword("testUserX", "12345", "ABCDE");
//Validates password has been changed
prov.ValidateUser(user.UserName, "ABCDE");
Assert.IsTrue(isAuthenticated);
// Change password back
prov.ChangePassword("testUserX", "ABCDE", "12345");
//Validates password has been changed back
prov.ValidateUser(user.UserName, "12345");
//Deletes User
prov.DeleteUser("testUserX", true);
//tries to get user again
user = prov.GetUser("testUserX", false);
//test that no user is returned
Assert.AreEqual(null, user);
}
catch (Exception ex)
{
LogMessage(ex);
Assert.Fail(ex.Message);
}
}
One option would be to write an extension method targeting AsaMembershipProvider which would validate the password and then call ChangePassword from within it to do the actual change
The downside of the approach is that you will have more code to maintain
public static class CryptoExtensions {
public static void ChangePasswordEx(this AsaMembershipProvider mp, string username, string oldPassword, string newPassword){
// validate format of the password
if (true /*validation code*/ )
{
throw new Exception("Invalid password format");
}
// rest of the code to encrypt and store the password
mp.ChangePassword(username, oldPassword, newPassword);
}
}
Your test code should now call prov.ChangePassword with prov.ChangePasswordEx

Categories