001/* 002 * The MIT License 003 * Copyright (c) 2012 Microsoft Corporation 004 * 005 * Permission is hereby granted, free of charge, to any person obtaining a copy 006 * of this software and associated documentation files (the "Software"), to deal 007 * in the Software without restriction, including without limitation the rights 008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 009 * copies of the Software, and to permit persons to whom the Software is 010 * furnished to do so, subject to the following conditions: 011 * 012 * The above copyright notice and this permission notice shall be included in 013 * all copies or substantial portions of the Software. 014 * 015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 021 * THE SOFTWARE. 022 */ 023 024package microsoft.exchange.webservices.data.autodiscover; 025 026import microsoft.exchange.webservices.data.autodiscover.configuration.ConfigurationSettingsBase; 027import microsoft.exchange.webservices.data.autodiscover.configuration.outlook.OutlookConfigurationSettings; 028import microsoft.exchange.webservices.data.autodiscover.enumeration.AutodiscoverEndpoints; 029import microsoft.exchange.webservices.data.autodiscover.enumeration.AutodiscoverErrorCode; 030import microsoft.exchange.webservices.data.autodiscover.exception.AutodiscoverLocalException; 031import microsoft.exchange.webservices.data.autodiscover.exception.AutodiscoverRemoteException; 032import microsoft.exchange.webservices.data.autodiscover.request.AutodiscoverRequest; 033import microsoft.exchange.webservices.data.autodiscover.request.GetDomainSettingsRequest; 034import microsoft.exchange.webservices.data.autodiscover.request.GetUserSettingsRequest; 035import microsoft.exchange.webservices.data.autodiscover.response.GetDomainSettingsResponse; 036import microsoft.exchange.webservices.data.autodiscover.response.GetDomainSettingsResponseCollection; 037import microsoft.exchange.webservices.data.autodiscover.response.GetUserSettingsResponse; 038import microsoft.exchange.webservices.data.autodiscover.response.GetUserSettingsResponseCollection; 039import microsoft.exchange.webservices.data.core.EwsUtilities; 040import microsoft.exchange.webservices.data.core.EwsXmlReader; 041import microsoft.exchange.webservices.data.core.ExchangeServiceBase; 042import microsoft.exchange.webservices.data.core.request.HttpClientWebRequest; 043import microsoft.exchange.webservices.data.core.request.HttpWebRequest; 044import microsoft.exchange.webservices.data.credential.WSSecurityBasedCredentials; 045import microsoft.exchange.webservices.data.autodiscover.enumeration.DomainSettingName; 046import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion; 047import microsoft.exchange.webservices.data.core.enumeration.misc.TraceFlags; 048import microsoft.exchange.webservices.data.autodiscover.enumeration.UserSettingName; 049import microsoft.exchange.webservices.data.core.exception.misc.ArgumentException; 050import microsoft.exchange.webservices.data.core.exception.http.EWSHttpException; 051import microsoft.exchange.webservices.data.core.exception.misc.FormatException; 052import microsoft.exchange.webservices.data.autodiscover.exception.MaximumRedirectionHopsExceededException; 053import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException; 054import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException; 055import microsoft.exchange.webservices.data.core.exception.service.local.ServiceVersionException; 056import microsoft.exchange.webservices.data.misc.OutParam; 057import microsoft.exchange.webservices.data.security.XmlNodeType; 058 059import javax.xml.stream.XMLStreamException; 060 061import java.io.ByteArrayInputStream; 062import java.io.ByteArrayOutputStream; 063import java.io.IOException; 064import java.io.InputStream; 065import java.io.OutputStream; 066import java.io.PrintWriter; 067import java.net.MalformedURLException; 068import java.net.URI; 069import java.net.URISyntaxException; 070import java.util.ArrayList; 071import java.util.Arrays; 072import java.util.Collection; 073import java.util.EnumSet; 074import java.util.List; 075 076/** 077 * Represents a binding to the Exchange Autodiscover Service. 078 */ 079public class AutodiscoverService extends ExchangeServiceBase 080 implements IAutodiscoverRedirectionUrl, IFunctionDelegate { 081 082 // region Private members 083 /** 084 * The domain. 085 */ 086 private String domain; 087 088 /** 089 * The is external. 090 */ 091 private Boolean isExternal = true; 092 093 /** 094 * The url. 095 */ 096 private URI url; 097 098 /** 099 * The redirection url validation callback. 100 */ 101 private IAutodiscoverRedirectionUrl 102 redirectionUrlValidationCallback; 103 104 /** 105 * The dns client. 106 */ 107 private AutodiscoverDnsClient dnsClient; 108 109 /** 110 * The dns server address. 111 */ 112 private String dnsServerAddress; 113 114 /** 115 * The enable scp lookup. 116 */ 117 private boolean enableScpLookup = true; 118 119 // Autodiscover legacy path 120 /** 121 * The Constant AutodiscoverLegacyPath. 122 */ 123 private static final String AutodiscoverLegacyPath = 124 "/autodiscover/autodiscover.xml"; 125 126 // Autodiscover legacy HTTPS Url 127 /** 128 * The Constant AutodiscoverLegacyHttpsUrl. 129 */ 130 private static final String AutodiscoverLegacyHttpsUrl = "https://%s" + 131 AutodiscoverLegacyPath; 132 // Autodiscover legacy HTTP Url 133 /** 134 * The Constant AutodiscoverLegacyHttpUrl. 135 */ 136 private static final String AutodiscoverLegacyHttpUrl = "http://%s" + 137 AutodiscoverLegacyPath; 138 // Autodiscover SOAP HTTPS Url 139 /** 140 * The Constant AutodiscoverSoapHttpsUrl. 141 */ 142 private static final String AutodiscoverSoapHttpsUrl = 143 "https://%s/autodiscover/autodiscover.svc"; 144 // Autodiscover SOAP WS-Security HTTPS Url 145 /** 146 * The Constant AutodiscoverSoapWsSecurityHttpsUrl. 147 */ 148 private static final String AutodiscoverSoapWsSecurityHttpsUrl = 149 AutodiscoverSoapHttpsUrl + 150 "/wssecurity"; 151 152 /** 153 * Autodiscover SOAP WS-Security symmetrickey HTTPS Url 154 */ 155 private static final String AutodiscoverSoapWsSecuritySymmetricKeyHttpsUrl = 156 AutodiscoverSoapHttpsUrl + "/wssecurity/symmetrickey"; 157 158 /** 159 * Autodiscover SOAP WS-Security x509cert HTTPS Url 160 */ 161 private static final String AutodiscoverSoapWsSecurityX509CertHttpsUrl = 162 AutodiscoverSoapHttpsUrl + "/wssecurity/x509cert"; 163 164 165 // Autodiscover request namespace 166 /** 167 * The Constant AutodiscoverRequestNamespace. 168 */ 169 private static final String AutodiscoverRequestNamespace = 170 "http://schemas.microsoft.com/exchange/autodiscover/" + 171 "outlook/requestschema/2006"; 172 // Maximum number of Url (or address) redirections that will be followed by 173 // an Autodiscover call 174 /** 175 * The Constant AutodiscoverMaxRedirections. 176 */ 177 protected static final int AutodiscoverMaxRedirections = 10; 178 // HTTP header indicating that SOAP Autodiscover service is enabled. 179 /** 180 * The Constant AutodiscoverSoapEnabledHeaderName. 181 */ 182 private static final String AutodiscoverSoapEnabledHeaderName = 183 "X-SOAP-Enabled"; 184 // HTTP header indicating that WS-Security Autodiscover service is enabled. 185 /** 186 * The Constant AutodiscoverWsSecurityEnabledHeaderName. 187 */ 188 private static final String AutodiscoverWsSecurityEnabledHeaderName = 189 "X-WSSecurity-Enabled"; 190 191 192 /** 193 * HTTP header indicating that WS-Security/SymmetricKey Autodiscover service is enabled. 194 */ 195 196 private static final String AutodiscoverWsSecuritySymmetricKeyEnabledHeaderName = 197 "X-WSSecurity-SymmetricKey-Enabled"; 198 199 200 /** 201 * HTTP header indicating that WS-Security/X509Cert Autodiscover service is enabled. 202 */ 203 204 private static final String AutodiscoverWsSecurityX509CertEnabledHeaderName = 205 "X-WSSecurity-X509Cert-Enabled"; 206 207 208 // Minimum request version for Autodiscover SOAP service. 209 /** 210 * The Constant MinimumRequestVersionForAutoDiscoverSoapService. 211 */ 212 private static final ExchangeVersion 213 MinimumRequestVersionForAutoDiscoverSoapService = 214 ExchangeVersion.Exchange2010; 215 216 /** 217 * Default implementation of AutodiscoverRedirectionUrlValidationCallback. 218 * Always returns true indicating that the URL can be used. 219 * 220 * @param redirectionUrl the redirection url 221 * @return Returns true. 222 * @throws AutodiscoverLocalException the autodiscover local exception 223 */ 224 private boolean defaultAutodiscoverRedirectionUrlValidationCallback( 225 String redirectionUrl) throws AutodiscoverLocalException { 226 throw new AutodiscoverLocalException(String.format( 227 "Autodiscover blocked a potentially insecure redirection to %s. To allow Autodiscover to follow the " 228 + "redirection, use the AutodiscoverUrl(string, AutodiscoverRedirectionUrlValidationCallback) " 229 + "overload.", redirectionUrl)); 230 } 231 232 // Legacy Autodiscover 233 234 /** 235 * Calls the Autodiscover service to get configuration settings at the 236 * specified URL. 237 * 238 * @param <TSettings> the generic type 239 * @param cls the cls 240 * @param emailAddress the email address 241 * @param url the url 242 * @return The requested configuration settings. (TSettings The type of the 243 * settings to retrieve) 244 * @throws Exception the exception 245 */ 246 private <TSettings extends ConfigurationSettingsBase> 247 TSettings getLegacyUserSettingsAtUrl( 248 Class<TSettings> cls, String emailAddress, URI url) 249 throws Exception { 250 this 251 .traceMessage(TraceFlags.AutodiscoverConfiguration, 252 String.format("Trying to call Autodiscover for %s on %s.", emailAddress, url)); 253 254 TSettings settings = cls.newInstance(); 255 256 HttpWebRequest request = null; 257 try { 258 request = this.prepareHttpWebRequestForUrl(url); 259 260 this.traceHttpRequestHeaders( 261 TraceFlags.AutodiscoverRequestHttpHeaders, 262 request); 263 // OutputStreamWriter out = new 264 // OutputStreamWriter(request.getOutputStream()); 265 OutputStream urlOutStream = request.getOutputStream(); 266 267 // If tracing is enabled, we generate the request in-memory so that we 268 // can pass it along to the ITraceListener. Then we copy the stream to 269 // the request stream. 270 if (this.isTraceEnabledFor(TraceFlags.AutodiscoverRequest)) { 271 ByteArrayOutputStream memoryStream = new ByteArrayOutputStream(); 272 273 PrintWriter writer = new PrintWriter(memoryStream); 274 this.writeLegacyAutodiscoverRequest(emailAddress, settings, writer); 275 writer.flush(); 276 277 this.traceXml(TraceFlags.AutodiscoverRequest, memoryStream); 278 // out.write(memoryStream.toString()); 279 // out.close(); 280 memoryStream.writeTo(urlOutStream); 281 urlOutStream.flush(); 282 urlOutStream.close(); 283 memoryStream.close(); 284 } else { 285 PrintWriter writer = new PrintWriter(urlOutStream); 286 this.writeLegacyAutodiscoverRequest(emailAddress, settings, writer); 287 288 /* Flush Start */ 289 writer.flush(); 290 urlOutStream.flush(); 291 urlOutStream.close(); 292 /* Flush End */ 293 } 294 request.executeRequest(); 295 request.getResponseCode(); 296 URI redirectUrl; 297 OutParam<URI> outParam = new OutParam<URI>(); 298 if (this.tryGetRedirectionResponse(request, outParam)) { 299 redirectUrl = outParam.getParam(); 300 settings.makeRedirectionResponse(redirectUrl); 301 return settings; 302 } 303 InputStream serviceResponseStream = request.getInputStream(); 304 // If tracing is enabled, we read the entire response into a 305 // MemoryStream so that we 306 // can pass it along to the ITraceListener. Then we parse the response 307 // from the 308 // MemoryStream. 309 if (this.isTraceEnabledFor(TraceFlags.AutodiscoverResponse)) { 310 ByteArrayOutputStream memoryStream = new ByteArrayOutputStream(); 311 312 while (true) { 313 int data = serviceResponseStream.read(); 314 if (-1 == data) { 315 break; 316 } else { 317 memoryStream.write(data); 318 } 319 } 320 memoryStream.flush(); 321 322 this.traceResponse(request, memoryStream); 323 ByteArrayInputStream memoryStreamIn = new ByteArrayInputStream( 324 memoryStream.toByteArray()); 325 EwsXmlReader reader = new EwsXmlReader(memoryStreamIn); 326 reader.read(new XmlNodeType(XmlNodeType.START_DOCUMENT)); 327 settings.loadFromXml(reader); 328 329 } else { 330 EwsXmlReader reader = new EwsXmlReader(serviceResponseStream); 331 reader.read(new XmlNodeType(XmlNodeType.START_DOCUMENT)); 332 settings.loadFromXml(reader); 333 } 334 335 serviceResponseStream.close(); 336 } finally { 337 if (request != null) { 338 try { 339 request.close(); 340 } catch (Exception e2) { 341 // Ignore exception while closing the request. 342 } 343 } 344 } 345 346 return settings; 347 } 348 349 /** 350 * Writes the autodiscover request. 351 * 352 * @param emailAddress the email address 353 * @param settings the settings 354 * @param writer the writer 355 * @throws java.io.IOException Signals that an I/O exception has occurred. 356 */ 357 private void writeLegacyAutodiscoverRequest(String emailAddress, 358 ConfigurationSettingsBase settings, PrintWriter writer) 359 throws IOException { 360 writer.write(String.format("<Autodiscover xmlns=\"%s\">", AutodiscoverRequestNamespace)); 361 writer.write("<Request>"); 362 writer.write(String.format("<EMailAddress>%s</EMailAddress>", 363 emailAddress)); 364 writer.write( 365 String.format("<AcceptableResponseSchema>%s</AcceptableResponseSchema>", settings.getNamespace())); 366 writer.write("</Request>"); 367 writer.write("</Autodiscover>"); 368 } 369 370 /** 371 * Gets a redirection URL to an SSL-enabled Autodiscover service from the 372 * standard non-SSL Autodiscover URL. 373 * 374 * @param domainName the domain name 375 * @return A valid SSL-enabled redirection URL. (May be null) 376 * @throws EWSHttpException the EWS http exception 377 * @throws XMLStreamException the XML stream exception 378 * @throws IOException Signals that an I/O exception has occurred. 379 * @throws ServiceLocalException the service local exception 380 * @throws URISyntaxException the uRI syntax exception 381 */ 382 private URI getRedirectUrl(String domainName) 383 throws EWSHttpException, XMLStreamException, IOException, ServiceLocalException, URISyntaxException { 384 String url = String.format(AutodiscoverLegacyHttpUrl, "autodiscover." + domainName); 385 386 traceMessage(TraceFlags.AutodiscoverConfiguration, 387 String.format("Trying to get Autodiscover redirection URL from %s.", url)); 388 389 HttpWebRequest request = null; 390 391 try { 392 request = new HttpClientWebRequest(httpClient, httpContext); 393 request.setProxy(getWebProxy()); 394 395 try { 396 request.setUrl(URI.create(url).toURL()); 397 } catch (MalformedURLException e) { 398 String strErr = String.format("Incorrect format : %s", url); 399 throw new ServiceLocalException(strErr); 400 } 401 402 request.setRequestMethod("GET"); 403 request.setAllowAutoRedirect(false); 404 405 // Do NOT allow authentication as this single request will be made over plain HTTP. 406 request.setAllowAuthentication(false); 407 408 prepareCredentials(request); 409 410 request.prepareConnection(); 411 try { 412 request.executeRequest(); 413 } catch (IOException e) { 414 traceMessage(TraceFlags.AutodiscoverConfiguration, "No Autodiscover redirection URL was returned."); 415 return null; 416 } 417 418 OutParam<URI> outParam = new OutParam<URI>(); 419 if (tryGetRedirectionResponse(request, outParam)) { 420 return outParam.getParam(); 421 } 422 } finally { 423 if (request != null) { 424 try { 425 request.close(); 426 } catch (Exception e) { 427 // Ignore exception when closing the request 428 } 429 } 430 } 431 432 traceMessage(TraceFlags.AutodiscoverConfiguration, "No Autodiscover redirection URL was returned."); 433 return null; 434 } 435 436 /** 437 * Tries the get redirection response. 438 * 439 * @param request the request 440 * @param redirectUrl the redirect URL 441 * @return true if a valid redirection URL was found 442 * @throws XMLStreamException the XML stream exception 443 * @throws IOException signals that an I/O exception has occurred. 444 * @throws EWSHttpException the EWS http exception 445 */ 446 private boolean tryGetRedirectionResponse(HttpWebRequest request, 447 OutParam<URI> redirectUrl) throws XMLStreamException, IOException, 448 EWSHttpException { 449 // redirectUrl = null; 450 if (AutodiscoverRequest.isRedirectionResponse(request)) { 451 // Get the redirect location and verify that it's valid. 452 String location = request.getResponseHeaderField("Location"); 453 454 if (!(location == null || location.isEmpty())) { 455 try { 456 redirectUrl.setParam(new URI(location)); 457 458 // Check if URL is SSL and that the path matches. 459 if ((redirectUrl.getParam().getScheme().toLowerCase() 460 .equals("https")) && 461 (redirectUrl.getParam().getPath() 462 .equalsIgnoreCase( 463 AutodiscoverLegacyPath))) { 464 this.traceMessage(TraceFlags.AutodiscoverConfiguration, 465 String.format("Redirection URL found: '%s'", 466 redirectUrl.getParam().toString())); 467 468 return true; 469 } 470 } catch (URISyntaxException ex) { 471 this 472 .traceMessage( 473 TraceFlags.AutodiscoverConfiguration, 474 String 475 .format( 476 "Invalid redirection URL " + 477 "was returned: '%s'", 478 location)); 479 return false; 480 } 481 } 482 } 483 return false; 484 } 485 486 /** 487 * Calls the legacy Autodiscover service to retrieve configuration settings. 488 * 489 * @param <TSettings> the generic type 490 * @param cls the cls 491 * @param emailAddress The email address to retrieve configuration settings for. 492 * @return The requested configuration settings. 493 * @throws Exception the exception 494 */ 495 protected <TSettings extends ConfigurationSettingsBase> 496 TSettings getLegacyUserSettings( 497 Class<TSettings> cls, String emailAddress) throws Exception { 498 /*int currentHop = 1; 499 return this.internalGetConfigurationSettings(cls, emailAddress, 500 currentHop);*/ 501 502 // If Url is specified, call service directly. 503 if (this.url != null) { 504 // this.Uri is intended for Autodiscover SOAP service, convert to Legacy endpoint URL. 505 URI autodiscoverUrl = new URI(this.url.toString() + AutodiscoverLegacyPath); 506 return this.getLegacyUserSettingsAtUrl(cls, emailAddress, autodiscoverUrl); 507 } 508 509 // If Domain is specified, figure out the endpoint Url and call service. 510 else if (!(this.domain == null || this.domain.isEmpty())) { 511 URI autodiscoverUrl = new URI(String.format(AutodiscoverLegacyHttpsUrl, this.domain)); 512 return this.getLegacyUserSettingsAtUrl(cls, 513 emailAddress, autodiscoverUrl); 514 } else { 515 // No Url or Domain specified, need to 516 //figure out which endpoint to use. 517 int currentHop = 1; 518 OutParam<Integer> outParam = new OutParam<Integer>(); 519 outParam.setParam(currentHop); 520 List<String> redirectionEmailAddresses = new ArrayList<String>(); 521 return this.internalGetLegacyUserSettings( 522 cls, 523 emailAddress, 524 redirectionEmailAddresses, 525 outParam); 526 } 527 } 528 529 /** 530 * Calls the Autodiscover service to retrieve configuration settings. 531 * 532 * @param <TSettings> the generic type 533 * @param cls the cls 534 * @param emailAddress The email address to retrieve configuration settings for. 535 * @param currentHop Current number of redirection urls/addresses attempted so far. 536 * @return The requested configuration settings. 537 * @throws Exception the exception 538 */ 539 private <TSettings extends ConfigurationSettingsBase> 540 TSettings internalGetLegacyUserSettings( 541 Class<TSettings> cls, 542 String emailAddress, 543 List<String> redirectionEmailAddresses, 544 OutParam<Integer> currentHop) 545 throws Exception { 546 String domainName = EwsUtilities.domainFromEmailAddress(emailAddress); 547 548 int scpUrlCount; 549 OutParam<Integer> outParamInt = new OutParam<Integer>(); 550 List<URI> urls = this.getAutodiscoverServiceUrls(domainName, outParamInt); 551 scpUrlCount = outParamInt.getParam(); 552 if (urls.size() == 0) { 553 throw new ServiceValidationException( 554 "This Autodiscover request requires that either the Domain or Url be specified."); 555 } 556 557 // Assume caller is not inside the Intranet, regardless of whether SCP 558 // Urls 559 // were returned or not. SCP Urls are only relevent if one of them 560 // returns 561 // valid Autodiscover settings. 562 this.isExternal = true; 563 564 int currentUrlIndex = 0; 565 566 // Used to save exception for later reporting. 567 Exception delayedException = null; 568 TSettings settings; 569 570 do { 571 URI autodiscoverUrl = urls.get(currentUrlIndex); 572 boolean isScpUrl = currentUrlIndex < scpUrlCount; 573 574 try { 575 settings = this.getLegacyUserSettingsAtUrl(cls, 576 emailAddress, autodiscoverUrl); 577 578 switch (settings.getResponseType()) { 579 case Success: 580 // Not external if Autodiscover endpoint found via SCP 581 // returned the settings. 582 if (isScpUrl) { 583 this.isExternal = false; 584 } 585 this.url = autodiscoverUrl; 586 return settings; 587 case RedirectUrl: 588 if (currentHop.getParam() < AutodiscoverMaxRedirections) { 589 currentHop.setParam(currentHop.getParam() + 1); 590 591 this 592 .traceMessage( 593 TraceFlags.AutodiscoverResponse, 594 String 595 .format( 596 "Autodiscover " + 597 "service " + 598 "returned " + 599 "redirection URL '%s'.", 600 settings 601 .getRedirectTarget())); 602 603 urls.add(currentUrlIndex, new URI( 604 settings.getRedirectTarget())); 605 606 break; 607 } else { 608 throw new MaximumRedirectionHopsExceededException(); 609 } 610 case RedirectAddress: 611 if (currentHop.getParam() < AutodiscoverMaxRedirections) { 612 currentHop.setParam(currentHop.getParam() + 1); 613 614 this 615 .traceMessage( 616 TraceFlags.AutodiscoverResponse, 617 String 618 .format( 619 "Autodiscover " + 620 "service " + 621 "returned " + 622 "redirection email " + 623 "address '%s'.", 624 settings 625 .getRedirectTarget())); 626 // Bug E14:255576 If this email address was already tried, we may have a loop 627 // in SCP lookups. Disable consideration of SCP records. 628 this.disableScpLookupIfDuplicateRedirection( 629 settings.getRedirectTarget(), 630 redirectionEmailAddresses); 631 632 return this.internalGetLegacyUserSettings(cls, 633 settings.getRedirectTarget(), 634 redirectionEmailAddresses, 635 currentHop); 636 } else { 637 throw new MaximumRedirectionHopsExceededException(); 638 } 639 case Error: 640 // Don't treat errors from an SCP-based Autodiscover service 641 // to be conclusive. 642 // We'll try the next one and record the error for later. 643 if (isScpUrl) { 644 this 645 .traceMessage( 646 TraceFlags.AutodiscoverConfiguration, 647 "Error returned by " + 648 "Autodiscover service " + 649 "found via SCP, treating " + 650 "as inconclusive."); 651 652 delayedException = new AutodiscoverRemoteException( 653 "The Autodiscover service returned an error.", settings.getError()); 654 currentUrlIndex++; 655 } else { 656 throw new AutodiscoverRemoteException("The Autodiscover service returned an error.", settings.getError()); 657 } 658 break; 659 default: 660 EwsUtilities 661 .ewsAssert(false, "Autodiscover.GetConfigurationSettings", 662 "An unexpected error has occured. This code path should never be reached."); 663 break; 664 } 665 } catch (XMLStreamException ex) { 666 this.traceMessage(TraceFlags.AutodiscoverConfiguration, String 667 .format("%s failed: XML parsing error: %s", url, ex 668 .getMessage())); 669 670 // The content at the URL wasn't a valid response, let's try the 671 // next. 672 currentUrlIndex++; 673 } catch (IOException ex) { 674 this.traceMessage( 675 TraceFlags.AutodiscoverConfiguration, 676 String.format("%s failed: I/O error: %s", 677 url, ex.getMessage())); 678 679 // The content at the URL wasn't a valid response, let's try the next. 680 currentUrlIndex++; 681 } catch (Exception ex) { 682 HttpWebRequest response = null; 683 URI redirectUrl; 684 OutParam<URI> outParam1 = new OutParam<URI>(); 685 if ((response != null) && 686 this.tryGetRedirectionResponse(response, outParam1)) { 687 redirectUrl = outParam1.getParam(); 688 this.traceMessage(TraceFlags.AutodiscoverConfiguration, 689 String.format( 690 "Host returned a redirection to url %s", 691 redirectUrl.toString())); 692 693 currentHop.setParam(currentHop.getParam() + 1); 694 urls.add(currentUrlIndex, redirectUrl); 695 } else { 696 if (response != null) { 697 this.processHttpErrorResponse(response, ex); 698 699 } 700 701 this.traceMessage(TraceFlags.AutodiscoverConfiguration, 702 String.format("%s failed: %s (%s)", url, ex 703 .getClass().getName(), ex.getMessage())); 704 705 // The url did not work, let's try the next. 706 currentUrlIndex++; 707 } 708 } 709 } while (currentUrlIndex < urls.size()); 710 711 // If we got this far it's because none of the URLs we tried have 712 // worked. As a next-to-last chance, use GetRedirectUrl to 713 // try to get a redirection URL using an HTTP GET on a non-SSL 714 // Autodiscover endpoint. If successful, use this 715 // redirection URL to get the configuration settings for this email 716 // address. (This will be a common scenario for 717 // DataCenter deployments). 718 URI redirectionUrl = this.getRedirectUrl(domainName); 719 OutParam<TSettings> outParam = new OutParam<TSettings>(); 720 if ((redirectionUrl != null) 721 && this.tryLastChanceHostRedirection(cls, emailAddress, 722 redirectionUrl, outParam)) { 723 settings = outParam.getParam(); 724 return settings; 725 } else { 726 // Getting a redirection URL from an HTTP GET failed too. As a last 727 // chance, try to get an appropriate SRV Record 728 // using DnsQuery. If successful, use this redirection URL to get 729 // the configuration settings for this email address. 730 redirectionUrl = this.getRedirectionUrlFromDnsSrvRecord(domainName); 731 if ((redirectionUrl != null) 732 && this.tryLastChanceHostRedirection(cls, emailAddress, 733 redirectionUrl, outParam)) { 734 return outParam.getParam(); 735 } 736 737 // If there was an earlier exception, throw it. 738 if (delayedException != null) { 739 throw delayedException; 740 } 741 742 throw new AutodiscoverLocalException("The Autodiscover service couldn't be located."); 743 } 744 } 745 746 /** 747 * Get an autodiscover SRV record in DNS and construct autodiscover URL. 748 * 749 * @param domainName Name of the domain. 750 * @return Autodiscover URL (may be null if lookup failed) 751 * @throws Exception the exception 752 */ 753 protected URI getRedirectionUrlFromDnsSrvRecord(String domainName) 754 throws Exception { 755 756 this 757 .traceMessage( 758 TraceFlags.AutodiscoverConfiguration, 759 String 760 .format( 761 "Trying to get Autodiscover host " + 762 "from DNS SRV record for %s.", 763 domainName)); 764 765 String hostname = this.dnsClient 766 .findAutodiscoverHostFromSrv(domainName); 767 if (!(hostname == null || hostname.isEmpty())) { 768 this 769 .traceMessage(TraceFlags.AutodiscoverConfiguration, 770 String.format( 771 "Autodiscover host %s was returned.", 772 hostname)); 773 774 return new URI(String.format(AutodiscoverLegacyHttpsUrl, 775 hostname)); 776 } else { 777 this.traceMessage(TraceFlags.AutodiscoverConfiguration, 778 "No matching Autodiscover DNS SRV records were found."); 779 780 return null; 781 } 782 } 783 784 /** 785 * Tries to get Autodiscover settings using redirection Url. 786 * 787 * @param <TSettings> the generic type 788 * @param cls the cls 789 * @param emailAddress The email address. 790 * @param redirectionUrl Redirection Url. 791 * @param settings The settings. 792 * @return boolean The boolean. 793 * @throws AutodiscoverLocalException the autodiscover local exception 794 * @throws AutodiscoverRemoteException the autodiscover remote exception 795 * @throws Exception the exception 796 */ 797 private <TSettings extends ConfigurationSettingsBase> boolean 798 tryLastChanceHostRedirection( 799 Class<TSettings> cls, String emailAddress, URI redirectionUrl, 800 OutParam<TSettings> settings) throws AutodiscoverLocalException, 801 AutodiscoverRemoteException, Exception { 802 List<String> redirectionEmailAddresses = new ArrayList<String>(); 803 804 // Bug 60274: Performing a non-SSL HTTP GET to retrieve a redirection 805 // URL is potentially unsafe. We allow the caller 806 // to specify delegate to be called to determine whether we are allowed 807 // to use the redirection URL. 808 if (this 809 .callRedirectionUrlValidationCallback(redirectionUrl.toString())) { 810 for (int currentHop = 0; currentHop < AutodiscoverService.AutodiscoverMaxRedirections; currentHop++) { 811 try { 812 settings.setParam(this.getLegacyUserSettingsAtUrl(cls, 813 emailAddress, redirectionUrl)); 814 815 switch (settings.getParam().getResponseType()) { 816 case Success: 817 return true; 818 case Error: 819 throw new AutodiscoverRemoteException("The Autodiscover service returned an error.", settings.getParam() 820 .getError()); 821 case RedirectAddress: 822 // If this email address was already tried, 823 //we may have a loop 824 // in SCP lookups. Disable consideration of SCP records. 825 this.disableScpLookupIfDuplicateRedirection(settings.getParam().getRedirectTarget(), 826 redirectionEmailAddresses); 827 OutParam<Integer> outParam = new OutParam<Integer>(); 828 outParam.setParam(currentHop); 829 settings.setParam( 830 this.internalGetLegacyUserSettings(cls, 831 emailAddress, 832 redirectionEmailAddresses, 833 outParam)); 834 currentHop = outParam.getParam(); 835 return true; 836 case RedirectUrl: 837 try { 838 redirectionUrl = new URI(settings.getParam() 839 .getRedirectTarget()); 840 } catch (URISyntaxException ex) { 841 this 842 .traceMessage( 843 TraceFlags. 844 AutodiscoverConfiguration, 845 String 846 .format( 847 "Service " + 848 "returned " + 849 "invalid " + 850 "redirection " + 851 "URL %s", 852 settings 853 .getParam() 854 .getRedirectTarget())); 855 return false; 856 } 857 break; 858 default: 859 String failureMessage = String.format( 860 "Autodiscover call at %s failed with error %s, target %s", 861 redirectionUrl, 862 settings.getParam().getResponseType(), 863 settings.getParam().getRedirectTarget()); 864 this.traceMessage( 865 TraceFlags.AutodiscoverConfiguration, failureMessage); 866 867 return false; 868 } 869 } catch (XMLStreamException ex) { 870 // If the response is malformed, it wasn't a valid 871 // Autodiscover endpoint. 872 this 873 .traceMessage(TraceFlags.AutodiscoverConfiguration, 874 String.format( 875 "%s failed: XML parsing error: %s", 876 redirectionUrl.toString(), ex 877 .getMessage())); 878 return false; 879 } catch (IOException ex) { 880 this.traceMessage( 881 TraceFlags.AutodiscoverConfiguration, 882 String.format("%s failed: I/O error: %s", 883 redirectionUrl, ex.getMessage())); 884 return false; 885 } catch (Exception ex) { 886 // TODO: BUG response is always null 887 HttpWebRequest response = null; 888 OutParam<URI> outParam = new OutParam<URI>(); 889 if ((response != null) 890 && this.tryGetRedirectionResponse(response, 891 outParam)) { 892 redirectionUrl = outParam.getParam(); 893 this 894 .traceMessage( 895 TraceFlags.AutodiscoverConfiguration, 896 String 897 .format( 898 "Host returned a " + 899 "redirection" + 900 " to url %s", 901 redirectionUrl)); 902 903 } else { 904 if (response != null) { 905 this.processHttpErrorResponse(response, ex); 906 } 907 908 this 909 .traceMessage( 910 TraceFlags.AutodiscoverConfiguration, 911 String.format("%s failed: %s (%s)", 912 url, ex.getClass().getName(), 913 ex.getMessage())); 914 return false; 915 } 916 } 917 } 918 } 919 920 return false; 921 } 922 923 /** 924 * Disables SCP lookup if duplicate email address redirection. 925 * 926 * @param emailAddress The email address to use. 927 * @param redirectionEmailAddresses The list of prior redirection email addresses. 928 */ 929 private void disableScpLookupIfDuplicateRedirection( 930 String emailAddress, 931 List<String> redirectionEmailAddresses) { 932 // SMTP addresses are case-insensitive so entries are converted to lower-case. 933 emailAddress = emailAddress.toLowerCase(); 934 935 if (redirectionEmailAddresses.contains(emailAddress)) { 936 this.enableScpLookup = false; 937 } else { 938 redirectionEmailAddresses.add(emailAddress); 939 } 940 } 941 942 /** 943 * Gets user settings from Autodiscover legacy endpoint. 944 * 945 * @param emailAddress The email address to use. 946 * @param requestedSettings The requested settings. 947 * @return GetUserSettingsResponse 948 * @throws Exception on error 949 */ 950 protected GetUserSettingsResponse internalGetLegacyUserSettings( 951 String emailAddress, 952 List<UserSettingName> requestedSettings) throws Exception { 953 // Cannot call legacy Autodiscover service with WindowsLive and other WSSecurity-based credential 954 if ((this.getCredentials() != null) && (this.getCredentials() instanceof WSSecurityBasedCredentials)) { 955 throw new AutodiscoverLocalException( 956 "WindowsLiveCredentials can't be used with this Autodiscover endpoint."); 957 } 958 959 OutlookConfigurationSettings settings = this.getLegacyUserSettings( 960 OutlookConfigurationSettings.class, 961 emailAddress); 962 963 964 965 return settings.convertSettings(emailAddress, requestedSettings); 966 } 967 968 /** 969 * Calls the SOAP Autodiscover service 970 * for user settings for a single SMTP address. 971 * 972 * @param smtpAddress SMTP address. 973 * @param requestedSettings The requested settings. 974 * @return GetUserSettingsResponse 975 * @throws Exception on error 976 */ 977 protected GetUserSettingsResponse internalGetSoapUserSettings( 978 String smtpAddress, 979 List<UserSettingName> requestedSettings) throws Exception { 980 List<String> smtpAddresses = new ArrayList<String>(); 981 smtpAddresses.add(smtpAddress); 982 983 List<String> redirectionEmailAddresses = new ArrayList<String>(); 984 redirectionEmailAddresses.add(smtpAddress.toLowerCase()); 985 986 for (int currentHop = 0; currentHop < AutodiscoverService.AutodiscoverMaxRedirections; currentHop++) { 987 GetUserSettingsResponse response = this.getUserSettings(smtpAddresses, 988 requestedSettings).getTResponseAtIndex(0); 989 990 switch (response.getErrorCode()) { 991 case RedirectAddress: 992 this.traceMessage( 993 TraceFlags.AutodiscoverResponse, 994 String.format("Autodiscover service returned redirection email address '%s'.", 995 response.getRedirectTarget())); 996 997 smtpAddresses.clear(); 998 smtpAddresses.add(response.getRedirectTarget(). 999 toLowerCase()); 1000 this.url = null; 1001 this.domain = null; 1002 1003 // If this email address was already tried, 1004 //we may have a loop 1005 // in SCP lookups. Disable consideration of SCP records. 1006 this.disableScpLookupIfDuplicateRedirection(response.getRedirectTarget(), 1007 redirectionEmailAddresses); 1008 break; 1009 1010 case RedirectUrl: 1011 this.traceMessage( 1012 TraceFlags.AutodiscoverResponse, 1013 String.format("Autodiscover service returned redirection URL '%s'.", 1014 response.getRedirectTarget())); 1015 1016 //this.url = new URI(response.getRedirectTarget()); 1017 this.url = this.getCredentials().adjustUrl(new URI(response.getRedirectTarget())); 1018 break; 1019 1020 case NoError: 1021 default: 1022 return response; 1023 } 1024 } 1025 1026 throw new AutodiscoverLocalException("The Autodiscover service couldn't be located."); 1027 } 1028 1029 /** 1030 * Gets the user settings using Autodiscover SOAP service. 1031 * 1032 * @param smtpAddresses The SMTP addresses of the users. 1033 * @param settings The settings. 1034 * @return GetUserSettingsResponseCollection Object. 1035 * @throws Exception the exception 1036 */ 1037 protected GetUserSettingsResponseCollection getUserSettings( 1038 final List<String> smtpAddresses, List<UserSettingName> settings) 1039 throws Exception { 1040 EwsUtilities.validateParam(smtpAddresses, "smtpAddresses"); 1041 EwsUtilities.validateParam(settings, "settings"); 1042 1043 return this.getSettings( 1044 GetUserSettingsResponseCollection.class, UserSettingName.class, 1045 smtpAddresses, settings, null, this, 1046 new IFuncDelegate<String>() { 1047 public String func() throws FormatException { 1048 return EwsUtilities 1049 .domainFromEmailAddress(smtpAddresses.get(0)); 1050 } 1051 }); 1052 } 1053 1054 /** 1055 * Gets user or domain settings using Autodiscover SOAP service. 1056 * 1057 * @param <TGetSettingsResponseCollection> the generic type 1058 * @param <TSettingName> the generic type 1059 * @param cls the cls 1060 * @param cls1 the cls1 1061 * @param identities Either the domains or the SMTP addresses of the users. 1062 * @param settings The settings. 1063 * @param requestedVersion Requested version of the Exchange service. 1064 * @param getSettingsMethod The method to use. 1065 * @param getDomainMethod The method to calculate the domain value. 1066 * @return TGetSettingsResponse Collection. 1067 * @throws Exception the exception 1068 */ 1069 private <TGetSettingsResponseCollection, TSettingName> 1070 TGetSettingsResponseCollection getSettings( 1071 Class<TGetSettingsResponseCollection> cls, 1072 Class<TSettingName> cls1, 1073 List<String> identities, 1074 List<TSettingName> settings, 1075 ExchangeVersion requestedVersion, 1076 IFunctionDelegate<List<String>, List<TSettingName>, 1077 TGetSettingsResponseCollection> getSettingsMethod, 1078 IFuncDelegate<String> getDomainMethod) throws Exception { 1079 TGetSettingsResponseCollection response; 1080 1081 // Autodiscover service only exists in E14 or later. 1082 if (this.getRequestedServerVersion().compareTo( 1083 MinimumRequestVersionForAutoDiscoverSoapService) < 0) { 1084 throw new ServiceVersionException(String.format( 1085 "The Autodiscover service only supports %s or a later version.", 1086 MinimumRequestVersionForAutoDiscoverSoapService)); 1087 } 1088 1089 // If Url is specified, call service directly. 1090 if (this.url != null) { 1091 URI autodiscoverUrl = this.url; 1092 response = getSettingsMethod.func(identities, settings, 1093 requestedVersion, this.url); 1094 this.url = autodiscoverUrl; 1095 return response; 1096 } 1097 // If Domain is specified, determine endpoint Url and call service. 1098 else if (!(this.domain == null || this.domain.isEmpty())) { 1099 URI autodiscoverUrl = this.getAutodiscoverEndpointUrl(this.domain); 1100 response = getSettingsMethod.func(identities, settings, 1101 requestedVersion, 1102 autodiscoverUrl); 1103 1104 // If we got this far, response was successful, set Url. 1105 this.url = autodiscoverUrl; 1106 return response; 1107 } 1108 // No Url or Domain specified, need to figure out which endpoint(s) to 1109 // try. 1110 else { 1111 // Assume caller is not inside the Intranet, regardless of whether 1112 // SCP Urls 1113 // were returned or not. SCP Urls are only relevent if one of them 1114 // returns 1115 // valid Autodiscover settings. 1116 this.isExternal = true; 1117 1118 URI autodiscoverUrl; 1119 1120 String domainName = getDomainMethod.func(); 1121 int scpHostCount; 1122 OutParam<Integer> outParam = new OutParam<Integer>(); 1123 List<String> hosts = this.getAutodiscoverServiceHosts(domainName, 1124 outParam); 1125 scpHostCount = outParam.getParam(); 1126 if (hosts.size() == 0) { 1127 throw new ServiceValidationException( 1128 "This Autodiscover request requires that either the Domain or Url be specified."); 1129 } 1130 1131 for (int currentHostIndex = 0; currentHostIndex < hosts.size(); currentHostIndex++) { 1132 String host = hosts.get(currentHostIndex); 1133 boolean isScpHost = currentHostIndex < scpHostCount; 1134 OutParam<URI> outParams = new OutParam<URI>(); 1135 if (this.tryGetAutodiscoverEndpointUrl(host, outParams)) { 1136 autodiscoverUrl = outParams.getParam(); 1137 response = getSettingsMethod.func(identities, settings, 1138 requestedVersion, 1139 autodiscoverUrl); 1140 1141 // If we got this far, the response was successful, set Url. 1142 this.url = autodiscoverUrl; 1143 1144 // Not external if Autodiscover endpoint found via SCP 1145 // returned the settings. 1146 if (isScpHost) { 1147 this.isExternal = false; 1148 } 1149 1150 return response; 1151 } 1152 } 1153 1154 // Next-to-last chance: try unauthenticated GET over HTTP to be 1155 // redirected to appropriate service endpoint. 1156 autodiscoverUrl = this.getRedirectUrl(domainName); 1157 OutParam<URI> outParamUrl = new OutParam<URI>(); 1158 if ((autodiscoverUrl != null) && 1159 this 1160 .callRedirectionUrlValidationCallback( 1161 autodiscoverUrl.toString()) && 1162 this.tryGetAutodiscoverEndpointUrl(autodiscoverUrl 1163 .getHost(), outParamUrl)) { 1164 autodiscoverUrl = outParamUrl.getParam(); 1165 response = getSettingsMethod.func(identities, settings, 1166 requestedVersion, 1167 autodiscoverUrl); 1168 1169 // If we got this far, the response was successful, set Url. 1170 this.url = autodiscoverUrl; 1171 1172 return response; 1173 } 1174 1175 // Last Chance: try to read autodiscover SRV Record from DNS. If we 1176 // find one, use 1177 // the hostname returned to construct an Autodiscover endpoint URL. 1178 autodiscoverUrl = this 1179 .getRedirectionUrlFromDnsSrvRecord(domainName); 1180 if ((autodiscoverUrl != null) && 1181 this 1182 .callRedirectionUrlValidationCallback( 1183 autodiscoverUrl.toString()) && 1184 this.tryGetAutodiscoverEndpointUrl(autodiscoverUrl 1185 .getHost(), outParamUrl)) { 1186 autodiscoverUrl = outParamUrl.getParam(); 1187 response = getSettingsMethod.func(identities, settings, 1188 requestedVersion, 1189 autodiscoverUrl); 1190 1191 // If we got this far, the response was successful, set Url. 1192 this.url = autodiscoverUrl; 1193 1194 return response; 1195 } else { 1196 throw new AutodiscoverLocalException("The Autodiscover service couldn't be located."); 1197 } 1198 } 1199 } 1200 1201 /** 1202 * Gets settings for one or more users. 1203 * 1204 * @param smtpAddresses The SMTP addresses of the users. 1205 * @param settings The settings. 1206 * @param requestedVersion Requested version of the Exchange service. 1207 * @param autodiscoverUrl The autodiscover URL. 1208 * @return GetUserSettingsResponse collection. 1209 * @throws ServiceLocalException the service local exception 1210 * @throws Exception the exception 1211 */ 1212 private GetUserSettingsResponseCollection internalGetUserSettings( 1213 List<String> smtpAddresses, List<UserSettingName> settings, 1214 ExchangeVersion requestedVersion, 1215 URI autodiscoverUrl) throws ServiceLocalException, Exception { 1216 // The response to GetUserSettings can be a redirection. Execute 1217 // GetUserSettings until we get back 1218 // a valid response or we've followed too many redirections. 1219 for (int currentHop = 0; currentHop < AutodiscoverService.AutodiscoverMaxRedirections; currentHop++) { 1220 GetUserSettingsRequest request = new GetUserSettingsRequest(this, 1221 autodiscoverUrl); 1222 request.setSmtpAddresses(smtpAddresses); 1223 request.setSettings(settings); 1224 GetUserSettingsResponseCollection response = request.execute(); 1225 1226 // Did we get redirected? 1227 if (response.getErrorCode() == AutodiscoverErrorCode.RedirectUrl 1228 && response.getRedirectionUrl() != null) { 1229 this.traceMessage( 1230 TraceFlags.AutodiscoverConfiguration, 1231 String.format("Request to %s returned redirection to %s", 1232 autodiscoverUrl.toString(), response.getRedirectionUrl())); 1233 1234 autodiscoverUrl = response.getRedirectionUrl(); 1235 } else { 1236 return response; 1237 } 1238 } 1239 1240 this.traceMessage(TraceFlags.AutodiscoverConfiguration, String.format( 1241 "Maximum number of redirection hops %d exceeded", 1242 AutodiscoverMaxRedirections)); 1243 1244 throw new MaximumRedirectionHopsExceededException(); 1245 } 1246 1247 /** 1248 * Gets the domain settings using Autodiscover SOAP service. 1249 * 1250 * @param domains The domains. 1251 * @param settings The settings. 1252 * @param requestedVersion Requested version of the Exchange service. 1253 * @return GetDomainSettingsResponse collection. 1254 * @throws Exception the exception 1255 */ 1256 protected GetDomainSettingsResponseCollection getDomainSettings( 1257 final List<String> domains, List<DomainSettingName> settings, 1258 ExchangeVersion requestedVersion) 1259 throws Exception { 1260 EwsUtilities.validateParam(domains, "domains"); 1261 EwsUtilities.validateParam(settings, "settings"); 1262 1263 return this.getSettings( 1264 GetDomainSettingsResponseCollection.class, 1265 DomainSettingName.class, domains, settings, 1266 requestedVersion, this, 1267 new IFuncDelegate<String>() { 1268 public String func() { 1269 return domains.get(0); 1270 } 1271 }); 1272 } 1273 1274 /** 1275 * Gets settings for one or more domains. 1276 * 1277 * @param domains The domains. 1278 * @param settings The settings. 1279 * @param requestedVersion Requested version of the Exchange service. 1280 * @param autodiscoverUrl The autodiscover URL. 1281 * @return GetDomainSettingsResponse Collection. 1282 * @throws ServiceLocalException the service local exception 1283 * @throws Exception the exception 1284 */ 1285 private GetDomainSettingsResponseCollection internalGetDomainSettings( 1286 List<String> domains, List<DomainSettingName> settings, 1287 ExchangeVersion requestedVersion, 1288 URI autodiscoverUrl) throws ServiceLocalException, Exception { 1289 // The response to GetDomainSettings can be a redirection. Execute 1290 // GetDomainSettings until we get back 1291 // a valid response or we've followed too many redirections. 1292 for (int currentHop = 0; currentHop < AutodiscoverService.AutodiscoverMaxRedirections; currentHop++) { 1293 GetDomainSettingsRequest request = new GetDomainSettingsRequest( 1294 this, autodiscoverUrl); 1295 request.setDomains(domains); 1296 request.setSettings(settings); 1297 request.setRequestedVersion(requestedVersion); 1298 GetDomainSettingsResponseCollection response = request.execute(); 1299 1300 // Did we get redirected? 1301 if (response.getErrorCode() == AutodiscoverErrorCode.RedirectUrl 1302 && response.getRedirectionUrl() != null) { 1303 autodiscoverUrl = response.getRedirectionUrl(); 1304 } else { 1305 return response; 1306 } 1307 } 1308 1309 this.traceMessage(TraceFlags.AutodiscoverConfiguration, String.format( 1310 "Maximum number of redirection hops %d exceeded", 1311 AutodiscoverMaxRedirections)); 1312 1313 throw new MaximumRedirectionHopsExceededException(); 1314 } 1315 1316 /** 1317 * Gets the autodiscover endpoint URL. 1318 * 1319 * @param host The host. 1320 * @return URI The URI. 1321 * @throws Exception the exception 1322 */ 1323 private URI getAutodiscoverEndpointUrl(String host) throws Exception { 1324 URI autodiscoverUrl = null; 1325 OutParam<URI> outParam = new OutParam<URI>(); 1326 if (this.tryGetAutodiscoverEndpointUrl(host, outParam)) { 1327 return autodiscoverUrl; 1328 } else { 1329 throw new AutodiscoverLocalException( 1330 "No appropriate Autodiscover SOAP or WS-Security endpoint is available."); 1331 } 1332 } 1333 1334 /** 1335 * Tries the get Autodiscover Service endpoint URL. 1336 * 1337 * @param host The host. 1338 * @param url the url 1339 * @return boolean The boolean. 1340 * @throws Exception the exception 1341 */ 1342 private boolean tryGetAutodiscoverEndpointUrl(String host, 1343 OutParam<URI> url) 1344 throws Exception { 1345 EnumSet<AutodiscoverEndpoints> endpoints; 1346 OutParam<EnumSet<AutodiscoverEndpoints>> outParam = 1347 new OutParam<EnumSet<AutodiscoverEndpoints>>(); 1348 if (this.tryGetEnabledEndpointsForHost(host, outParam)) { 1349 endpoints = outParam.getParam(); 1350 url 1351 .setParam(new URI(String.format(AutodiscoverSoapHttpsUrl, 1352 host))); 1353 1354 // Make sure that at least one of the non-legacy endpoints is 1355 // available. 1356 if ((!endpoints.contains(AutodiscoverEndpoints.Soap)) && 1357 (!endpoints.contains( 1358 AutodiscoverEndpoints.WsSecurity)) 1359 // (endpoints .contains( AutodiscoverEndpoints.WSSecuritySymmetricKey) ) && 1360 //(endpoints .contains( AutodiscoverEndpoints.WSSecurityX509Cert)) 1361 ) { 1362 this 1363 .traceMessage( 1364 TraceFlags.AutodiscoverConfiguration, 1365 String 1366 .format( 1367 "No Autodiscover endpoints " + 1368 "are available for host %s", 1369 host)); 1370 1371 return false; 1372 } 1373 1374 // If we have WLID credential, make sure that we have a WS-Security 1375 // endpoint 1376 /* 1377 if (this.getCredentials() instanceof WindowsLiveCredentials) { 1378 if (endpoints.contains(AutodiscoverEndpoints.WsSecurity)) { 1379 this 1380 .traceMessage( 1381 TraceFlags.AutodiscoverConfiguration, 1382 String 1383 .format( 1384 "No Autodiscover " + 1385 "WS-Security " + 1386 "endpoint is available" + 1387 " for host %s", 1388 host)); 1389 1390 return false; 1391 } else { 1392 url.setParam(new URI(String.format( 1393 AutodiscoverSoapWsSecurityHttpsUrl, host))); 1394 } 1395 } 1396 else if (this.getCredentials() instanceof PartnerTokenCredentials) 1397 { 1398 if (endpoints.contains( AutodiscoverEndpoints.WSSecuritySymmetricKey)) 1399 { 1400 this.traceMessage( 1401 TraceFlags.AutodiscoverConfiguration, 1402 String.format("No Autodiscover WS-Security/SymmetricKey endpoint is available for host {0}", host)); 1403 1404 return false; 1405 } 1406 else 1407 { 1408 url.setParam( new URI(String.format(AutodiscoverSoapWsSecuritySymmetricKeyHttpsUrl, host))); 1409 } 1410 } 1411 else if (this.getCredentials()instanceof X509CertificateCredentials) 1412 { 1413 if ((endpoints.contains(AutodiscoverEndpoints.WSSecurityX509Cert)) 1414 { 1415 this.traceMessage( 1416 TraceFlags.AutodiscoverConfiguration, 1417 String.format("No Autodiscover WS-Security/X509Cert endpoint is available for host {0}", host)); 1418 1419 return false; 1420 } 1421 else 1422 { 1423 url.setParam( new URI(String.format(AutodiscoverSoapWsSecurityX509CertHttpsUrl, host))); 1424 } 1425 } 1426 */ 1427 return true; 1428 1429 1430 } else { 1431 this 1432 .traceMessage( 1433 TraceFlags.AutodiscoverConfiguration, 1434 String 1435 .format( 1436 "No Autodiscover endpoints " + 1437 "are available for host %s", 1438 host)); 1439 1440 return false; 1441 } 1442 } 1443 1444 /** 1445 * Gets the list of autodiscover service URLs. 1446 * 1447 * @param domainName Domain name. 1448 * @param scpHostCount Count of hosts found via SCP lookup. 1449 * @return List of Autodiscover URLs. 1450 * @throws java.net.URISyntaxException the URI Syntax exception 1451 */ 1452 protected List<URI> getAutodiscoverServiceUrls(String domainName, 1453 OutParam<Integer> scpHostCount) throws URISyntaxException { 1454 List<URI> urls; 1455 1456 urls = new ArrayList<URI>(); 1457 1458 scpHostCount.setParam(urls.size()); 1459 1460 // As a fallback, add autodiscover URLs base on the domain name. 1461 urls.add(new URI(String.format(AutodiscoverLegacyHttpsUrl, 1462 domainName))); 1463 urls.add(new URI(String.format(AutodiscoverLegacyHttpsUrl, 1464 "autodiscover." + domainName))); 1465 1466 return urls; 1467 } 1468 1469 /** 1470 * Gets the list of autodiscover service hosts. 1471 * 1472 * @param domainName Domain name. 1473 * @param outParam the out param 1474 * @return List of hosts. 1475 * @throws java.net.URISyntaxException the uRI syntax exception 1476 * @throws ClassNotFoundException the class not found exception 1477 */ 1478 protected List<String> getAutodiscoverServiceHosts(String domainName, 1479 OutParam<Integer> outParam) throws URISyntaxException, 1480 ClassNotFoundException { 1481 1482 List<URI> urls = this.getAutodiscoverServiceUrls(domainName, outParam); 1483 List<String> lst = new ArrayList<String>(); 1484 for (URI url : urls) { 1485 lst.add(url.getHost()); 1486 } 1487 return lst; 1488 } 1489 1490 /** 1491 * Gets the enabled autodiscover endpoints on a specific host. 1492 * 1493 * @param host The host. 1494 * @param endpoints Endpoints found for host. 1495 * @return Flags indicating which endpoints are enabled. 1496 * @throws Exception the exception 1497 */ 1498 private boolean tryGetEnabledEndpointsForHost(String host, 1499 OutParam<EnumSet<AutodiscoverEndpoints>> endpoints) throws Exception { 1500 this.traceMessage(TraceFlags.AutodiscoverConfiguration, String.format( 1501 "Determining which endpoints are enabled for host %s", host)); 1502 1503 // We may get redirected to another host. And therefore need to limit the number of redirections we'll 1504 // tolerate. 1505 for (int currentHop = 0; currentHop < AutodiscoverMaxRedirections; currentHop++) { 1506 URI autoDiscoverUrl = new URI(String.format(AutodiscoverLegacyHttpsUrl, host)); 1507 1508 endpoints.setParam(EnumSet.of(AutodiscoverEndpoints.None)); 1509 1510 HttpWebRequest request = null; 1511 try { 1512 request = new HttpClientWebRequest(httpClient, httpContext); 1513 request.setProxy(getWebProxy()); 1514 1515 try { 1516 request.setUrl(autoDiscoverUrl.toURL()); 1517 } catch (MalformedURLException e) { 1518 String strErr = String.format("Incorrect format : %s", url); 1519 throw new ServiceLocalException(strErr); 1520 } 1521 1522 request.setRequestMethod("GET"); 1523 request.setAllowAutoRedirect(false); 1524 request.setPreAuthenticate(false); 1525 request.setUseDefaultCredentials(this.getUseDefaultCredentials()); 1526 1527 prepareCredentials(request); 1528 1529 request.prepareConnection(); 1530 try { 1531 request.executeRequest(); 1532 } catch (IOException e) { 1533 return false; 1534 } 1535 1536 OutParam<URI> outParam = new OutParam<URI>(); 1537 if (this.tryGetRedirectionResponse(request, outParam)) { 1538 URI redirectUrl = outParam.getParam(); 1539 this.traceMessage(TraceFlags.AutodiscoverConfiguration, 1540 String.format("Host returned redirection to host '%s'", redirectUrl.getHost())); 1541 1542 host = redirectUrl.getHost(); 1543 } else { 1544 endpoints.setParam(this.getEndpointsFromHttpWebResponse(request)); 1545 1546 this.traceMessage(TraceFlags.AutodiscoverConfiguration, 1547 String.format("Host returned enabled endpoint flags: %s", endpoints.getParam().toString())); 1548 1549 return true; 1550 } 1551 } finally { 1552 if (request != null) { 1553 try { 1554 request.close(); 1555 } catch (Exception e) { 1556 // Connection can't be closed. We'll ignore this... 1557 } 1558 } 1559 } 1560 } 1561 1562 this.traceMessage(TraceFlags.AutodiscoverConfiguration, 1563 String.format("Maximum number of redirection hops %d exceeded", AutodiscoverMaxRedirections)); 1564 1565 throw new MaximumRedirectionHopsExceededException(); 1566 } 1567 1568 /** 1569 * Gets the endpoints from HTTP web response. 1570 * 1571 * @param request the request 1572 * @return Endpoints enabled. 1573 * @throws EWSHttpException the EWS http exception 1574 */ 1575 private EnumSet<AutodiscoverEndpoints> getEndpointsFromHttpWebResponse( 1576 HttpWebRequest request) throws EWSHttpException { 1577 EnumSet<AutodiscoverEndpoints> endpoints = EnumSet 1578 .noneOf(AutodiscoverEndpoints.class); 1579 endpoints.add(AutodiscoverEndpoints.Legacy); 1580 1581 if (!(request.getResponseHeaders().get( 1582 AutodiscoverSoapEnabledHeaderName) == null || request 1583 .getResponseHeaders().get(AutodiscoverSoapEnabledHeaderName) 1584 .isEmpty())) { 1585 endpoints.add(AutodiscoverEndpoints.Soap); 1586 } 1587 if (!(request.getResponseHeaders().get( 1588 AutodiscoverWsSecurityEnabledHeaderName) == null || request 1589 .getResponseHeaders().get( 1590 AutodiscoverWsSecurityEnabledHeaderName).isEmpty())) { 1591 endpoints.add(AutodiscoverEndpoints.WsSecurity); 1592 } 1593 1594 /* if (! (request.getResponseHeaders().get( 1595 AutodiscoverWsSecuritySymmetricKeyEnabledHeaderName) !=null || request 1596 .getResponseHeaders().get( 1597 AutodiscoverWsSecuritySymmetricKeyEnabledHeaderName).isEmpty())) 1598 { 1599 endpoints .add( AutodiscoverEndpoints.WSSecuritySymmetricKey); 1600 } 1601 if (!(request.getResponseHeaders().get( 1602 AutodiscoverWsSecurityX509CertEnabledHeaderName)!=null || 1603 request.getResponseHeaders().get( 1604 AutodiscoverWsSecurityX509CertEnabledHeaderName).isEmpty())) 1605 1606 { 1607 endpoints .add(AutodiscoverEndpoints.WSSecurityX509Cert); 1608 }*/ 1609 1610 return endpoints; 1611 } 1612 1613 /** 1614 * Traces the response. 1615 * 1616 * @param request the request 1617 * @param memoryStream the memory stream 1618 * @throws XMLStreamException the XML stream exception 1619 * @throws IOException signals that an I/O exception has occurred. 1620 * @throws EWSHttpException the EWS http exception 1621 */ 1622 public void traceResponse(HttpWebRequest request, ByteArrayOutputStream memoryStream) throws XMLStreamException, 1623 IOException, EWSHttpException { 1624 this.processHttpResponseHeaders( 1625 TraceFlags.AutodiscoverResponseHttpHeaders, request); 1626 String contentType = request.getResponseContentType(); 1627 if (!(contentType == null || contentType.isEmpty())) { 1628 contentType = contentType.toLowerCase(); 1629 if (contentType.toLowerCase().startsWith("text/") || 1630 contentType.toLowerCase(). 1631 startsWith("application/soap")) { 1632 this.traceXml(TraceFlags.AutodiscoverResponse, memoryStream); 1633 } else { 1634 this.traceMessage(TraceFlags.AutodiscoverResponse, 1635 "Non-textual response"); 1636 } 1637 } 1638 } 1639 1640 /** 1641 * Creates an HttpWebRequest instance and initializes it with the 1642 * appropriate parameters, based on the configuration of this service 1643 * object. 1644 * 1645 * @param url The URL that the HttpWebRequest should target 1646 * @return HttpWebRequest The HttpWebRequest 1647 * @throws ServiceLocalException the service local exception 1648 * @throws java.net.URISyntaxException the uRI syntax exception 1649 */ 1650 public HttpWebRequest prepareHttpWebRequestForUrl(URI url) 1651 throws ServiceLocalException, URISyntaxException { 1652 return this.prepareHttpWebRequestForUrl(url, false, 1653 // acceptGzipEncoding 1654 false); // allowAutoRedirect 1655 } 1656 1657 /** 1658 * Calls the redirection URL validation callback. If the redirection URL 1659 * validation callback is null, use the default callback which does not 1660 * allow following any redirections. 1661 * 1662 * @param redirectionUrl The redirection URL. 1663 * @return True if redirection should be followed. 1664 * @throws AutodiscoverLocalException the autodiscover local exception 1665 */ 1666 private boolean callRedirectionUrlValidationCallback(String redirectionUrl) 1667 throws AutodiscoverLocalException { 1668 IAutodiscoverRedirectionUrl callback = 1669 (this.redirectionUrlValidationCallback == null) ? this 1670 : this.redirectionUrlValidationCallback; 1671 return callback 1672 .autodiscoverRedirectionUrlValidationCallback(redirectionUrl); 1673 } 1674 1675 /** 1676 * Processes an HTTP error response. 1677 * 1678 * @param httpWebResponse The HTTP web response. 1679 * @throws Exception the exception 1680 */ 1681 @Override public void processHttpErrorResponse(HttpWebRequest httpWebResponse, Exception webException) throws Exception { 1682 this.internalProcessHttpErrorResponse( 1683 httpWebResponse, 1684 webException, 1685 TraceFlags.AutodiscoverResponseHttpHeaders, 1686 TraceFlags.AutodiscoverResponse); 1687 } 1688 1689 /* 1690 * (non-Javadoc) 1691 * 1692 * @see microsoft.exchange.webservices.AutodiscoverRedirectionUrlInterface# 1693 * autodiscoverRedirectionUrlValidationCallback(java.lang.String) 1694 */ 1695 public boolean autodiscoverRedirectionUrlValidationCallback( 1696 String redirectionUrl) throws AutodiscoverLocalException { 1697 return defaultAutodiscoverRedirectionUrlValidationCallback( 1698 redirectionUrl); 1699 } 1700 1701 /** 1702 * Initializes a new instance of the "AutodiscoverService" class. 1703 * 1704 * @throws ArgumentException on validation error 1705 */ 1706 public AutodiscoverService() throws ArgumentException { 1707 this(ExchangeVersion.Exchange2010); 1708 } 1709 1710 /** 1711 * Initializes a new instance of the "AutodiscoverService" class. 1712 * 1713 * @param requestedServerVersion The requested server version 1714 * @throws ArgumentException on validation error 1715 */ 1716 public AutodiscoverService(ExchangeVersion requestedServerVersion) 1717 throws ArgumentException { 1718 this(null, null, requestedServerVersion); 1719 } 1720 1721 /** 1722 * Initializes a new instance of the "AutodiscoverService" class. 1723 * 1724 * @param domain The domain that will be used to determine the URL of the service 1725 * @throws ArgumentException on validation error 1726 */ 1727 public AutodiscoverService(String domain) throws ArgumentException { 1728 this(null, domain); 1729 } 1730 1731 /** 1732 * Initializes a new instance of the "AutodiscoverService" class. 1733 * 1734 * @param domain The domain that will be used to determine the URL of the service 1735 * @param requestedServerVersion The requested server version 1736 * @throws ArgumentException on validation error 1737 */ 1738 public AutodiscoverService(String domain, 1739 ExchangeVersion requestedServerVersion) throws ArgumentException { 1740 this(null, domain, requestedServerVersion); 1741 } 1742 1743 /** 1744 * Initializes a new instance of the "AutodiscoverService" class. 1745 * 1746 * @param url The URL of the service 1747 * @throws ArgumentException on validation error 1748 */ 1749 public AutodiscoverService(URI url) throws ArgumentException { 1750 this(url, url.getHost()); 1751 } 1752 1753 /** 1754 * Initializes a new instance of the "AutodiscoverService" class. 1755 * 1756 * @param url The URL of the service 1757 * @param requestedServerVersion The requested server version 1758 * @throws ArgumentException on validation error 1759 */ 1760 public AutodiscoverService(URI url, 1761 ExchangeVersion requestedServerVersion) throws ArgumentException { 1762 this(url, url.getHost(), requestedServerVersion); 1763 } 1764 1765 /** 1766 * Initializes a new instance of the "AutodiscoverService" class. 1767 * 1768 * @param url The URL of the service 1769 * @param domain The domain that will be used to determine the URL of the service 1770 * @throws ArgumentException on validation error 1771 */ 1772 public AutodiscoverService(URI url, String domain) 1773 throws ArgumentException { 1774 super(); 1775 EwsUtilities.validateDomainNameAllowNull(domain, "domain"); 1776 this.url = url; 1777 this.domain = domain; 1778 this.dnsClient = new AutodiscoverDnsClient(this); 1779 } 1780 1781 /** 1782 * Initializes a new instance of the "AutodiscoverService" class. 1783 * 1784 * @param url The URL of the service. 1785 * @param domain The domain that will be used to determine the URL of the 1786 * service. 1787 * @param requestedServerVersion The requested server version. 1788 * @throws ArgumentException on validation error 1789 */ 1790 public AutodiscoverService(URI url, String domain, 1791 ExchangeVersion requestedServerVersion) throws ArgumentException { 1792 super(requestedServerVersion); 1793 EwsUtilities.validateDomainNameAllowNull(domain, "domain"); 1794 1795 this.url = url; 1796 this.domain = domain; 1797 this.dnsClient = new AutodiscoverDnsClient(this); 1798 } 1799 1800 /** 1801 * Initializes a new instance of the AutodiscoverService class. 1802 * 1803 * @param service The other service. 1804 * @param requestedServerVersion The requested server version. 1805 */ 1806 public AutodiscoverService(ExchangeServiceBase service, 1807 ExchangeVersion requestedServerVersion) { 1808 super(service, requestedServerVersion); 1809 this.dnsClient = new AutodiscoverDnsClient(this); 1810 } 1811 1812 /** 1813 * Initializes a new instance of the "AutodiscoverService" class. 1814 * 1815 * @param service The service. 1816 */ 1817 public AutodiscoverService(ExchangeServiceBase service) { 1818 super(service, service.getRequestedServerVersion()); 1819 } 1820 1821 /** 1822 * Retrieves the specified settings for single SMTP address. 1823 * <p>This method will run the entire Autodiscover "discovery" 1824 * algorithm and will follow address and URL redirections.</p> 1825 1826 * @param userSmtpAddress The SMTP addresses of the user. 1827 * @param userSettingNames The user setting names. 1828 * @return A UserResponse object containing the requested settings for the 1829 * specified user. 1830 * @throws Exception on error 1831 */ 1832 public GetUserSettingsResponse getUserSettings(String userSmtpAddress, 1833 UserSettingName... userSettingNames) throws Exception { 1834 List<UserSettingName> requestedSettings = new ArrayList<UserSettingName>(); 1835 requestedSettings.addAll(Arrays.asList(userSettingNames)); 1836 1837 if (userSmtpAddress == null || userSmtpAddress.isEmpty()) { 1838 throw new ServiceValidationException("A valid SMTP address must be specified."); 1839 } 1840 1841 if (requestedSettings.size() == 0) { 1842 throw new ServiceValidationException("At least one setting must be requested."); 1843 } 1844 1845 if (this.getRequestedServerVersion().compareTo(MinimumRequestVersionForAutoDiscoverSoapService) < 0) { 1846 return this.internalGetLegacyUserSettings(userSmtpAddress, 1847 requestedSettings); 1848 } else { 1849 return this.internalGetSoapUserSettings(userSmtpAddress, 1850 requestedSettings); 1851 } 1852 1853 } 1854 1855 /** 1856 * Retrieves the specified settings for a set of users. 1857 * 1858 * @param userSmtpAddresses the user smtp addresses 1859 * @param userSettingNames The user setting names. 1860 * @return A GetUserSettingsResponseCollection object containing the 1861 * response for each individual user. 1862 * @throws Exception the exception 1863 */ 1864 public GetUserSettingsResponseCollection getUsersSettings( 1865 Iterable<String> userSmtpAddresses, 1866 UserSettingName... userSettingNames) throws Exception { 1867 if (this.getRequestedServerVersion().compareTo(MinimumRequestVersionForAutoDiscoverSoapService) < 0) { 1868 throw new ServiceVersionException( 1869 String.format("The Autodiscover service only supports %s or a later version.", 1870 MinimumRequestVersionForAutoDiscoverSoapService)); 1871 } 1872 List<String> smtpAddresses = new ArrayList<String>(); 1873 smtpAddresses.addAll((Collection<? extends String>) userSmtpAddresses); 1874 List<UserSettingName> settings = new ArrayList<UserSettingName>(); 1875 settings.addAll(Arrays.asList(userSettingNames)); 1876 return this.getUserSettings(smtpAddresses, settings); 1877 } 1878 1879 /** 1880 * Retrieves the specified settings for a domain. 1881 * 1882 * @param domain The domain. 1883 * @param requestedVersion Requested version of the Exchange service. 1884 * @param domainSettingNames The domain setting names. 1885 * @return A DomainResponse object containing the requested settings for the 1886 * specified domain. 1887 * @throws Exception the exception 1888 */ 1889 public GetDomainSettingsResponse getDomainSettings(String domain, 1890 ExchangeVersion requestedVersion, 1891 DomainSettingName... domainSettingNames) throws Exception { 1892 List<String> domains = new ArrayList<String>(1); 1893 domains.add(domain); 1894 1895 List<DomainSettingName> settings = new ArrayList<DomainSettingName>(); 1896 settings.addAll(Arrays.asList(domainSettingNames)); 1897 1898 return this.getDomainSettings(domains, settings, requestedVersion). 1899 getTResponseAtIndex(0); 1900 } 1901 1902 /** 1903 * Retrieves the specified settings for a set of domains. 1904 * 1905 * @param domains the domains 1906 * @param requestedVersion Requested version of the Exchange service. 1907 * @param domainSettingNames The domain setting names. 1908 * @return A GetDomainSettingsResponseCollection object containing the 1909 * response for each individual domain. 1910 * @throws Exception the exception 1911 */ 1912 public GetDomainSettingsResponseCollection getDomainSettings( 1913 Iterable<String> domains, ExchangeVersion requestedVersion, 1914 DomainSettingName... domainSettingNames) 1915 throws Exception { 1916 List<DomainSettingName> settings = new ArrayList<DomainSettingName>(); 1917 settings.addAll(Arrays.asList(domainSettingNames)); 1918 1919 List<String> domainslst = new ArrayList<String>(); 1920 domainslst.addAll((Collection<? extends String>) domains); 1921 1922 return this.getDomainSettings(domainslst, settings, requestedVersion); 1923 } 1924 1925 /** 1926 * Gets the domain this service is bound to. When this property is 1927 * set, the domain name is used to automatically determine the Autodiscover service URL. 1928 * 1929 * @return the domain 1930 */ 1931 public String getDomain() { 1932 return this.domain; 1933 } 1934 1935 /** 1936 * Sets the domain this service is bound to. When this property is 1937 * set, the domain 1938 * name is used to automatically determine the Autodiscover service URL. 1939 * 1940 * @param value the new domain 1941 * @throws ArgumentException on validation error 1942 */ 1943 public void setDomain(String value) throws ArgumentException { 1944 EwsUtilities.validateDomainNameAllowNull(value, "Domain"); 1945 1946 // If Domain property is set to non-null value, Url property is nulled. 1947 if (value != null) { 1948 this.url = null; 1949 } 1950 this.domain = value; 1951 } 1952 1953 /** 1954 * Gets the url this service is bound to. 1955 * 1956 * @return the url 1957 */ 1958 public URI getUrl() { 1959 return this.url; 1960 } 1961 1962 /** 1963 * Sets the url this service is bound to. 1964 * 1965 * @param value the new url 1966 */ 1967 public void setUrl(URI value) { 1968 // If Url property is set to non-null value, Domain property is set to 1969 // host portion of Url. 1970 if (value != null) { 1971 this.domain = value.getHost(); 1972 } 1973 this.url = value; 1974 } 1975 1976 public Boolean isExternal() { 1977 return this.isExternal; 1978 } 1979 1980 protected void setIsExternal(Boolean value) { 1981 this.isExternal = value; 1982 } 1983 1984 1985 /** 1986 * Gets the redirection url validation callback. 1987 * 1988 * @return the redirection url validation callback 1989 */ 1990 public IAutodiscoverRedirectionUrl 1991 getRedirectionUrlValidationCallback() { 1992 return this.redirectionUrlValidationCallback; 1993 } 1994 1995 /** 1996 * Sets the redirection url validation callback. 1997 * 1998 * @param value the new redirection url validation callback 1999 */ 2000 public void setRedirectionUrlValidationCallback( 2001 IAutodiscoverRedirectionUrl value) { 2002 this.redirectionUrlValidationCallback = value; 2003 } 2004 2005 /** 2006 * Gets the dns server address. 2007 * 2008 * @return the dns server address 2009 */ 2010 protected String getDnsServerAddress() { 2011 return this.dnsServerAddress; 2012 } 2013 2014 /** 2015 * Sets the dns server address. 2016 * 2017 * @param value the new dns server address 2018 */ 2019 protected void setDnsServerAddress(String value) { 2020 this.dnsServerAddress = value; 2021 } 2022 2023 /** 2024 * Gets a value indicating whether the AutodiscoverService should 2025 * perform SCP (ServiceConnectionPoint) record lookup when determining 2026 * the Autodiscover service URL. 2027 * 2028 * @return the enable scp lookup 2029 */ 2030 public boolean getEnableScpLookup() { 2031 return this.enableScpLookup; 2032 } 2033 2034 /** 2035 * Sets the enable scp lookup. 2036 * 2037 * @param value the new enable scp lookup 2038 */ 2039 public void setEnableScpLookup(boolean value) { 2040 this.enableScpLookup = value; 2041 } 2042 2043 /* 2044 * (non-Javadoc) 2045 * 2046 * @see 2047 * microsoft.exchange.webservices.FuncDelegateInterface#func(java.util.List, 2048 * java.util.List, java.net.URI) 2049 */ 2050 @Override 2051 public Object func(List arg1, List arg2, ExchangeVersion arg3, URI arg4) 2052 throws ServiceLocalException, Exception { 2053 if (arg2.get(0).getClass().equals(DomainSettingName.class)) { 2054 return internalGetDomainSettings(arg1, arg2, arg3, arg4); 2055 } else if (arg2.get(0).getClass().equals(UserSettingName.class)) { 2056 return internalGetUserSettings(arg1, arg2, arg3, arg4); 2057 } else { 2058 return null; 2059 } 2060 } 2061 2062}