Using Proxy PAC with EWS API
Asked Answered
A

1

10

I have a web application that calls the EWS Managed API to connect to office365.

I've followed the Get started with EWS Managed API 2.0 client applications documentation on MSDN.

In the web.config I've specified the proxy pac:

<configuration>
  <system.net>
    <defaultProxy useDefaultCredentials="false">
      <proxy autoDetect="False" bypassonlocal="True" scriptLocation="http://example.com:8080/proxy.pac" usesystemdefault="False" />
    </defaultProxy>
  </system.net>
  [...]
</configuration>

And I try to connect to Exchange in the following way:

public static ExchangeService getExchangeService(String username)
{
    ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;

    ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
    service.Credentials = new WebCredentials(USER_365, PWD_365, DOMAIN_365);
    service.UseDefaultCredentials = true;

    //I've tried both WebProxy settings, this:
    service.WebProxy = WebRequest.GetSystemWebProxy();
    //And this (with no success):
    //service.WebProxy = WebRequest.DefaultWebProxy;

    //I've also tried Autodiscover...
    service.AutodiscoverUrl(USER_365, RedirectionUrlValidationCallback);
    //...and direct url
    //service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");

    service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, username);

    return service;
}

And the following are the method copied & pasted from MSDN:

private static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
    // The default for the validation callback is to reject the URL.
    bool result = false;

    Uri redirectionUri = new Uri(redirectionUrl);

    // Validate the contents of the redirection URL. In this simple validation
    // callback, the redirection URL is considered valid if it is using HTTPS
    // to encrypt the authentication credentials. 
    if (redirectionUri.Scheme == "https")
    {
        result = true;
    }
    return result;
}

private static bool CertificateValidationCallBack(object sender,
    System.Security.Cryptography.X509Certificates.X509Certificate certificate,
    System.Security.Cryptography.X509Certificates.X509Chain chain,
    System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
    // If the certificate is a valid, signed certificate, return true.
    if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
    {
        return true;
    }

    // If there are errors in the certificate chain, look at each error to determine the cause.
    if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
    {
        if (chain != null && chain.ChainStatus != null)
        {
            foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
            {
                if ((certificate.Subject == certificate.Issuer) &&
                   (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
                {
                    // Self-signed certificates with an untrusted root are valid. 
                    continue;
                }
                else
                {
                    if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
                    {
                        // If there are any other errors in the certificate chain, the certificate is invalid,
                        // so the method returns false.
                        return false;
                    }
                }
            }
        }

        // When processing reaches this line, the only errors in the certificate chain are 
        // untrusted root errors for self-signed certificates. These certificates are valid
        // for default Exchange server installations, so return true.
        return true;
    }
    else
    {
        // In all other cases, return false.
        return false;
    }
}

I tried to comment out the line:

//service.Url = new Uri("https://outlook.office365.com/ews/Exchange.asmx");

And add the Autodiscover:

service.AutodiscoverUrl(username);

Set the proxy or not, comment out the line:

ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;

But it seems that the ExchangeService calls directly the server without passing trough the proxy... what am I missing?

Thanks

Amulet answered 8/3, 2018 at 9:18 Comment(0)
F
3

Try to remove bypassonlocal attribute altogether from your proxy configuration in web.config. There is an issue with setting this attribute along with scriptLocation.

For more info: https://blogs.msdn.microsoft.com/rickrain/2011/03/25/why-scriptlocation-may-not-work-when-pointing-to-a-proxy-script-file-in-your-application-config-file/

Also the web.config default proxy configuration should be sufficient so you can remove any proxy setting in your code.

Maybe that's the case here.

UPDATE: Specifying pac script location in proxyaddress instead of scriptLocation attribute in web.config should resolve this issue.

Feodor answered 20/3, 2018 at 0:4 Comment(7)
Sorry, but it still doesn't work... I get the same error: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 40.xxx.xx.x:443Amulet
@Amulet have you tried setting "Use automatic configuration script" in Internet Explorer -> Internet Options -> Conncections -> Lan Settings?Feodor
Yes, I've already set that setting in "Lan Settings" and IE can't reach the 40.xxx.xx.x instead Chrome redirect me fine to login.microsoftonline.comAmulet
@Amulet Is specifying proxy directly like proxyaddress="127.0.0.1:8888" instead of scriptLocation works? If so the problem might be in a script itself.Feodor
Yes, it works... I've already seen that setting the WebProxy directly in the ExchangeService works, but I did't try to set the proxy directly in the web.config. Thanks... So the error should be in the pac, but I still don't understand why it works with Chrome.Amulet
It also worked with the proxy pac, but I had to use the attribute proxyaddress instead of scriptLocation. Please edit your answer so I can accept it.Amulet
oh that's very interesting, I'll update my answer. I'm glad I could helpFeodor

© 2022 - 2024 — McMap. All rights reserved.