<securityPolicy>
...
<credentials>
<password>
<storageMethod>
<storageType>hashing</storageType>
</storageMethod>
</password>
</credentials>
</securityPolicy>
Password Storage Configuration
Introduction
Passwords are sensitive, therefore they were always be handled with utmost care in midPoint. MidPoint has a special data type to store sensitive information (ProtectedString) and there is special component that takes care of protecting the values before storage.
Storing Encrypted Passwords
MidPoint has stored passwords in encrypted forms from the very beginning. And this is still the default setting. In this case midPoint encrypts the password with a symmetric cipher before storage. Using symmetric encryption allows midPoint to get a cleartext value of the password if needed. And this is really needed relatively often in the identity management world. Almost all the target resources need clear text password to create a working account. This is easy to do when a midPoint user is created as at that point we usually have (generated) cleartext password. But if an account is assigned at a later time then we have a problem. We need cleartext password to create this new account. Therefore midPoint stored the passwords in encrypted form. This seems to be a common practice in the IDM field.
That encryption was the only practical measure to provide at least some protection for the password. We take care to select a good cipher (AES), generate random key for every midPoint deployment, store the key in the keystore and not in the database and so on. However as midPoint needs to be able to get a cleartext version of the password at any time it is not really possible to provide complete protection for the password.
The passwords are encrypted using the following parameters:
JCE extension installed | JCE extension not installed | |
---|---|---|
Cipher |
AES |
AES |
Key size (bits) |
256 |
128 |
Password Hashing
MidPoint 3.6 introduces ability to hash passwords instead of encrypting them for storage. This approach to password storage is more secure, but it has its drawbacks.MidPoint knows cleartext password only when midPoint user is created or when user changes the password. It does not know the password at other times. Therefore if a new account is assigned to the user, the valid password cannot be set for that account. We can either create a password-less account (if the resource allows it) or generate a randomly-generated password. Either way that account will not be be usable until is it explicitly initialized by the user.
The process works like this: user will get mail notification that there are new accounts ready for him and that he needs to initialize them. The notification will contain link to the midPoint end-user interface. The user will follow the link and gets to the account initialization page. He needs to enter his current midPoint password first. This is both a form of user authentication but also a way how midPoint gets cleartext version of user’s password. MidPoint then displays list of new user accounts and offers user the option to initialize them. The initialization means setting the password to those accounts to make them usable.
The password is hashed using the following parameters:
Algorithm | PBKDF2 with HMAC SHA512 |
---|---|
Key size (bits) |
256 |
Work factor (iterations) |
10 000 |
Salt size (bits) |
32 |
Configuring the Storage Mechanism
It is clear that in this case one size does not fit all. Some midPoint deployment will prefer ease of use and operational advantages of password encryption. Other deployment will choose hashing for security reasons and accept the inconvenience of account initialization mechanism. Therefore the password storage mechanism is configurable. The storage mechanism can be configured in security policy:
Possible storage type values are:
Type | Meaning |
---|---|
|
Credential will be stored in an encrypted form. This is a symmetric (reversible) encryption. MidPoint will be able to get a cleartext form of the credential if needed. |
|
Credential will be stored in a hashed form. One-way (irreversible) cryptographic hash or key derivation function will be used to transform the credential before storage. MidPoint will NOT be able to get a cleartext form of the credential, but it can still compare credential values. |
|
MidPoint will not store the credential at all. MidPoint will only work with credential in the memory while it is needed to complete current operation. The credential will be discarded after the operation. This is only partially implemented in midPoint 3.6 and it is not fully supported. MidPoint should be able not to store the credentials when this setting is used. But there may be side effects that are not completely addressed yet. This is not entirely tests and not supported. Use at your own risk. |
Account Lifecycle and Initialization
Accounts that were created and were not yet initialized are marked in midPoint by using the lifecycle state property. The uninitialized accounts are in the proposed
lifecycle state.
Account initialization will transition the account to the active
lifecycle state.
<accountActivationNotifier>
<recipientExpression>
<script xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="c:ScriptExpressionEvaluatorType">
<code>
return requestee.getEmailAddress()
</code>
</script>
</recipientExpression>
<transport>mail</transport>
<confirmationMethod>link</confirmationMethod>
</accountActivationNotifier>
<accountActivationNotifier>
<recipientExpression>
<script xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="c:ScriptExpressionEvaluatorType">
<code>
return requestee.getEmailAddress()
</code>
</script>
</recipientExpression>
<bodyExpression>
<script xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="c:ScriptExpressionEvaluatorType">
<code>
import com.evolveum.midpoint.notifications.api.events.ModelEvent
modelEvent = (ModelEvent) event
newUser = modelEvent.getFocusContext().getObjectNew();
userType = newUser.asObjectable();
message = "Dear " + userType.getGivenName() + ",\n\n" +
"your account was successfully created. To activate your account click on the activation link below in the email."
accountsToActivate = "Shadow to be activated: \n";
shadows = getMidpointFunctions().getShadowsToActivate(modelEvent.getProjectionContexts())
for (shadow in shadows) {
accountsToActivate = accountsToActivate + shadow.asPrismObject().debugDump() + "\n";
}
link = midpoint.createAccountActivationLink(userType);
bodyMessage = message + "\n\n" + link + "\n\n" + accountsToActivate;
return bodyMessage;
</code>
</script>
</bodyExpression>
<transport>mail</transport>
<confirmationMethod>link</confirmationMethod>
</accountActivationNotifier>
Password History
The default setting for password history storage is hashing. This can also be configured in security policy:
<securityPolicy>
...
<credentials>
<password>
...
<historyStorageMethod>
<storageType>encryption</storageType>
</historyStorageMethod>
</password>
</credentials>
</securityPolicy>
Password history in midPoint 3.5.1 and earlier had a different default. Hasing was not supported at that time therefore that password history entries were stored in encrypted form. The old password history entries will remain in the form in which they were originally stored after upgrade to midPoint 3.6 and/or after change of the storage scheme. |
Misc
-
If password storage scheme is changed then the existing passwords stored in the system will not be changed. If they were encrypted they will remain encrypted. They will not be re-hashed. Currently there is no task that could support this migration process. The only method how to change the stored version of the passwords is the usual password change process. However, please be careful about password history. Please check that the old passwords are stored in the password history in appropriate form.
-
When switching to password hashing do not forget to change the password of the
administrator
user - or any other existing users that were used for configuration. Otherwise the password will remain in encrypted form and it will not be hashed.