Creating a Password Field with a Validating Password Control in NetIQ IDM Forms

0 Likes
over 6 years ago
I recently implemented the cool solution, “Setting a password in workflow” (https://www.netiq.com/communities/cool-solutions/setting-password-workflow/) for one of my clients. This allows us to set userPassword within a workflow.

But the source of the password data might often be a form. A common configuration is that when using a password field, you have the ability to provide a “new password” and “confirm password” field. It would seem intuitive that this could be done using two password fields in a PRD form. But it cannot.

The reason is called out in the documentation (https://www.netiq.com/documentation/idm45/dgpro/data/prdefformcontrolreference.html#prdefpassword : “The password control can only be submitted. It does not support any script such as getValues() or setValues().” So there is no way, in real time, to confirm a password was entered correctly.

Now you could send two password fields into the workflow and if they don't match, reject it, and maybe send it back to the user to do over, but that's not particularly user friendly. This cool solution will describe how to implement a confirmed password control within a workflow form that can be validated in real time..

The Challenge of Using an HTML control in your form


 
Also intuitive is to embed your own HTML within a form field. This is in fact the way we will solve this problem, but to get there, important details must be dealt with.

  • First, you have to get the data out of your arbitrary HTML and into a field that the form can then map to the workflow.

  • Additionally, you have to prevent the browser from offering to save your password. The “autocomplete=off” feature support is spotty across different browser versions


This overcomes these challenges and will allow you to create a validating password control in your forms.

Components


 
The solution involves the following components:

  • A List object containing the labels to be displayed on the fields as well as the names of the fields

  • Global Variables (defined form-wide)

  • An HTML field

  • A script function to create the fields

  • A hidden text field to hold the results



Strictly speaking, the list object could have been hard coded into the script function but I decided to make this a bit easier to localize.

Creating the basic fields


 
Create two fields in your PRD: One HTML field (here named “Test”) and a second field named “Password”.

Create a global list named “Passwords” similar to this:


Add the following code to an inline script on the PRD:

function mask(value,maskchar)
{
var result = "";
for (var i=0; i < value.length; i )
{
result = maskchar;
}
return result;
}
function table(IDVault,form,field,eventName,defaultValue,fieldType) // creates the new password / confirm password table
{
var R = "<table style=\"display: inline; width:200px;\" class=\"nv-fontExtraSmall\" >";
var Apps = IDVault.globalList(null, "Passwords")
var ctrl = JUICE.UICtrlUtil.getControl(field.getName());
for (var i=0; i < Apps[0].length; i )
{
R = R "<tr class=\"nv-formFieldLabel \">";
R = R "<td style=\" width: 60px\">" Apps[1][i] "</td>" ;
var ID = ""
ID = Apps[0][i];
R = R "<td style=\"width:140px\">";
R = R "<input id=\"" Apps[0][i] "\" "
//get instance of control
switch (fieldType)
{
case "password":
case "input":
{
R = R " onchange=\"var evtData = this.id '#' this.value; var ctrl = JUICE.UICtrlUtil.getControl('" field.getName() "'); var vals = ctrl.getValues(); var evt = new JUICE.WFASEvent('" field.getName() "', '" eventName "', vals, null, evtData); var evt_array = new Array(evt); dojo.publish('WFAS_" eventName "', evt_array);\" ";
R = R " value=\"" defaultValue "\" ";
R = R " type=\"" fieldType "\" autocomplete=\"off\" class=\"nv-fontExtraSmall\" name=\"TB ";
R = R Apps[0][i] "\"/>";
break;
}
case "fake":
{
R = R " value=\"" mask(defaultValue,"*") "\" ";
R = R " type=\"input\" autocomplete=\"off\" class=\"nv-fontExtraSmall\" name=\"TB ";
R = R Apps[0][i] "\"/>";
break;
}
}
R = R "</td></tr>";
}
R = R "</table>";
return R;
}


In the “Events” tab, open the form's onload event.


and add the following code:

newPassword="newPassword"confirmPassword="confirmPassword"


On the field named Test, under the Property “HTML Content”, insert the following code:

table(IDVault,form,field,"PWDChanged","","password")


On the field named “Password”, under “Properties”, set Visible to “false”, then go to “Events” and create an event handler for an event named “PWDChanged”.


In the event's Action Expression, include the following code:

var eventData=event.getCustomData();var eventArray = eventData.split("#")

switch (eventArray[0])

{

case "nnnnnnnn":

{

newPassword = eventArray[1];

if ((confirmPassword!="confirmPassword") && (confirmPassword !=newPassword))

{

form.showError("Passwords do not match")

field.setValues("")

}

else

{

if (confirmPassword==newPassword)

{

field.setValues(eventArray[1])

form.clearMessages();

}

}

break;

}

case "cccccccc":

{

confirmPassword = eventArray[1];

if ((newPassword!="newPassword") && (confirmPassword !=newPassword))

{

form.showError("Passwords do not match")

field.setValues("")

}

else

{

if (confirmPassword==newPassword)

{

field.setValues(eventArray[1])

form.clearMessages();

}

}

break;

}

}


At this point, you should have a functional set of controls which will provide you with your new password / confirm password functionality.

How it works


 
The HTML code created by the function “Table” contains two columns, labels and input controls. The “onchange” event of these controls sends an “custom event” named “PWDChange” (or whatever you wish to name it when you invoke the function). The custom data within the event is in the format “FieldLabel#value”. The Password field is listening for these events, and storing the results in global form variables named newPassword and confirmPassword. When both values are the same, the value is set in the field Password. If two different values are added, an error message is displayed that the values are not the same (this is cleared when you correct the fields to be the same).

Suppressing Autocomplete


 
This would be the end of the story except that when I tried to deploy this, despite the fact that the PRD was not for self service, it would ask me whether I wanted to save my password. I tried putting the attribute autocomplete=“off” on the input tags, and using jQuery to put it on the form tag, but neither was effective.

The solution I came up with for this was simple: At the time you click “submit”, wipe away the password controls. Since those controls don't get used to actually submit to the workflow, their content is immaterial. What I did was to implement a method to create a “fake” set of password controls which replace the real ones immediately before the submit. To implement this:

On the “Test” control, add an onload event. The action expression for this event will be as follows:

ACTION_SUBMIT = "SubmitAction";form.interceptAction( ACTION_SUBMIT, "before",

function ( invocation )

{

field.setValues(table(IDVault,form,field,"oblivion",form.getValue("Password"),"fake"))

return invocation;

}

);

field.hide()

 

This will intercept the submit and set the value of the Test field to the fake password fields.

Conclusion


 
If I put back on my product manager hat for a moment, an ideal enhancement for IDM that would eliminate the need for this would be to add a “confirmation required” property to the password field type, if you set it to true it would display two password fields and require that they are both set the same. I have filed that as an enhancement request.

But for now, this can provide the necessary functionality to allow you to provide help desk personnel, or even users themselves with the mechanism to set a password, and confirm the value within a workflow form.

Labels:

How To-Best Practice
Comment List
Anonymous
Related Discussions
Recommended