Skip to main content

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 = oUser.sn
oForm.fields("Bphone").value = oUser.TelephoneNumber
oForm.fields("Mphone").value = oUser.mobile
oForm.fields("Hphone").value = oUser.homephone
oForm.fields.update
oForm.Render
else
If Request.ServerVariables("REQUEST_METHOD") = "POST" Then
if oForm.Fields("FName").Value = "" then
oForm.Elements("FName").ErrorString = "<span style=""COLOR:red"">First Name
Required<span>"
oForm.Render
elseif oForm.Fields("LName").Value = "" then
oForm.Elements("LName").ErrorString = "<span style=""COLOR:red"">Last Name
Required<span>"
oForm.Render
else
oUser.GivenName = oForm.Fields("FName").Value
oUser.sn = oForm.Fields("LName").Value
oUser.TelephoneNumber = oForm.Fields("BPhone").Value
if oForm.Fields("BPhone").Value = "" then
oUser.putex 1,"TelephoneNumber", vbNull
else
oUser.TelephoneNumber = oForm.Fields("BPhone").Value
end if
if oForm.Fields("MPhone").Value = "" then
oUser.putex 1,"mobile", vbNull
else
oUser.mobile = oForm.Fields("MPhone").Value
end if
if oForm.Fields("HPhone").Value = "" then
oUser.putex 1,"homephone", vbNull
else
oUser.homephone = oForm.Fields("HPhone").Value
end if
oUser.setinfo
oForm.Elements("Result").ErrorString = "<span style=""COLOR:red"">Updated<span>"

oForm.Render
end if
else
end if
end if
%>

<HTML>
<HEAD>
<BASE TARGET="_top">

</HEAD>

<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"
target="_self">

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

<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">
<br><br>
<b>Mobile PhoneNumber:</b><INPUT class="field"
name="Mphone" style="HEIGHT: 23px; WIDTH: 200px">
<br><br>
<b>Home Phone:</b> <INPUT class="field" name="Hphone"
style="HEIGHT: 25px; WIDTH: 200px"> <br>
<br><br>
&nbsp;<INPUT id=submit1 name=submit1 type=submit
value=Submit>

</FORM>

</BODY>
</HTML>
 

Popular posts from this blog

Testing and Sending email via SMTP using Opportunistic TLS and oAuth in Office365 with PowerShell

As well as EWS and Remote PowerShell (RPS) other mail protocols POP3, IMAP and SMTP have had OAuth authentication enabled in Exchange Online (Official announcement here ). A while ago I created  this script that used Opportunistic TLS to perform a Telnet style test against a SMTP server using SMTP AUTH. Now that oAuth authentication has been enabled in office365 I've updated this script to be able to use oAuth instead of SMTP Auth to test against Office365. I've also included a function to actually send a Message. Token Acquisition  To Send a Mail using oAuth you first need to get an Access token from Azure AD there are plenty of ways of doing this in PowerShell. You could use a library like MSAL or ADAL (just google your favoured method) or use a library less approach which I've included with this script . Whatever way you do this you need to make sure that your application registration  https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-

How to test SMTP using Opportunistic TLS with Powershell and grab the public certificate a SMTP server is using

Most email services these day employ Opportunistic TLS when trying to send Messages which means that wherever possible the Messages will be encrypted rather then the plain text legacy of SMTP.  This method was defined in RFC 3207 "SMTP Service Extension for Secure SMTP over Transport Layer Security" and  there's a quite a good explanation of Opportunistic TLS on Wikipedia  https://en.wikipedia.org/wiki/Opportunistic_TLS .  This is used for both Server to Server (eg MTA to MTA) and Client to server (Eg a Message client like Outlook which acts as a MSA) the later being generally Authenticated. Basically it allows you to have a normal plain text SMTP conversation that is then upgraded to TLS using the STARTTLS verb. Not all servers will support this verb so if its not supported then a message is just sent as Plain text. TLS relies on PKI certificates and the administrative issue s that come around certificate management like expired certificates which is why I wrote th

The MailboxConcurrency limit and using Batching in the Microsoft Graph API

If your getting an error such as Application is over its MailboxConcurrency limit while using the Microsoft Graph API this post may help you understand why. Background   The Mailbox  concurrency limit when your using the Graph API is 4 as per https://docs.microsoft.com/en-us/graph/throttling#outlook-service-limits . This is evaluated for each app ID and mailbox combination so this means you can have different apps running under the same credentials and the poor behavior of one won't cause the other to be throttled. If you compared that to EWS you could have up to 27 concurrent connections but they are shared across all apps on a first come first served basis. Batching Batching in the Graph API is a way of combining multiple requests into a single HTTP request. Batching in the Exchange Mail API's EWS and MAPI has been around for a long time and its common, for email Apps to process large numbers of smaller items for a variety of reasons.  Batching in the Graph is limited to a m
All sample scripts and source code is provided by for illustrative purposes only. All examples are untested in different environments and therefore, I cannot guarantee or imply reliability, serviceability, or function of these programs.

All code contained herein is provided to you "AS IS" without any warranties of any kind. The implied warranties of non-infringement, merchantability and fitness for a particular purpose are expressly disclaimed.