Wednesday, August 11, 2010

Upgrade from Exchange 2007 to Exchange 2010: An IIS directory entry couldn’t be created. The error message is Access is denied. HResult = -2147024891

After we upgraded our infrastructure from Exchange 2007 to Exchange 2010, when I tried to access the CAS from Exchange 2010 EMC I received “An IIS directory entry couldn’t be created. The error message was “Access is denied. HResult = -2147024891 It was running the command ‘Get-OWAVirtualDirectory’” and the OWA Virtual Directory wasn’t visible in EMC.
If you run the same command from PowerShell you will get

[PS] C:\>Get-OwaVirtualDirectory |fl
An IIS directory entry couldn’t be created. The error message is Access is denied.
. HResult = -2147024891
+ CategoryInfo : NotInstalled: (EXCH01\owa (Default Web Site):A
DObjectId) [Get-OwaVirtualDirectory], IISGeneralCOMException
+ FullyQualifiedErrorId : 46C81F27,Microsoft.Exchange.Management.SystemConfi
gurationTasks.GetOwaVirtualDirectory

In my configuration, EXCH01 was the old Exchange 2007 server. This error is generated because the Exchange 2010 does not have rights to enumerate IIS virtual directory from the old Exchange 2007 server. To solve this issue you have two options:

1. Add the “Exchange Trusted Subsystem” group to the Local Administrators group on the Exchange 2007 server.



2. Open Internet Information Service (IIS) Manager role on the Exchange 2007 server, expand to SERVER (local Computer) -> Sites -> Default Web Site select Edit Permissions, add “Exchange Trusted Subsystem” group and grant it Full Control, Run “iisreset /noforce”


Thursday, August 5, 2010

Exchange impersonation not working

We had a request from a customer regarding Exchange Impersonation. The customer wanted to use impersonation for an application that had to send emails as another user. He didn’t wanted to use “Send As” right and he asked us specifically to use Impersonation.
Exchange Impersonation enables a caller to impersonate a given user account. This enables the caller to perform operations by using the permissions that are associated with the impersonated account, instead of the permissions that are associated with the caller's account.

Our customer’ application was trying to send emails in the name of an user using SMTP protocol, connecting to an Exchange HUB Transport Server. We configured user1 to be able to impersonate user2.

Microsoft Exchange Server 2010 uses Role-Based Access Control (RBAC) to assign permissions to accounts. You can read more about impersonation configuration here: http://msdn.microsoft.com/en-us/library/bb204095.aspx .

If you still use Exchange 2007, you have to read this: http://msdn.microsoft.com/en-us/library/bb204095(EXCHG.80).aspx.

We configured the application to authenticate to the SMTP service as user1 and send emails as user2. We made a lot of tests and all we've got was “5.7.1 Client does not have permissions to send as this sender”. After some extensive research we found out a simple thing. You cannot use impersonation to send emails as another user using SMTP authentication, OWA or Outlook.
Exchange impersonation is designed to be used only for Exchange Web Services (EWS). For other requirements, you should use “Send As” right (http://technet.microsoft.com/en-us/library/bb676368.aspx). 

Sunday, August 1, 2010

Configure Autodiscovery and EWS to work with HTTP in Exchange 2010

Last week we upgraded our email system to Exchange 2010. It’s strange that a company that sells implementation services for MS Exchange has waited so long to migrate to the latest version ☺, but we are always short on time and we prefer to work for our customers instead of working on our own network. Now it’s summer, and everybody is on vacation so we decided to upgrade our network and to implement some new internal services. The obvious start was to upgrade the email system. Of course that we encountered some issues and I will blog about them here ☺.

Our Exchange 2007 was configured not to 'Require secure channel (SSL)’ for Internet Information Services (IIS). All the encryption is offloaded to another device. We tried to do the same configuration with new Exchange 2010 server and surprise, it was not working as expected. The Autodiscovery service and Exchange Web Services (EWS) were not functioning. When I tested the services using a browser via HTTP and answer was “HTTP 404 Resource Not Found”.

It seems that in Exchange 2010 RTM this kind of configuration is no longer possible, maybe this issue will be solved in SP1 but for the moment to make it work you must do some tricks.
Exchange 2010 Web Services are now based on Windows Communication Foundation (WCF). WCF attempts to locate the endpoint for HTTP but there is not endpoint defined for this service and the system gives you a System.ServiceModel.EndpointNotFoundException exception which is treated by the client as HTTP 404 error.

The trick to make it work is to change some settings in the web.config files for Autodiscovery and EWS virtual directory.

Autodiscovery Service

1. Verify that 'Require SSL' in IIS box is not checked
2. Open the C:\Program Files\Microsoft\Exchange Server\V14\ClientAccess\Autodiscover folder
3. Save a backup of the current web.config file and modify the it using the following settings
4. Replace

<endpoint address="" binding="customBinding" bindingConfiguration="AutodiscoverHttpsBinding"
contract="Microsoft.Exchange.Autodiscover.WCF.ILegacyAutodiscover" />

with

<!-- Autodiscovery HTTP endpoint-->
<endpoint address="" binding="customBinding" bindingConfiguration="AutodiscoverHttpBinding"
contract="Microsoft.Exchange.Autodiscover.WCF.ILegacyAutodiscover" />
<!-- Autdiscovery HTTPS endpoint -->
<endpoint address="" binding="customBinding" bindingConfiguration="AutodiscoverHttpsBinding"
contract="Microsoft.Exchange.Autodiscover.WCF.ILegacyAutodiscover" />

5. Replace

<endpoint address="" binding="customBinding" bindingConfiguration="AutodiscoverSoapHttpsBinding"
contract="Microsoft.Exchange.Autodiscover.WCF.IAutodiscover" />

with

<!-- Autodiscovery Soap HTTP endpoint-->
<endpoint address="" binding="customBinding" bindingConfiguration="AutodiscoverSoapHttpBinding"
contract="Microsoft.Exchange.Autodiscover.WCF.IAutodiscover" />
<!-- Autodiscovery Soap HTTPS endpoint -->
<endpoint address="" binding="customBinding" bindingConfiguration="AutodiscoverSoapHttpsBinding"
contract="Microsoft.Exchange.Autodiscover.WCF.IAutodiscover" />

6. Replace

<binding name="AutodiscoverHttpsBinding">
<LegacyMessageEncoderBindingElement />
<httpsTransport maxReceivedMessageSize="8388608" authenticationScheme="Anonymous"
transferMode="StreamedRequest">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpsTransport>
</binding>

with

<!-- Autodiscovery endpoint binding for HTTP-->
<binding name="AutodiscoverHttpBinding">
<LegacyMessageEncoderBindingElement />
<httpTransport maxReceivedMessageSize="8388608" authenticationScheme="Anonymous"
transferMode="StreamedRequest">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpTransport>
</binding>
<!-- Autodiscovery endpoint binding for HTTPS -->
<binding name="AutodiscoverHttpsBinding">
<LegacyMessageEncoderBindingElement />
<httpsTransport maxReceivedMessageSize="8388608" authenticationScheme="Anonymous"
transferMode="StreamedRequest">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpsTransport>
</binding>

7. Replace

<binding name="AutodiscoverSoapHttpsBinding">
<textMessageEncoding messageVersion="Soap11WSAddressing10" />
<httpsTransport maxReceivedMessageSize="8388608" authenticationScheme="Anonymous"
transferMode="Streamed">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpsTransport>
</binding>

With

<!-- Autodiscovery Soap endpoint binding for HTTP-->
<binding name="AutodiscoverSoapHttpBinding">
<textMessageEncoding messageVersion="Soap11WSAddressing10" />
<httpTransport maxReceivedMessageSize="8388608" authenticationScheme="Anonymous"
transferMode="Streamed">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpTransport>
</binding>
<!-- Autodiscovery endpoint binding for HTTPS -->
<binding name="AutodiscoverSoapHttpsBinding">
<textMessageEncoding messageVersion="Soap11WSAddressing10" />
<httpsTransport maxReceivedMessageSize="8388608" authenticationScheme="Anonymous"
transferMode="Streamed">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpsTransport>
</binding>

8. Save the file. The IIS should detect the change in the web.config and reload the settings. If not you sould run iisreset /noforce to restart the IIS.
9. If you want to enable 'Require secure channel (SSL)’ for this virtual directory, you have to get back to the old settings, otherwise you will receive HTTP 500 - Internal Server Error and the service will not work.


Exchange Web Services (EWS)

1. Verify that 'Require SSL' in IIS box is not checked
2. Open the C:\Program Files\Microsoft\Exchange Server\V14\ClientAccess\Exchweb\EWS folder
3. Save a backup of the current web.config file and modify the it using the following settings
4. Replace

<endpoint address="" binding="customBinding" bindingConfiguration="EWSHttpsBinding"
contract="Microsoft.Exchange.Services.Wcf.IEWSContract" />

with

<!-- EWS HTTP endpoint-->
<endpoint address="" binding="customBinding" bindingConfiguration="EWSHttpBinding"
contract="Microsoft.Exchange.Services.Wcf.IEWSContract" />
<!-- EWS HTTPS endpoint -->
<endpoint address="" binding="customBinding" bindingConfiguration="EWSHttpsBinding"
contract="Microsoft.Exchange.Services.Wcf.IEWSContract" />

5. Replace

<binding name="EWSHttpsBinding">
<EWSMessageEncoderSoap11Element />
<httpsTransport maxReceivedMessageSize="13600000" authenticationScheme="Anonymous"
maxBufferSize="81920" transferMode="Streamed" />
</binding>

With

<!-- EWS endpoint binding for HTTP -->
<binding name="EWSHttpBinding">
<EWSMessageEncoderSoap11Element />
<httpTransport maxReceivedMessageSize="13600000" authenticationScheme="Anonymous"
maxBufferSize="81920" transferMode="Streamed">
</httpTransport>
</binding>
<!-- EWS endpoint binding for HTTPS-->
<binding name="EWSHttpsBinding">
<EWSMessageEncoderSoap11Element />
<httpsTransport maxReceivedMessageSize="13600000" authenticationScheme="Anonymous"
maxBufferSize="81920" transferMode="Streamed" >
</httpsTransport>
</binding>

8. Save the file. The IIS should detect the change in the web.config and reload the settings. If not you sould run iisreset /noforce to restart the IIS.
9. If you want to enable 'Require secure channel (SSL)’ for this virtual directory, you have to get back to the old settings, otherwise you will receive HTTP 500 - Internal Server Error and the service will not work.