Пример #1
0
        // CheckNonSecuredEndpointForRedirect
        //   This function does an unauthenticated GET request to a non-https
        //   URL to see if the server will respond with a 302 redirect. If so, it will
        //   attempt to use the value of the Location header to perform Autodiscover.
        //
        // Parameters:
        //   useSoapEndpoints: Indicates whether SOAP endpoints should be tried.
        //
        // Returns:
        //   A Dictionary object that contains the settings returned by the
        //   Autodiscover process. If null, either the redirect failed or the URL failed.
        //
        private Dictionary <string, string> CheckNonSecuredEndpointForRedirect(bool useSoapEndpoints)
        {
            // Get the non-https URL, or "last ditch" URL.
            string nonHttpsEndpoint = UrlList.GetLastDitchUrl(EmailAddress);

            Tracing.WriteLine("Sending non-authenticated GET to " + nonHttpsEndpoint);

            HttpWebRequest getRequest = (HttpWebRequest)WebRequest.Create(nonHttpsEndpoint);

            getRequest.Method            = "GET";
            getRequest.AllowAutoRedirect = false;
            getRequest.PreAuthenticate   = false;

            try
            {
                HttpWebResponse getResponse = (HttpWebResponse)getRequest.GetResponse();
                if (getResponse != null)
                {
                    if (getResponse.StatusCode == HttpStatusCode.Redirect ||
                        getResponse.StatusCode == HttpStatusCode.Moved ||
                        getResponse.StatusCode == HttpStatusCode.RedirectKeepVerb ||
                        getResponse.StatusCode == HttpStatusCode.RedirectMethod)
                    {
                        Tracing.WriteLine("Received a redirect status: " + getResponse.StatusCode.ToString());
                        string redirectUrl = getResponse.Headers["Location"].ToString();
                        Tracing.WriteLine("Location header: " +
                                          (string.IsNullOrEmpty(redirectUrl) ? "MISSING" : redirectUrl));
                        if (IsValidRedirectUrl(redirectUrl))
                        {
                            // You got a valid redirect; try it.
                            UrlRedirects++;
                            return(TryAutodiscoverUrl(AutodiscoverUrlList.NormalizeAutodiscoverUrl(redirectUrl),
                                                      useSoapEndpoints));
                        }
                        else
                        {
                            Tracing.WriteLine("Redirect returned missing or invalid URL, unable to proceed.");
                        }
                    }
                    else
                    {
                        Tracing.WriteLine("Received a non-redirect status: " + getResponse.StatusCode.ToString());
                    }
                }
            }
            catch (WebException e)
            {
                Tracing.WriteLine("Unable to connect.");
                Tracing.WriteLine(e.ToString());
            }

            return(null);
        }
Пример #2
0
        // TryPoxAutodiscoverUrl
        //   This function trys a URL as a POX endpoint.
        //
        // Parameters:
        //   url: The URL to try. Note that this value is a POX URL, meaning
        //        it has a .xml file extension. ("https://contoso.com/autodiscover/autodiscover.xml")
        //   useSoapEndpoints: Indicates whether SOAP endpoints should be tried.
        //
        // Returns:
        //   A Dictionary object that contains the settings returned by the
        //   Autodiscover process. If null, the URL failed.
        //
        private Dictionary <string, string> TryPoxAutodiscoverUrl(string url, bool useSoapEndpoints)
        {
            Tracing.WriteLine("Trying " + url);

            Dictionary <string, string> settingsDictionary = null;

            // Generate the POX request.
            XElement autodiscover = new XElement(PoxXmlStrings.Autodiscover,
                                                 new XElement(PoxXmlStrings.Request,
                                                              new XElement(PoxXmlStrings.EMailAddress, EmailAddress),
                                                              new XElement(PoxXmlStrings.AcceptableResponseSchema, "http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a")
                                                              )
                                                 );

            Tracing.WriteLine("POX Request:");
            PrintElement(autodiscover);

            try
            {
                HttpWebRequest poxRequest = (HttpWebRequest)WebRequest.Create(url);
                poxRequest.AllowAutoRedirect = false;
                poxRequest.Credentials       = this.Credentials;
                poxRequest.Method            = "POST";
                poxRequest.ContentType       = "text/xml";

                Stream requestStream = poxRequest.GetRequestStream();
                autodiscover.Save(requestStream);
                requestStream.Close();

                HttpWebResponse poxResponse = (HttpWebResponse)poxRequest.GetResponse();
                if (poxResponse.StatusCode == HttpStatusCode.OK)
                {
                    // Successful response.
                    Stream responseStream = poxResponse.GetResponseStream();

                    XElement responseAutodiscover = XElement.Load(responseStream);
                    if (responseAutodiscover != null)
                    {
                        Tracing.WriteLine("Response:");
                        PrintElement(responseAutodiscover);

                        // If no errors, it is safe to proceed.
                        string error = CheckPoxResponseForError(responseAutodiscover);
                        if (error == "NoError")
                        {
                            // Check Action value.
                            XElement action = FindFirstDescendant(responseAutodiscover, PoxXmlStrings.Action);
                            if (action != null)
                            {
                                if (action.Value == "settings")
                                {
                                    settingsDictionary = new Dictionary <string, string>();

                                    IEnumerable <XElement> protocols = from protocol in responseAutodiscover.Descendants
                                                                           (PoxXmlStrings.Protocol)
                                                                       select protocol;
                                    foreach (XElement protocol in protocols)
                                    {
                                        XElement type = protocol.Element(PoxXmlStrings.Type);
                                        if (type != null && type.Value == "EXCH")
                                        {
                                            // You found what you are looking for.
                                            AddPoxSettingToDictionary(settingsDictionary, protocol, PoxXmlStrings.EwsUrl);
                                            break;
                                        }
                                    }
                                }
                                else if (action.Value == "redirectAddr")
                                {
                                    // The server has given you a better email address to use.
                                    Tracing.WriteLine("Server response contains a RedirectAddr element.");
                                    XElement redirectAddr = FindFirstDescendant(responseAutodiscover,
                                                                                PoxXmlStrings.RedirectAddr);

                                    if (redirectAddr != null &&
                                        IsValidRedirectAddress(redirectAddr.Value, EmailAddress))
                                    {
                                        Tracing.WriteLine("Restarting Autodiscover with email address: " +
                                                          redirectAddr.Value);

                                        EmailAddress = redirectAddr.Value;
                                        UrlList.Clear();
                                        UrlList.GenerateList(this.EmailAddress);

                                        visitedUrls.Clear();
                                        AddressRedirects++;
                                        return(TryAutodiscoverUrls(useSoapEndpoints));
                                    }
                                    Tracing.WriteLine("Invalid or missing redirectAddr element, continuing...");
                                }
                                else if (action.Value == "redirectUrl")
                                {
                                    // The server has given you a better URL
                                    // to use. Validate that it is https and
                                    // try it.
                                    Tracing.Write("Server response contains a RedirectUrl element for url: ");

                                    XElement redirectUrl = FindFirstDescendant(responseAutodiscover,
                                                                               PoxXmlStrings.RedirectUrl);

                                    if (redirectUrl != null && IsValidRedirectUrl(redirectUrl.Value.ToLower()))
                                    {
                                        Tracing.WriteLine(redirectUrl.Value);

                                        UrlRedirects++;
                                        return(TryAutodiscoverUrl(
                                                   AutodiscoverUrlList.NormalizeAutodiscoverUrl(redirectUrl.Value),
                                                   useSoapEndpoints));
                                    }
                                    else
                                    {
                                        Tracing.WriteLine("Missing or invalid RedirectUrl element, continuing...");
                                    }
                                }
                            }
                        }
                    }
                }
                else if (poxResponse.StatusCode == HttpStatusCode.Redirect ||
                         poxResponse.StatusCode == HttpStatusCode.Moved ||
                         poxResponse.StatusCode == HttpStatusCode.RedirectKeepVerb ||
                         poxResponse.StatusCode == HttpStatusCode.RedirectMethod)
                {
                    // Redirect HTTP status scenario.
                    Tracing.WriteLine("Received a redirect status: " + poxResponse.StatusCode.ToString());
                    string redirectUrl = poxResponse.Headers["Location"].ToString();
                    Tracing.WriteLine("Location header: " +
                                      (string.IsNullOrEmpty(redirectUrl) ? "MISSING" : redirectUrl));
                    if (IsValidRedirectUrl(redirectUrl.ToLower()))
                    {
                        UrlRedirects++;
                        return(TryAutodiscoverUrl(AutodiscoverUrlList.NormalizeAutodiscoverUrl(redirectUrl),
                                                  useSoapEndpoints));
                    }

                    Tracing.WriteLine("Invalid or missing redirect URL returned. Unable to proceed.");
                    return(null);
                }
            }
            catch (WebException e)
            {
                Tracing.WriteLine("Error connection:");
                Tracing.WriteLine(e.ToString());
            }

            return(settingsDictionary);
        }
Пример #3
0
 public AutodiscoverRequest(string email, NetworkCredential creds)
 {
     EmailAddress = email;
     Credentials  = creds;
     UrlList      = new AutodiscoverUrlList();
 }
Пример #4
0
        // TrySoapAutodiscoverUrl
        //   This function trys a URL as a SOAP endpoint.
        //   NOTE: The SOAP Autodiscover service is only available in versions of Exchange starting
        //   with Exchange 2010, including Exchange Online.
        //
        // Parameters:
        //   url: The URL to try. Note that this value is a SOAP URL, meaning
        //        it has a .svc file extension. ("https://contoso.com/autodiscover/autodiscover.svc")
        //   useSoapEndpoints: Indicates whether SOAP endpoints should be tried.
        //
        // Returns:
        //   A Dictionary object that contains the settings returned by the
        //   Autodiscover process. If null, the URL failed.
        //
        private Dictionary <string, string> TrySoapAutodiscoverUrl(string url, bool useSoapEndpoints)
        {
            Tracing.WriteLine("Trying " + url);

            Dictionary <string, string> settingsDictionary = null;

            // Generate the SOAP request.
            XElement envelope = new XElement(SoapXmlStrings.Envelope,
                                             new XElement(SoapXmlStrings.Header,
                                                          new XElement(SoapXmlStrings.RequestedServerVersion, SoapXmlStrings.MinServerVersion),
                                                          new XElement(SoapXmlStrings.Action, "http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetUserSettings"),
                                                          new XElement(SoapXmlStrings.To, url)
                                                          ),
                                             new XElement(SoapXmlStrings.Body,
                                                          new XElement(SoapXmlStrings.GetUserSettingsRequestMessage,
                                                                       new XElement(SoapXmlStrings.Request,
                                                                                    new XElement(SoapXmlStrings.Users,
                                                                                                 new XElement(SoapXmlStrings.User,
                                                                                                              new XElement(SoapXmlStrings.Mailbox, EmailAddress)
                                                                                                              )
                                                                                                 ),
                                                                                    new XElement(SoapXmlStrings.RequestedSettings,
                                                                                                 new XElement(SoapXmlStrings.Setting, "InternalEwsUrl"),
                                                                                                 new XElement(SoapXmlStrings.Setting, "ExternalEwsUrl"),
                                                                                                 new XElement(SoapXmlStrings.Setting, "ExternalEwsVersion"),
                                                                                                 new XElement(SoapXmlStrings.Setting, "EwsSupportedSchemas")
                                                                                                 )
                                                                                    )
                                                                       )
                                                          )
                                             );

            Tracing.WriteLine("SOAP Request:");
            PrintElement(envelope);

            try
            {
                HttpWebRequest soapRequest = (HttpWebRequest)WebRequest.Create(url);
                soapRequest.AllowAutoRedirect = false;
                soapRequest.Credentials       = this.Credentials;
                soapRequest.Method            = "POST";
                soapRequest.ContentType       = "text/xml";

                Stream requestStream = soapRequest.GetRequestStream();
                envelope.Save(requestStream);
                requestStream.Close();

                HttpWebResponse soapResponse = (HttpWebResponse)soapRequest.GetResponse();
                if (soapResponse.StatusCode == HttpStatusCode.OK)
                {
                    // Successful response.
                    Stream responseStream = soapResponse.GetResponseStream();

                    XElement responseEnvelope = XElement.Load(responseStream);
                    if (responseEnvelope != null)
                    {
                        Tracing.WriteLine("Response:");
                        PrintElement(responseEnvelope);

                        // If no errors, it is safe to proceed.
                        string error = CheckSoapResponseForError(responseEnvelope);
                        if (error == "NoError")
                        {
                            settingsDictionary = new Dictionary <string, string>();

                            // Load settings.
                            IEnumerable <XElement> userSettings = from userSetting in responseEnvelope.Descendants
                                                                      (SoapXmlStrings.UserSetting)
                                                                  select userSetting;

                            foreach (XElement userSetting in userSettings)
                            {
                                XElement name  = userSetting.Element(SoapXmlStrings.Name);
                                XElement value = userSetting.Element(SoapXmlStrings.Value);

                                if (name != null && value != null)
                                {
                                    settingsDictionary.Add(name.Value, value.Value);
                                }
                            }
                        }
                        else if (error == "RedirectAddress")
                        {
                            // The server has given you a better email
                            // address to use.
                            Tracing.WriteLine("Server response contains a RedirectAddress error.");

                            XElement redirectTarget = FindFirstDescendant(responseEnvelope,
                                                                          SoapXmlStrings.RedirectTarget);

                            if (redirectTarget != null &&
                                IsValidRedirectAddress(redirectTarget.Value, EmailAddress))
                            {
                                Tracing.WriteLine("Restarting Autodiscover with email address: " +
                                                  redirectTarget.Value);

                                EmailAddress = redirectTarget.Value;
                                UrlList.Clear();
                                UrlList.GenerateList(this.EmailAddress);

                                visitedUrls.Clear();
                                AddressRedirects++;
                                return(TryAutodiscoverUrls(useSoapEndpoints));
                            }
                            Tracing.WriteLine("Invalid or missing RedirectTarget element, continuing...");
                        }
                        else if (error == "RedirectUrl")
                        {
                            // The server has given you a better URL
                            // to use. Validate that it is https and
                            // try it.
                            Tracing.Write("Server response contains a redirect to URL: ");

                            XElement redirectTarget = FindFirstDescendant(responseEnvelope,
                                                                          SoapXmlStrings.RedirectTarget);

                            if (redirectTarget != null && IsValidRedirectUrl(redirectTarget.Value.ToLower()))
                            {
                                Tracing.WriteLine(redirectTarget.Value);

                                UrlRedirects++;

                                return(TryAutodiscoverUrl(
                                           AutodiscoverUrlList.NormalizeAutodiscoverUrl(redirectTarget.Value),
                                           useSoapEndpoints));
                            }
                            Tracing.WriteLine("Invalid or missing RedirectTarget element, continuing...");
                            return(null);
                        }
                    }
                }
                else if (soapResponse.StatusCode == HttpStatusCode.Redirect ||
                         soapResponse.StatusCode == HttpStatusCode.Moved ||
                         soapResponse.StatusCode == HttpStatusCode.RedirectKeepVerb ||
                         soapResponse.StatusCode == HttpStatusCode.RedirectMethod)
                {
                    // Redirect HTTP status scenario.
                    Tracing.WriteLine("Received a redirect status: " + soapResponse.StatusCode.ToString());
                    string redirectUrl = soapResponse.Headers["Location"].ToString();
                    Tracing.WriteLine("Location header: " +
                                      (string.IsNullOrEmpty(redirectUrl) ? "MISSING" : redirectUrl));
                    if (IsValidRedirectUrl(redirectUrl.ToLower()))
                    {
                        UrlRedirects++;
                        return(TryAutodiscoverUrl(
                                   AutodiscoverUrlList.NormalizeAutodiscoverUrl(redirectUrl),
                                   useSoapEndpoints));
                    }
                    Tracing.WriteLine("Invalid (non-https) redirect URL returned. Unable to proceed.");
                    return(null);
                }
            }
            catch (WebException e)
            {
                // Some errors will be exposed as WebExceptions.
                // For example, 401 (Unauthorized)
                // 302 should not generate a WebException and is handled above.
                Tracing.WriteLine("Error connecting:");
                Tracing.WriteLine(e.ToString());
            }

            return(settingsDictionary);
        }