Login Procedure that does not require a Email Address - asp.net-mvc-3

I have been asked to create a site where the user isn't required to provide a email to login because of privacy issues. In the past I have simple said this isn't advisable but in this case the client has stringently requested it. My initial thoughts are to potentially create administrators with a email whom could create generic logins (username and a password) and pass them to members of there group on site. Then at least I have a point of contact for login resets and such.
Has anyone had any experience with such situations where they have needed to create logins without the use of a email address? Could you direct me towards any relevant materials or tutorials that may be of use. I'm using MVC3 to develop this project.

I hope I understand your question right and you want to implement a login using username and password instead of email adress and password.
In that case you would have to implement your own custom membership provider and a custom roleprovider if needed.
You want to check the following page for more information:
Custom Membership Provider # Codeproject
EDIT
Fyi you dont need to implement every function - just implement the ones you need.
Custom membership provider from some of my older mvc3 projects. Removed most of the not-implemented functions for shorter code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
namespace Domain.Models
{
public class PlatformMembershipProvider : MembershipProvider
{
public SalesModelContainer ******** = new SalesModelContainer();
public override bool ChangePassword(string username, string oldPassword, string newPassword)
{
var user = ********.UserSet.Single(s => s.Email == username);
if (user.Password == oldPassword)
{
user.Password = newPassword;
return true;
}
else
{
return false;
}
}
public override string GetUserNameByEmail(string email)
{
var user = ********.UserSet.Single(s => s.Email == email);
return user.CompanyName;
}
public override void UpdateUser(System.Web.Security.MembershipUser user)
{
throw new NotImplementedException();
}
//TODO: use MD5 for password encryption
public override bool ValidateUser(string username, string password)
{
bool returnValue;
var user = ********.UserSet.SingleOrDefault(s => (s.Email == username) && (s.Password == password));
if (user != null)
returnValue = true;
else
returnValue = false;
return returnValue;
}
}
}

Related

Correct Implementation of Forgot Password AspNetBoilerPlate

Im using aspnetboilerplate (MVC) and wanted to implement a forgot password feature to allow the user to reset their own passwords using a link on the login screen.
I imagine this to work by generating a password reset code which is then emailed to the user.The user follows the link and is taken to a screen allowing them to reset the password.
Im stuck at the initial stage. i started with a copy of the login action after noticing that when attempting to log in the user object was returned. From here i attempt to set a password reset code.
[HttpPost]
[UnitOfWork]
public virtual async Task<JsonResult> ForgotPassword(ForgotPasswordViewModel forgotPasswordModel, string returnUrl = "", string returnUrlHash = "")
{
returnUrl = NormalizeReturnUrl(returnUrl);
if (!string.IsNullOrWhiteSpace(returnUrlHash))
{
returnUrl = returnUrl + returnUrlHash;
}
var loginResult = await _logInManager.LoginAsync(forgotPasswordModel.UsernameOrEmailAddress, "ForgotPassword", GetTenancyNameOrNull());
loginResult.User.SetNewPasswordResetCode();
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return Json(loginResult);
default:
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, forgotPasswordModel.UsernameOrEmailAddress, GetTenancyNameOrNull());
}
}
Checking the AbpUser table after the
loginResult.User.SetNewPasswordResetCode();
i cannot see any password reset code for the user, they are all null.
Could someone point me in the right direction.
Thanks in advance
Thanks to answer below for being correct, just for completion below is exactly what worked. Obviously ignore the json return at the end
public virtual async Task<JsonResult> ForgotPassword(ForgotPasswordViewModel forgotPasswordModel, string returnUrl = "", string returnUrlHash = "")
{
//var user = await GetUserByChecking(emailAddress);
var user = await _userManager.FindByEmailAsync(forgotPasswordModel.UsernameOrEmailAddress);
if (user == null)
{
throw new UserFriendlyException("User not found!");
}
user.SetNewPasswordResetCode();
//Send an email to user with the below password reset code
/* Uri.EscapeDataString(user.PasswordResetCode) */
return Json("");
}
public class AccountAppService: IAccountAppService
{
public UserManager UserManager {get; set; }
public async Task SendPasswordResetCode(string emailAddress)
{
var user = await UserManager.FindByEmailAsync(emailAddress);
if (user == null)
{
throw new UserFriendlyException("User not found!");
}
user.SetNewPasswordResetCode();
//Send an email to user with the below password reset code
/* Uri.EscapeDataString(user.PasswordResetCode) */
}
}

How to get user context during Web Api calls?

I have an web front end calling an ASP Web Api 2 backend. Authentication is managed with ASP Identity. For some of the controllers I'm creating I need to know the user making the call. I don't want to have to create some weird model to pass in including the user's identity (which I don't even store in the client).
All calls to the API are authorized using a bearer token, my thought is the controller should be able to determine the user context based on this but I do not know how to implement. I have searched but I don't know what I'm searching for exactly and haven't found anything relevant. I'm going for something like...
public async Task<IHttpActionResult> Post(ApplicationIdentity identity, WalkthroughModel data)
Update
I found the below which looked very promising... but the value is always null! My controller inherits from ApiController and has an Authorize header.
var userid = User.Identity.GetUserId();
Update 2
I have also tried all of the solutions in Get the current user, within an ApiController action, without passing the userID as a parameter but none work. No matter what I am getting an Identity that is valid and auth'd, but has a null UserID
Update 3
Here's where I'm at now.
[Authorize]
[Route("Email")]
public async Task<IHttpActionResult> Get()
{
var testa = User.Identity.GetType();
var testb = User.Identity.GetUserId();
var testc = User.Identity.AuthenticationType;
var testd = User.Identity.IsAuthenticated;
return Ok();
}
testa = Name: ClaimsIdentity,
testb = null,
testc = Bearer,
testd = true
The user is obviously authenticated but I am unable to retrieve their userID.
Update 4
I found an answer, but I'm really unhappy with it...
ClaimsIdentity identity = (ClaimsIdentity)User.Identity;
string username = identity.Claims.First().Value;
That gets me the username without any db calls but it seems very janky and a pain to support in the future. Would love if anyone had a better answer.
What if I need to change what claims are issued down the road? Plus any time I actually need the user's id I have to make a db call to convert username to ID
A common approach is to create a base class for your ApiControllers and take advantage of the ApplicationUserManager to retrieve the information you need. With this approach, you can keep the logic for accessing the user's information in one location and reuse it across your controllers.
public class BaseApiController : ApiController
{
private ApplicationUser _member;
public ApplicationUserManager UserManager
{
get { return HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>(); }
}
public string UserIdentityId
{
get
{
var user = UserManager.FindByName(User.Identity.Name);
return user.Id;
}
}
public ApplicationUser UserRecord
{
get
{
if (_member != null)
{
return _member ;
}
_member = UserManager.FindByEmail(Thread.CurrentPrincipal.Identity.Name);
return _member ;
}
set { _member = value; }
}
}
I use a custom user authentication (I dont use AspIdentity because my existing user table fields was far different from IdentityUser properties) and create ClaimsIdentity passing my table UserID and UserName to validate my bearer token on API calls.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
User user;
try
{
var scope = Autofac.Integration.Owin.OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext);
_service = scope.Resolve<IUserService>();
user = await _service.FindUserAsync(context.UserName);
if (user?.HashedPassword != Helpers.CustomPasswordHasher.GetHashedPassword(context.Password, user?.Salt))
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
catch (Exception ex)
{
context.SetError("invalid_grant", ex.Message);
return;
}
var properties = new Dictionary<string, string>()
{
{ ClaimTypes.NameIdentifier, user.UserID.ToString() },
{ ClaimTypes.Name, context.UserName }
};
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
properties.ToList().ForEach(c => identity.AddClaim(new Claim(c.Key, c.Value)));
var ticket = new AuthenticationTicket(identity, new AuthenticationProperties(properties));
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(identity);
}
And how I use the ClaimsIdentity to retrieve my User table details on User ApiController Details call.
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("Details")]
public async Task<IHttpActionResult> Details()
{
var user = await _service.GetAsync(RequestContext.Principal.Identity.GetUserId<int>());
var basicDetails = Mapper.Map<User, BasicUserModel>(user);
return Ok(basicDetails);
}
Notice the
ClaimTypes.NameIdentifier = GetUserId() and ClaimTypes.Name = GetUserName()

Passing a variables in C#

I am trying to pass a variable that identifies a staff member from their login details to the next screen to populate the Tester ID box.
Would I be better using a global variable that is then read when the next screen is set up or would I be better to put it into a variable and send it to the next screen?
The login code sits as follows:
public Login()
{
InitializeComponent();
}
private void LoginButton_Click(object sender, EventArgs e)
{
String Username1 = StaffUsername.Text;
String Password1 = StaffPassword.Text;
String HardUser = "Test";
String HardPass = "Merlin123";
if (Username1 == "" && Password1 == "")
{
MessageBox.Show("Please Enter Login Id and Password");
}
else
{
if (Username1.Equals(HardUser) && Password1.Equals(HardPass))
{
this.Hide();
AddingClients M1 = new AddingClients();
M1.Show();
}
else{
this.Hide();
Login Lg = new Login();
Lg.Show();
MessageBox.Show("Incorrect Username or Password Entered");
}
}
}
}
}
I am using a hardcoded username and password for now, but in the actual program, I would have this call on a database and compare the username and the password and then go through to the next screen.
Would lit be better to have a global variable that the login action throws over to the next screen or would it be easier having a variable that the next screen reads and then populates the text box required? How would I go about this?
Thanks
The way you do this is to use the Thread.CurrentPrincipal.
Once the user is confirmed to be who they say they are, you can do:
private static void SignUserIn(string userName)
{
GenericIdentity identity = new GenericIdentity(userName, null);
Thread.CurrentPrincipal = new GenericPrincipal(identity);
}
Then whenever you need the userName, you use Thread.CurrentPrincipal.Identity.Name.
To extend this a little further, its probably best to abstract this a little bit, so you can swap in and out providers e.g. you might want to use Windows Authentication.
So you could do it like this:
public interface IAuthenticator
{
bool IsValidUser ( string username, string password );
IPrincipal SignInUser ( string username );
void SignOutCurrentUser();
}
public class DbAuthenticator : IAuthenticator
{
public bool IsValidUser ( string username, string password )
{
// Check user here and return bool if valid
}
public void SignInUser(string userName, string[] roles = null)
{
GenericIdentity identity = new GenericIdentity(userName, roles);
Thread.CurrentPrincipal = new GenericPrincipal(identity);
return Thread.CurrentPrincipal;
}
public void SignOutUser()
{
Thread.CurrentPrincipal = WindowsPrincipal.GetCurrent();
}
}
Then in your code, inject the authenticator using some sort of DI pattern. So MEF would be like this:
[Export(typeof(IAuthenticator))]
public interface IAuthenticator { }
And in your form:
[Import]
internal IAuthenticator authenticator;
private static void SignUserIn(string userName)
{
authenticator.SignUserIn(username);
}
You should have a User object and pass it to other pages and functions. That way they become more testable.
But you also need to store the object somewhere globally so you can retrieve the currently logged in user when needed. The problem with that is that piece of code then depends on that user storage existing/working, but if it's only one place it's okay.
PS: your title should be: pass the user on or store globally?

MVC 3 where to encrypt the user's password?

I have my own password encryption dll that I am using to check the user's password when they login, this is referenced in my User entity.
Now I have created the ability for a user to register which is working fine, apart from the passwords are yet to be encrypted.
My question is quite simple, where should I put the encryption of the new user's password? I'm not sure as I am aware that the user's password shouldn't be transmitted in plain text, therefore I don't know where the best place to call the encryption function:
User Entity (where the encryption dll is already used for validation).
The User repository where the save user method is.
The User controller where the user creation views are controlled.
Somewhere else that I haven't considered!
Thanks very much
First of all, for client - server communication, I would suggest you to use SSL for the sensitive information (like passwords) not to be transferred in plain text format.
Afterwards, it's the common practice not to save passwords anywhere (even with encryption, but the hashed values of them.
You can put the hash function to the set method of password property. Here is an example:
public class Member
{
private string _username;
public string Username
{
get { return _username; }
set { _username = value.ToLowerInvariant(); }
}
public string Passhash {get;set;}
public void SetPassword(string password)
{
Passhash = Crypto.Hash(password);
}
public bool CheckPassword(string password)
{
return string.Equals(Passhash, Crypto.Hash(password));
}
}
public static class Crypto
{
public static string Hash(string value)
{
return Convert.ToBase64String(
System.Security.Cryptography.SHA256.Create()
.ComputeHash(Encoding.UTF8.GetBytes(value)));
}
}
Edit:
As Craig Stuntz pointed out, the Hash code in this example is very simple. See the following post for a more secure way to hash your password: Hashing passwords with MD5 or sha-256 C#
In a service layer method that will be responsible for doing 2 things:
call your encryption layer to hash the password (not to encrypt it)
call your user repository to persist the user entity to the database with the hashed password
The controller action will of course talk to the service layer.
Don't do your own password hashing and don't even think about encrypting passwords.
The effort of making this secure are tremendous. Use an existing method based on publicly available specs and algorithms.
//ENCODE
public string base64Encode(string sData)
{
try
{
byte[] encData_byte = new byte[sData.Length];
encData_byte = System.Text.Encoding.UTF8.GetBytes(sData);
string encodedData = Convert.ToBase64String(encData_byte);
return encodedData;
}
catch(Exception ex)
{
throw new Exception("Error in base64Encode" + ex.Message);
}
}
//DECODE
public string base64Decode(string sData)
{
try
{
System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
System.Text.Decoder utf8Decode = encoder.GetDecoder();
byte[] todecode_byte = Convert.FromBase64String(sData);
int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
char[] decoded_char = new char[charCount];
utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
string result = new String(decoded_char);
return result;
}
catch (Exception ex)
{
throw new Exception("Error in base64Decode" + ex.Message);
}
}
How to call
string encode= base64Encode(val);
string decode= base64Decode(val);
This is very helpful to decode and encode your string(password)

How to initialize information on authorization [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Ok, so this seems like a common need. A little googling finds a lot of ways to do this. I'm interested in the most "mvc correct" way to do it.
I have, in the upper right hand corner of my app, a greeting that says Hello FirstName LastName. Now, it's quite easy to get at the username of the logged in user, through the IPrincipal (aka User.Identity.Name). However, this won't give me the First and Last name of the user. I have to hit the Membership API to get that.
Hitting the Membership API has its drawbacks. It hits the database every time, which adds an additional db access to every served page. It's easy enough to set some session variables on login, but this only works for that session. If the user clicks the "Remember me", then no login occurs next time and i have to still load these values.
I could create my own membership provider to do some cacheing, but that's a lot of work for a more or less single purpose.
I could use Application_AuthenticateRequest and hit the membership api and store the values in session variables, or something similar. This is ok, but seems a little brute force.
I could register a global filter and handle OnAuthenticate, essentially doing the same thing. This seems a little better, but i'm unusre of the ramifications here.
I could derive a base controller, and simly add properties to provide this information. This seems a bit "old school", and I hate having to make a base class for a single purpose.
I could create a cacheing static method that would get the information on first access. This is basically not much better than a singleton.
I could also create my own IPrincipal, but that means casting it every time to get at the data, and that seems clunky. I could wrap that in another class to simplify it, but still...
I could store the data in the forms authentication cookie, and get it from there. There's some tools available to make that easier.
Are there any methods I haven't thought of? And what is the most "mvc correct" way of doing it?
I think the best way is using Cookies. Here is the solution I used in my project:
Create a class to save data in it
[DataContract]
[Serializable()]
public class AuthData {
[DataMember]
public String UserName { get; set; }
[DataMember]
public String FirstName { get; set; }
[DataMember]
public String LastName { get; set; }
[DataMember]
public String Email { get; set; }
// any other property you need to a light-store for each user
public override string ToString() {
string result = "";
try {
using (MemoryStream stream = new MemoryStream()) {
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
result = Convert.ToBase64String(stream.ToArray());
}
} catch (Exception ex) {
throw new HttpException(ex.Message);
}
return result;
}
static public AuthData FromString(String data) {
AuthData result = null;
try {
byte[] array = Convert.FromBase64String(data);
using (MemoryStream stream = new MemoryStream(array)) {
stream.Seek(0, 0);
BinaryFormatter formatter = new BinaryFormatter();
result = (AuthData)formatter.Deserialize(stream, null);
}
} catch (Exception ex) {
throw new HttpException(ex.Message);
}
return result;
}
}
Signin method:
public static bool SignIn(string userName, string password, bool persistent){
if (Membership.ValidateUser(userName, password)) {
SetAuthCookie(userName, persistent);
return true;
}
return false;
}
Setting AuthCookie:
public static void SetAuthCookie(string userName, bool persistent) {
AuthData data = GetAuthDataFromDB(); // implement this method to retrieve data from database as an AuthData object
var ticket = new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.Add(FormsAuthentication.Timeout),
persistent,
data.ToString(),
FormsAuthentication.FormsCookiePath
);
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
cookie.Expires = DateTime.Now.Add(FormsAuthentication.Timeout);
cookie.HttpOnly = false;
cookie.Path = FormsAuthentication.FormsCookiePath;
HttpContext.Current.Response.Cookies.Add(cookie);
}
Getting AuthCookie:
public static AuthData GetAuthCookie() {
if (HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated && HttpContext.Current.User.Identity is FormsIdentity) {
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
var data = AuthData.FromString(ticket.UserData);
HttpContext.Current.Items["AuthDataContext"] = data;
return data;
}
return null;
}
In ControllerBase:
private AuthData _authData;
private bool _authDataIsChecked;
public AuthData AuthData {
get {
_authData = System.Web.HttpContext.Current.Items["AuthDataContext"] as AuthData;
if (!_authDataIsChecked && _authData == null) {
SignService.GetAuthCookie();
_authData = System.Web.HttpContext.Current.Items["AuthDataContext"] as AuthData;
_authDataIsChecked = true;
}
return _authData;
}
}
The FormsAuthenticationExtensions project solves this problem storing the additional information in the auth cookie itself. http://formsauthext.codeplex.com/
This spares the database hit, and lives as long as the auth cookie, hence it works if the users asks for "remember me". It can be used the same way (in MVC too) as the standard forms authentication.
To your question, what is the most MVCisch way: I would first decide where I want to keep the information. This part of the question is rather independent of the MVC framework as the concepts (session, post data, cookies, etc.) are given with or without it.
I will implement and extend the IPrincipal and IIdentity, so when you access User.Identity you will find LastName and FirstName.
This way is better imo.
For my projects I have extended IIdentity and IPrincipal with my classes adding the properties I always need "to be there". To me is not this big work, I mean, there are only a bunch of methods that need to be implemented.
For IIdentity the interface requirement are only AuthenticationType (string), IsAuthenticated (bool) and Name (string).
While in IPrincipal Identity (IIDentity) and IsInRole (boolean)

Resources