Send an One Time Password (OTP) via the Twilio SMS gateway
Problem this snippet solves:
This snippet makes it possible to send an One Time Password (OTP) via the Twilio SMS gateway. This snippet uses iRuleLX and the node.js twilio package to interact with the Twilio API.
How to use this snippet:
Prepare the BIG-IP
- Provision the BIG-IP with iRuleLX.
- Create LX Workspace: workspace_twilio
- Add iRule: irule_twilio
- Add Extension: extension_twilio
- Add LX Plugin: plugin_twilio -> From Workspace: workspace_twilio
Install the node.js twilio module
# cd /var/ilx/workspaces/Common/workspace_twilio/extensions/extension_twilio # npm install twilio --save /var/ilx/workspaces/Common/workspace_twilio/extensions/extension_twilio └─┬ twilio@3.13.0 (lots and lots of modules follow...) #
iRule
To make it works, you need to install the irule on the Virtual Server that publish your application with APM authentication.
Access Profile
If you already have an existing access profile, you will need to modify it and include some additional configuration in your VPE. If you have no access profile, you can starts building your own based on the description we provide below.
Configuring the Visual Policy Editor
The printscreen below is a minimal Visual Policy Editor used to make Twilio OTP Authentication works properly:
IE – Twilio
This is an Irule Event with the ID set to
twilio
. This will trigger the irule_twilio iRule to come into action.
EA - Twilio Status
This is an Empty Action with two branches. The branch named "successful" contains the following expression :
expr { [mcget {session.custom.twilio.status}] starts_with "SM" }
Message Box
This is a Message Box that will inform the user that there was a failure sending the One Time Password. For example:
Oops, something went wrong. Please login again.
irule_twilio
when ACCESS_POLICY_AGENT_EVENT { if { [ACCESS::policy agent_id ] eq "twilio" } { set username "[ACCESS::session data get session.logon.last.username]" set generatedOTP "[ACCESS::session data get session.otp.assigned.val]" set telephoneNumber "[ACCESS::session data get session.ad.last.attr.telephoneNumber]" # The sender of the message. From a valid Twilio number. set sender "+31123456789" if {[info exists username] && ($username eq "")} { log local0. "Error: username variable is empty; no OTP sent." return } if {[info exists generatedOTP] && ($generatedOTP eq "")} { log local0. "Error: generatedOTP variable is empty; no OTP sent for user $username." return } if {([info exists telephoneNumber] && $telephoneNumber eq "")} { log local0. "Error: telephoneNumber variable is empty; no OTP sent for user $username." return } set rpc_handle [ ILX::init plugin_twilio extension_twilio] if {[ catch { ILX::call $rpc_handle sendOTP $generatedOTP $telephoneNumber $sender } result ] } { log local0. "sendOTP failed for telephoneNumber: $telephoneNumber, ILX failure: $result" return } log local0. "Twilio status for user $username ($telephoneNumber): $result" ACCESS::session data set session.custom.twilio.status $result } }
Code :
// Import the f5-nodejs module. var f5 = require('f5-nodejs'); // Create a new rpc server for listening to TCL iRule calls. var ilx = new f5.ILXServer(); const accountSid = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // Your Account SID from www.twilio.com/console const authToken = 'your_auth_token'; // Your Auth Token from www.twilio.com/console const client = require('twilio')(accountSid, authToken); ilx.addMethod('sendOTP', function(req, res) { var generatedOTP = req.params()[0]; var telephoneNumber = req.params()[1]; var sender = req.params()[2]; var message = 'Your OTP is: ' + generatedOTP; client.messages.create({ body: message, to: telephoneNumber, // Text this number from: sender // From a valid Twilio number }) .then(function(message) { return res.reply(message.sid); }); }); // Start listening for ILX::call and ILX::notify events. ilx.listen();
Tested this on version:
13.0- Manuel_Cristob2Nimbostratus
One more question... Where do I paste the code (node.js the entire 30 lines)? Do I modify/replace the index.js under this path with the code? PATH--- workspace_twilio=>extension_twilio=>f5-nodesjs=>twilio=>index.js
Thanks again
Manuel
Hi Manuel,
You can replace the nodejs javascript in the index.js file with the javascript code in this snippet.
Kind regards,
Niels
- AdamM07_249516Nimbostratus
Niels,
I keep getting the error "Unable to find app_project (plugin_twilio) when applying the iRule to a VIP.
I have the following directory:
/var/ilx/workspaces/Common/workspace_twilio/extensions/extension_twilio
Under it I have:
- index.js (With the nodejs script from above in it)
- node_modules directory
- lib directory
- package.json ( pulled from https://github.com/F5Networks/f5-cloud-libs/blob/master/package.json)
Any ideas?
No idea. I have never seen this error message. Only thing I never done is pulling the package.json. With exception of running the npm install command, I configure everything from the workspace.
- kinjeyan_365942Nimbostratus
Have you test it with Alphanumeric id instead of number? I can't get it work with.
To what ID are you referring to? If you are talking about the accountSid, then I have used an alphanumeric ID. Do you get an error message? What does /var/log/ltm show?
- kinjeyan_365942Nimbostratus
I mean istead of (set sender "+31123456789") use (set sender "blablabla") on irule or use (messagingServiceSid: 'MG5XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') instead of (from: sender) on index.js
I didn't try that myself, but according to the docs you should use something like this:
// Download the helper library from https://www.twilio.com/docs/node/install // Your Account Sid and Auth Token from twilio.com/console const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; const authToken = 'your_auth_token'; const client = require('twilio')(accountSid, authToken); client.messages .create({ body: 'Phantom Menace was clearly the best of the prequel trilogy.', messagingServiceSid: 'MG9752274e9e519418a7406176694466fa', to: '+441632960675' }) .then(message => console.log(message.sid)) .done();
- kinjeyan_365942Nimbostratus
That's what i tried but doesn't seem to work. i fallback on EA - Twilio Status
You should see the output of this log message back in /var/log/ltm:
log local0. "Twilio status for user $username ($telephoneNumber): $result"
What result do you get?