Passwords in the Security System
- 5 minutes to read
This topic describes built-in XAF tools for generating and changing user passwords when using the AuthenticationStandard authentication.
Password Encryption
The ApplicationUser
class generated by the XAF Solution Wizard does not store a password as plain text. Instead, the derived hash is created from a password using the Rfc2898DeriveBytes or SHA512 class. Use the static EnableRfc2898 and SupportLegacySha512 properties of the DevExpress.Persistent.Base.PasswordCryptographer class to specify the password encryption algorithm.
| EnableRfc2898 = true | EnableRfc2898 = false |
SupportLegacySha512 = true | SHA512-encrypted passwords that exist in the database are supported. Newly created passwords are encrypted and verified using RFC 2898 algorithm. | All passwords are encrypted and verified using SHA512. |
SupportLegacySha512 = false | Default mode. SHA512-encrypted passwords are NOT supported. All passwords are encrypted and verified using the RFC 2898 algorithm. This mode is FIPS-compliant. |
|
You can specify these static property values in one of the following locations:
- in the constructor of your platform-agnostic module located in the Module.cs (Module.vb) file;
- in the constructor of your application located in the WinApplication.cs (WinApplication.vb) or WebApplication.cs (WebApplication.vb) file;
- in the Main method of the WinForms application located in the Program.cs (Program.vb) file, before the WinApplication.Start call;
- in the Application_Start method of the ASP.NET Web Forms application located in the Global.asax.cs (Global.asax.vb) file, before the WebApplication.Start call.
Note
If you use the Middle-tier level security, you also need to specify these static properties in the server application’s Main method located in the Program.cs (Program.vb) file.
The DevExpress.Persistent.Base.PasswordCryptographer class supports FIPS compatibility. Refer to the following topic for details: FIPS-compliance changes to the DevExpress.Persistent.Base.PasswordCryptographer and DevExpress.ExpressApp.Utils.ImageLoader classes. XAF applications created with Solution Wizard version 17.1 or higher use the RFC 2898 algorithm.
Important
The Sha512 algorithm is vulnerable. Use the RFC 2898 algorithm in your applications.
If you need to use the Sha512 algorithm for backward compatibility, set the PasswordCryptographer.SupportLegacySha512 property to true
as follows:
ASP.NET Core Blazor, Web API
File: MySolution.WebApi\Startup.cs (MySolution.Blazor.Server\Startup.cs)
public class Startup {
// ...
public void ConfigureServices(IServiceCollection services) {
// ...
PasswordCryptographer.SupportLegacySha512 = true;
// ...
}
}
WinForms
File: MySolution.Win\WinApplication.cs
namespace MySolution.Win {
public partial class MySolutionWindowsFormsApplication : WinApplication {
static MySolutionWindowsFormsApplication() {
DevExpress.Persistent.Base.PasswordCryptographer.SupportLegacySha512 = true;
}
// ...
}
}
You can also configure application settings to match the specified version of DevExpress frameworks and libraries. Use the FrameworkSettings.DefaultSettingsCompatibilityMode property for this purpose.
Administrator-Generated Passwords
Administrators can use the ResetPassword Action to generate a password for a particular user. This Action is activated if a user type implements the IAuthenticationStandardUser interface, and the Standard Authentication is applied.
The ResetPasswordController View Controller provides the ResetPassword Action, which is enabled for root Views and located in the RecordEdit Action Container. This Action invokes the following dialog:
The user can change the generated password later.
Note
Changes you made in the Detail View are lost after the ResetPassword Action execution. To save changes when this Action is executed, set the SaveUserObjectOnPasswordChanging property to true.
Change the Password After the First Logon
User objects that implement the IAuthenticationStandardUser interface have the IAuthenticationStandardUser.ChangePasswordOnFirstLogon property. If you set this property to true for a particular user, the following dialog displays after this user is logged on:
Since the AuthenticationActiveDirectory authentication type does not expect XAF application passwords to change, this window displays only when Standard Authentication is used.
End-User Password Modifications
When using the Standard Authentication type, end users that have access to the My Details Detail View can change their passwords using the ChangeMyPassword Action. This Action is located in the Edit Action Container and is activated for the My Details Detail View. It invokes the following dialog:
Note
- You can force users to have complex passwords using the approach described in the Non-Persistent Objects Validation topic.
- Changes you made in the Detail View are lost after the ChangeMyPassword Action execution. To save changes when this Action is executed, set the SaveUserObjectOnPasswordChanging property to true.
Access Passwords in Code
It is impossible to decrypt the stored value to get the original password. To verify or encrypt passwords with a custom algorithm, use one of the following methods:
The static PasswordCryptographer.VerifyHashedPasswordDelegate and PasswordCryptographer.HashPasswordDelegate methods.
The following code snippet demonstrates how to customize the behavior of these methods:
using DevExpress.Persistent.Base; // ... PasswordCryptographer.VerifyHashedPasswordDelegate = VerifyHashedPassword; PasswordCryptographer.HashPasswordDelegate = HashPassword; // ... static bool VerifyHashedPassword(string saltedPassword, string password) { bool result; // validate password here. return result; } static string HashPassword(string password) { string hash; // create hash here. return hash; }
To compare a plain password with a hashed password in a non-XAF .NET app with XPO, use the following code:
using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl.PermissionPolicy; using DevExpress.Xpo; using DevExpress.Xpo.DB; using DevExpress.Xpo.Metadata; using System.Linq; namespace ConsoleApp1 { class Program { static void Main(string[] args) { PasswordCryptographer.EnableRfc2898 = true; PasswordCryptographer.SupportLegacySha512 = false; var dictionary = new ReflectionDictionary(); dictionary.GetDataStoreSchema(typeof(ApplicationUser)); var cs = @"integrated security=SSPI;pooling=false;data source=(localdb)\mssqllocaldb;initial catalog=MainDemo_v20.1"; XpoDefault.DataLayer= XpoDefault.GetDataLayer(cs, AutoCreateOption.None); XpoDefault.Session = null; var session = new UnitOfWork(); var user = session.Query<ApplicationUser>().FirstOrDefault(u => u.UserName == "John"); var saltedPassword = (string)user?.GetMemberValue("StoredPassword"); var areEqual = PasswordCryptographer.VerifyHashedPasswordDelegate(saltedPassword, "test"); } } }
The IAuthenticationStandardUser.ComparePassword and IAuthenticationStandardUser.SetPassword methods. To use these methods, obtain an instance of the target user class that implements the IAuthenticationStandardUser interface. See the example in the following help topic: How to: Implement a Custom Security System User Based on an Existing Business Class.
Validate Password Complexity
For more information, refer to the following topic: Validate Password Complexity.