Implementing the challenge handler in Ionic applications
Overview
When trying to access a protected resource, the server (the security check) sends to the client a list containing one or more challenges for the client to handle.
This list is received as a JSON object
, listing the security check name with an optional JSON
containing additional data:
{
"challenges": {
"SomeSecurityCheck1":null,
"SomeSecurityCheck2":{
"some property": "some value"
}
}
}
The client is then expected to register a challenge handler for each security check.
The challenge handler defines the client-side behaviour that is specific to the security check.
Creating the challenge handler
A challenge handler handles challenges sent by the PMF, such as displaying a login screen, collecting credentials, and submitting them back to the security check.
In this example, the security check is PinCodeAttempts
which was defined in Implementing the CredentialsValidationSecurityCheck. The challenge sent by this security check contains the number of remaining attempts to log in (remainingAttempts
) and an optional errorMsg
.
Use the WL.Client.createSecurityCheckChallengeHandler()
API method to create and register a challenge Handler:
PincodeChallengeHandler = WL.Client.createSecurityCheckChallengeHandler("PinCodeAttempts");
Handling the challenge
The minimum requirement from the createSecurityCheckChallengeHandler
protocol is to implement the handleChallenge()
method, which is responsible for asking the user to provide the credentials. The handleChallenge
method receives the challenge as a JSON
Object.
In this example, an alert prompts the user to enter the PIN code:
registerChallengeHandler() {
this.PincodeChallengeHandler = WL.Client.createSecurityCheckChallengeHandler("PinCodeAttempts");
this.PincodeChallengeHandler.handleChallenge = ((challenge: any) => {
console.log('--> PincodeChallengeHandler.handleChallenge called');
this.displayLoginChallenge(challenge);
});
}
displayLoginChallenge(response) {
if (response.errorMsg) {
var msg = response.errorMsg + ' <br> Remaining attempts: ' + response.remainingAttempts;
console.log('--> displayLoginChallenge ERROR: ' + msg);
}
let prompt = this.alertCtrl.create({
title: 'PMF Gateway',
message: msg,
inputs: [
{
name: 'pin',
placeholder: 'please enter the pincode',
type: 'password'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: () => {
console.log('PincodeChallengeHandler: Cancel clicked');
this.PincodeChallengeHandler.Cancel();
prompt.dismiss();
return false
}
},
{
text: 'Ok',
handler: data => {
console.log('PincodeChallengeHandler', data.username);
this.PincodeChallengeHandler.submitChallengeAnswer(data);
}
}
]
});
prompt.present();
}
If the credentials are incorrect, you can expect the framework to call handleChallenge
again.
Submitting the challenge’s answer
After the credentials have been collected from the UI, use createSecurityCheckChallengeHandler
’s submitChallengeAnswer()
to send an answer back to the security check. In this example, PinCodeAttempts
expects a property called pin
containing the submitted PIN code:
PincodeChallengeHandler.submitChallengeAnswer(data);
Cancelling the challenge
In some cases, such as clicking a Cancel button in the UI, you want to tell the framework to discard this challenge completely.
To achieve this, call:
PincodeChallengeHandler.cancel();
Handling failures
Some scenarios might trigger a failure (such as maximum attempts reached). To handle these, implement createSecurityCheckChallengeHandler
’s handleFailure()
.
The structure of the JSON object passed as a parameter greatly depends on the nature of the failure.
PinCodeChallengeHandler.handleFailure = function(error) {
WL.Logger.debug("Challenge Handler Failure!");
if(error.failure && error.failure == "account blocked") {
alert("No Remaining Attempts!");
} else {
alert("Error! " + JSON.stringify(error));
}
};
Handling successes
In general, successes are automatically processed by the framework to allow the rest of the application to continue.
Optionally, you can also choose to do something before the framework closes the challenge handler flow, by implementing createSecurityCheckChallengeHandler
’s handleSuccess()
. Here again, the content and structure of the success
JSON object depends on what the security check sends.
In the PinCodeAttemptsIonic
sample application, the success does not contain any additional data.
Registering the challenge handler
For the challenge handler to listen for the right challenges, you must tell the framework to associate the challenge handler with a specific security check name.
To do so, create the challenge handler with the security check as follows:
someChallengeHandler = WL.Client.createSecurityCheckChallengeHandler("the-securityCheck-name");
Sample applications
The PinCodeIonic project uses WLResourceRequest
to get a bank balance.
The method is protected by a PIN code, with a maximum of 3 attempts.
Click to download the Ionic project.
Click to download the SecurityAdapters Maven project.
Sample usage
Follow the sample’s README.md file for instructions.
▲