Thursday, November 17, 2005

Allowing someone to update their own Active Directory Contact details via OWA

Modifying your own user details via GALMOD or one of it derivates has been around for sometime. I wrote this little app a few years ago at the bequest of a secretary to allow users with non admin rights to modify other people’s details using a WSC Com object. A question came up last week about being able to do this in OWA via a public folder for those users that might be outside your network that may only have access to OWA though a front backend setup etc. Exchange does give you the ability in OWA to register and run your own custom forms (do a search on WSS.forms in the Exchange SDK for more details). So one way of achieving what this person asked to do was to register a custom ASP WSS form and include some ADSI to do the work of modifying the user’s account and phone details. If you’re not running Exchange on a Domain controller (which should be the case for most people bar SBS users) you have to consider delegation issues when your page is going to request the changes be made on behalf of the user. A couple a ways to work around this is to specify alternate credentials in your code to make the changes with. Or use a COM+ wrapper and a com object (or a WSC com object like I did here). Security wise it’s usually better to use a COM+ wrapper to store your username and password instead of storing it as clear text in the asp file if your going to be storing your asp file in the Exchange store where someone may be able to get easy access to the source. I decided to put together a real simple example of a WSS.From that could be used to change a user’s phone number detail’s using ADSI and some hard coded credentials.

The code itself is pretty simple installing it and getting it to work can be a little challenging for the uninitiated. I’ve used the method that is prescribed in the Exchange SDK which involves a few steps.

Before you start you need to make sure that you enable scripts for ASP pages on the Exchange server or you will receive a 403 permissions error when you try and view the folder. To enabled scripts you use Exchange System Manager go to Servers-Protocols-HTTP-Exchange Virtual Directory. Select the Public virtual directory and then right click and select properties. Go to the access table under execute permission select scripts then save and exit.

Hard coded script bits the following script has 2 hardcoded bits you need to change to use it the first is the servername of a Domain controller where the changes are going to be made. The second is the username and password of a user with rights to make changes to the properties that you are modifying. Both these setting are in the following line

Set oUser = Dirobj.OpenDSObject("LDAP://servername/"& sysinfo.UserName, "domain\user", "password", 0)

Installation I’ve created a script call forminst.vbs and included it in the download of this post that performs the following steps for you it will prompt you for the name of the root folder to create and it will also upload the asp page from d:\ into the public folder

The first step is to create the folder you want the form to be registered on.
The next step is to create a hidden folder that will contain the form registration and the ASP page itself.
The next step is to set the urn:schemas-microsoft-com:exch-data:schema-collection-ref property on the parent folder to point to the folder that was created in step two.
The next step is to create the default form registration on the child folder that will tell exchange to display the ASP page for any requests made for the parent folder in OWA.
The last step is then to upload the asp page to the child folder.

That’s it if you receive a 403 error when you try and view the folder in OWA make sure you have set scripting rights in Exchange System Manager (the rights should also be reflected in IIS admin). From a security point of view you should consider building a com object and using a COM+ wrapper if you where going to use this in production.

I’ve put a downloadable copy of the code from this post here the Form itself looks like

Set oForm = Server.CreateObject("WSS.Form")
dim sysinfo
dim oUser
Set sysinfo = CreateObject("ADSystemInfo")
set Dirobj = GetObject("LDAP:")
Set oUser = Dirobj.OpenDSObject("LDAP://DCservername/"& sysinfo.UserName,
"domain\user", "password", 0)
If Request.ServerVariables("REQUEST_METHOD") = "GET" Then
oForm.fields("FName").value = oUser.GivenName
oForm.fields("LName").value =
oForm.fields("Bphone").value = oUser.TelephoneNumber
oForm.fields("Mphone").value =
oForm.fields("Hphone").value = oUser.homephone
If Request.ServerVariables("REQUEST_METHOD") = "POST" Then
if oForm.Fields("FName").Value = "" then
oForm.Elements("FName").ErrorString = "<span style=""COLOR:red"">First Name
elseif oForm.Fields("LName").Value = "" then
oForm.Elements("LName").ErrorString = "<span style=""COLOR:red"">Last Name
oUser.GivenName = oForm.Fields("FName").Value = oForm.Fields("LName").Value
oUser.TelephoneNumber = oForm.Fields("BPhone").Value
if oForm.Fields("BPhone").Value = "" then
oUser.putex 1,"TelephoneNumber", vbNull
oUser.TelephoneNumber = oForm.Fields("BPhone").Value
end if
if oForm.Fields("MPhone").Value = "" then
oUser.putex 1,"mobile", vbNull
else = oForm.Fields("MPhone").Value
end if
if oForm.Fields("HPhone").Value = "" then
oUser.putex 1,"homephone", vbNull
oUser.homephone = oForm.Fields("HPhone").Value
end if
oForm.Elements("Result").ErrorString = "<span style=""COLOR:red"">Updated<span>"

end if
end if
end if

<BASE TARGET="_top">


<BODY><!The Data URL macro is expanded at runtime by
the renderer so that the Submit
button will post back to the item itself.>
<FORM action="" id=FORM1 method=post name="FORM1"

<H1> Phone Number Details
<INPUT class="field" name="result"
style="HEIGHT: 25px; WIDTH: 0px"></H1>

<b>First Name:</b> <INPUT class="field" name="FName"
style="HEIGHT: 25px; WIDTH: 200px"> <br><br>
<b>Last Name:</b> <INPUT class="field" name="LName"
style="HEIGHT: 25px; WIDTH: 200px"> <br><br>
<b>Business PhoneNumber:</b> <INPUT class="field"
name="Bphone" style="HEIGHT: 23px; WIDTH: 200px">
<b>Mobile PhoneNumber:</b><INPUT class="field"
name="Mphone" style="HEIGHT: 23px; WIDTH: 200px">
<b>Home Phone:</b> <INPUT class="field" name="Hphone"
style="HEIGHT: 25px; WIDTH: 200px"> <br>
&nbsp;<INPUT id=submit1 name=submit1 type=submit