I have a problem using UserManager.CheckPassword(...) with a custom IUser implementation.
I am using .net Identity with Owin, creating my own implementations of IUser and IUserStore.
For the store, I only use the optional Email- and Password-Stores.
The IUser implementation is seen here, with the basic fields:
public class RegisteredUser : IUser<string>
{
public RegisteredUser()
{
Id = Guid.NewGuid().ToString();
}
public string Id { get; }
public string UserName { get; set; }
public string PasswordHash { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
}
The problem occurs when validating the user when logging in.
I am unable to use the SignInManager.PasswordSignIn(...) as my store doesnt implement the LockoutStore.
Instead I use the UserManager.CheckPassword(...), but this throws an FormatException, saying:
The input is not a valid Base-64 string...
UserSignInManager manager = HttpContext.GetOwinContext().Get<UserSignInManager>();
RegisteredUser user = manager.UserManager.FindByEmail(model.Email);
if (user != null && manager.UserManager.CheckPassword(user, model.Password))
{
manager.SignIn(user, model.RememberMe, model.RememberMe);
return RedirectToAction("UserProfile");
}
Thinking about this, I also fail to understand how the CheckPassword() method is able to check the password of my custom implementation without knowing where to look.
What am I doing wrong?
Alright - Brainfart on my behalf..
The UserManager is able to check the password as my UserStore implements the following method
public Task<string> GetPasswordHashAsync(RegisteredUser user)
{
string passwordHash = AWSUser.GetPasswordHash(user.Id);
return Task.FromResult(passwordHash);
}
The problem was in the AWSUser class, which has the following method
public static string GetPasswordHash(string id)
{
return tblUsers.Find(u => u.Id.Equals(id)).Id;
}
And as I am errorously returning the ID, that ofcourse fails..
Related
I am working on a project in C# which needs to store information about a user. This information is retrieved from their respective libraries which have their own implementations and interfaces. Currently users can either connect from Twitch or Discord, so they will be represented as either TwitchUser or DiscordUser objects. However, I would like to write a class User that will contain one of the 2 classes which should make it easier for me to refer to them in code.
Here is an example of how TwitchUser and DiscordUser look like:
public class TwitchUser : IChatUser
{
public TwitchUser();
public string Id { get; }
public string UserName { get; }
public string DisplayName { get; }
public string Color { get; }
//and so on...
}
public class DiscordUser : SnowflakeObject, IEquatable<DiscordUser>
{
public virtual string Email { get; internal set; }
public virtual string Username { get; internal set; }
public bool Equals(DiscordUser e);
//and so on...
}
I thought I could create a class which accepts generic types but with my implementation I would have to pass BOTH classes which means one of them would be null. This doesn't feel right to me.
public class User<T,D>
{
public TwitchUser VarA { get; set; }
public DiscordUser VarB { get; set; }
}
What is the correct way of combining 2 classes that have different implementations and don't have interfaces in common between?
I would then also write code inside my User class to return user IDs etc.
Update
For example, when I request a user ID I would perform a check inside User whether I stored a TwitchUser or DiscordUser, and based on the outcome I would return an attribute which represents the user's ID on that platform.
Update 2
A user may only be represented by one of the two classes. For example, if they used Discord as their platform to login then they will only have a DiscordUser object associated with them. Same applies to Twitch platform and it using TwitchUser object. The reason they are different is because these implementation were written by different people using 2 different libraries, which is why they don't use the same interfaces, or inherit from one common class. So what I am trying to do is retroactively add some sort of an inheritance here. This way, when I want to refer to the user in my code, I don't need to write 2 overloads for a function (where one uses TwitchUser and the other uses DiscordUser). I just want to be able to refer to User and let that class decide for me.
those 2 clases I mentioned cannot be modified [...] I want to be able to access all the necessary attributes stored in DiscordUser and TwitchUser
That sounds like a good fit for the adapter pattern. Define an interface as common denominator:
public interface IUser
{
string Id { get; }
string Username { get; }
}
Note that this interface can only contain properties that both objects share, or you're going to need null checks all over the place.
Then create an adapter for each type you want to wrap:
public class TwitchUserAdapter : IUser
{
private readonly TwitchUser _user;
public TwitchUserAdapter(TwitchUser user)
{
_user = user;
}
public string Id => _user.Id;
public string Username => _user.UserName;
}
public class DiscordUserAdapter : IUser
{
private readonly DiscordUser _user;
public TwitchUserAdapter(DiscordUser user)
{
_user = user;
}
public string Id => _user.Id;
public string Username => _user.Username;
}
Now you can treat both the same:
var users = new List<IUser>();
users.Add(new TwitchUserAdapter(new TwitchUser { Id = "Tfoo", UserName = "Tbar" }));
users.Add(new DiscordUserAdapter(new DiscordUser { Id = "Dfoo", Username = "Dbar" }));
foreach (var user in users)
{
Console.WriteLine($"Id: {user.Id}, Name: {user.Username}");
}
"What is the correct way of combining 2 classes that have different implementations and don't have interfaces in common between?"
One way to accomplish this might be to create a class that contains all the properties you care about, and then create static methods that return an instance of the class based on the properties of a TwitchUser or a DiscordUser:
public class User
{
// Add just the properties you care about
public string Id { get; private set; }
public string UserName { get; private set; }
public string DisplayName { get; private set; }
public string Color { get; private set; }
public string Email { get; private set; }
// Make the default constructor private so instances of this
// class can only be created from one of our static methods
private User() { }
public static User FromTwitch(TwitchUser twitchUser)
{
return new User
{
Id = twitchUser.Id,
Color = twitchUser.Color,
DisplayName = twitchUser.DisplayName,
UserName = twitchUser.UserName
};
}
public static User FromDiscord(DiscordUser discordUser)
{
return new User
{
Email = discordUser.Email,
UserName = discordUser.Username
};
}
}
I have a service in my application which creates a User, and saves it to the database. Here's a method of my service:
public async Task<UserDTO> CreateUserAsync(User newUser)
{
var result = (UserDTO)await _userRepository.CreateUserAsync(newUser);
if (result != null)
{
await _userRepository.SaveChangesAsync();
}
return result;
}
And a method from a UserRepository:
public async Task<User> CreateUserAsync(User newUser) => (await _dbContext.AddAsync(newUser)).Entity;
Here's a User class:
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
The problem is when the user is being added via service, UserId is not known yet. It has default value 0, then ef core saves it to a database, finding a proper UserId. But value returned by my methods has no UserId updated - it is still 0, and i would like to return updated value. How to achieve that in a proper way?
newUser WILL have an Id read from the database.
Your code is casting from User to UserDTO, which is unlikely to work.
I am working on an api which serves creating,updating,deleting of user settings for an application. My users are of two types
admin user
common user
I have a field public bool ReadOnly { get; set; } which says whether a common user is allowed to change the setting or not.
Now the question is in which layer i need to validate this and throw the 405 response to the client. Please suggest.
private readonly SettingsRepository _SettingsRepository;
[HttpPut("{userid}/settings/{settingName}")]
public IActionResult Put(string userid, [FromBody]Setting setting)
{
var result = _SettingsRepository.Update(userid, setting);
if (result == true)
{
return Ok(201);
}
else
{
return BadRequest();
}
}
//Updates the existing setting for a user having userid
public bool Update(string userid, Setting setting)
{
bool flag = false;
if (userid == null || setting == null)
{
return flag;
}
var existing = Profiles.profiles.Where(p => p.UserID.ToLower() == userid.ToLower() && p.Settings.Any(s => s.Name.ToLower() == setting.Name.ToLower())).SelectMany(res => res.Settings).ToList();
if (existing.Count() > 0)
{
existing.ForEach(e =>
{
e.Name = setting.Name;
e.Value = setting.Value;
e.Type = setting.Type;
e.Valid = setting.Valid;
e.ReadOnly = setting.ReadOnly;
e.ModifiedOn = DateTime.UtcNow;
e.Encrypted = setting.Encrypted;
e.Enabled = setting.Enabled;
e.CreatedOn = setting.CreatedOn;
e.Description = setting.Description;
});
FileSerDe.SerializeSettings<IList<Profile>>(Profiles.profiles, System.IO.Directory.GetCurrentDirectory() + "\\" + "seed.txt");
flag = true;
}
return flag;
}
//Profile Entity
public class Profile
{
public string UserID { get; set; }
public string UserName { get; set; }
public List<Setting> Settings { get; set; }
}
//Setting Entity
public class Setting
{
public string Name { get; set; }
public object Value { get; set; }
public string Type { get; set; }
public bool Encrypted { get; set; }
public bool ReadOnly { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime ModifiedOn { get; set; }
public bool Valid { get; set; }
public bool Enabled { get; set; }
public string Description { get; set; }
}
It looks business logic is in repository. so you can put security measure in repository. do that first thing in repository & throw exception on failed.
this will centralize your business logic to single place.
405 Method not allowed would be used when the HTTP method (e.g. GET or PUT) is specifically not allowed to be used with a given URL, and would apply to all users. For something which is permissions-within your application and related to a specific user it would be more accurate to a send a 403 Forbidden response.
As for the layers, clearly the API Action method is the only one which can return the actual HTTP error code, but since the information that tells you whether the user has permission is held in the database, you could arrange it so that the data layer tells the API layer what the appropriate response should be, perhaps by throwing an exception or by setting a flag on an output parameter to the database method. This would require you to pass information about the current user to the database layer, though, some people think that's unnecessary overhead, unless it's required anyway to record audit data etc.
The alternative is that you could get the API layer to retrieve the relevant data from the database before attempting to run the Update, and make a decision based on that retrieved data, entirely within the API action method. It's really a design decision that is up to you and what suits your application structure. Either way is possible, and, arguably, valid.
I wish to implement OWIN as per the example I could find here:
http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api
However, since this way of working is new to me especially using my self created database I would like some guidance.
I can submit my registration request without a problem.
The post takes me to the AccountController:
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
try {
var email = model.Email;
var password = model.Password;
var user = new users() {
Email = email,
PasswordHash = password,
Password = password
};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
catch(Exception ex)
{
throw;
}
}
This triggers the below code:
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
ApplicationUserManager:
public class ApplicationUserManager : UserManager<users>
{
public ApplicationUserManager(IUserStore<users> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<users>(context.Get<DaumAuctionEntities>()));
var dataProtectionProvider = options.DataProtectionProvider;
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = true,
RequireUppercase = true,
};
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<users>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
But for some weird reason I'm getting
modelState: {undefined: ["Name cannot be null or empty."]}
Even though I don't use name anywhere?! Where is this name coming from?
So I presume I'm doing something wrong but it's hard to debug without a clear explanation on how to implement OWIN with an existing DB.
Below my context/entity and users table that I would like to use to store me user data.
context:
public partial class DaumAuctionEntities : IdentityDbContext<users>
{
public DaumAuctionEntities()
: base("name=DaumAuctionEntities")
{
}
public DbSet<addresses> addresses { get; set; }
public DbSet<auctions> auctions { get; set; }
public DbSet<images> images { get; set; }
public DbSet<users> users { get; set; }
}
users : IdentityUser:
public partial class users : IdentityUser
{
public override string UserName
{
get
{
return Email;
}
set
{
Email = value;
}
}
override public string PasswordHash
{
get
{
return Password;
}
set
{
Password = value;
}
}
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<users> manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
}
public partial class users
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public System.DateTime CreatedDate { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
}
Edit:
If I add UserName back to my new users object before I try to call CreateAsync, the error is gone but I get another one instead:
"The specified type member 'UserName' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."
Edit II:
I also have this issue in the tutorial code! This is just a freaking bug in .NET?
Edit III
I tried to do an override as you can see in the partial class Users above. But I still have the same error.
The issue is due to the fact that I did not add UserName to my new user before I call UserManager.CreateAsync. If I add the UserName I have the exact same issue as this: MVC 5 IdentityDbContext and DbContext transactions
That issue seems to point to the fact that ASP.NET Identity is using the UserName property in a query, but Entity Framework compains that the property is not mapped to a database column in your Entity model (EDML).
I don't see many problems with your code
Remove the users DbSet from your DaumAuctionEntities class (See this)
Remove the Id property from your users class
Set the CreatedDate property when you create a new users inside the Register
method
Then you should be OK
Also,about:
Nope, it actually passes that. It comes from I believe the manager but
whenever I try to debug that code the debugger states that it jumped
over it (most likely due to the fact that it's an external library
from Microsoft).
If you wrap the call with a try/catch you'll be able to see the error message
I got few issues with the code you have shared here but not exactly the same as you mentioned. I have shared the example on git for your reference. Try it by your self and let me know if you see any issues.
Git URL - https://github.com/JitJDN/OWINStack
See, code is still the same as yours:
var email = model.Email;
var password = model.Password;
var user = new users()
{
Email = email,
PasswordHash = password,
Password = password
};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
I finally got it working.
In the end I had to add adjust the partial class Users (which is a table in my SQL database) so that UserName and Password override the fields of IDentityUser (so not like I did in my question):
public partial class users
{
public int Id { get; set; }
public string UserName {get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? CreatedDate { get; set; }
public DateTime? ModifiedDate { get; set; }
}
I then just had to pass the password and UserName when I created the user:
var user = new users() {
Email = email,
UserName = email,
PasswordHash = password,
Password = password
};
I'm trying to add some architecture to my projects and enrich my models.
I started with CQS (implementation similar to that one: CQS-Sample) and here's my first problem.
Let's say I have two classes like these below:
public class Network
{
public int Id { get; set; }
public User User { get; set; }
private IQueryFactory _queryFactory { get; set; }
public Network(IQueryFactory queryFactory)
{
_queryFactory = queryFactory;
}
public void AddUser(User user)
{
if(this.User == null && user != null)
{
userHasUniqueEmail(user);
this.User = user;
}
}
private void userHasUniqueEmail(User user)
{
bool isUnique = _queryFactory.ResolveQuery<INewUserUniqueQuery>().Execute(user.Email);
if (!isUnique)
{
throw new ArgumentException("E-mail is not unique");
}
}
}
public class User
{
public int Id { get; set; }
public string Email { get; set; }
}
Network object can have User, but I need to check first in database that given e-mail doesn't already exists or do some other checkings, so my commands will be executed successfully.
By adding user I mean adding completely new User to database.
Would it be correct way to do this?
You can do it the way you do it now and it's ok.
Another option is to make this Validation in Contoller. Then you should use Remote attribute. And Move your IsEmailUnique(string mail) method to Controller.
If you want to know how you can do it with email check - this question will help you.