Password Change Form
Last month I was lamenting the fact that Domino's change password form couldn't meet my requirements. I've since done some digging around and come up with my own fully-functional change password form.
Following some investigation I fond that the special Domino password change form simply creates an Adminp request document. I also found that you can create the same kind of document using a new Domino 6 LotusScript method called ChangeHTTPPassword(). Hence, we can use our own form and have the WebQuerySave agent call this method after it's done all the other checks - such as password quality.
My form is very similar to Domino's in that it has three fields on it, called Password, PasswordNew and PasswordConfirm. The WQS code uses these values to decide whether to create a Adminp request or raise an error. The code makes use of some other new Domino 6 functions, such as VerifyPassword() to make sure the old one is correct and the new Like operator to make sure the new one is in the right format.
The full code is in this file, but the important parts are listed here, in order:
First, get the current user's (they must be logged in to do this) person document:
Set UserDoc = UserView.GetDocumentByKey(sUserName, True)
Make sure that the old password they entered matches the one stored:
If session.VerifyPassword(ThisDoc.Password(0), UserDoc.HTTPPassword(0)) Then
Make sure the new one they entered matches with the confirm field:
If ThisDoc.PasswordNew(0) <> ThisDoc.PasswordConfirm(0) Then
Make sure the password is at least 6 characters long:
If Len(ThisDoc.PasswordNew(0)) < 6 Then
Make sure it contains letters and numbers:
If ThisDoc.PasswordNew(0) Like "*[A-z]*" And ThisDoc.PasswordNew(0) Like "*#*" Then
If all the above conditions are passed then submit the Adminp request:
Call Adminp.ChangeHTTPPassword( UserName.Canonical , ThisDoc.Password(0) , ThisDoc.PasswordNew(0) )
At this point, the changed password should take affect immediately. In my testing I've found that this is the case. So, there you have it - a change password form that does exactly the same as Domino's as well as doing the other stuff you want it to.
Hey Jake, a long time ago since I'm not using one of your "hacks", and in this moment I'm doing some development that needed custom password reset.
Thanks again pal.
.::AleX::.
Jake,
Be carefull with NotesDatabase.FilePath, it returns backslashes for subdirectories and not slashes. I use Evaluate("@webdbname") for such operations.
(oh, and i didn't knew there were natively kind of regexp in Lotusscript ! that's great)
YoGi. The server seems to translate the slashes properly before returning to the browser. Seems to work ok to me.
The Like operator isn't exactly regular expressions as we know them. More tomorrow.
Jake. The server does not translate anything. It returns the %5C symbol, which stands for backslash. That's your browser which translate the backslash into slash. But it does not work with all browsers (i've just tested IE, Firefox and Opera and it's OK, but Lynx returns a 404 error).
YoGi. Makes sense I suppose. Thanks for setting me right. I'll make sure I don't use that again. I'll probably use Replace("\","/") rather than an Evaluate() though.
Hi,
just tried to check the code in a test-database. The idea is great, but in my case i got severals Datarecords for the web-username (tester). So the agent runs on a "database" document instead of the person-document.
Greetings from Berlin
Maiko
Maiko. I am not sure what you mean. Does this line "GetDocumentByKey(sUserName, True)" return more than one match? Is that the problem you had?
Jake. Yes thats the problem, there are several documents returning for the username. $User contains not just users, it contains databases, users, groups etc.
So this could be a problem if a database (mail-in-db) is called like the username.
Thanks Maiko. I'd not considered that and will now go and recode using a better view for the job.
Jake. I think the view called "People" should do the job.
The view called ($VIMPeople) seems like a better choice maiko. The lookup then needs to be on the abbreviated user's name though.
I'm not sure how this would stand up in a multi-address book environment like mine. I have 8 address books that need hiking through. I may use a hidden field which tells the system which address book to go and use.
Nice work.
Dragon, in your Directory Assistance db are you using replica database links, or file path information for each directory? We switched ours to filepath setup so that we can programmatically access the multiple address books.
oops
BTW: Awesome work Jake!!
I've used the $VIMPeople view in a custom application HTTP password management DB I wrote for quite some time...(unfortuantely, cannot share publicly).
If it's just the change password feature that you're looking for, I would almost suggest modifying the person document on the fly to make it truly instant, instead of submitting an AdminP request. This would entail signing the WQS agent to run on behalf of an Administrative user, and using the result = Evaluate("@HashPassword(""" + strPassword + """)" if you're using more secure passwords(names.nsf -> edit directory profile) or replace @HashPassword with @Password if not. AdminP may not be as instantaenous in a larger organization, however, would manage the policies you have set forth with ease, vs. coding something else to ensure that the policies are enforced (i.e. password age).
Matt. I've found that changing the person doc directly is anything but instant. The adminp request may not always be instant, but mosly is. At least with the adminp you can blame Lotus and have your customer complain to them instead ;o)
Rebuilding the view index for $users programmatically makes the password change instant on the person doc without needing to submit an adminP req.
Also helps for new user registration.
Does not seem to take much time even for large nabs.
Jake,
what do you mean the new "like" operator? It's been there since Notes 4 - and I love it!
Really Andrew?! Hmm, just new to me then I guess.
AdminP is definitely the faster choice, and you can hurry it along in a multiserver environment by issuing a console command through LotusScript in the later versions as well. (Obviously needs to run with adequate permissions.)
Never really sat down and thought about this...
If you want to notify the user after a _successful_ password change, then it's almost easier to simply do everything programmatically and refresh the $Users view for instant effect, but then you have to incorporate policy management in to this code.
If you were to use the ChangeHTTPPassword method, you'd then have to submit the console command of 'tell adminp process new', and then actively monitor the Note ID that the method returns, until it shows completed, and the notify the user. I guess the big plus here at least IMO would be that it incorporates the use of the policies inheritly.
..and while I'm thinking outloud here, I really wish that I could find a way for Domino, when using the ?ChangePassword URL syntax to be pointed to it's own custom database, instead of requiring the use of a form stored in DOMCFG.NSF.
The default password change form works fine, especially in a multiserver, global environment. I prefer the adminP process because of its stability and transaction logging. With only 3 fields on this form, IMO it really doesn't warrant building something from scratch. I built the UI in Websphere Studio, then just transferred it over to the form as pass-thru, while using the fields provided on the default form. It looks great, is stable, and works fine...the new password is instantly valid.
Hi everyone,
We used a customized form in Domcfg for the password change and it worked. But I saw those Domino 6 LotusScript methods and tought that we could try to make our own form (with all the flexibility). We did it and it worked ... sort of.
The request is sent to the adminp and is treated. But after 5 or 6 minutes, Domino is asking the users to log on again?! If we are using the Domcfg form, the same request is sent to the adminp but Domino is not asking the user to log on another time.
My question is this : 'What is the difference between the two methods?'
It seems like Domino knows when you changed your password with Domcfg and do not need to validate the session.
Thanx for your comments. For now, we had to use our customized Domcfg form because our users do not like to be bothered by Domino.
Nota bene : Sorry for my english!
Emmanuel
I have the same problem as Emmanuel. I have tried 3 different methods to change passwords.
The problem may be related to the fact that my site uses directory assistance with a second domino directory for the usernames for this particular website.
Method 1:
Change the users person doc and update the ($Users) view in both the main and secondary Domino Directories. It takes 5-10 minutes for the change to happen. If your logged in still, you get logged out at this moment, ie the old password is not cached.
Method 2:
Use a custom form for ?ChangePassword. This changes the password instantly. And both passwords work for however long you have set in the notes.ini variable for HTTP_PWD_Change_Cache_Hours. But you have no ability to run your own webquerysave agent. It gets completely ignored. So you can't send an email to the user for example.
Method 3:
Use the LS code Call adminp.ChangeHTTPPassword(doc.FullName(0), doc.OldPassword(0), doc.NewPassword(0)) to createan AdminP request. You can see the request go in instantly. But it still takes 5-10 minutes for it to get processed. When it does get processed the old password is not cached, so you get logged out if you were still logged in.
So method 2 (custom ?changepassword form) is your best bet for instant sucess, but don't expect to be able to do any WQS agents.
This is pretty poor by Lotus IMO.
Cheers
Craig
Hi Jake,
Great article and user like me get good understanding on the password management behind the screen.
Can you please rollout this as an Notes template file? Hope this is not too much of asking.
Thank you
Sam Kown
Hi Jake,
It's great article. But we have run into one issue here. All our passwords were run by upgrade to more secure internet password agent which salted all the passwords. When I used VerifyPassword(), it did not find them match. How can we get around that?
Thank you very much in advance and thanks for create a good article.
Pat K.
Good stuff, and I know this is a few years late. I also wanted to check whether the user was recycling the old password as the new one so I used this test as well:
If session.VerifyPassword(ThisDoc.PasswordNew(0), UserDoc.HTTPPassword(0)) Then
If that returns 'True' then they haven't changed their password.