Adaptive Authentication Implementation in WSO2 Identity Server
Adaptive Authentication and WSO2 Identity Server
Do you remember whenever you try to login to your Google account from a new device, you have to authenticate yourself again with an SMS OTP just after entering your login credentials ? This is a simple scenario of adaptive authentication.
Adaptive Authentication enables service providers to authenticate users with enough security while also considering their user experience. It is a way of varying the number of authentication steps before granting access to a resource based on the context at hand.
Adaptive Authentication and WSO2 Identity Server
As WSO2 Identity Server aims helps organizations to build agile, extensible CIAM solutions to bring in better and seamless user experiences for their customers, it provides a way for the organizations to build their own adaptive authentication implementation with WSO2 Identity server.
The WSO2 IS management console provides an authentication script editor that allows you to define authentication scripts using JavaScript . The script editor provides a set of predefined templates that you can use to easily set up adaptive authentication for some of the most common authentication scenarios. Additionally you can add your your JavaScript functions to the Functions Library and make use of them in the Authentication Script.
Implementation in Identity Server
WSO2 Identity Server Uses a graph based authentication mechanism to implement adaptive authentication. Phases related to the authentication flow are handled by different nodes of the authentication graph. As the authentication flow continues, depending on the precious outcome, appropriate nodes are added to the Dynamic Authentication Graph.
The Dynamic Authentication Graph can contain the following types of Graph Nodes,
- ShowPromtNode- Show prompt to user
- LongWaitNode-
- StepConfigGraphNode- Handles an authentication step
- DynamicDecisionNode- Handles the callback of an authentication step
- EndStep- Completes the authentication flow
- FailNode- Handles the errors in authentication flow
When an authentication flow starts for the first time, The user defined authentication script is evaluated by a Script Engine in the server and then a specific mandatory function called onLoginRequest
will be invoked. The contents of this function will be responsible for creation of the Authentication graph and the authentication flow will continue. Let’s understand how this works with an Example Scenario
Authentication Flow with Role Based Adaptive Authentication Scenario
The following is the Role based Adaptive Authentication Script Provided in WSO2 Identity Server.
// Role-Based from Template...// This script will step up authentication for any user belonging
// to one of the given roles
// If the user has any of the below roles, authentication will be stepped up
var rolesToStepUp = ['admin', 'manager'];var onLoginRequest = function(context) {
executeStep(1, {
onSuccess: function (context) {
// Extracting authenticated subject from the first step
var user = context.currentKnownSubject;
// Checking if the user is assigned to one of the given roles
var hasRole = hasAnyOfTheRoles(user, rolesToStepUp);
if (hasRole) {
Log.info(user.username + ' Has one of Roles: ' + rolesToStepUp.toString());
executeStep(2);
}
}
});
};// End of Role-Based.......
The script basically says if the user attempting to login has the role of admin
or manager
, after the first authentication step (the authentication steps are defined separate from the authentication script, and you can see the stepId is mentioned in the script) is completed successfully, they will have to go through an additional authentication step.
As mentioned earlier, the script will be evaluated and the mandatory onLoginRequest
will be invoked. This specific onLoginRequest
contains,
executestep
withstepId
of 1 (the first authentication step usually is traditional username&password authentication)callbackfunction
which should be executed after a successful first step authentication (theonSuccess
function).
Additionally, the onLoginRequest
can contain onFail,onFallback,onUserAbort
callbackfunctions which will be executed in the event of authentication failure and other applicable scenarios. Further, additional options to handle filter authenticators and service providers can also be included.
Let’s get into the flow
When the code initially gets executed, a graph is created an array rolesToStepUp
is created to keep keep track of which users with which roles should go through second authentication. The the above defined onLoginRequest
will be executed. It will create the first node of the authentication graph namely StepConfigGraphNode
with stepId:1
. The current node will be set to this node.
Consequently the event listeners will be added to the graph via Dynamic Decision Node. In this case only onSuccess
will be the event listener. So aDynamicDecisionNode
will be created and added to the StepGraphConfigNode
and it will contain the Java Script function of onSuccess
in the function map.
Now without more JavaScript code to execute, the current node will be handled, which is StepConfigGraphNode
. This will handle the authentication step associated with stepId:1
. Depending of the outcome of the authentication step a new node will be added or the currently available next node will be handled.
Let’s assume that the authentication completes successfully. this outcome will enable the DynamicDesionNode
to be handled with the onSuccess
function. The specific JavaScript function will be executed. As in the code, the user will be extracted from the authentication context and will checked if the user has one of the roles in rolesToStepUp
. If the user doesn’t have one of those roles the authentication will be completed.
When the user has one of the roles, authentication step with stepId:2
will have to be executed. Let’s assume that the user is an Admin and he has successfully completed first authentication step. Now, a new StepConfigGraphNode
will be added to the authentication graph and will be set as current node. Since there are no event listeners, No DynamicDecisionNode
will be added.
This will enable the next current node to be handled which is a step config node. The user will be prompted to the next authentication step. After the user completes the step, The outcome will be either success or failure. Depending on the outcome, a new node will be added to the authentication graph, since there were no event listeners. Let’s say the user successfully completes the second authentication step. A new endStep
node will be added to the authentication graph.
Finally, the current node will be set to endStep
which will complete the authentication flow and user will be logged in to the service. This flow only explains what happens when a user with admin role successfully logs in without retrying. As you can see the authentication graph is built as the authentication flow progresses. In the event of a different flow, the graph will be built differently. For example, if the user had failed the second authentication step here, the endStep
would have been replaced by failNode
or stepCofigGraphNode
depending on whether retrying is allowed.
Summary
Adaptive authentication can be used to dynamically change the authentication flow depending on the context at hand. It can be used to authenticate users with enough security while also considering their user experience. WSO2 identity server implements adaptive authentication with dynamic authentication graph. The graph is built while the authentication flow progresses as specified in the JavaScript based authentication script.
References
[1] WSO2 Identity Server: Adaptive Authentication : https://is.docs.wso2.com/en/latest/learn/adaptive-authentication/
[2] WSO2 carbon-identity-framework https://github.com/wso2/carbon-identity-framework