When I hash a password using Aspnet Identity's PasswordHasher, the password is not linked to the TUser whose password is set. So technically I can copy that password hash and set it for a different user and that same password hash will work.
The method signature takes TUser user as a parameter however it is not used in the hash/salt implementation.
Is this an oversight or is there some other reason TUser user is declared in the method signatures but not used?
Line 94:
public virtual string HashPassword(TUser user, string password)
and
Line 172:
public virtual PasswordVerificationResult VerifyHashedPassword(TUser user, string hashedPassword, string providedPassword)
Here is source code.
Related
I am trying to construct JWT token using System.IdentityModel.Tokens.Jwt nuget package (version 5.4.0). It is .net standard 2.0 compliant and I am using .net core 2.2 for my project.
Under System.IdentityModel.Tokens.Jwt namespace, I can find following method:
public virtual JwtSecurityToken CreateJwtSecurityToken(string issuer, string audience, ClaimsIdentity subject, DateTime? notBefore, DateTime? expires, DateTime? issuedAt, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials);
I can use this method to supply both SigningCredentials and EncryptingCredentials. However I would like to use following code (for finer control) to create the json string.
var header = new JwtHeader(...);
var payload = new JwtPayload(...);
var t = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
var json = handler.WriteToken(t);
To my surprise, I found that JwtHeader does not offer a constructor that takes both SigningCredentials and EncryptingCredentials. All the constructors are shown below:
public JwtHeader();
public JwtHeader(SigningCredentials signingCredentials);
public JwtHeader(EncryptingCredentials encryptingCredentials);
public JwtHeader(SigningCredentials signingCredentials, IDictionary<string, string> outboundAlgorithmMap);
public JwtHeader(EncryptingCredentials encryptingCredentials, IDictionary<string, string> outboundAlgorithmMap);
Is there a reason why JwtHeader does not offer the constructor that takes both? Am I missing something here?
I figured out why JwtHeader does not provide a constructor that takes both SigningCredentials and EncryptingCredentials at the same time. At any given time, JwtHeader can be either JWS (JSON Web Signature) token or JWE (JSON Web Encryption) token. It can NOT be both at one time. If you want to sign and then encrypt, then the outer JWT will represent JWE whose nested token is of type JWS. If you want to encrypt and then sign, the outer JWT will be represent the JWS whose nested token is of type JWE.
If you need to validate the token that is first signed and then encrypted, you can use JwtSecurityTokenHandler.ValidateToken method with both SigningCredentials as well as EncryptingCredentials at the same time to validate in one shot.
However if you need to validate the token that is first encrypted and then signed, you will have to use JwtSecurityTokenHandler.ValidateToken method twice.
First with only SigningCredentials to validate the signature to retrieve the encrypted information (typically in form a claim).
Next you will have to use JwtSecurityTokenHandler.ValidateToken again, this time with only EncryptingCredentials but providing the encrypted token string (retrieved from previous step).
This is why JwtSecurityTokenHandler can accept both SigningCredentials and EncryptingCredentials at the same time while the JwtHeader can not.
It would have been nice to have some documentation on how to use this API properly. I guess one has to read the standards on JWT, JWS and JWE.
https://www.rfc-editor.org/rfc/rfc7519 (JWT)
https://www.rfc-editor.org/rfc/rfc7515 (JWS)
https://www.rfc-editor.org/rfc/rfc7516 (JWE)
Does anyone have an example of how to use DNN's built-in functionality for a custom Login Module which can store the User Login with a Session and Cookie?
I don't want to re-invent the wheel.
Thanks
Check out DotNetNuke.Entities.Users.UserController.
It has all kinds of methods for user handling. For login it has
void UserLogin(int portalId, UserInfo user, string portalName, string ip, bool createPersistentCookie);
UserInfo UserLogin(int portalId, string username, string password, string verificationCode, string portalName, string ip, ref UserLoginStatus loginStatus, bool createPersistentCookie);
I have user table with plain passwords. I need connect the table into .net core web's AspNetUsers table.How to hash my user table's plain passwords like AspNetUsers's PasswordHash.
How can login with SignInManger plain-text password?
I recently did something like this. Our legacy system had its own password hashing method. I needed to covert everything over to asp.net users.
First thing I did was add two new columns to the Application user. These contain my legacy user password and that hash that was used to create it.
public string LegacyPasswordHash { get; set; }
public string LegacyPasswordSalt { get; set; }
Then i ran my sql script that copied all of the users in including their legacy password hash and salt.
Then i created a custom SignInManager.
public class ApplicationSignInManager : SignInManager<ApplicationUser> {}
In the password check method I test if its a legacy password user and if it is i covert the password that they just sent me over to a asp.net users password and delete their legacy password. Tip: is to remember to set the user security token on the user table as well this can not be null. You will have major issues with resting password if it is. As there is a bug in the token validation 2022
This is the section of the code i use for testing and resetting the password.
if (_password.EncodePassword(_user.LegacyPasswordSalt) == _user.LegacyPasswordHash)
{
_logger.LogInformation(LoggingEvents.LegacyUserCommand, "Legacy User {_user.Id} migrating password.", _user.Id);
await _userManager.AddPasswordAsync(_user, _password);
_user.SecurityStamp = Guid.NewGuid().ToString();
_user.LegacyPasswordHash = null;
_user.LegacyPasswordSalt = null;
await _userManager.UpdateAsync(_user);
return await new CheckTwoFactorCommand(_logger, _userManager, _user).Execute();
}
if (_shouldLockout)
{
_user.SecurityStamp = Guid.NewGuid().ToString();
await _userManager.UpdateAsync(_user);
_logger.LogInformation(LoggingEvents.LegacyUserCommand, "Login failed for Legacy user {_user.Id} invalid password. (LockoutEnabled)", _user.Id);
await _userManager.AccessFailedAsync(_user);
if (await _userManager.IsLockedOutAsync(_user))
return SignInResult.LockedOut;
}
_logger.LogInformation(LoggingEvents.LegacyUserCommand, "Login failed for Legacy user {_user.Id} invalid password", _user.Id);
return SignInResult.Failed;
How can I do registration via phone number in Asp.net core instead of Email. In UserManager only exist two method for phone number
Task<string> GenerateChangePhoneNumberTokenAsync(TUser user, string phoneNumber);
Task<bool> VerifyChangePhoneNumberTokenAsync(TUser user, string token, string phoneNumber)
Name of this methods is ambiguous. I can not found any sample in web.
I have couple of websites A, B, C .....
Website A: is an authentication website, depending on the user name, password and an extra parameter; Website A redirect a successful user login to Website B.
When the user is logged I get in the Website A a Token derived from System.IdentityModel.Tokens.SecurityToken. My first approach was trying to pass that Token to the other website via POST request but with no success because the token is too large. First I thought it was serializable but no: GenericXmlSecurityToken can be converted to XML using ToTokenXmlString(). This is an extension method on Thinktecture.IdentityModel.Extensions, below I am attaching the description of the class
public static class SecurityTokensExtensions
{
public static ClaimsPrincipal ToClaimsPrincipal(this SecurityToken token, SecurityTokenHandlerCollection handler);
public static ClaimsPrincipal ToClaimsPrincipal(this SecurityToken token, X509Certificate2 signingCertificate);
public static ClaimsPrincipal ToClaimsPrincipal(this SecurityToken token, X509Certificate2 signingCertificate, string audienceUri);
public static SecurityToken ToSecurityToken(this GenericXmlSecurityToken token);
public static SecurityToken ToSecurityToken(this GenericXmlSecurityToken token, SecurityTokenHandlerCollection handler);
public static SecurityToken ToSecurityToken(this GenericXmlSecurityToken token, X509Certificate2 decryptionCertificate);
public static string ToTokenXmlString(this GenericXmlSecurityToken token);
public static string ToTokenXmlString(this SecurityToken token);
public static string ToTokenXmlString(this SecurityToken token, SecurityTokenHandlerCollection handler);
}
As you can see we can convert the XML to String but not of the methods above takes that string and returns a SecurityToken, instead they take GenericXmlSecurityToken. The constructor of that class is here and depends on more than one parameter.
https://msdn.microsoft.com/en-us/library/system.identitymodel.tokens.genericxmlsecuritytoken.genericxmlsecuritytoken(v=vs.110).aspx
Questions:
Do I need to add something in my webconfigs to make this possible
withouth a POST?
Can I Serialize the SecurityToken and POST it to Website B and Deserialize it again with all original values(which is the approach on this case).
The proper solution would be to use an STS that both websites use for authentication. Manually posting tokens around is a bit hacky.
That said - you can construct an GenericXmlSecurityToken from the XML string. IIRC you can simply pass null to all the ctor arguments that you don't know about.