This blog article describes, how you can add two factor authentication to your web application using the authentication system privacyIDEA.
Two factor authentication has been added this way to ownCloud/Nextcloud, OTRS, dokuwiki, WordPress, TYPO3, Django, Kopano (Zarafa) and SimpleSAMLphp. See the plugin section of the privacyIDEA online documentation.
Two different concepts
There are basically two ways for the user to provide a second factor during authentication. The first one is to completely replace the authentication of your webapplication. In this case your application delegates the complete authentication process to privacyIDEA. This is implemented e.g. in the OTRS plugin and the WordPress plugin. In this case the plugin will take care of the first and second factor. And in certain cases it will also take care of the WebUI Login Screen.
The other possiblity is that your application uses its normal password based authentication, but after the user has successfully authenticated with his usual username and the application password, your application decides, not to immediately allow access, but hand over the authentication to the 2FA plugin, which will take care of quering the second factor. This is implemented in the privacyIDEA ownCloud App.
In addition we already published some basic requirements for modular two factor authentication in a web application.
Hand complete authentication process to the 2FA plugin
Your application should allow to register or configure a 3rd party module or class. This class would have to provide a method like authenticate_user for verifying the users input. The easiest way would be, that such a plugin does not even has to change or bring its own login screen. In such simple case, the authentication method authenticate_user would simple receive the credentials, that were entered at your applications default login screen. It then would return True or False or maybe raise an exception.
The privacyIDEA plugin for your webapplication would use this username and this password to issue a call to the privacyIDEA REST API. The plugin would call the /validate/check endpoint with username and password as parameters and simply evaluate the JSON response.
Managing users, returning user attributes or listing users would be out of scope of such an authentication plugin. Authorization would be out of scope, just as it is with the Unix PAM stack.
Example OTRS
An example implementation of the complete authentication replacement is the OTRS plugin for privacyIDEA.
In this case the administrator can configure in OTRS which Perl module should be used for authenticating the user. Note: Not for verifying if the user exists and not for fetching attributes like given name or email address of the user.
The Perl module has to provide a function Auth, which takes a dictionary/hash with the keys User and Pw. If the credentials were verified successfully this function returns the Username of the user, otherwise an empty string.
See the implementation at github.
In this case, privacyIDEA takes care of verifying two factors. The user has entered a knowledge and a One Time Password (2nd factor: possession) into the password field. privacyIDEA knows how to verify the static password (knowledge) and the OTP value.
Example WordPress
The WordPress plugin works the same. It does not modify the login screen, as this is not necessary. The user enters his static password and his one time password in the password field. The WordPress plugin registers or overwrites the function wp_authenticate, which takes the credentials that were entered by the user. WordPress relies on the return value of this function, which again is either a WordPress User object or null.
Within this function of the plugin, the credentials are verified against the configured privacyIDEA server. In this case this is done using curl.
Note: All authentication requests are forwarded to privacyIDEA. WordPress does not know if the user has a second factor or not. It does not know, which kind of second factor a user has. This is all handled by privacyIDEA. This way the plugin can be kept rather light weight.
Only hand second factor to the 2FA plugin
Instead of passing the complete authentication process to the 3rd party plugin, you can also design your authentication framework this way, that your application still verifies the static user password and request an additional authentication on top.
This can be interesting, if your application needs to know the user password, since it is used to contact email servers or encrypt data.
Your application will verify the password as before. But in addition it will pass the controll the the 2FA plugin
Example ownCloud
The ownCloud 2FA Framework is implemented this way.
In the first step the user has to authenticate against ownCloud with the ownCloud password.
If the user entered the correct password, which is still verified by ownCloud, the web application (ownCloud) calls the 2FA plugin to ask for the second factor.
The ownCloud 2FA framework requires the plugin to register a Class that is derived from a certain 2FA base class. This way the web application (ownCloud) knows, if two factor authentication can be used for the user, who is already authenticated in the first step.
The 2FA framework then asks the plugin/class to provide a template for the 2nd step of the Login UI. Finally the 2FA framework calls a class method in the plugin to verify the 2nd factor.
This good thing about it is, that ownCloud can know the user’s password and thus use the user’s for encryption and sending emails. The drawback of this design is, that the authentication workflow might be a bit more complicated, exspecially if it comes to special scenarios like challenge response authentication.
Special case for Challenge Response token like SMS and Email
Although NIST recommended to not use SMS for two factor authentication it is still an attractive and easy way. In addition privacyIDEA can run any combination of authentication devices. Some users may use Yubikeys, others Google Authenticators, some users use key fob tokens and another group could use SMS.
But privacyIDEA needs additional information to trigger an SMS. Not everybody can trigger the sending of an SMS, otherwise the user would get spammed with SMS on his mobile phone.
There are two ways to trigger and SMS:
- The user authenticates with his OTP PIN (static password). privacyIDEA realizes, that this is the correct password for an SMS token and will send the SMS.
- An administrative or system account requests the sending of an SMS for this specific user.
In both cases the 2FA framework of your application has to provide the possibility to issue a REST request before the user authenticats. Because this first REST request will send the user the code, which he then can use to finally authenticate.
Most applications do not allow this easily today.
There is a beta implementation for the ownCloud 2FA framework, which is not that perfect. The SMS is triggered when the Login UI is rendered. This has the side effect that the SMS is triggered again, if the user entered a wrong OTP value, since the UI is rendered again.
When designing the authentication framework of your web applications, you could have such corner cases in mind.
Now it is your turn!
If you want to add 2FA to your web application, please contact us in our Google Group.