LEFT | RIGHT |
1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 15 matching lines...) Expand all Loading... |
26 import com.google.enterprise.adaptor.DocIdPusher; | 26 import com.google.enterprise.adaptor.DocIdPusher; |
27 import com.google.enterprise.adaptor.GroupPrincipal; | 27 import com.google.enterprise.adaptor.GroupPrincipal; |
28 import com.google.enterprise.adaptor.IOHelper; | 28 import com.google.enterprise.adaptor.IOHelper; |
29 import com.google.enterprise.adaptor.PollingIncrementalAdaptor; | 29 import com.google.enterprise.adaptor.PollingIncrementalAdaptor; |
30 import com.google.enterprise.adaptor.Request; | 30 import com.google.enterprise.adaptor.Request; |
31 import com.google.enterprise.adaptor.Response; | 31 import com.google.enterprise.adaptor.Response; |
32 import com.google.enterprise.adaptor.UserPrincipal; | 32 import com.google.enterprise.adaptor.UserPrincipal; |
33 import com.google.enterprise.adaptor.sharepoint.RareModificationCache.CachedList
; | 33 import com.google.enterprise.adaptor.sharepoint.RareModificationCache.CachedList
; |
34 import com.google.enterprise.adaptor.sharepoint.RareModificationCache.CachedVirt
ualServer; | 34 import com.google.enterprise.adaptor.sharepoint.RareModificationCache.CachedVirt
ualServer; |
35 import com.google.enterprise.adaptor.sharepoint.RareModificationCache.CachedWeb; | 35 import com.google.enterprise.adaptor.sharepoint.RareModificationCache.CachedWeb; |
36 import com.google.enterprise.adaptor.sharepoint.SharePointAuthenticationHandler.
AuthenticationFactoryImpl; | |
37 import com.google.enterprise.adaptor.sharepoint.SiteDataClient.CursorPaginator; | 36 import com.google.enterprise.adaptor.sharepoint.SiteDataClient.CursorPaginator; |
38 import com.google.enterprise.adaptor.sharepoint.SiteDataClient.Paginator; | 37 import com.google.enterprise.adaptor.sharepoint.SiteDataClient.Paginator; |
39 import com.google.enterprise.adaptor.sharepoint.SiteDataClient.XmlProcessingExce
ption; | 38 import com.google.enterprise.adaptor.sharepoint.SiteDataClient.XmlProcessingExce
ption; |
| 39 import com.microsoft.schemas.sharepoint.soap.authentication.AuthenticationSoap; |
40 | 40 |
41 import com.microsoft.schemas.sharepoint.soap.ContentDatabase; | 41 import com.microsoft.schemas.sharepoint.soap.ContentDatabase; |
42 import com.microsoft.schemas.sharepoint.soap.ContentDatabases; | 42 import com.microsoft.schemas.sharepoint.soap.ContentDatabases; |
43 import com.microsoft.schemas.sharepoint.soap.Files; | 43 import com.microsoft.schemas.sharepoint.soap.Files; |
44 import com.microsoft.schemas.sharepoint.soap.FolderData; | 44 import com.microsoft.schemas.sharepoint.soap.FolderData; |
45 import com.microsoft.schemas.sharepoint.soap.Folders; | 45 import com.microsoft.schemas.sharepoint.soap.Folders; |
46 import com.microsoft.schemas.sharepoint.soap.GroupDescription; | 46 import com.microsoft.schemas.sharepoint.soap.GroupDescription; |
47 import com.microsoft.schemas.sharepoint.soap.GroupMembership; | 47 import com.microsoft.schemas.sharepoint.soap.GroupMembership; |
48 import com.microsoft.schemas.sharepoint.soap.Item; | 48 import com.microsoft.schemas.sharepoint.soap.Item; |
49 import com.microsoft.schemas.sharepoint.soap.ItemData; | 49 import com.microsoft.schemas.sharepoint.soap.ItemData; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 | 97 |
98 /** | 98 /** |
99 * SharePoint Adaptor for the GSA. | 99 * SharePoint Adaptor for the GSA. |
100 */ | 100 */ |
101 public class SharePointAdaptor extends AbstractAdaptor | 101 public class SharePointAdaptor extends AbstractAdaptor |
102 implements PollingIncrementalAdaptor { | 102 implements PollingIncrementalAdaptor { |
103 /** Charset used in generated HTML responses. */ | 103 /** Charset used in generated HTML responses. */ |
104 private static final Charset CHARSET = Charset.forName("UTF-8"); | 104 private static final Charset CHARSET = Charset.forName("UTF-8"); |
105 private static final String XMLNS_DIRECTORY | 105 private static final String XMLNS_DIRECTORY |
106 = "http://schemas.microsoft.com/sharepoint/soap/directory/"; | 106 = "http://schemas.microsoft.com/sharepoint/soap/directory/"; |
| 107 ·· |
| 108 /** SharePoint's namespace. */ |
| 109 private static final String XMLNS |
| 110 = "http://schemas.microsoft.com/sharepoint/soap/"; |
107 | 111 |
108 /** | 112 /** |
109 * The data element within a self-describing XML blob. See | 113 * The data element within a self-describing XML blob. See |
110 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms675943.aspx . | 114 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms675943.aspx . |
111 */ | 115 */ |
112 private static final QName DATA_ELEMENT | 116 private static final QName DATA_ELEMENT |
113 = new QName("urn:schemas-microsoft-com:rowset", "data"); | 117 = new QName("urn:schemas-microsoft-com:rowset", "data"); |
114 /** | 118 /** |
115 * The row element within a self-describing XML blob. See | 119 * The row element within a self-describing XML blob. See |
116 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms675943.aspx . | 120 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms675943.aspx . |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 .build(new MemberIdsCacheLoader()); | 218 .build(new MemberIdsCacheLoader()); |
215 private LoadingCache<String, MemberIdMapping> siteUserCache | 219 private LoadingCache<String, MemberIdMapping> siteUserCache |
216 = CacheBuilder.newBuilder() | 220 = CacheBuilder.newBuilder() |
217 .refreshAfterWrite(30, TimeUnit.MINUTES) | 221 .refreshAfterWrite(30, TimeUnit.MINUTES) |
218 .expireAfterWrite(45, TimeUnit.MINUTES) | 222 .expireAfterWrite(45, TimeUnit.MINUTES) |
219 .build(new SiteUserCacheLoader()); | 223 .build(new SiteUserCacheLoader()); |
220 private RareModificationCache rareModCache; | 224 private RareModificationCache rareModCache; |
221 /** Map from Content Database GUID to last known Change Token for that DB. */ | 225 /** Map from Content Database GUID to last known Change Token for that DB. */ |
222 private final ConcurrentSkipListMap<String, String> contentDatabaseChangeId | 226 private final ConcurrentSkipListMap<String, String> contentDatabaseChangeId |
223 = new ConcurrentSkipListMap<String, String>(); | 227 = new ConcurrentSkipListMap<String, String>(); |
224 /** Production factory for all SiteDataSoap communication objects. */ | 228 private final SoapFactory soapFactory; |
225 private final SiteDataClient.SiteDataFactory siteDataFactory; | |
226 private final UserGroupFactory userGroupFactory; | |
227 /** Client for initiating raw HTTP connections. */ | 229 /** Client for initiating raw HTTP connections. */ |
228 private final HttpClient httpClient; | 230 private final HttpClient httpClient; |
229 private final Callable<ExecutorService> executorFactory; | 231 private final Callable<ExecutorService> executorFactory; |
230 private ExecutorService executor; | 232 private ExecutorService executor; |
231 private boolean xmlValidation; | 233 private boolean xmlValidation; |
232 private long maxIndexableSize; | 234 private long maxIndexableSize; |
| 235 ·· |
| 236 private ScheduledThreadPoolExecutor scheduledExecutor· |
| 237 = new ScheduledThreadPoolExecutor(1); |
233 /** Authenticator instance that authenticates with SP. */ | 238 /** Authenticator instance that authenticates with SP. */ |
234 /** | 239 /** |
235 * Cached value of whether we are talking to a SP 2010 server or not. This | 240 * Cached value of whether we are talking to a SP 2010 server or not. This |
236 * value is used in case of error in certain situations. | 241 * value is used in case of error in certain situations. |
237 */ | 242 */ |
238 private boolean isSp2010; | 243 private boolean isSp2010; |
239 private NtlmAuthenticator ntlmAuthenticator; | 244 private NtlmAuthenticator ntlmAuthenticator; |
240 /** | 245 /** |
241 * Lock for refreshing MemberIdMapping. We use a unique lock because it is | 246 * Lock for refreshing MemberIdMapping. We use a unique lock because it is |
242 * held while waiting on I/O. | 247 * held while waiting on I/O. |
243 */ | 248 */ |
244 private final Object refreshMemberIdMappingLock = new Object(); | 249 private final Object refreshMemberIdMappingLock = new Object(); |
245 ·· | 250 ·· |
246 private static SharePointAuthenticationHandler authenticationHandler; | 251 private FormsAuthenticationHandler authenticationHandler; |
247 | 252 |
248 public SharePointAdaptor() { | 253 public SharePointAdaptor() { |
249 this(new SiteDataClient.SiteDataFactoryImpl(), new UserGroupFactoryImpl(), | 254 this(new SoapFactoryImpl(), new HttpClientImpl(), |
250 new HttpClientImpl(), new CachedThreadPoolFactory()); | 255 new CachedThreadPoolFactory()); |
251 } | 256 } |
252 | 257 |
253 @VisibleForTesting | 258 @VisibleForTesting |
254 SharePointAdaptor(SiteDataClient.SiteDataFactory siteDataFactory, | 259 SharePointAdaptor(SoapFactory soapFactory, HttpClient httpClient, |
255 UserGroupFactory userGroupFactory, HttpClient httpClient, | |
256 Callable<ExecutorService> executorFactory) { | 260 Callable<ExecutorService> executorFactory) { |
257 if (siteDataFactory == null || httpClient == null | 261 if (soapFactory == null || httpClient == null || executorFactory == null) { |
258 || userGroupFactory == null || executorFactory == null) { | |
259 throw new NullPointerException(); | 262 throw new NullPointerException(); |
260 } | 263 } |
261 this.siteDataFactory = siteDataFactory; | 264 this.soapFactory = soapFactory; |
262 this.userGroupFactory = userGroupFactory; | |
263 this.httpClient = httpClient; | 265 this.httpClient = httpClient; |
264 this.executorFactory = executorFactory; | 266 this.executorFactory = executorFactory; |
265 } | 267 } |
266 | 268 |
267 /** | 269 /** |
268 * Method to cause static initialization of the class. Mainly useful to tests | 270 * Method to cause static initialization of the class. Mainly useful to tests |
269 * so that the cost of initializing the class does not count toward the first | 271 * so that the cost of initializing the class does not count toward the first |
270 * test case run. | 272 * test case run. |
271 */ | 273 */ |
272 @VisibleForTesting | 274 @VisibleForTesting |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 | 306 |
305 log.log(Level.CONFIG, "VirtualServer: {0}", virtualServer); | 307 log.log(Level.CONFIG, "VirtualServer: {0}", virtualServer); |
306 log.log(Level.CONFIG, "Username: {0}", username); | 308 log.log(Level.CONFIG, "Username: {0}", username); |
307 log.log(Level.CONFIG, "Password: {0}", password); | 309 log.log(Level.CONFIG, "Password: {0}", password); |
308 | 310 |
309 ntlmAuthenticator = new NtlmAuthenticator(username, password); | 311 ntlmAuthenticator = new NtlmAuthenticator(username, password); |
310 // Unfortunately, this is a JVM-wide modification. | 312 // Unfortunately, this is a JVM-wide modification. |
311 Authenticator.setDefault(ntlmAuthenticator); | 313 Authenticator.setDefault(ntlmAuthenticator); |
312 URL virtualServerUrl = new URL(virtualServer); | 314 URL virtualServerUrl = new URL(virtualServer); |
313 ntlmAuthenticator.addPermitForHost(virtualServerUrl); | 315 ntlmAuthenticator.addPermitForHost(virtualServerUrl); |
314 authenticationHandler = new SharePointAuthenticationHandler(virtualServer,· | 316 String authenticationEndPoint· |
315 virtualServerUrl.getPort(),username, password,· | 317 = virtualServer + "/_vti_bin/Authentication.asmx"; |
316 new ScheduledThreadPoolExecutor(1), new AuthenticationFactoryImpl()); | 318 authenticationHandler = new FormsAuthenticationHandler(username, |
| 319 password, scheduledExecutor, |
| 320 soapFactory.newAuthentication(authenticationEndPoint)); |
317 authenticationHandler.start(); | 321 authenticationHandler.start(); |
318 executor = executorFactory.call(); | 322 executor = executorFactory.call(); |
319 try { | 323 try { |
320 SiteDataClient virtualServerSiteDataClient = | 324 SiteDataClient virtualServerSiteDataClient = |
321 getSiteAdaptor(virtualServer, virtualServer).getSiteDataClient(); | 325 getSiteAdaptor(virtualServer, virtualServer).getSiteDataClient(); |
322 rareModCache | 326 rareModCache |
323 = new RareModificationCache(virtualServerSiteDataClient, executor); | 327 = new RareModificationCache(virtualServerSiteDataClient, executor); |
324 | 328 |
325 // Test out configuration. | 329 // Test out configuration. |
326 virtualServerSiteDataClient.getContentVirtualServer(); | 330 virtualServerSiteDataClient.getContentVirtualServer(); |
327 } catch (Exception e) { | 331 } catch (Exception e) { |
328 // Don't leak the executor. | 332 // Don't leak the executor. |
329 destroy(); | 333 destroy(); |
330 throw e; | 334 throw e; |
331 } | 335 } |
332 } | 336 } |
333 | 337 |
334 @Override | 338 @Override |
335 public void destroy() { | 339 public void destroy() { |
336 executor.shutdown(); | 340 executor.shutdown(); |
| 341 scheduledExecutor.shutdown(); |
337 try { | 342 try { |
338 executor.awaitTermination(10, TimeUnit.SECONDS); | 343 executor.awaitTermination(10, TimeUnit.SECONDS); |
| 344 scheduledExecutor.awaitTermination(10, TimeUnit.SECONDS); |
339 } catch (InterruptedException ex) { | 345 } catch (InterruptedException ex) { |
340 Thread.currentThread().interrupt(); | 346 Thread.currentThread().interrupt(); |
341 } | 347 } |
| 348 ···· |
342 executor.shutdownNow(); | 349 executor.shutdownNow(); |
| 350 scheduledExecutor.shutdownNow(); |
343 executor = null; | 351 executor = null; |
| 352 scheduledExecutor = null; |
344 rareModCache = null; | 353 rareModCache = null; |
345 Authenticator.setDefault(null); | 354 Authenticator.setDefault(null); |
346 ntlmAuthenticator = null; | 355 ntlmAuthenticator = null; |
347 } | 356 } |
348 | 357 |
349 @Override | 358 @Override |
350 public void getDocContent(Request request, Response response) | 359 public void getDocContent(Request request, Response response) |
351 throws IOException { | 360 throws IOException { |
352 log.entering("SharePointAdaptor", "getDocContent", | 361 log.entering("SharePointAdaptor", "getDocContent", |
353 new Object[] {request, response}); | 362 new Object[] {request, response}); |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 web = web.substring(0, web.length() - 1); | 500 web = web.substring(0, web.length() - 1); |
492 } | 501 } |
493 SiteAdaptor siteAdaptor = siteAdaptors.get(web); | 502 SiteAdaptor siteAdaptor = siteAdaptors.get(web); |
494 if (siteAdaptor == null) { | 503 if (siteAdaptor == null) { |
495 if (site.endsWith("/")) { | 504 if (site.endsWith("/")) { |
496 // Always end without a '/' for a canonical form. | 505 // Always end without a '/' for a canonical form. |
497 site = site.substring(0, site.length() - 1); | 506 site = site.substring(0, site.length() - 1); |
498 } | 507 } |
499 ntlmAuthenticator.addPermitForHost(new URL(web)); | 508 ntlmAuthenticator.addPermitForHost(new URL(web)); |
500 String endpoint = web + "/_vti_bin/SiteData.asmx"; | 509 String endpoint = web + "/_vti_bin/SiteData.asmx"; |
501 SiteDataSoap siteDataSoap = siteDataFactory.newSiteData(endpoint); | 510 SiteDataSoap siteDataSoap = soapFactory.newSiteData(endpoint); |
502 addFormsAuthenticationCookies((BindingProvider) siteDataSoap); | 511 ······ |
503 | |
504 String endpointUserGroup = site + "/_vti_bin/UserGroup.asmx"; | 512 String endpointUserGroup = site + "/_vti_bin/UserGroup.asmx"; |
505 UserGroupSoap userGroupSoap | 513 UserGroupSoap userGroupSoap = soapFactory.newUserGroup(endpointUserGroup); |
506 = userGroupFactory.newUserGroup(endpointUserGroup); | 514 // JAX-WS RT 2.1.4 doesn't handle headers correctly and always assumes the |
507 addFormsAuthenticationCookies((BindingProvider) userGroupSoap); | 515 // list contains precisely one entry, so we work around it here. |
508 | 516 if (authenticationHandler.isFormsAuthentication()) { |
| 517 addFormsAuthenticationCookies((BindingProvider) siteDataSoap); |
| 518 addFormsAuthenticationCookies((BindingProvider) userGroupSoap);········ |
| 519 } |
509 siteAdaptor = new SiteAdaptor(site, web, siteDataSoap, userGroupSoap, | 520 siteAdaptor = new SiteAdaptor(site, web, siteDataSoap, userGroupSoap, |
510 new MemberIdMappingCallable(site), | 521 new MemberIdMappingCallable(site), |
511 new SiteUserIdMappingCallable(site)); | 522 new SiteUserIdMappingCallable(site)); |
512 siteAdaptors.putIfAbsent(web, siteAdaptor); | 523 siteAdaptors.putIfAbsent(web, siteAdaptor); |
513 siteAdaptor = siteAdaptors.get(web); | 524 siteAdaptor = siteAdaptors.get(web); |
514 } | 525 } |
515 return siteAdaptor; | 526 return siteAdaptor; |
516 } | 527 } |
517 ·· | 528 ·· |
518 private void addFormsAuthenticationCookies(BindingProvider port) { | 529 private void addFormsAuthenticationCookies(BindingProvider port) { |
519 List<String> authenticationCookies· | 530 port.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, |
520 = authenticationHandler.getAuthenticationCookies(); | 531 Collections.singletonMap("Cookie",· |
521 if (authenticationCookies != null && !authenticationCookies.isEmpty()) { | 532 authenticationHandler.getAuthenticationCookies())); |
522 port.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, | |
523 Collections.singletonMap("Cookie", authenticationCookies)); | |
524 } | |
525 } | 533 } |
526 | 534 |
527 static URI spUrlToUri(String url) throws IOException { | 535 static URI spUrlToUri(String url) throws IOException { |
528 // Because SP is silly, the path of the URI is unencoded, but the rest of | 536 // Because SP is silly, the path of the URI is unencoded, but the rest of |
529 // the URI is correct. Thus, we split up the path from the host, and then | 537 // the URI is correct. Thus, we split up the path from the host, and then |
530 // turn them into URIs separately, and then turn everything into a | 538 // turn them into URIs separately, and then turn everything into a |
531 // properly-escaped string. | 539 // properly-escaped string. |
532 String[] parts = url.split("/", 4); | 540 String[] parts = url.split("/", 4); |
533 if (parts.length < 3) { | 541 if (parts.length < 3) { |
534 throw new IllegalArgumentException("Too few '/'s: " + url); | 542 throw new IllegalArgumentException("Too few '/'s: " + url); |
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1200 * security issues, this should only be used after the DocId has been | 1208 * security issues, this should only be used after the DocId has been |
1201 * verified to be a valid document on the SharePoint instance. In addition, | 1209 * verified to be a valid document on the SharePoint instance. In addition, |
1202 * ACLs and other metadata and security measures should be set before making | 1210 * ACLs and other metadata and security measures should be set before making |
1203 * this call. | 1211 * this call. |
1204 */ | 1212 */ |
1205 private void getFileDocContent(Request request, Response response) | 1213 private void getFileDocContent(Request request, Response response) |
1206 throws IOException { | 1214 throws IOException { |
1207 log.entering("SiteAdaptor", "getFileDocContent", | 1215 log.entering("SiteAdaptor", "getFileDocContent", |
1208 new Object[] {request, response}); | 1216 new Object[] {request, response}); |
1209 URI displayUrl = docIdToUri(request.getDocId()); | 1217 URI displayUrl = docIdToUri(request.getDocId()); |
1210 FileInfo fi = httpClient.issueGetRequest(displayUrl.toURL()); | 1218 FileInfo fi = httpClient.issueGetRequest(displayUrl.toURL(), |
| 1219 authenticationHandler.getAuthenticationCookies()); |
1211 if (fi == null) { | 1220 if (fi == null) { |
1212 response.respondNotFound(); | 1221 response.respondNotFound(); |
1213 return; | 1222 return; |
1214 } | 1223 } |
1215 try { | 1224 try { |
1216 response.setDisplayUrl(displayUrl); | 1225 response.setDisplayUrl(displayUrl); |
1217 String contentType = fi.getFirstHeaderWithName("Content-Type"); | 1226 String contentType = fi.getFirstHeaderWithName("Content-Type"); |
1218 if (contentType != null) { | 1227 if (contentType != null) { |
1219 response.setContentType(contentType); | 1228 response.setContentType(contentType); |
1220 } | 1229 } |
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1874 } | 1883 } |
1875 } | 1884 } |
1876 | 1885 |
1877 @VisibleForTesting | 1886 @VisibleForTesting |
1878 interface HttpClient { | 1887 interface HttpClient { |
1879 /** | 1888 /** |
1880 * The caller must call {@code fileInfo.getContents().close()} after use. | 1889 * The caller must call {@code fileInfo.getContents().close()} after use. |
1881 * | 1890 * |
1882 * @return {@code null} if not found, {@code FileInfo} instance otherwise | 1891 * @return {@code null} if not found, {@code FileInfo} instance otherwise |
1883 */ | 1892 */ |
1884 public FileInfo issueGetRequest(URL url) throws IOException; | 1893 public FileInfo issueGetRequest(URL url, List<String> authenticationCookies) |
| 1894 throws IOException; |
1885 } | 1895 } |
1886 | 1896 |
1887 static class HttpClientImpl implements HttpClient { | 1897 static class HttpClientImpl implements HttpClient { |
1888 @Override | 1898 @Override |
1889 public FileInfo issueGetRequest(URL url) throws IOException { | 1899 public FileInfo issueGetRequest(URL url, List<String> authenticationCookies) |
| 1900 throws IOException { |
1890 // Handle Unicode. Java does not properly encode the GET. | 1901 // Handle Unicode. Java does not properly encode the GET. |
1891 try { | 1902 try { |
1892 url = new URL(url.toURI().toASCIIString()); | 1903 url = new URL(url.toURI().toASCIIString()); |
1893 } catch (URISyntaxException ex) { | 1904 } catch (URISyntaxException ex) { |
1894 throw new IOException(ex); | 1905 throw new IOException(ex); |
1895 } | 1906 } |
1896 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); | 1907 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); |
1897 List<String> authenticationCookies | 1908 ····· |
1898 = authenticationHandler.getAuthenticationCookies(); | |
1899 for (String cookie : authenticationCookies) { | 1909 for (String cookie : authenticationCookies) { |
1900 conn.addRequestProperty("Cookie", cookie); | 1910 conn.addRequestProperty("Cookie", cookie); |
1901 } | 1911 } |
1902 conn.setDoInput(true); | 1912 conn.setDoInput(true); |
1903 conn.setDoOutput(false); | 1913 conn.setDoOutput(false); |
1904 if (conn.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { | 1914 if (conn.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { |
1905 return null; | 1915 return null; |
1906 } | 1916 } |
1907 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { | 1917 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { |
1908 throw new IOException("Got status code: " + conn.getResponseCode()); | 1918 throw new IOException("Got status code: " + conn.getResponseCode()); |
1909 } | 1919 } |
1910 List<String> headers = new LinkedList<String>(); | 1920 List<String> headers = new LinkedList<String>(); |
1911 // Start at 1 since index 0 is special. | 1921 // Start at 1 since index 0 is special. |
1912 for (int i = 1;; i++) { | 1922 for (int i = 1;; i++) { |
1913 String key = conn.getHeaderFieldKey(i); | 1923 String key = conn.getHeaderFieldKey(i); |
1914 if (key == null) { | 1924 if (key == null) { |
1915 break; | 1925 break; |
1916 } | 1926 } |
1917 String value = conn.getHeaderField(i); | 1927 String value = conn.getHeaderField(i); |
1918 headers.add(key); | 1928 headers.add(key); |
1919 headers.add(value); | 1929 headers.add(value); |
1920 } | 1930 } |
1921 log.log(Level.FINER, "Response HTTP headers: {0}", headers); | 1931 log.log(Level.FINER, "Response HTTP headers: {0}", headers); |
1922 return new FileInfo.Builder(conn.getInputStream()).setHeaders(headers) | 1932 return new FileInfo.Builder(conn.getInputStream()).setHeaders(headers) |
1923 .build(); | 1933 .build(); |
1924 } | 1934 } |
1925 } | 1935 } |
1926 | 1936 |
1927 @VisibleForTesting | 1937 @VisibleForTesting |
1928 interface UserGroupFactory { | 1938 interface SoapFactory { |
| 1939 /** |
| 1940 * The {@code endpoint} string is a SharePoint URL, meaning that spaces are |
| 1941 * not encoded. |
| 1942 */ |
| 1943 public SiteDataSoap newSiteData(String endpoint) throws IOException; |
| 1944 |
1929 public UserGroupSoap newUserGroup(String endpoint); | 1945 public UserGroupSoap newUserGroup(String endpoint); |
1930 } | 1946 ···· |
1931 | 1947 public AuthenticationSoap newAuthentication(String endpoint); |
1932 static class UserGroupFactoryImpl implements UserGroupFactory { | 1948 } |
| 1949 |
| 1950 @VisibleForTesting |
| 1951 static class SoapFactoryImpl implements SoapFactory { |
| 1952 private final Service siteDataService; |
1933 private final Service userGroupService; | 1953 private final Service userGroupService; |
1934 | 1954 private final Service authenticationService; |
1935 public UserGroupFactoryImpl() { | 1955 |
1936 URL url = UserGroupSoap.class.getResource("UserGroup.wsdl"); | 1956 public SoapFactoryImpl() { |
1937 QName qname = new QName(XMLNS_DIRECTORY, "UserGroup"); | 1957 this.siteDataService = SiteDataClient.createSiteDataService(); |
1938 this.userGroupService = Service.create(url, qname); | 1958 this.userGroupService = Service.create( |
| 1959 UserGroupSoap.class.getResource("UserGroup.wsdl"), |
| 1960 new QName(XMLNS_DIRECTORY, "UserGroup")); |
| 1961 this.authenticationService = Service.create( |
| 1962 AuthenticationSoap.class.getResource("Authentication.wsdl"), |
| 1963 new QName(XMLNS, "Authentication")); |
| 1964 } |
| 1965 |
| 1966 @Override |
| 1967 public SiteDataSoap newSiteData(String endpoint) throws IOException { |
| 1968 EndpointReference endpointRef = new W3CEndpointReferenceBuilder() |
| 1969 .address(SharePointAdaptor.spUrlToUri(endpoint).toString()).build(); |
| 1970 return siteDataService.getPort(endpointRef, SiteDataSoap.class); |
1939 } | 1971 } |
1940 | 1972 |
1941 @Override | 1973 @Override |
1942 public UserGroupSoap newUserGroup(String endpoint) { | 1974 public UserGroupSoap newUserGroup(String endpoint) { |
1943 EndpointReference endpointRef = new W3CEndpointReferenceBuilder() | 1975 EndpointReference endpointRef = new W3CEndpointReferenceBuilder() |
1944 .address(endpoint).build(); | 1976 .address(endpoint).build(); |
1945 return userGroupService.getPort(endpointRef, UserGroupSoap.class); | 1977 return userGroupService.getPort(endpointRef, UserGroupSoap.class); |
| 1978 } |
| 1979 ···· |
| 1980 @Override |
| 1981 public AuthenticationSoap newAuthentication(String endpoint) { |
| 1982 EndpointReference endpointRef = new W3CEndpointReferenceBuilder() |
| 1983 .address(endpoint).build(); |
| 1984 return· |
| 1985 authenticationService.getPort(endpointRef, AuthenticationSoap.class); |
1946 } | 1986 } |
1947 } | 1987 } |
1948 | 1988 |
1949 private static class NtlmAuthenticator extends Authenticator { | 1989 private static class NtlmAuthenticator extends Authenticator { |
1950 private final String username; | 1990 private final String username; |
1951 private final char[] password; | 1991 private final char[] password; |
1952 private final Set<String> permittedHosts = new HashSet<String>(); | 1992 private final Set<String> permittedHosts = new HashSet<String>(); |
1953 | 1993 |
1954 public NtlmAuthenticator(String username, String password) { | 1994 public NtlmAuthenticator(String username, String password) { |
1955 this.username = username; | 1995 this.username = username; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2063 } | 2103 } |
2064 | 2104 |
2065 private static class CachedThreadPoolFactory | 2105 private static class CachedThreadPoolFactory |
2066 implements Callable<ExecutorService> { | 2106 implements Callable<ExecutorService> { |
2067 @Override | 2107 @Override |
2068 public ExecutorService call() { | 2108 public ExecutorService call() { |
2069 return Executors.newCachedThreadPool(); | 2109 return Executors.newCachedThreadPool(); |
2070 } | 2110 } |
2071 } | 2111 } |
2072 } | 2112 } |
LEFT | RIGHT |