Adaptive authentication is an evolved form of multi factor authentication (MFA) where the authentication mechanism is decided depending on the the user’s risk profile and the behavior.
You can understand this concept in detail by following “Adaptive Authentication: Why? What? How?” .
WSO2 Identity Server supports script-based adaptive authentication since WSO2-IS 5.7.0 adding numerous advantages to users.
NOT only that !!! WSO2 IS introduced function library support for
adaptive authentication to handle adaptive authentication scripts in a
hassle free manner.
require()
in NodeJS.Let’s use management console to add new function library. We are going to modify the “IP-Based” template which already contains two java script functions inside the authentication script itself. (convertIpToLong and isCorporateIP functions are the two common JS functions.). Let’s move them to one module and make the authentication script more cleaner.
Add Function Library [details]
1. Sign in to in to the Management Console.
2. On the Main menu, click Manage →Function Libraries →Add.
3. Fill in the Function Library Name, provide a brief Description (optional) and write the Function Library Script for the function library. Then click Register.
4. If the script doesn’t have any compilation errors, it will be sucessfully registerd.
.js
extension is added to the name you specified. You need to use that .js
extension when importing a function library. (Can see later)There are three main methods:
Option 01: Add individual functions and export all individually. (Even though some functions are only invoked inside the same function library, those functions should be exported. Further, use
this.<function>
as similar to this.convertIpToLong
usage inside isCorporateIP
function).// Function to convert ip address string to long value
var convertIpToLong = function(ip) {
var components = ip.split('.');
if (components) {
var ipAddr = 0, pow = 1;
for (var i = 3; i >= 0; i -= 1) {
ipAddr += pow * parseInt(components[i]);
pow *= 256;
}
return ipAddr;
} else {
return -1;
}
};
// Function to check if the ip address is within the given subnet
var isCorporateIP = function(ip, subnets) {
var subnetLength = subnets.length;
for (var i = 0; i < subnetLength; i++) {
var subnetComponents = subnets[i].split('/');
var minHost = this.convertIpToLong(subnetComponents[0]);
var ipAddr = this.convertIpToLong(ip);
var mask = subnetComponents[1];
if (subnetComponents && minHost >= 0) {
var numHosts = Math.pow(2, 32 - parseInt(mask));
if ((ipAddr >= minHost) && (ipAddr <= minHost + numHosts - 1)) {
return true;
}
}
}
return false;
};
module.exports.convertIpToLong = convertIpToLong;
module.exports.isCorporateIP = isCorporateIP;
Option 02: Create a a module which contains multiple functions and export the whole module itself.
var networkUtils = {
// Function to convert ip address string to long value
convertIpToLong : function(ip) {
var components = ip.split('.');
if (components) {
var ipAddr = 0, pow = 1;
for (var i = 3; i >= 0; i -= 1) {
ipAddr += pow * parseInt(components[i]);
pow *= 256;
}
return ipAddr;
} else {
return -1;
}
},
// Function to check if the ip address is within the given subnet
isCorporateIP : function(ip, subnets) {
var subnetLength = subnets.length;
for (var i = 0; i < subnetLength; i++) {
var subnetComponents = subnets[i].split('/');
var minHost = this.convertIpToLong(subnetComponents[0]);
var ipAddr = this.convertIpToLong(ip);
var mask = subnetComponents[1];
if (subnetComponents && minHost >= 0) {
var numHosts = Math.pow(2, 32 - parseInt(mask));
if ((ipAddr >= minHost) && (ipAddr <= minHost + numHosts - 1)) {
return true;
}
}
}
return false;
}
};
module.exports = networkUtils;
Option 03: Define a module and add each function separately. Finally export the module.
var networkUtils = { };
// Function to convert ip address string to long value
networkUtils.convertIpToLong = function(ip) {
var components = ip.split('.');
if (components) {
var ipAddr = 0, pow = 1;
for (var i = 3; i >= 0; i -= 1) {
ipAddr += pow * parseInt(components[i]);
pow *= 256;
}
return ipAddr;
} else {
return -1;
}
};
// Function to check if the ip address is within the given subnet
networkUtils.isCorporateIP = function(ip, subnets) {
var subnetLength = subnets.length;
for (var i = 0; i < subnetLength; i++) {
var subnetComponents = subnets[i].split('/');
var minHost = this.convertIpToLong(subnetComponents[0]);
var ipAddr = this.convertIpToLong(ip);
var mask = subnetComponents[1];
if (subnetComponents && minHost >= 0) {
var numHosts = Math.pow(2, 32 - parseInt(mask));
if ((ipAddr >= minHost) && (ipAddr <= minHost + numHosts - 1)) {
return true;
}
}
}
return false;
};
module.exports = networkUtils;
What’s Next !!
Now you have a well prepared function library. It’s time to get use of it.
1. Follow all steps in this document to configure a service provider for adaptive authentication.
2. Instead of original IP-Based template, copy paste the following as the adaptive authentication script and try out the sample scenario.
var networkUtilsModule = require('networkUtils.js');
// IP-Based from Template...
// This script will step up authentication for any user who are trying to log in outside from the configured network
// Configure the network ranges here
var corpNetwork = ['192.168.1.0/24', '10.100.0.0/16'];
var onLoginRequest = function(context) {
executeStep(1, {
onSuccess: function (context) {
var user = context.currentKnownSubject;
// Extracting the origin IP of the request
var loginIp = context.request.ip;
Log.info('User: ' + user.username + ' logged in from IP: ' + loginIp);
// Checking if the IP is within the allowed range
if (!networkUtilsModule.isCorporateIP(loginIp, corpNetwork)) {
executeStep(2);
}
}
});
};
// End of IP-Based.......
To import a function library,
var <module_name> = require('<function library name>');
Eg:
var networkUtilsModule = require(‘networkUtils.js’);
on top of the script/ before the usage of functions in the function library.E.g:
networkUtilsModule.isCorporateIP(loginIp, corpNetwork)
3. Similarly you can import multiple function libraries into one adaptive authentication script and use them.
When you compare the above script (which uses the imported library) and the original IP-Based template, you will agree with the “advantages of function library usage” which I pointed earlier.
Nothing difficult right?? Try out this and enjoy your life !!
NOTE: Please read on the instructions to import function libraries to the adaptive authentication scripts.
Limitation:
require()
functionality is not supported inside function libraries. (i.e You won’t be able to import one function library into another function library)Grab more knowledge:
Previously published at https://medium.com/@anuradha.15/try-out-adaptive-authentication-with-function-libraries-in-wso2-is-35147aea14e7