First of all, I would like to thank the PrivacyIDEA developers and community for creating such a great and flexible open-source MFA solution. The flexibility of PrivacyIDEA was especially valuable during this migration, as it allowed me to adapt the authentication and enrollment workflows to the requirements of the existing environment.
As part of an MFA migration from an unnamed commercial solution to PrivacyIDEA, I focused mainly on how to perform the migration gradually and with minimal impact on users.
In the original solution, approximately 70% of the tokens were SMS-based, so I decided to use temporary parallel operation and gradually enroll users into the new solution.
RADIUS Authentication
All authentication requests from our security devices are handled via the RADIUS protocol. For RADIUS authentication, I originally planned to use a passthrough policy. However, this proved to be insufficient, so I created a dedicated RADIUS token in PrivacyIDEA for every user who had an MFA token in the original system. The main reason was the need to support RADIUS challenge-response.
For the user migration, I created a script that reads the account from a report - CSV file and assigns a RADIUS token to the user if they do not already have one. When processing a larger number of users, I encountered an interesting issue: the script created a new database session for every insert, while the sessions were only closed after the script finished. I therefore had to split the CSV file into smaller batches.
I also had to modify the RADIUS plugin script to correctly handle challenge-response communication. The following PrivacyIDEA Community thread was particularly helpful and also points to a modification of the FreeRADIUS script:
PrivacyIDEA Community – Change PIN on first use not working
For RADIUS authentication, I then configured policy withlogin_mode: privacyIDEA.
PrivacyIDEA WebUI
The next step was to prepare the PrivacyIDEA portal for users. I configured WebUI login using the domain password and a dedicated authentication policy.
The goal was to allow users to continue using the original token or SMS-based MFA during the migration, then log in to the PrivacyIDEA portal and enroll a new TOTP token on their mobile device.
After the user logged in to the WebUI, I wanted the temporary RADIUS token and SPASS token to be removed automatically so that the user could enroll a new TOTP token. Since events could not be easily associated with the User-Agent: Radius, I eventually based the condition on a group of IP addresses belonging to the security devices communicating via RADIUS.
Enrollment Policies
I also needed to distinguish between token enrollment performed by the user and enrollment performed by an administrator.
The goal was to allow a user to have a maximum of one TOTP token, while an administrator should still be able to create a new token even if the user already has one. I solved this using extended conditions and header parsing, that there is blank email or phone value.
New Users
For users who did not yet have access to the PrivacyIDEA WebUI, I prepared an alternative onboarding process. An administrator or helpdesk employee can create a temporary SPass token, with the password sent to the user via SMS together with an email containing instructions.
Since the event could not directly send the SPass password, I used a workaround where the password is stored in the token description and is also used as the SPass parameter.
In a similar way, an administrator can create a TOTP token for a user. In this case, only the token PIN is sent via SMS and TOTP QR-code instructions via email.
When the TOTP token is used for the first time, the user is prompted to change the PIN. After setting the new PIN, the token description is also updated and the original PIN is removed from it.
There is no direct policy condition for the specific token type in this case either, so I used additional conditions to handle this: token.tokentype !in spass,radius.
Database High Availability
For high availability, I chose MariaDB master-master replication, following the procedure described in the PrivacyIDEA documentation. I also configured different auto_increment_offset values on the database servers to reduce the possibility of ID collisions in the tables.
I also changed the database collation to utf8mb4_unicode_ci. In my opinion, this could also be a suitable default value for a new installation.
Conclusion
The migration ultimately turned out to be mainly about designing a gradual migration process and configuring the individual workflows correctly.
Temporary parallel operation allowed users to continue using the existing SMS-based MFA while gradually enrolling new TOTP tokens in PrivacyIDEA. The combination of RADIUS authentication, WebUI, policies, and events provided enough flexibility to automate most of the migration process.
However, a significant amount of work was required before the actual migration could begin. I spent considerable time testing different approaches, trying various policy and event configurations, and validating the complete workflow in a test environment. There were also several challenges that required workarounds or custom scripting.
From the user perspective, communication was equally important. The migration was accompanied by several notifications and reminders explaining the upcoming changes and providing step-by-step instructions on how to enroll the new TOTP token. This helped users understand what was changing and reduced the number of issues during the actual migration.