Support added for ADFS 2.0 and Live Authentication.
This required additional changes and some refactoring in FormsAuthenticationHandler
Code Review : https://codereview.appspot.com/83730043/
diff --git a/src/com/google/enterprise/adaptor/sharepoint/AdfsHandshakeManager.java b/src/com/google/enterprise/adaptor/sharepoint/AdfsHandshakeManager.java
new file mode 100644
index 0000000..1625484
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/sharepoint/AdfsHandshakeManager.java
@@ -0,0 +1,256 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+package com.google.enterprise.adaptor.sharepoint;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.HttpPostClient;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.HttpPostClientImpl;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.PostResponseInfo;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.SamlHandshakeManager;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * SamlHandshakeManager implementation to support ADFS 2.0
+ * to request ADFS authentication token and extract authentication cookie.
+ */
+public class AdfsHandshakeManager implements SamlHandshakeManager {
+ private static final Logger log
+ = Logger.getLogger(AdfsHandshakeManager.class.getName());
+
+ private static final String DEFAULT_LOGIN = "/_layouts/Authenticate.aspx";
+ private static final String DEFAULT_TRUST = "/_trust";
+
+ protected final String login;
+ protected final String username;
+ protected final String password;
+ protected final String sharePointUrl;
+ protected final String stsendpoint;
+ protected final String stsrealm;
+ protected final HttpPostClient httpClient;
+ protected final String trustLocation;
+ private static final String reqXML
+ = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+ + "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" "
+ + "xmlns:a=\"http://www.w3.org/2005/08/addressing\" "
+ + "xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/"
+ + "oasis-200401-wss-wssecurity-utility-1.0.xsd\"><s:Header>"
+ + "<a:Action s:mustUnderstand=\"1\">"
+ + "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>"
+ + "<a:ReplyTo><a:Address>"
+ + "http://www.w3.org/2005/08/addressing/anonymous</a:Address>"
+ + "</a:ReplyTo><a:To s:mustUnderstand=\"1\">"
+ + "%s</a:To>" // stsendpont
+ + "<o:Security s:mustUnderstand=\"1\" "
+ + "xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/"
+ + "oasis-200401-wss-wssecurity-secext-1.0.xsd\">"
+ + "<o:UsernameToken><o:Username>%s</o:Username>" //username
+ + "<o:Password>%s</o:Password></o:UsernameToken>" //password
+ + "</o:Security></s:Header><s:Body>"
+ + "<t:RequestSecurityToken "
+ + "xmlns:t=\"http://schemas.xmlsoap.org/ws/2005/02/trust\">"
+ + "<wsp:AppliesTo xmlns:wsp=\""
+ + "http://schemas.xmlsoap.org/ws/2004/09/policy\">"
+ + "<a:EndpointReference><a:Address>%s</a:Address>" //stsrealm
+ + "</a:EndpointReference></wsp:AppliesTo>"
+ + "<t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey"
+ + "</t:KeyType>"
+ + "<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue"
+ + "</t:RequestType>"
+ + "<t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>"
+ + "</t:RequestSecurityToken></s:Body></s:Envelope>";
+
+ @VisibleForTesting
+ AdfsHandshakeManager(String sharePointUrl, String username,
+ String password, String stsendpoint, String stsrealm, String login,
+ String trustLocation, HttpPostClient httpClient) {
+ this.sharePointUrl = sharePointUrl;
+ this.username = username;
+ this.password = password;
+ this.stsendpoint = stsendpoint;
+ this.stsrealm = stsrealm;
+ this.login = login;
+ this.trustLocation = trustLocation;
+ this.httpClient = httpClient;
+ }
+
+ public static class Builder {
+ private final String username;
+ private final String password;
+ private final String sharePointUrl;
+ private final String stsendpoint;
+ private final String stsrealm;
+ private final HttpPostClient httpClient;
+ private String login;
+ private String trustLocation;
+
+ public Builder(String sharePointUrl, String username,
+ String password, String stsendpoint, String stsrealm) {
+ this(sharePointUrl, username, password, stsendpoint, stsrealm,
+ new HttpPostClientImpl());
+ }
+
+ @VisibleForTesting
+ Builder(String sharePointUrl, String username,
+ String password, String stsendpoint, String stsrealm,
+ HttpPostClient httpClient) {
+ if (sharePointUrl == null || username == null || password == null
+ || stsendpoint == null || httpClient == null || stsrealm == null) {
+ throw new NullPointerException();
+ }
+ this.sharePointUrl = sharePointUrl;
+ this.username = username;
+ this.password = password;
+ this.stsendpoint = stsendpoint;
+ this.stsrealm = stsrealm;
+ this.httpClient = httpClient;
+ this.login = sharePointUrl + DEFAULT_LOGIN;
+ this.trustLocation = sharePointUrl + DEFAULT_TRUST;
+ }
+
+ public Builder setLoginUrl(String login) {
+ this.login = login;
+ return this;
+ }
+
+ public Builder setTrustLocation(String trustLocation) {
+ this.trustLocation = trustLocation;
+ return this;
+ }
+
+ public AdfsHandshakeManager build() {
+ if (Strings.isNullOrEmpty(trustLocation)
+ || Strings.isNullOrEmpty(login)) {
+ throw new NullPointerException();
+ }
+ return new AdfsHandshakeManager(sharePointUrl, username,
+ password, stsendpoint, stsrealm, login, trustLocation, httpClient);
+ }
+ }
+
+ @Override
+ public String requestToken() throws IOException {
+ String saml = generateSamlRequest();
+ URL u = new URL(stsendpoint);
+ Map<String, String> requestHeaders = new HashMap<String, String>();
+ requestHeaders.put("SOAPAction", stsendpoint);
+ requestHeaders.put("Content-Type",
+ "application/soap+xml; charset=utf-8");
+ PostResponseInfo postResponse
+ = httpClient.issuePostRequest(u, requestHeaders, saml);
+ String result = postResponse.getPostContents();
+ return extractToken(result);
+ }
+
+ @Override
+ public String getAuthenticationCookie(String token) throws IOException {
+ URL u = new URL(trustLocation);
+ String param = "wa=wsignin1.0"
+ + "&wctx=" + URLEncoder.encode(login,"UTF-8")
+ + "&wresult=" + URLEncoder.encode(token, "UTF-8");
+
+ Map<String, String> requestHeaders = new HashMap<String, String>();
+ requestHeaders.put("SOAPAction", stsendpoint);
+ PostResponseInfo postResponse
+ = httpClient.issuePostRequest(u, requestHeaders, param);
+ String cookie = postResponse.getPostResponseHeaderField("Set-Cookie");
+ return cookie;
+ }
+
+ private String generateSamlRequest() {
+ return String.format(reqXML, escapeCdata(stsendpoint),
+ escapeCdata(username), escapeCdata(password), escapeCdata(stsrealm));
+ }
+
+ @VisibleForTesting
+ String extractToken(String tokenResponse) throws IOException {
+ if (tokenResponse == null) {
+ throw new IOException("tokenResponse is null");
+ }
+ try {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document document
+ = db.parse(new InputSource(new StringReader(tokenResponse)));
+ NodeList nodes
+ = document.getElementsByTagNameNS(
+ "http://schemas.xmlsoap.org/ws/2005/02/trust",
+ "RequestSecurityTokenResponse");
+ if (nodes.getLength() == 0) {
+ log.log(Level.WARNING,
+ "ADFS token not available in response {0}", tokenResponse);
+ throw new IOException("ADFS token not available in response");
+ }
+ Node responseToken = nodes.item(0);
+ String token = getOuterXml(responseToken);
+ log.log(Level.FINER, "ADFS Authentication Token {0}", token);
+ return token;
+ } catch (ParserConfigurationException ex) {
+ throw new IOException("Error parsing result", ex);
+ } catch (SAXException ex) {
+ throw new IOException("Error parsing result", ex);
+ }
+ }
+
+ private String getOuterXml(Node node) throws IOException {
+ try {
+ Transformer transformer
+ = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty("omit-xml-declaration", "yes");
+ StringWriter writer = new StringWriter();
+ transformer.transform(new DOMSource(node), new StreamResult(writer));
+ return writer.toString();
+ } catch (TransformerConfigurationException ex) {
+ throw new IOException(ex);
+ } catch (TransformerException ex) {
+ throw new IOException(ex);
+ }
+ }
+
+ @VisibleForTesting
+ String escapeCdata(String input) {
+ if (Strings.isNullOrEmpty(input)) {
+ return "";
+ }
+ return "<![CDATA[" + input.replace("]]>", "]]]]><![CDATA[>") + "]]>";
+ }
+}
diff --git a/src/com/google/enterprise/adaptor/sharepoint/AuthenticationClientFactory.java b/src/com/google/enterprise/adaptor/sharepoint/AuthenticationClientFactory.java
new file mode 100644
index 0000000..5626b14
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/sharepoint/AuthenticationClientFactory.java
@@ -0,0 +1,38 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.sharepoint;
+
+
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.SamlHandshakeManager;
+import com.microsoft.schemas.sharepoint.soap.authentication.AuthenticationSoap;
+
+import java.io.IOException;
+
+/**
+ * Authentication Factory to return appropriate authentication client for
+ * FormsAuthenticationHandler implementation.
+ */
+public interface AuthenticationClientFactory {
+ public AuthenticationSoap newSharePointFormsAuthentication(
+ String virtualServer, String username, String password)
+ throws IOException;
+
+ public SamlHandshakeManager newAdfsAuthentication(String virtualServer,
+ String username, String password, String stsendpoint, String stsrealm,
+ String login, String trustlocation) throws IOException;
+
+ public SamlHandshakeManager newLiveAuthentication(String virtualServer,
+ String username, String password) throws IOException;
+}
diff --git a/src/com/google/enterprise/adaptor/sharepoint/AuthenticationClientFactoryImpl.java b/src/com/google/enterprise/adaptor/sharepoint/AuthenticationClientFactoryImpl.java
new file mode 100644
index 0000000..7e92880
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/sharepoint/AuthenticationClientFactoryImpl.java
@@ -0,0 +1,123 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.sharepoint;
+
+import com.google.common.base.Strings;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.SamlHandshakeManager;
+
+import com.microsoft.schemas.sharepoint.soap.authentication.AuthenticationSoap;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+import javax.xml.ws.EndpointReference;
+import javax.xml.ws.Service;
+import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;
+
+/**
+ * Authentication Factory implementation to return appropriate
+ * authentication client for FormsAuthenticationHandler implementation.
+ */
+public class AuthenticationClientFactoryImpl
+ implements AuthenticationClientFactory {
+ /** SharePoint's namespace. */
+ private static final String XMLNS
+ = "http://schemas.microsoft.com/sharepoint/soap/";
+
+ private static final Logger log
+ = Logger.getLogger(AuthenticationClientFactoryImpl.class.getName());
+
+ private final Service authenticationService;
+
+ public AuthenticationClientFactoryImpl() {
+ this.authenticationService = Service.create(
+ AuthenticationSoap.class.getResource("Authentication.wsdl"),
+ new QName(XMLNS, "Authentication"));
+ }
+
+ private static String handleEncoding(String endpoint) {
+ // Handle Unicode. Java does not properly encode the POST path.
+ return URI.create(endpoint).toASCIIString();
+ }
+
+ private static URI spUrlToUri(String url) throws IOException {
+ // Because SP is silly, the path of the URI is unencoded, but the rest of
+ // the URI is correct. Thus, we split up the path from the host, and then
+ // turn them into URIs separately, and then turn everything into a
+ // properly-escaped string.
+ String[] parts = url.split("/", 4);
+ if (parts.length < 3) {
+ throw new IllegalArgumentException("Too few '/'s: " + url);
+ }
+ String host = parts[0] + "/" + parts[1] + "/" + parts[2];
+ // Host must be properly-encoded already.
+ URI hostUri = URI.create(host);
+ if (parts.length == 3) {
+ // There was no path.
+ return hostUri;
+ }
+ URI pathUri;
+ try {
+ pathUri = new URI(null, null, "/" + parts[3], null);
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+ return hostUri.resolve(pathUri);
+ }
+
+ @Override
+ public AuthenticationSoap newSharePointFormsAuthentication(
+ String virtualServer, String username, String password)
+ throws IOException {
+ String authenticationEndPoint = spUrlToUri(virtualServer
+ + "/_vti_bin/Authentication.asmx").toString();
+ EndpointReference endpointRef = new W3CEndpointReferenceBuilder()
+ .address(handleEncoding(authenticationEndPoint)).build();
+ authenticationService.getPort(endpointRef, AuthenticationSoap.class);
+ return
+ authenticationService.getPort(endpointRef, AuthenticationSoap.class);
+ }
+
+ @Override
+ public SamlHandshakeManager newAdfsAuthentication(String virtualServer,
+ String username, String password, String stsendpoint, String stsrealm,
+ String login, String trustlocation) throws IOException {
+ AdfsHandshakeManager.Builder manager
+ = new AdfsHandshakeManager.Builder(virtualServer, username,
+ password, stsendpoint, stsrealm);
+ if (!Strings.isNullOrEmpty(login)) {
+ log.log(Level.CONFIG,
+ "Using non default login value for ADFS [{0}]", login);
+ manager.setLoginUrl(login);
+ }
+ if (!Strings.isNullOrEmpty(trustlocation)) {
+ log.log(Level.CONFIG, "Using non default trust location for ADFS [{0}]",
+ trustlocation);
+ manager.setTrustLocation(trustlocation);
+ }
+ return manager.build();
+ }
+
+ @Override
+ public SamlHandshakeManager newLiveAuthentication(String virtualServer,
+ String username, String password) throws IOException {
+ return new LiveAuthenticationHandshakeManager.Builder(
+ virtualServer, username, password).build();
+ }
+}
diff --git a/src/com/google/enterprise/adaptor/sharepoint/FormsAuthenticationHandler.java b/src/com/google/enterprise/adaptor/sharepoint/FormsAuthenticationHandler.java
index a223818..cccd7cc 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/FormsAuthenticationHandler.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/FormsAuthenticationHandler.java
@@ -29,7 +29,7 @@
/**
* Helper class to handle forms authentication.
*/
-class FormsAuthenticationHandler {
+abstract class FormsAuthenticationHandler {
/** SharePoint's namespace. */
private static final String XMLNS
= "http://schemas.microsoft.com/sharepoint/soap/";
@@ -39,40 +39,36 @@
// Default time out for forms authentication with .NET is 30 mins
private static final long DEFAULT_COOKIE_TIMEOUT_SECONDS = 30 * 60;
- private final String userName;
- private final String password;
+ protected final String username;
+ protected final String password;
private final ScheduledExecutorService executor;
private final Runnable refreshRunnable = new RefreshRunnable();
private final List<String> authenticationCookiesList
- = new CopyOnWriteArrayList<String>();
- private final AuthenticationHandler authenticationClient;
+ = new CopyOnWriteArrayList<String>();
private boolean isFormsAuthentication = false;
@VisibleForTesting
- FormsAuthenticationHandler(String userName, String password,
- ScheduledExecutorService executor,
- AuthenticationHandler authenticationClient) {
- if (userName == null || password == null || executor == null ||
- authenticationClient == null) {
+ FormsAuthenticationHandler(String username, String password,
+ ScheduledExecutorService executor) {
+ if (username == null || password == null || executor == null) {
throw new NullPointerException();
}
- this.userName = userName;
+ this.username = username;
this.password = password;
- this.executor = executor;
- this.authenticationClient = authenticationClient;
+ this.executor = executor;
}
public List<String> getAuthenticationCookies() {
return Collections.unmodifiableList(authenticationCookiesList);
}
+ // TODO : Remove isFormAuthentication.
+ abstract boolean isFormsAuthentication() throws IOException;
- public boolean isFormsAuthentication() {
- return isFormsAuthentication;
- }
+ abstract AuthenticationResult authenticate() throws IOException;
private void refreshCookies() throws IOException {
- if ("".equals(userName) || "".equals(password)) {
+ if ("".equals(username) || "".equals(password)) {
log.log(Level.FINE,
"Empty username / password. Using authentication mode as Windows");
isFormsAuthentication = false;
@@ -84,7 +80,7 @@
}
log.log(Level.FINE, "About to refresh authentication cookie.");
- AuthenticationResult result = authenticationClient.authenticate();
+ AuthenticationResult result = authenticate();
log.log(Level.FINE, "Authentication Result {0}", result.getErrorCode());
String cookie = result.getCookie();
@@ -107,13 +103,13 @@
}
public void start() throws IOException {
- if ("".equals(userName) || "".equals(password)) {
+ if ("".equals(username) || "".equals(password)) {
log.log(Level.FINE, "Empty username or password. Using windows"
+ " integrated authentication.");
isFormsAuthentication = false;
return;
}
- isFormsAuthentication = authenticationClient.isFormsAuthentication();
+ isFormsAuthentication = isFormsAuthentication();
refreshCookies();
}
@@ -129,9 +125,4 @@
}
}
}
-
- interface AuthenticationHandler {
- AuthenticationResult authenticate() throws IOException;
- boolean isFormsAuthentication() throws IOException;
- }
}
\ No newline at end of file
diff --git a/src/com/google/enterprise/adaptor/sharepoint/LiveAuthenticationHandshakeManager.java b/src/com/google/enterprise/adaptor/sharepoint/LiveAuthenticationHandshakeManager.java
new file mode 100644
index 0000000..a44878f
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/sharepoint/LiveAuthenticationHandshakeManager.java
@@ -0,0 +1,153 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.sharepoint;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.HttpPostClient;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.HttpPostClientImpl;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * SamlHandshakeManager implementation for Live Authentication
+ * to request Live authentication token and extract authentication cookie.
+ */
+public class LiveAuthenticationHandshakeManager
+ extends AdfsHandshakeManager {
+ private static final Logger log
+ = Logger.getLogger(LiveAuthenticationHandshakeManager.class.getName());
+ private static final String LIVE_STS
+ = "https://login.microsoftonline.com/extSTS.srf";
+ private static final String LIVE_LOGIN_URL
+ = "/_forms/default.aspx?wa=wsignin1.0";
+
+ public static class Builder {
+ private final String username;
+ private final String password;
+ private final String sharePointUrl;
+ private String stsendpoint;
+ private final String stsrealm;
+ private final HttpPostClient httpClient;
+ private String login;
+ private String trustLocation;
+
+ public Builder(String sharePointUrl, String username, String password) {
+ this(sharePointUrl, username, password, new HttpPostClientImpl());
+ }
+
+ @VisibleForTesting
+ Builder(String sharePointUrl, String username, String password,
+ HttpPostClient httpClient) {
+ if (sharePointUrl == null || username == null || password == null
+ || httpClient == null) {
+ throw new NullPointerException();
+ }
+ this.sharePointUrl = sharePointUrl;
+ this.username = username;
+ this.password = password;
+ this.httpClient = httpClient;
+ this.login = sharePointUrl + LIVE_LOGIN_URL;
+ this.trustLocation = "";
+ this.stsendpoint = LIVE_STS;
+ this.stsrealm = sharePointUrl;
+ }
+
+ public Builder setLoginUrl(String login) {
+ this.login = login;
+ return this;
+ }
+
+ public Builder setStsendpoint(String stsendpoint) {
+ this.stsendpoint = stsendpoint;
+ return this;
+ }
+
+ public LiveAuthenticationHandshakeManager build() {
+ if (Strings.isNullOrEmpty(stsendpoint) || Strings.isNullOrEmpty(login)) {
+ throw new NullPointerException();
+ }
+ return new LiveAuthenticationHandshakeManager(sharePointUrl, username,
+ password, stsendpoint, stsrealm, login, trustLocation, httpClient);
+ }
+ }
+
+ private LiveAuthenticationHandshakeManager(String sharePointUrl,
+ String username, String password, String stsendpoint, String stsrealm,
+ String login, String trustLocation, HttpPostClient httpClient) {
+ super(sharePointUrl, username, password, stsendpoint,
+ stsrealm, login, trustLocation, httpClient);
+ }
+
+ @Override
+ @VisibleForTesting
+ String extractToken(String tokenResponse) throws IOException {
+ if (tokenResponse == null) {
+ throw new IOException("tokenResponse is null");
+ }
+ try {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document document
+ = db.parse(new InputSource(new StringReader(tokenResponse)));
+ NodeList nodes
+ = document.getElementsByTagNameNS(
+ "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-"
+ + "wssecurity-secext-1.0.xsd", "BinarySecurityToken");
+ if (nodes == null || nodes.getLength() == 0) {
+ log.log(Level.WARNING, "Live Authentication token not available"
+ + " in response {0}", tokenResponse);
+ throw new IOException(
+ "Live Authentication token not available in response");
+ }
+ String token = nodes.item(0).getTextContent();
+ log.log(Level.FINER, "Live Authentication Token {0}", token);
+ return token;
+ } catch (ParserConfigurationException ex) {
+ throw new IOException(ex);
+ } catch (SAXException ex) {
+ throw new IOException(ex);
+ } catch (DOMException ex) {
+ throw new IOException(ex);
+ }
+ }
+
+ @Override
+ public String getAuthenticationCookie(String token) throws IOException {
+ URL u = new URL(login);
+ Map<String, String> requestProperties = new HashMap<String, String>();
+ requestProperties.put("SOAPAction", stsendpoint);
+ SamlAuthenticationHandler.PostResponseInfo postResponse
+ = httpClient.issuePostRequest(u, requestProperties, token);
+ return postResponse.getPostResponseHeaderField("Set-Cookie");
+ }
+}
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SamlAuthenticationHandler.java b/src/com/google/enterprise/adaptor/sharepoint/SamlAuthenticationHandler.java
new file mode 100644
index 0000000..d7c64ae
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/sharepoint/SamlAuthenticationHandler.java
@@ -0,0 +1,201 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.sharepoint;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import com.google.enterprise.adaptor.IOHelper;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.HttpURLConnection;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * FormsAuthenticationHandler for SAML based authentication.
+ */
+public class SamlAuthenticationHandler extends FormsAuthenticationHandler {
+
+ private static final Logger log
+ = Logger.getLogger(SamlAuthenticationHandler.class.getName());
+ private static final int DEFAULT_COOKIE_TIMEOUT_SECONDS = 600;
+ private static final Charset CHARSET = Charset.forName("UTF-8");
+
+ private final SamlHandshakeManager samlClient;
+
+ private SamlAuthenticationHandler(String username, String password,
+ ScheduledExecutorService executor, SamlHandshakeManager samlClient) {
+ super(username, password, executor);
+ this.samlClient = samlClient;
+ }
+
+ public static class Builder {
+ private final String username;
+ private final String password;
+ private final ScheduledExecutorService executor;
+ private final SamlHandshakeManager samlClient;
+ public Builder(String username, String password,
+ ScheduledExecutorService executor, SamlHandshakeManager samlClient) {
+ if (username == null || password == null || executor == null
+ || samlClient == null) {
+ throw new NullPointerException();
+ }
+ this.username = username;
+ this.password = password;
+ this.executor = executor;
+ this.samlClient = samlClient;
+ }
+
+ public SamlAuthenticationHandler build() {
+ SamlAuthenticationHandler authenticationHandler
+ = new SamlAuthenticationHandler(username, password, executor,
+ samlClient);
+ return authenticationHandler;
+ }
+
+ }
+
+ @Override
+ public AuthenticationResult authenticate() throws IOException {
+ String token = samlClient.requestToken();
+ if (Strings.isNullOrEmpty(token)) {
+ throw new IOException("Invalid SAML token");
+ }
+ String cookie = samlClient.getAuthenticationCookie(token);
+ log.log(Level.FINER, "Authentication Cookie {0}", cookie);
+ return new AuthenticationResult(cookie,
+ DEFAULT_COOKIE_TIMEOUT_SECONDS, "NO_ERROR");
+ }
+
+ @Override
+ public boolean isFormsAuthentication() throws IOException {
+ return true;
+ }
+
+ @VisibleForTesting
+ interface SamlHandshakeManager {
+ public String requestToken() throws IOException;
+ public String getAuthenticationCookie(String token) throws IOException;
+ }
+
+ @VisibleForTesting
+ interface HttpPostClient {
+ public PostResponseInfo issuePostRequest(URL url,
+ Map<String, String> connectionProperties, String requestBody)
+ throws IOException;
+ }
+
+ @VisibleForTesting
+ static class HttpPostClientImpl implements HttpPostClient{
+ @Override
+ public PostResponseInfo issuePostRequest(URL url,
+ Map<String, String> connectionProperties, String requestBody)
+ throws IOException {
+
+ // Handle Unicode. Java does not properly encode the GET.
+ try {
+ url = new URL(url.toURI().toASCIIString());
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ try {
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+ connection.setRequestMethod("POST");
+ connection.setInstanceFollowRedirects(false);
+
+ for(String key : connectionProperties.keySet()) {
+ connection.addRequestProperty(key, connectionProperties.get(key));
+ }
+
+ if (!connectionProperties.containsKey("Content-Length")) {
+ connection.addRequestProperty("Content-Length",
+ Integer.toString(requestBody.length()));
+ }
+
+ OutputStream out = connection.getOutputStream();
+ Writer wout = new OutputStreamWriter(out);
+ wout.write(requestBody);
+ wout.flush();
+ wout.close();
+ InputStream in = connection.getInputStream();
+ String result = IOHelper.readInputStreamToString(in, CHARSET);
+ return new PostResponseInfo(result, connection.getHeaderFields());
+ } finally {
+ InputStream inputStream = connection.getResponseCode() >= 400
+ ? connection.getErrorStream() : connection.getInputStream();
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static class PostResponseInfo {
+ /** Non-null contents. */
+ private final String contents;
+ /** Non-null headers. */
+ private final Map<String, List<String>> headers;
+
+ PostResponseInfo(
+ String contents, Map<String, List<String>> headers) {
+ this.contents = contents;
+ this.headers = (headers == null)
+ ? new HashMap<String, List<String>>()
+ : new HashMap<String, List<String>>(headers);
+ }
+
+ public String getPostContents() {
+ return contents;
+ }
+
+ public Map<String, List<String>> getPostResponseHeaders() {
+ return Collections.unmodifiableMap(headers);
+ }
+
+ public String getPostResponseHeaderField(String header) {
+ if (headers == null || !headers.containsKey(header)) {
+ return null;
+ }
+ if (headers.get(header) == null || headers.get(header).isEmpty()) {
+ return null;
+ }
+ StringBuilder sbValues = new StringBuilder();
+ for(String value : headers.get(header)) {
+ if ("".equals(value)) {
+ continue;
+ }
+ sbValues.append(value);
+ sbValues.append(";");
+ }
+ return sbValues.toString();
+ }
+ }
+}
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
index ff5b128..eb422f0 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
@@ -36,6 +36,7 @@
import com.google.enterprise.adaptor.sharepoint.RareModificationCache.CachedList;
import com.google.enterprise.adaptor.sharepoint.RareModificationCache.CachedVirtualServer;
import com.google.enterprise.adaptor.sharepoint.RareModificationCache.CachedWeb;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.SamlHandshakeManager;
import com.google.enterprise.adaptor.sharepoint.SiteDataClient.CursorPaginator;
import com.google.enterprise.adaptor.sharepoint.SiteDataClient.Paginator;
import com.google.enterprise.adaptor.sharepoint.SiteDataClient.XmlProcessingException;
@@ -348,6 +349,8 @@
/** Client for initiating raw HTTP connections. */
private final HttpClient httpClient;
private final Callable<ExecutorService> executorFactory;
+
+ private final AuthenticationClientFactory authenticationClientFactory;
private ExecutorService executor;
private boolean xmlValidation;
private int feedMaxUrls;
@@ -404,18 +407,21 @@
public SharePointAdaptor() {
this(new SoapFactoryImpl(), new HttpClientImpl(),
- new CachedThreadPoolFactory());
+ new CachedThreadPoolFactory(), new AuthenticationClientFactoryImpl());
}
@VisibleForTesting
SharePointAdaptor(SoapFactory soapFactory, HttpClient httpClient,
- Callable<ExecutorService> executorFactory) {
- if (soapFactory == null || httpClient == null || executorFactory == null) {
+ Callable<ExecutorService> executorFactory,
+ AuthenticationClientFactory authenticationClientFactory) {
+ if (soapFactory == null || httpClient == null || executorFactory == null
+ || authenticationClientFactory == null) {
throw new NullPointerException();
}
this.soapFactory = soapFactory;
this.httpClient = httpClient;
this.executorFactory = executorFactory;
+ this.authenticationClientFactory = authenticationClientFactory;
}
/**
@@ -442,6 +448,22 @@
// because the GSA won't see links outside of that content.
config.addKey("sharepoint.maxIndexableSize", "2097152");
config.addKey("adaptor.namespace", "Default");
+ // When running against ADFS authentication, set this to ADFS endpoint.
+ config.addKey("sharepoint.sts.endpoint", "");
+ // When running against ADFS authentication, set this to realm value.
+ // Normally realm value is either http://sharepointurl/_trust or
+ // urn:sharepointenv:com format. You can use
+ // Get-SPTrustedIdentityTokenIssuer to get "DefaultProviderRealm" value
+ config.addKey("sharepoint.sts.realm", "");
+ // You can override default value of http://sharepointurl/_trust by
+ // specifying this property.
+ config.addKey("sharepoint.sts.trustLocation", "");
+ // You can override default value of
+ // http://sharepointurl/_layouts/Authenticate.aspx by specifying this
+ // property.
+ config.addKey("sharepoint.sts.login", "");
+ // Set this to true when using Live authentication.
+ config.addKey("sharepoint.useLiveAuthentication", "false");
}
@Override
@@ -462,11 +484,19 @@
maxIndexableSize = Integer.parseInt(
config.getValue("sharepoint.maxIndexableSize"));
defaultNamespace = config.getValue("adaptor.namespace");
+ String stsendpoint = config.getValue("sharepoint.sts.endpoint");
+ String stsrealm = config.getValue("sharepoint.sts.realm");
+ boolean useLiveAuthentication = Boolean.parseBoolean(
+ config.getValue("sharepoint.useLiveAuthentication"));
log.log(Level.CONFIG, "VirtualServer: {0}", virtualServer);
log.log(Level.CONFIG, "Username: {0}", username);
log.log(Level.CONFIG, "Password: {0}", password);
log.log(Level.CONFIG, "Default Namespace: {0}", defaultNamespace);
+ log.log(Level.CONFIG, "STS Endpoint: {0}", stsendpoint);
+ log.log(Level.CONFIG, "STS Realm: {0}", stsrealm);
+ log.log(Level.CONFIG, "Use Live Authentication: {0}",
+ useLiveAuthentication);
ntlmAuthenticator = new NtlmAuthenticator(username, password);
// Unfortunately, this is a JVM-wide modification.
@@ -474,14 +504,28 @@
URL virtualServerUrl = new URL(virtualServer);
ntlmAuthenticator.addPermitForHost(virtualServerUrl);
scheduledExecutor = new ScheduledThreadPoolExecutor(1);
- String authenticationEndPoint = spUrlToUri(
- virtualServer + "/_vti_bin/Authentication.asmx").toString();
- SharePointFormsAuthenticationHandler authenticationClient
- = new SharePointFormsAuthenticationHandler(
- soapFactory.newAuthentication(authenticationEndPoint),
- username, password);
- authenticationHandler = new FormsAuthenticationHandler(username,
- password, scheduledExecutor, authenticationClient);
+
+
+ if (useLiveAuthentication) {
+ SamlHandshakeManager manager = authenticationClientFactory
+ .newLiveAuthentication(virtualServer, username, password);
+ authenticationHandler = new SamlAuthenticationHandler.Builder(username,
+ password, scheduledExecutor, manager).build();
+ } else if (!"".equals(stsendpoint) && !"".equals(stsrealm)) {
+ SamlHandshakeManager manager = authenticationClientFactory
+ .newAdfsAuthentication(virtualServer, username, password, stsendpoint,
+ stsrealm, config.getValue("sharepoint.sts.login"),
+ config.getValue("sharepoint.sts.trustLocation"));
+ authenticationHandler = new SamlAuthenticationHandler.Builder(username,
+ password, scheduledExecutor, manager).build();
+ } else {
+ AuthenticationSoap authenticationSoap = authenticationClientFactory
+ .newSharePointFormsAuthentication(virtualServer, username, password);
+ authenticationHandler = new SharePointFormsAuthenticationHandler
+ .Builder(username, password, scheduledExecutor, authenticationSoap)
+ .build();
+ }
+
try {
authenticationHandler.start();
executor = executorFactory.call();
@@ -2674,8 +2718,6 @@
public UserGroupSoap newUserGroup(String endpoint);
- public AuthenticationSoap newAuthentication(String endpoint);
-
public PeopleSoap newPeople(String endpoint);
}
@@ -2683,7 +2725,6 @@
static class SoapFactoryImpl implements SoapFactory {
private final Service siteDataService;
private final Service userGroupService;
- private final Service authenticationService;
private final Service peopleService;
public SoapFactoryImpl() {
@@ -2691,9 +2732,6 @@
this.userGroupService = Service.create(
UserGroupSoap.class.getResource("UserGroup.wsdl"),
new QName(XMLNS_DIRECTORY, "UserGroup"));
- this.authenticationService = Service.create(
- AuthenticationSoap.class.getResource("Authentication.wsdl"),
- new QName(XMLNS, "Authentication"));
this.peopleService = Service.create(
PeopleSoap.class.getResource("People.wsdl"),
new QName(XMLNS, "People"));
@@ -2717,14 +2755,6 @@
.address(handleEncoding(endpoint)).build();
return userGroupService.getPort(endpointRef, UserGroupSoap.class);
}
-
- @Override
- public AuthenticationSoap newAuthentication(String endpoint) {
- EndpointReference endpointRef = new W3CEndpointReferenceBuilder()
- .address(handleEncoding(endpoint)).build();
- return
- authenticationService.getPort(endpointRef, AuthenticationSoap.class);
- }
@Override
public PeopleSoap newPeople(String endpoint) {
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointFormsAuthenticationHandler.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointFormsAuthenticationHandler.java
index c3c9406..37f314e 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointFormsAuthenticationHandler.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointFormsAuthenticationHandler.java
@@ -14,7 +14,6 @@
package com.google.enterprise.adaptor.sharepoint;
-import com.google.enterprise.adaptor.sharepoint.FormsAuthenticationHandler.AuthenticationHandler;
import com.microsoft.schemas.sharepoint.soap.authentication.AuthenticationMode;
import com.microsoft.schemas.sharepoint.soap.authentication.AuthenticationSoap;
import com.microsoft.schemas.sharepoint.soap.authentication.LoginErrorCode;
@@ -22,6 +21,7 @@
import java.io.IOException;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.ws.BindingProvider;
@@ -33,26 +33,48 @@
* using Authentication.asmx web service.
*/
public class SharePointFormsAuthenticationHandler
- implements AuthenticationHandler {
+ extends FormsAuthenticationHandler {
private static final Logger log
= Logger.getLogger(SharePointFormsAuthenticationHandler.class.getName());
// Default time out for forms authentication with .NET is 30 mins
private static final int DEFAULT_COOKIE_TIMEOUT_SECONDS = 30 * 60;
private final AuthenticationSoap authenticationClient;
private AuthenticationMode authenticationMode;
- private final String username;
- private final String password;
- SharePointFormsAuthenticationHandler(AuthenticationSoap authenticationClient,
- String username, String password) {
- if (authenticationClient == null || username == null || password == null) {
- throw new NullPointerException();
- }
+ private SharePointFormsAuthenticationHandler(String username, String password,
+ ScheduledExecutorService executor,
+ AuthenticationSoap authenticationClient) {
+ super(username, password, executor);
this.authenticationClient = authenticationClient;
- this.username = username;
- this.password = password;
+ }
+
+ public static class Builder {
+ private final String username;
+ private final String password;
+ private final ScheduledExecutorService executor;
+ private final AuthenticationSoap authenticationClient;
+ public Builder(String username, String password,
+ ScheduledExecutorService executor,
+ AuthenticationSoap authenticationClient) {
+ if (username == null || password == null || executor == null
+ || authenticationClient == null) {
+ throw new NullPointerException();
+ }
+ this.username = username;
+ this.password = password;
+ this.executor = executor;
+ this.authenticationClient = authenticationClient;
+ }
+
+ public SharePointFormsAuthenticationHandler build() {
+ SharePointFormsAuthenticationHandler authenticationHandler
+ = new SharePointFormsAuthenticationHandler(
+ username, password, executor, authenticationClient);
+ return authenticationHandler;
+ }
}
+ @Override
public AuthenticationResult authenticate() throws IOException {
if (!isFormsAuthentication()) {
return new AuthenticationResult(null, DEFAULT_COOKIE_TIMEOUT_SECONDS,
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java
index c4e3b87..6e91ec1 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java
@@ -26,6 +26,7 @@
import com.google.enterprise.adaptor.PollingIncrementalLister;
import com.google.enterprise.adaptor.Request;
import com.google.enterprise.adaptor.Response;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.SamlHandshakeManager;
import com.microsoft.schemas.sharepoint.soap.authentication.AuthenticationSoap;
import com.microsoft.webservices.sharepointportalserver.userprofilechangeservice.ArrayOfUserProfileChangeData;
@@ -141,6 +142,7 @@
private String mySiteHost;
private NtlmAuthenticator ntlmAuthenticator;
private final UserProfileServiceFactory userProfileServiceFactory;
+ private final AuthenticationClientFactory authenticationClientFactory;
private String userProfileChangeToken;
private boolean setAcl = true;
@@ -149,21 +151,27 @@
private ScheduledThreadPoolExecutor scheduledExecutor
= new ScheduledThreadPoolExecutor(1);
+ private FormsAuthenticationHandler authenticationHandler;
+
public static void main(String[] args) {
AbstractAdaptor.main(new SharePointUserProfileAdaptor(), args);
}
public SharePointUserProfileAdaptor() {
- this(new UserProfileServiceFactoryImpl());
+ this(new UserProfileServiceFactoryImpl(),
+ new AuthenticationClientFactoryImpl());
}
@VisibleForTesting
SharePointUserProfileAdaptor(
- UserProfileServiceFactory userProfileServiceFactory) {
- if (userProfileServiceFactory == null) {
+ UserProfileServiceFactory userProfileServiceFactory,
+ AuthenticationClientFactory authenticationClientFactory) {
+ if (userProfileServiceFactory == null
+ || authenticationClientFactory == null) {
throw new NullPointerException();
}
this.userProfileServiceFactory = userProfileServiceFactory;
+ this.authenticationClientFactory = authenticationClientFactory;
}
@VisibleForTesting
@@ -187,6 +195,22 @@
config.addKey("profile.setacl", "true");
config.addKey("adaptor.namespace", "Default");
config.addKey("profile.mysitehost", "");
+ // When running against ADFS authentication, set this to ADFS endpoint.
+ config.addKey("sharepoint.sts.endpoint", "");
+ // When running against ADFS authentication, set this to realm value.
+ // Normally realm value is either http://sharepointurl/_trust or
+ // urn:sharepointenv:com format. You can use
+ // Get-SPTrustedIdentityTokenIssuer to get "DefaultProviderRealm" value
+ config.addKey("sharepoint.sts.realm", "");
+ // You can override default value of http://sharepointurl/_trust by
+ // specifying this property.
+ config.addKey("sharepoint.sts.trustLocation", "");
+ // You can override default value of
+ // http://sharepointurl/_layouts/Authenticate.aspx by specifying this
+ // property.
+ config.addKey("sharepoint.sts.login", "");
+ // Set this to true when using Live authentication.
+ config.addKey("sharepoint.useLiveAuthentication", "false");
}
@Override
@@ -203,11 +227,19 @@
config.getValue("sharepoint.password"));
setAcl = Boolean.parseBoolean(config.getValue("profile.setacl"));
namespace = config.getValue("adaptor.namespace");
+ String stsendpoint = config.getValue("sharepoint.sts.endpoint");
+ String stsrealm = config.getValue("sharepoint.sts.realm");
+ boolean useLiveAuthentication = Boolean.parseBoolean(
+ config.getValue("sharepoint.useLiveAuthentication"));
log.log(Level.CONFIG, "virtualServer: {0}", virtualServer);
log.log(Level.CONFIG, "Username: {0}", username);
log.log(Level.CONFIG, "setAcl: {0}", setAcl);
log.log(Level.CONFIG, "Namespace: {0}", namespace);
+ log.log(Level.CONFIG, "STS Endpoint: {0}", stsendpoint);
+ log.log(Level.CONFIG, "STS Realm: {0}", stsrealm);
+ log.log(Level.CONFIG, "Use Live Authentication: {0}",
+ useLiveAuthentication);
mySiteHost = config.getValue("profile.mysitehost");
log.log(Level.CONFIG, "mySiteHost: {0}", mySiteHost);
@@ -224,15 +256,26 @@
ntlmAuthenticator = new NtlmAuthenticator(username, password);
// Unfortunately, this is a JVM-wide modification.
Authenticator.setDefault(ntlmAuthenticator);
- String authenticationEndPoint
- = virtualServer + "/_vti_bin/Authentication.asmx";
- SharePointFormsAuthenticationHandler authenticationClient
- = new SharePointFormsAuthenticationHandler(
- userProfileServiceFactory.newAuthentication(authenticationEndPoint),
- username, password);
- FormsAuthenticationHandler authenticationHandler
- = new FormsAuthenticationHandler(username, password, scheduledExecutor,
- authenticationClient);
+
+ if (useLiveAuthentication) {
+ SamlHandshakeManager manager = authenticationClientFactory
+ .newLiveAuthentication(virtualServer, username, password);
+ authenticationHandler = new SamlAuthenticationHandler.Builder(username,
+ password, scheduledExecutor, manager).build();
+ } else if (!"".equals(stsendpoint) && !"".equals(stsrealm)) {
+ SamlHandshakeManager manager = authenticationClientFactory
+ .newAdfsAuthentication(virtualServer, username, password, stsendpoint,
+ stsrealm, config.getValue("sharepoint.sts.login"),
+ config.getValue("sharepoint.sts.trustLocation"));
+ authenticationHandler = new SamlAuthenticationHandler.Builder(username,
+ password, scheduledExecutor, manager).build();
+ } else {
+ AuthenticationSoap authenticationSoap = authenticationClientFactory
+ .newSharePointFormsAuthentication(virtualServer, username, password);
+ authenticationHandler = new SharePointFormsAuthenticationHandler
+ .Builder(username, password, scheduledExecutor, authenticationSoap)
+ .build();
+ }
authenticationHandler.start();
log.log(Level.FINEST, "Initializing User profile Service Client for {0}",
virtualServer + USER_PROFILE_SERVICE_ENDPOINT);
@@ -298,15 +341,12 @@
interface UserProfileServiceFactory {
public UserProfileServiceWS newUserProfileService(String endpoint,
String endpointChangeService, List<String> cookies);
- public AuthenticationSoap newAuthentication(String endpoint);
-
}
private static class UserProfileServiceFactoryImpl
implements UserProfileServiceFactory {
private final Service userProfileServiceSoap;
private final Service userProfileChangeServiceSoap;
- private final Service authenticationService;
public UserProfileServiceFactoryImpl() {
URL urlUserProfileService =
@@ -320,9 +360,6 @@
QName qnameChange = new QName(XMLNS_CHANGE, "UserProfileChangeService");
this.userProfileChangeServiceSoap = Service.create(
urlUserProfileChangeService, qnameChange);
- this.authenticationService = Service.create(
- AuthenticationSoap.class.getResource("Authentication.wsdl"),
- new QName(AUTH_XMLNS, "Authentication"));
}
@Override
@@ -363,14 +400,6 @@
port.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS,
Collections.singletonMap(
"X-FORMS_BASED_AUTH_ACCEPTED", Collections.singletonList("f")));
- }
-
- @Override
- public AuthenticationSoap newAuthentication(String endpoint) {
- EndpointReference endpointRef = new W3CEndpointReferenceBuilder()
- .address(endpoint).build();
- return
- authenticationService.getPort(endpointRef, AuthenticationSoap.class);
}
}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/AdfsHandshakeManagerTest.java b/test/com/google/enterprise/adaptor/sharepoint/AdfsHandshakeManagerTest.java
new file mode 100644
index 0000000..2c6a06e
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/sharepoint/AdfsHandshakeManagerTest.java
@@ -0,0 +1,294 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.sharepoint;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.enterprise.adaptor.sharepoint.FormsAuthenticationHandlerTest.MockScheduledExecutor;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.HttpPostClient;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.PostResponseInfo;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+
+public class AdfsHandshakeManagerTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private static class UnsupportedHttpPostClient implements HttpPostClient {
+ @Override
+ public SamlAuthenticationHandler.PostResponseInfo issuePostRequest(
+ URL url, Map<String, String> connectionProperties, String requestBody)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private static class MockHttpPostClient implements HttpPostClient {
+
+ private Map<URL, PostResponseInfo> responseMap;
+ private Map<URL, String> receivedRequestBodyMap;
+ public MockHttpPostClient() {
+ responseMap = new HashMap<URL, PostResponseInfo>();
+ receivedRequestBodyMap = new HashMap<URL, String>();
+ }
+
+ @Override
+ public SamlAuthenticationHandler.PostResponseInfo issuePostRequest(
+ URL url, Map<String, String> connectionProperties, String requestBody)
+ throws IOException {
+ if (!responseMap.containsKey(url)) {
+ throw new UnsupportedOperationException(
+ "Unexpected Http Post for URL " + url);
+ }
+ // log incoming request body
+ receivedRequestBodyMap.put(url, requestBody);
+ return responseMap.get(url);
+ }
+ }
+
+ @Test
+ public void testConstructor() {
+ new AdfsHandshakeManager.Builder(
+ "http://endpoint", "username", "password", "https://sts", "realm")
+ .build();
+ }
+
+ @Test
+ public void testNullUsername() {
+ thrown.expect(NullPointerException.class);
+ new AdfsHandshakeManager.Builder(
+ "http://endpoint", null, "password", "https://sts", "realm").build();
+ }
+
+ @Test
+ public void testNullPassword() {
+ thrown.expect(NullPointerException.class);
+ new AdfsHandshakeManager.Builder(
+ "http://endpoint", "username", null, "https://sts", "realm").build();
+ }
+
+ @Test
+ public void testNullEndpoint() {
+ thrown.expect(NullPointerException.class);
+ new AdfsHandshakeManager.Builder(
+ null, "username", "password","https://sts", "realm").build();
+ }
+
+ @Test
+ public void testNullSts() {
+ thrown.expect(NullPointerException.class);
+ new AdfsHandshakeManager.Builder(
+ "http://endpoint", "username", "password", null, "realm").build();
+ }
+
+ @Test
+ public void testNullRealm() {
+ thrown.expect(NullPointerException.class);
+ new AdfsHandshakeManager.Builder(
+ "http://endpoint", "username", "password", "http://sts", null).build();
+ }
+
+ @Test
+ public void testRequestToken() throws IOException{
+ MockHttpPostClient postClient = new MockHttpPostClient();
+ AdfsHandshakeManager manager = new AdfsHandshakeManager.Builder(
+ "https://sharepoint.intranet.com", "username@domain", "pass]]>word&123",
+ "https://sts.dmain.com/adfs/services/trust/2005/usernamemixed",
+ "urn:realm:sharepoint", postClient).build();
+ URL tokenRequest = new URL(
+ "https://sts.dmain.com/adfs/services/trust/2005/usernamemixed");
+ String tokenResponse = "<s:Envelope "
+ + "xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\">"
+ + "<s:Header>Some header</s:Header>"
+ + "<t:RequestSecurityTokenResponse "
+ + "xmlns:t=\"http://schemas.xmlsoap.org/ws/2005/02/trust\">"
+ + "This is requested token"
+ + "</t:RequestSecurityTokenResponse>"
+ + "</s:Envelope>";
+ postClient.responseMap.put(tokenRequest,
+ new PostResponseInfo(tokenResponse, null));
+ assertEquals("<t:RequestSecurityTokenResponse "
+ + "xmlns:t=\"http://schemas.xmlsoap.org/ws/2005/02/trust\">"
+ + "This is requested token"
+ + "</t:RequestSecurityTokenResponse>", manager.requestToken());
+
+ String expectedRequestBody
+ = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+ + "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" "
+ + "xmlns:a=\"http://www.w3.org/2005/08/addressing\" "
+ + "xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-"
+ + "wssecurity-utility-1.0.xsd\"><s:Header><a:Action "
+ + "s:mustUnderstand=\"1\">"
+ + "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>"
+ + "<a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous"
+ + "</a:Address></a:ReplyTo><a:To s:mustUnderstand=\"1\"><![CDATA["
+ + "https://sts.dmain.com/adfs/services/trust/2005/usernamemixed]]>"
+ + "</a:To><o:Security s:mustUnderstand=\"1\" "
+ + "xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-"
+ + "wssecurity-secext-1.0.xsd\"><o:UsernameToken>"
+ + "<o:Username><![CDATA[username@domain]]></o:Username>"
+ + "<o:Password><![CDATA[pass]]]]><![CDATA[>word&123]]>"
+ + "</o:Password></o:UsernameToken></o:Security></s:Header>"
+ + "<s:Body><t:RequestSecurityToken "
+ + "xmlns:t=\"http://schemas.xmlsoap.org/ws/2005/02/trust\">"
+ + "<wsp:AppliesTo "
+ + "xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\">"
+ + "<a:EndpointReference><a:Address>"
+ + "<![CDATA[urn:realm:sharepoint]]></a:Address>"
+ + "</a:EndpointReference></wsp:AppliesTo><t:KeyType>"
+ + "http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey"
+ + "</t:KeyType><t:RequestType>"
+ + "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue"
+ + "</t:RequestType><t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion"
+ + "</t:TokenType></t:RequestSecurityToken></s:Body></s:Envelope>";
+
+ assertEquals(expectedRequestBody,
+ postClient.receivedRequestBodyMap.get(tokenRequest));
+
+ }
+
+ @Test
+ public void testNullRequestToken() throws IOException{
+ MockHttpPostClient postClient = new MockHttpPostClient();
+ AdfsHandshakeManager manager = new AdfsHandshakeManager.Builder(
+ "https://sharepoint.intranet.com", "username@domain", "password&123",
+ "https://sts.dmain.com/adfs/services/trust/2005/usernamemixed",
+ "urn:realm:sharepoint", postClient).build();
+ URL tokenRequest = new URL(
+ "https://sts.dmain.com/adfs/services/trust/2005/usernamemixed");
+ postClient.responseMap.put(tokenRequest,
+ new PostResponseInfo("<data>some invalid content</data>", null));
+ thrown.expect(IOException.class);
+ String token = manager.requestToken();
+ }
+
+ @Test
+ public void testGetAuthenticationCookie() throws IOException{
+ MockHttpPostClient postClient = new MockHttpPostClient();
+ AdfsHandshakeManager manager = new AdfsHandshakeManager.Builder(
+ "https://sharepoint.intranet.com", "username@domain", "password&123",
+ "https://sts.dmain.com/adfs/services/trust/2005/usernamemixed",
+ "urn:realm:sharepoint", postClient).build();
+
+ URL submitToken = new URL("https://sharepoint.intranet.com/_trust");
+
+ Map<String, List<String>> responseHeaders
+ = new HashMap<String, List<String>>();
+ responseHeaders.put("some-header", Arrays.asList("some value"));
+ responseHeaders.put("Set-Cookie", Arrays.asList("FedAuth=AutheCookie"));
+
+ postClient.responseMap.put(submitToken,
+ new PostResponseInfo("submit token response", responseHeaders));
+ String cookie = manager.getAuthenticationCookie(
+ "<t:RequestSecurityTokenResponse "
+ + "xmlns:t=\"http://schemas.xmlsoap.org/ws/2005/02/trust\">"
+ + "This is requested token"
+ + "</t:RequestSecurityTokenResponse>");
+
+ assertEquals("FedAuth=AutheCookie;", cookie);
+
+ String expectedSubmitTokenRequest = "wa=wsignin1.0&wctx="
+ + URLEncoder.encode("https://sharepoint.intranet.com/_layouts/"
+ + "Authenticate.aspx","UTF-8")
+ + "&wresult=" + URLEncoder.encode("<t:RequestSecurityTokenResponse "
+ + "xmlns:t=\"http://schemas.xmlsoap.org/ws/2005/02/trust\">"
+ + "This is requested token"
+ + "</t:RequestSecurityTokenResponse>", "UTF-8");
+ assertEquals(expectedSubmitTokenRequest,
+ postClient.receivedRequestBodyMap.get(submitToken));
+ }
+
+ @Test
+ public void testAuthenticateInSamlHandlerWithADFS() throws IOException{
+ MockHttpPostClient postClient = new MockHttpPostClient();
+ String username = "username@domain";
+ String password = "password&123";
+ AdfsHandshakeManager manager = new AdfsHandshakeManager.Builder(
+ "https://sharepoint.intranet.com", username, password,
+ "https://sts.dmain.com/adfs/services/trust/2005/usernamemixed",
+ "urn:realm:sharepoint", postClient).build();
+ URL tokenRequest = new URL(
+ "https://sts.dmain.com/adfs/services/trust/2005/usernamemixed");
+ String tokenResponse = "<s:Envelope "
+ + "xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\">"
+ + "<s:Header>Some header</s:Header>"
+ + "<t:RequestSecurityTokenResponse "
+ + "xmlns:t=\"http://schemas.xmlsoap.org/ws/2005/02/trust\">"
+ + "This is requested token"
+ + "</t:RequestSecurityTokenResponse>"
+ + "</s:Envelope>";
+ postClient.responseMap.put(tokenRequest,
+ new PostResponseInfo(tokenResponse, null));
+ URL submitToken = new URL("https://sharepoint.intranet.com/_trust");
+ Map<String, List<String>> responseHeaders
+ = new HashMap<String, List<String>>();
+ responseHeaders.put("some-header", Arrays.asList("some value"));
+ responseHeaders.put("Set-Cookie", Arrays.asList("FedAuth=AutheCookie"));
+
+ postClient.responseMap.put(submitToken,
+ new PostResponseInfo(null, responseHeaders));
+
+ SamlAuthenticationHandler authenticationHandler
+ = new SamlAuthenticationHandler.Builder(username, password,
+ new MockScheduledExecutor(), manager).build();
+ AuthenticationResult result = authenticationHandler.authenticate();
+
+ assertEquals("FedAuth=AutheCookie;", result.getCookie());
+ assertEquals("NO_ERROR", result.getErrorCode());
+ assertEquals(600, result.getCookieTimeOut());
+ }
+
+ @Test
+ public void testEscapeCdata() {
+
+ AdfsHandshakeManager manager = new AdfsHandshakeManager.Builder(
+ "http://endpoint", "username", "password", "https://sts", "realm")
+ .build();
+
+ assertEquals("<![CDATA[This is simple]]>",
+ manager.escapeCdata("This is simple"));
+
+ assertEquals(
+ "<![CDATA[This is simple]]]]><![CDATA[>with additional text]]>",
+ manager.escapeCdata("This is simple]]>with additional text"));
+
+ assertEquals(
+ "<![CDATA[This is > & simple]]]]><![CDATA[>]]>",
+ manager.escapeCdata("This is > & simple]]>"));
+
+ assertEquals(
+ "<![CDATA[]]]]><![CDATA[>]]>",
+ manager.escapeCdata("]]>"));
+
+ assertEquals("<![CDATA[<![CDATA[This is simple]]]]><![CDATA[>]]>",
+ manager.escapeCdata("<![CDATA[This is simple]]>"));
+
+ assertEquals("<![CDATA[This is simple]]]]>"
+ + "<![CDATA[>with multiple]]]]><![CDATA[>]]>",
+ manager.escapeCdata("This is simple]]>with multiple]]>"));
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/CallerRunsExecutor.java b/test/com/google/enterprise/adaptor/sharepoint/CallerRunsExecutor.java
index 8dbf573..28c5bba 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/CallerRunsExecutor.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/CallerRunsExecutor.java
@@ -17,7 +17,10 @@
import java.util.Collections;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.Callable;
import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
@@ -60,5 +63,5 @@
public List<Runnable> shutdownNow() {
shutdown();
return Collections.emptyList();
- }
+ }
}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/FormsAuthenticationHandlerTest.java b/test/com/google/enterprise/adaptor/sharepoint/FormsAuthenticationHandlerTest.java
index 84ec9da..fb699af 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/FormsAuthenticationHandlerTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/FormsAuthenticationHandlerTest.java
@@ -16,11 +16,8 @@
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.google.enterprise.adaptor.sharepoint.FormsAuthenticationHandler.AuthenticationHandler;
-
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -36,47 +33,9 @@
public class FormsAuthenticationHandlerTest {
@Rule
- public ExpectedException thrown = ExpectedException.none();
+ public ExpectedException thrown = ExpectedException.none();
- private static class UnsupportedAuthenticationHandler
- implements AuthenticationHandler {
-
- public AuthenticationResult authenticate() throws IOException {
- throw new UnsupportedOperationException();
- }
-
- public boolean isFormsAuthentication() throws IOException {
- throw new UnsupportedOperationException();
- }
- }
-
- private static class MockAuthenticationHandler
- extends UnsupportedAuthenticationHandler {
-
- private boolean isFormsAuthentication;
- private AuthenticationResult authenticationResult;
-
- MockAuthenticationHandler(boolean isFormsAuthentication,
- AuthenticationResult authenticationResult) {
- this.isFormsAuthentication = isFormsAuthentication;
- this.authenticationResult = authenticationResult;
- }
-
- @Override
- public AuthenticationResult authenticate() throws IOException {
- if (authenticationResult == null) {
- throw new UnsupportedOperationException();
- }
- return authenticationResult;
- }
-
- @Override
- public boolean isFormsAuthentication() throws IOException {
- return isFormsAuthentication;
- }
- }
-
- private static class UnsupportedScheduledExecutor extends CallerRunsExecutor
+ static class UnsupportedScheduledExecutor extends CallerRunsExecutor
implements ScheduledExecutorService {
public ScheduledFuture<?> schedule(Runnable command, long delay,
@@ -101,7 +60,7 @@
}
- private static class MockScheduledExecutor
+ static class MockScheduledExecutor
extends UnsupportedScheduledExecutor {
long executionDelay;
TimeUnit executionTimeUnit;
@@ -115,69 +74,73 @@
}
}
+ static class MockFormsAuthenticationHandler
+ extends FormsAuthenticationHandler {
+
+ public MockFormsAuthenticationHandler(String username, String password,
+ ScheduledExecutorService executor) {
+ super(username, password, executor);
+ }
+
+ @Override
+ boolean isFormsAuthentication() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ AuthenticationResult authenticate() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ }
+
@Test
public void testConstructor() {
- new FormsAuthenticationHandler("username", "password",
- new UnsupportedScheduledExecutor(),
- new UnsupportedAuthenticationHandler());
+ new MockFormsAuthenticationHandler("username", "password",
+ new UnsupportedScheduledExecutor());
}
@Test
public void testNullUserName() {
thrown.expect(NullPointerException.class);
- new FormsAuthenticationHandler(null, "password",
- new UnsupportedScheduledExecutor(),
- new UnsupportedAuthenticationHandler());
+ new MockFormsAuthenticationHandler(null, "password",
+ new UnsupportedScheduledExecutor());
}
@Test
public void testNullPassword() {
thrown.expect(NullPointerException.class);
- new FormsAuthenticationHandler("username", null,
- new UnsupportedScheduledExecutor(),
- new UnsupportedAuthenticationHandler());
+ new MockFormsAuthenticationHandler("username", null,
+ new UnsupportedScheduledExecutor());
}
@Test
public void testNullScheduledExecutor() {
thrown.expect(NullPointerException.class);
- new FormsAuthenticationHandler("username", "password", null,
- new UnsupportedAuthenticationHandler());
- }
-
- @Test
- public void testNullAuthenticationHandler() {
- thrown.expect(NullPointerException.class);
- new FormsAuthenticationHandler("username", "password",
- new UnsupportedScheduledExecutor(),null);
- }
-
- @Test
- public void testWindowsAuthentication() throws IOException {
- FormsAuthenticationHandler formsHandler = new FormsAuthenticationHandler(
- "username", "password", new UnsupportedScheduledExecutor(),
- new MockAuthenticationHandler(false, null));
- formsHandler.start();
- assertFalse(formsHandler.isFormsAuthentication());
- assertTrue(formsHandler.getAuthenticationCookies().isEmpty());
- }
+ new MockFormsAuthenticationHandler("username", "password", null);
+ }
@Test
public void testEmptyUsernamePassword() throws IOException {
- FormsAuthenticationHandler formsHandler = new FormsAuthenticationHandler(
- "", "", new UnsupportedScheduledExecutor(),
- new UnsupportedAuthenticationHandler());
- formsHandler.start();
- assertFalse(formsHandler.isFormsAuthentication());
+ FormsAuthenticationHandler formsHandler
+ = new MockFormsAuthenticationHandler("", "",
+ new UnsupportedScheduledExecutor());
+ formsHandler.start();
assertTrue(formsHandler.getAuthenticationCookies().isEmpty());
}
@Test
public void testFormsAuthenticationNoError() throws IOException {
- MockScheduledExecutor executor = new MockScheduledExecutor();
- FormsAuthenticationHandler formsHandler = new FormsAuthenticationHandler(
- "username", "password", executor, new MockAuthenticationHandler(true,
- new AuthenticationResult("AuthenCookie", 99, "NO_ERROR")));
+ MockScheduledExecutor executor = new MockScheduledExecutor();
+ FormsAuthenticationHandler formsHandler
+ = new MockFormsAuthenticationHandler("username", "password", executor) {
+ @Override public boolean isFormsAuthentication() throws IOException {
+ return true;
+ }
+ @Override public AuthenticationResult authenticate()
+ throws IOException {
+ return new AuthenticationResult("AuthenCookie", 99, "NO_ERROR");
+ }
+ };
formsHandler.start();
assertTrue(formsHandler.isFormsAuthentication());
assertEquals(Collections.unmodifiableList(Arrays.asList("AuthenCookie")),
@@ -189,10 +152,17 @@
@Test
public void testFormsAuthenticationPasswordMismatch() throws IOException {
- FormsAuthenticationHandler formsHandler = new FormsAuthenticationHandler(
- "username", "password", new UnsupportedScheduledExecutor(),
- new MockAuthenticationHandler(true,
- new AuthenticationResult(null, 99, "PASSWORD_NOT_MATCH")));
+ FormsAuthenticationHandler formsHandler
+ = new MockFormsAuthenticationHandler("username", "password",
+ new UnsupportedScheduledExecutor()) {
+ @Override public boolean isFormsAuthentication() throws IOException {
+ return true;
+ }
+ @Override public AuthenticationResult authenticate()
+ throws IOException {
+ return new AuthenticationResult(null, 99, "PASSWORD_MISMATCH");
+ }
+ };
formsHandler.start();
assertTrue(formsHandler.isFormsAuthentication());
assertTrue(formsHandler.getAuthenticationCookies().isEmpty());
diff --git a/test/com/google/enterprise/adaptor/sharepoint/LiveAuthenticationHandshakeManagerTest.java b/test/com/google/enterprise/adaptor/sharepoint/LiveAuthenticationHandshakeManagerTest.java
new file mode 100644
index 0000000..c7d08e9
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/sharepoint/LiveAuthenticationHandshakeManagerTest.java
@@ -0,0 +1,215 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.sharepoint;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.enterprise.adaptor.sharepoint.FormsAuthenticationHandlerTest.MockScheduledExecutor;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.HttpPostClient;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.PostResponseInfo;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+
+public class LiveAuthenticationHandshakeManagerTest {
+
+ private static final String LIVE_AUTHENTICATION_RESPONSE
+ = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+ + "<S:Envelope xmlns:S=\"http://www.w3.org/2003/05/soap-envelope\" "
+ + "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-"
+ + "wssecurity-secext-1.0.xsd\" "
+ + "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-"
+ + "wss-wssecurity-utility-1.0.xsd\" "
+ + "xmlns:wsa=\"http://www.w3.org/2005/08/addressing\">"
+ + "<S:Header><wsa:Action "
+ + "xmlns:S=\"http://www.w3.org/2003/05/soap-envelope\" "
+ + "xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" "
+ + "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-"
+ + "wss-wssecurity-utility-1.0.xsd\" wsu:Id=\"Action\" "
+ + "S:mustUnderstand=\"1\">"
+ + "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue"
+ + "</wsa:Action><wsa:To "
+ + "xmlns:S=\"http://www.w3.org/2003/05/soap-envelope\" "
+ + "xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" "
+ + "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-"
+ + "wss-wssecurity-utility-1.0.xsd\" "
+ + "wsu:Id=\"To\" S:mustUnderstand=\"1\">"
+ + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"
+ + "</wsa:To><wsse:Security S:mustUnderstand=\"1\">"
+ + "<wsu:Timestamp xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/"
+ + "oasis-200401-wss-wssecurity-utility-1.0.xsd\" wsu:Id=\"TS\">"
+ + "<wsu:Created>2014-03-27T20:56:38Z</wsu:Created><wsu:Expires>"
+ + "2014-03-27T21:01:38Z</wsu:Expires></wsu:Timestamp></wsse:Security>"
+ + "</S:Header><S:Body><wst:RequestSecurityTokenResponse "
+ + "xmlns:S=\"http://www.w3.org/2003/05/soap-envelope\" "
+ + "xmlns:wst=\"http://schemas.xmlsoap.org/ws/2005/02/trust\" "
+ + "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-"
+ + "wss-wssecurity-secext-1.0.xsd\" "
+ + "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-"
+ + "wss-wssecurity-utility-1.0.xsd\" "
+ + "xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" "
+ + "xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\" "
+ + "xmlns:psf=\"http://schemas.microsoft.com/Passport"
+ + "/SoapServices/SOAPFault\"><wst:TokenType>urn:passport:compact"
+ + "</wst:TokenType><wsp:AppliesTo "
+ + "xmlns:wsa=\"http://www.w3.org/2005/08/addressing\">"
+ + "<wsa:EndpointReference><wsa:Address>"
+ + "https://sharepoint.example.com"
+ + "</wsa:Address></wsa:EndpointReference>"
+ + "</wsp:AppliesTo><wst:Lifetime><wsu:Created>2014-03-27T20:56:38Z"
+ + "</wsu:Created><wsu:Expires>2014-03-28T20:56:38Z</wsu:Expires>"
+ + "</wst:Lifetime><wst:RequestedSecurityToken>"
+ + "<wsse:BinarySecurityToken Id=\"Compact0\">"
+ + "t=This is live authentication token to extract"
+ + "</wsse:BinarySecurityToken></wst:RequestedSecurityToken>"
+ + "<wst:RequestedAttachedReference><wsse:SecurityTokenReference>"
+ + "<wsse:Reference URI=\"euzZqFurd7rgUGVjTUnCah09kbA=\">"
+ + "</wsse:Reference></wsse:SecurityTokenReference>"
+ + "</wst:RequestedAttachedReference><wst:RequestedUnattachedReference>"
+ + "<wsse:SecurityTokenReference><wsse:Reference "
+ + "URI=\"euzZqFurd7rgUGVjTUnCah09kbA=\"></wsse:Reference>"
+ + "</wsse:SecurityTokenReference></wst:RequestedUnattachedReference>"
+ + "</wst:RequestSecurityTokenResponse></S:Body></S:Envelope>";
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testConstructor() {
+ new LiveAuthenticationHandshakeManager.Builder(
+ "http://sharepointurl", "username", "password")
+ .build();
+ }
+
+ @Test
+ public void testNullUsername() {
+ thrown.expect(NullPointerException.class);
+ new LiveAuthenticationHandshakeManager.Builder(
+ "http://endpoint", null, "password").build();
+ }
+
+ @Test
+ public void testNullPassword() {
+ thrown.expect(NullPointerException.class);
+ new LiveAuthenticationHandshakeManager.Builder(
+ "http://endpoint", "username", null).build();
+ }
+
+ @Test
+ public void testNullSharePointUrl() {
+ thrown.expect(NullPointerException.class);
+ new LiveAuthenticationHandshakeManager.Builder(
+ null, "username", "password").build();
+ }
+
+ @Test
+ public void testExtractToken() throws IOException {
+ LiveAuthenticationHandshakeManager manager
+ = new LiveAuthenticationHandshakeManager.Builder(
+ "https://sharepoint.example.com", "username", "password").build();
+
+ assertEquals("t=This is live authentication token to extract",
+ manager.extractToken(LIVE_AUTHENTICATION_RESPONSE));
+ }
+
+ @Test
+ public void testExtractTokenWithInvalidInput() throws IOException {
+ LiveAuthenticationHandshakeManager manager
+ = new LiveAuthenticationHandshakeManager.Builder(
+ "https://sharepoint.example.com", "username", "password").build();
+
+ String tokenResponse = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+ + "<S:Envelope xmlns:S=\"http://www.w3.org/2003/05/soap-envelope\">"
+ + "<data>Something went wrong this is invalid</data>"
+ + "</S:Envelope>";
+
+ thrown.expect(IOException.class);
+ String extractedToken = manager.extractToken(tokenResponse);
+ }
+
+ @Test
+ public void testExtractTokenWithNullInput() throws IOException {
+ LiveAuthenticationHandshakeManager manager
+ = new LiveAuthenticationHandshakeManager.Builder(
+ "https://sharepoint.example.com", "username", "password").build();
+ thrown.expect(IOException.class);
+ String extractedToken = manager.extractToken(null);
+ }
+
+ @Test
+ public void testAuthenticateInSamlHandlerWithLive() throws IOException{
+ MockHttpPostClient postClient = new MockHttpPostClient();
+ LiveAuthenticationHandshakeManager manager
+ = new LiveAuthenticationHandshakeManager.Builder(
+ "https://sharepoint.example.com", "username@domain", "password&123",
+ postClient).build();
+ URL tokenRequest = new URL(
+ "https://login.microsoftonline.com/extSTS.srf");
+ postClient.responseMap.put(tokenRequest,
+ new PostResponseInfo(LIVE_AUTHENTICATION_RESPONSE, null));
+ URL submitToken = new URL(
+ "https://sharepoint.example.com/_forms/default.aspx?wa=wsignin1.0");
+ Map<String, List<String>> responseHeaders
+ = new HashMap<String, List<String>>();
+ responseHeaders.put("some-header", Arrays.asList("some value"));
+ responseHeaders.put("Set-Cookie",
+ Arrays.asList("FedAuth=AutheCookie", "rfta=rftaValue"));
+
+ postClient.responseMap.put(submitToken,
+ new PostResponseInfo(null, responseHeaders));
+
+ SamlAuthenticationHandler authenticationHandler
+ = new SamlAuthenticationHandler.Builder("username@domain",
+ "password&123", new MockScheduledExecutor(), manager).build();
+ AuthenticationResult result = authenticationHandler.authenticate();
+
+ assertEquals("FedAuth=AutheCookie;rfta=rftaValue;", result.getCookie());
+ assertEquals("NO_ERROR", result.getErrorCode());
+ assertEquals(600, result.getCookieTimeOut());
+ }
+
+
+ private static class MockHttpPostClient implements HttpPostClient {
+
+ private Map<URL, SamlAuthenticationHandler.PostResponseInfo> responseMap;
+ private Map<URL, String> receivedRequestBodyMap;
+ public MockHttpPostClient() {
+ responseMap = new HashMap<URL, PostResponseInfo>();
+ receivedRequestBodyMap = new HashMap<URL, String>();
+ }
+
+ @Override
+ public PostResponseInfo issuePostRequest(
+ URL url, Map<String, String> connectionProperties, String requestBody)
+ throws IOException {
+ if (!responseMap.containsKey(url)) {
+ throw new UnsupportedOperationException(
+ "Unexpected Http Post for URL " + url);
+ }
+ // log incoming request body
+ receivedRequestBodyMap.put(url, requestBody);
+ return responseMap.get(url);
+ }
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SamlAuthenticationHandlerTest.java b/test/com/google/enterprise/adaptor/sharepoint/SamlAuthenticationHandlerTest.java
new file mode 100644
index 0000000..4b05103
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/sharepoint/SamlAuthenticationHandlerTest.java
@@ -0,0 +1,119 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.sharepoint;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.enterprise.adaptor.sharepoint.FormsAuthenticationHandlerTest.UnsupportedScheduledExecutor;
+import com.google.enterprise.adaptor.sharepoint.FormsAuthenticationHandlerTest.MockScheduledExecutor;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.SamlHandshakeManager;
+
+import java.io.IOException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+
+public class SamlAuthenticationHandlerTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testBuilder() {
+ new SamlAuthenticationHandler.Builder("username", "password",
+ new UnsupportedScheduledExecutor(),
+ new UnsupportedSamlHandshakeManager()).build();
+ }
+
+ @Test
+ public void testNullSamlClient() {
+ thrown.expect(NullPointerException.class);
+ new SamlAuthenticationHandler.Builder("username", "password",
+ new UnsupportedScheduledExecutor(), null).build();
+ }
+
+ @Test
+ public void testIsFormsAutentication() throws IOException {
+ assertTrue(new SamlAuthenticationHandler.Builder("username", "password",
+ new UnsupportedScheduledExecutor(),
+ new UnsupportedSamlHandshakeManager()).build().isFormsAuthentication());
+ }
+
+ @Test
+ public void testNullToken() throws IOException {
+ SamlAuthenticationHandler handler = new SamlAuthenticationHandler.Builder(
+ "username", "password", new UnsupportedScheduledExecutor(),
+ new MockSamlHandshakeManager(null, null) {
+ @Override public String getAuthenticationCookie(String token) {
+ throw new UnsupportedOperationException();
+ }
+ }).build();
+
+ assertTrue(handler.isFormsAuthentication());
+ thrown.expect(IOException.class);
+ AuthenticationResult result = handler.authenticate();
+ }
+
+ @Test
+ public void testSAMLAutentication() throws IOException {
+ SamlAuthenticationHandler handler
+ = new SamlAuthenticationHandler.Builder("username", "password",
+ new MockScheduledExecutor(),
+ new MockSamlHandshakeManager("token", "AuthenticationCookie"))
+ .build();
+ assertTrue(handler.isFormsAuthentication());
+ AuthenticationResult result = handler.authenticate();
+ assertNotNull(result);
+ assertEquals("AuthenticationCookie", result.getCookie());
+ assertEquals(600, result.getCookieTimeOut());
+ assertEquals("NO_ERROR", result.getErrorCode());
+ }
+
+ private static class UnsupportedSamlHandshakeManager
+ implements SamlHandshakeManager {
+ @Override
+ public String requestToken() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getAuthenticationCookie(String token) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private static class MockSamlHandshakeManager
+ extends UnsupportedSamlHandshakeManager {
+ private String token;
+ private String cookie;
+ MockSamlHandshakeManager(String token, String cookie) {
+ this.token = token;
+ this.cookie = cookie;
+ }
+
+ @Override
+ public String requestToken() {
+ return token;
+ }
+
+ @Override
+ public String getAuthenticationCookie(String token) throws IOException {
+ return cookie;
+ }
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
index 4606c23..4162017 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
@@ -35,6 +35,7 @@
import com.google.enterprise.adaptor.Metadata;
import com.google.enterprise.adaptor.Principal;
import com.google.enterprise.adaptor.UserPrincipal;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.SamlHandshakeManager;
import com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.SiteUserIdMappingCallable;
import com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.SoapFactory;
@@ -116,6 +117,9 @@
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicLong;
+import javax.xml.ws.Binding;
+import javax.xml.ws.BindingProvider;
+import javax.xml.ws.EndpointReference;
import javax.xml.ws.Holder;
import javax.xml.ws.WebServiceException;
@@ -244,7 +248,6 @@
};
private final MockSoapFactory initableSoapFactory
= MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE)
.register(CD_CONTENT_EXCHANGE));
@@ -316,26 +319,90 @@
@Test
public void testNullSoapFactory() {
thrown.expect(NullPointerException.class);
- new SharePointAdaptor(null, new UnsupportedHttpClient(), executorFactory);
+ new SharePointAdaptor(null, new UnsupportedHttpClient(), executorFactory,
+ new UnsupportedAuthenticationClientFactory());
}
@Test
public void testNullHttpClient() {
thrown.expect(NullPointerException.class);
- new SharePointAdaptor(MockSoapFactory.blank(), null, executorFactory);
+ new SharePointAdaptor(MockSoapFactory.blank(), null, executorFactory,
+ new UnsupportedAuthenticationClientFactory());
}
@Test
public void testNullExecutorFactory() {
thrown.expect(NullPointerException.class);
new SharePointAdaptor(MockSoapFactory.blank(), new UnsupportedHttpClient(),
- null);
+ null, new UnsupportedAuthenticationClientFactory());
}
@Test
public void testInitDestroy() throws Exception {
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
+ adaptor.init(new MockAdaptorContext(config, pusher));
+ adaptor.destroy();
+ adaptor = null;
+ }
+
+ @Test
+ public void testAdaptorInitWithAdfs() throws Exception {
+ SoapFactory siteDataFactory = MockSoapFactory.blank()
+ .endpoint(VS_ENDPOINT, MockSiteData.blank()
+ .register(VS_CONTENT_EXCHANGE)
+ .register(CD_CONTENT_EXCHANGE))
+ .endpoint("http://localhost:1/_vti_bin/People.asmx",
+ new MockPeopleSoap())
+ .endpoint("http://localhost:1/_vti_bin/UserGroup.asmx",
+ new MockUserGroupSoap(null));
+
+ adaptor = new SharePointAdaptor(siteDataFactory,
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryAdfs());
+ config.overrideKey("sharepoint.sts.endpoint", "https://stsendpoint");
+ config.overrideKey("sharepoint.sts.realm", "urn:sharepoint:com");
+ adaptor.init(new MockAdaptorContext(config, pusher));
+ adaptor.destroy();
+ adaptor = null;
+ }
+
+ @Test
+ public void testAdaptorInitWithMissingRelam() throws Exception {
+ SoapFactory siteDataFactory = MockSoapFactory.blank()
+ .endpoint(VS_ENDPOINT, MockSiteData.blank()
+ .register(VS_CONTENT_EXCHANGE)
+ .register(CD_CONTENT_EXCHANGE))
+ .endpoint("http://localhost:1/_vti_bin/People.asmx",
+ new MockPeopleSoap())
+ .endpoint("http://localhost:1/_vti_bin/UserGroup.asmx",
+ new MockUserGroupSoap(null));
+
+ adaptor = new SharePointAdaptor(siteDataFactory,
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
+ config.overrideKey("sharepoint.sts.endpoint", "https://stsendpoint");
+ adaptor.init(new MockAdaptorContext(config, pusher));
+ adaptor.destroy();
+ adaptor = null;
+ }
+
+ @Test
+ public void testAdaptorInitWithLive() throws Exception {
+ SoapFactory siteDataFactory = MockSoapFactory.blank()
+ .endpoint(VS_ENDPOINT, MockSiteData.blank()
+ .register(VS_CONTENT_EXCHANGE)
+ .register(CD_CONTENT_EXCHANGE))
+ .endpoint("http://localhost:1/_vti_bin/People.asmx",
+ new MockPeopleSoap())
+ .endpoint("http://localhost:1/_vti_bin/UserGroup.asmx",
+ new MockUserGroupSoap(null));
+
+ adaptor = new SharePointAdaptor(siteDataFactory,
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryLive());
+ config.overrideKey("sharepoint.useLiveAuthentication", "true");
adaptor.init(new MockAdaptorContext(config, pusher));
adaptor.destroy();
adaptor = null;
@@ -344,7 +411,8 @@
@Test
public void testInitDestroyInitDestroy() throws Exception {
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
adaptor.destroy();
adaptor.init(new MockAdaptorContext(config, pusher));
@@ -355,7 +423,8 @@
@Test
public void testTrailingSlashInit() throws Exception {
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
config.overrideKey("sharepoint.server", "http://localhost:1/");
adaptor.init(new MockAdaptorContext(config, pusher));
}
@@ -416,8 +485,7 @@
@Test
public void testGetDocContentWrongServer() throws Exception {
- SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
+ SoapFactory siteDataFactory = MockSoapFactory.blank()
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE)
.register(CD_CONTENT_EXCHANGE)
@@ -425,7 +493,8 @@
"http://wronghost:1/", 1, null, null)));
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -439,7 +508,6 @@
public void testGetDocContentWrongPage() throws Exception {
final String wrongPage = "http://localhost:1/wrongPage";
SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE)
.register(CD_CONTENT_EXCHANGE)
@@ -449,7 +517,8 @@
wrongPage, false, null, null, null, null)));
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(new DocId(wrongPage));
@@ -467,14 +536,14 @@
mockPeople.addToResult("GDC-PSL\\Administrator", "dministrator",
SPPrincipalType.USER);
SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE)
.register(CD_CONTENT_EXCHANGE))
.endpoint("http://localhost:1/_vti_bin/People.asmx", mockPeople);
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsResponse response = new GetContentsResponse(baos);
@@ -526,7 +595,6 @@
SPPrincipalType.USER);
SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE
.replaceInContent("</Policies>", claimsPolicyUsers))
@@ -534,7 +602,8 @@
.endpoint("http://localhost:1/_vti_bin/People.asmx", mockPeople);
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsResponse response = new GetContentsResponse(baos);
@@ -555,7 +624,6 @@
@Test
public void testGetDocContentSiteCollection() throws Exception {
SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE)
.register(CD_CONTENT_EXCHANGE)
@@ -566,7 +634,8 @@
.register(SITES_SITECOLLECTION_SC_CONTENT_EXCHANGE));
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -621,7 +690,6 @@
@Test
public void testGetDocContentSiteCollectionWithAdGroup() throws Exception {
SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE)
.register(CD_CONTENT_EXCHANGE)
@@ -640,7 +708,8 @@
"IsDomainGroup=\"True\"")));
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -667,7 +736,6 @@
+ "<permission memberid='15' mask='756052856929' />"
+ "<permission memberid='19' mask='756052856929' /></permissions>";
SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE)
.register(CD_CONTENT_EXCHANGE)
@@ -681,7 +749,8 @@
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -713,7 +782,6 @@
throws Exception {
ReferenceSiteData siteData = new ReferenceSiteData();
SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE)
.register(CD_CONTENT_EXCHANGE)
@@ -734,7 +802,8 @@
.replaceInContent("spuser2", "spuser100"));
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
// This populates the cache, but otherwise doesn't test anything new.
@@ -781,7 +850,8 @@
.replaceInContent("NoIndex=\"False\"", "NoIndex=\"True\"")));
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -800,7 +870,8 @@
.register(SITES_SITECOLLECTION_S_CONTENT_EXCHANGE);
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -858,7 +929,8 @@
.replaceInContent("NoIndex=\"False\"", "NoIndex=\"True\""));
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -883,7 +955,8 @@
+ "/NonDefault.aspx", false, null, null, null, null))
.register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_L_CONTENT_EXCHANGE);
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -913,7 +986,8 @@
true, null, null, "{6F33949A-B3FF-4B0C-BA99-93CB518AC2C0}",
null));
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -972,7 +1046,7 @@
return "http://localhost:1/sites/SiteCollection/Lists/Custom List"
+ "/AllItems.aspx";
}
- }, executorFactory);
+ }, executorFactory, new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -1032,7 +1106,7 @@
return "http://localhost:1/sites/SiteCollection/Lists/Custom List"
+ "/AllItems.aspx";
}
- }, executorFactory);
+ }, executorFactory, new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -1061,7 +1135,8 @@
.register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_2_A_CONTENT_EXCHANGE);
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -1215,7 +1290,8 @@
"http://localhost:1/sites/SiteCollection/Lists/Custom List/2_.000",
true, null, null, "{6F33949A-B3FF-4B0C-BA99-93CB518AC2C0}", "2"));
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -1264,7 +1340,8 @@
"ows_ScopeId='2;#{f9cb02b3-7f29-4cac-804f-ba6e14f1eb39}'"));
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -1309,7 +1386,8 @@
"http://localhost:1/sites/SiteCollection/_vti_bin/UserGroup.asmx",
mockUserGroupSoap)
.endpoint(SITES_SITECOLLECTION_ENDPOINT, new UnsupportedSiteData()),
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -1415,7 +1493,8 @@
.register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_1_F_CONTENT_EXCHANGE);
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -1566,7 +1645,8 @@
.register(SITES_SITECOLLECTION_LISTS_CUSTOMLIST_1_F_CONTENT_EXCHANGE);
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GetContentsRequest request = new GetContentsRequest(
@@ -1603,7 +1683,6 @@
// Force a full batch of 2 and a final batch of 1.
config.overrideKey("feed.maxUrls", "2");
adaptor = new SharePointAdaptor(MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, MockSiteData.blank()
.register(VS_CONTENT_EXCHANGE)
.register(CD_CONTENT_EXCHANGE
@@ -1612,7 +1691,8 @@
.register(SITES_SITECOLLECTION_SAW_EXCHANGE))
.endpoint(SITES_SITECOLLECTION_ENDPOINT, MockSiteData.blank()
.register(SITES_SITECOLLECTION_SC_CONTENT_EXCHANGE)),
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
assertEquals(0, pusher.getRecords().size());
@@ -1697,10 +1777,10 @@
}
};
SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, countingSiteData);
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
siteData.setSiteDataSoap(state0);
adaptor.init(new MockAdaptorContext(config, pusher));
@@ -1787,10 +1867,10 @@
}
};
SoapFactory siteDataFactory = MockSoapFactory.blank()
- .endpoint(AUTH_ENDPOINT, new MockAuthenticationSoap())
.endpoint(VS_ENDPOINT, countingSiteData);
adaptor = new SharePointAdaptor(siteDataFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
@@ -1808,7 +1888,8 @@
final String getChangesContentDatabase
= loadTestString("testModifiedGetDocIdsClient.changes-cd.xml");
adaptor = new SharePointAdaptor(initableSoapFactory,
- new UnsupportedHttpClient(), executorFactory);
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms());
adaptor.init(new MockAdaptorContext(config, pusher));
SPContentDatabase result = parseChanges(getChangesContentDatabase);
List<DocId> docIds = new ArrayList<DocId>();
@@ -1967,8 +2048,9 @@
}
}
- private static class UnsupportedPeopleSoap extends DelegatingPeopleSoap {
- private final String endpoint;
+ private static class UnsupportedPeopleSoap extends DelegatingPeopleSoap
+ implements BindingProvider {
+ private final String endpoint;
public UnsupportedPeopleSoap() {
this(null);
@@ -1986,10 +2068,38 @@
throw new UnsupportedOperationException("Endpoint: " + endpoint);
}
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, Object> getResponseContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Binding getBinding() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public EndpointReference getEndpointReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends EndpointReference> T getEndpointReference(
+ Class<T> clazz) {
+ throw new UnsupportedOperationException();
+ }
}
private static class MockPeopleSoap extends UnsupportedPeopleSoap {
private final ArrayOfPrincipalInfo result;
+ private Map<String, Object> requestContext = new HashMap<String, Object>();
+
public MockPeopleSoap() {
this.result = new ArrayOfPrincipalInfo();
}
@@ -2009,10 +2119,16 @@
p.setPrincipalType(type);
result.getPrincipalInfo().add(p);
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ return requestContext;
+ }
}
private static class MockUserGroupSoap extends UnsupportedUserGroupSoap {
- final Users users;
+ final Users users;
+ private Map<String, Object> requestContext = new HashMap<String, Object>();
public MockUserGroupSoap(Users users) {
this.users = users;
}
@@ -2031,11 +2147,16 @@
result.setGetUserCollectionFromSite(siteUsers);
return result;
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ return requestContext;
+ }
}
private static class UnsupportedUserGroupSoap
- extends DelegatingUserGroupSoap {
- private final String endpoint;
+ extends DelegatingUserGroupSoap implements BindingProvider {
+ private final String endpoint;
public UnsupportedUserGroupSoap() {
this(null);
@@ -2053,6 +2174,32 @@
throw new UnsupportedOperationException("Endpoint: " + endpoint);
}
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, Object> getResponseContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Binding getBinding() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public EndpointReference getEndpointReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends EndpointReference> T
+ getEndpointReference(Class<T> clazz) {
+ throw new UnsupportedOperationException();
+ }
}
private abstract static class DelegatingUserGroupSoap
@@ -2366,11 +2513,38 @@
/**
* Throw UnsupportedOperationException for all calls.
*/
- private static class UnsupportedSiteData extends DelegatingSiteData {
+ private static class UnsupportedSiteData extends DelegatingSiteData
+ implements BindingProvider{
@Override
protected SiteDataSoap delegate() {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, Object> getResponseContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Binding getBinding() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public EndpointReference getEndpointReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends EndpointReference> T
+ getEndpointReference(Class<T> clazz) {
+ throw new UnsupportedOperationException();
+ }
}
private static class UnsupportedCallable<V> implements Callable<V> {
@@ -2383,50 +2557,40 @@
private static class MockSoapFactory implements SoapFactory {
private final String expectedEndpoint;
private final SiteDataSoap siteData;
- private final UserGroupSoap userGroup;
- private final AuthenticationSoap authentication;
+ private final UserGroupSoap userGroup;
private final PeopleSoap people;
private final MockSoapFactory chain;
private MockSoapFactory(String expectedEndpoint, SiteDataSoap siteData,
- UserGroupSoap userGroup, PeopleSoap people,
- AuthenticationSoap authentication, MockSoapFactory chain) {
+ UserGroupSoap userGroup, PeopleSoap people, MockSoapFactory chain) {
this.expectedEndpoint = expectedEndpoint;
this.siteData = siteData;
this.userGroup = userGroup;
- this.people = people;
- // Tests will always use windows authentication.
- this.authentication = authentication;
+ this.people = people;
this.chain = chain;
}
public static MockSoapFactory blank() {
- return new MockSoapFactory(null, null, null, null, null, null);
+ return new MockSoapFactory(null, null, null, null, null);
}
public MockSoapFactory endpoint(String expectedEndpoint,
SiteDataSoap siteData) {
return new MockSoapFactory(
- expectedEndpoint, siteData, null, null, null, this);
+ expectedEndpoint, siteData, null, null, this);
}
public MockSoapFactory endpoint(String expectedEndpoint,
UserGroupSoap userGroup) {
return new MockSoapFactory(
- expectedEndpoint, null, userGroup, null, null, this);
+ expectedEndpoint, null, userGroup, null, this);
}
public MockSoapFactory endpoint(String expectedEndpoint,
PeopleSoap people) {
return new MockSoapFactory(
- expectedEndpoint, null, null, people, null, this);
- }
-
- public MockSoapFactory endpoint(String expectedEndpoint,
- AuthenticationSoap authentication) {
- return new MockSoapFactory(
- expectedEndpoint, null, null, null, authentication, this);
- }
+ expectedEndpoint, null, null, people, this);
+ }
@Override
public SiteDataSoap newSiteData(String endpoint) {
@@ -2438,17 +2602,6 @@
}
return chain.newSiteData(endpoint);
}
-
- @Override
- public AuthenticationSoap newAuthentication(String endpoint) {
- if (chain == null) {
- fail("Could not find endpoint " + endpoint);
- }
- if (expectedEndpoint.equals(endpoint) && authentication != null) {
- return authentication;
- }
- return chain.newAuthentication(endpoint);
- }
@Override
public UserGroupSoap newUserGroup(String endpoint) {
@@ -2477,7 +2630,7 @@
}
private static class ReferenceSiteData extends DelegatingSiteData {
- private volatile SiteDataSoap siteData = new UnsupportedSiteData();
+ private volatile SiteDataSoap siteData = new UnsupportedSiteData();
@Override
protected SiteDataSoap delegate() {
@@ -2497,6 +2650,7 @@
private final List<ContentExchange> contentList;
private final List<ChangesExchange> changesList;
private final List<SiteAndWebExchange> siteAndWebList;
+ private Map<String, Object> requestContext = new HashMap<String, Object>();
private MockSiteData() {
this.urlSegmentsList = Collections.emptyList();
@@ -2592,6 +2746,11 @@
}
fail("Could not find " + strUrl);
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ return requestContext;
+ }
public static MockSiteData blank() {
return new MockSiteData();
@@ -2622,7 +2781,7 @@
List<T> l = new ArrayList<T>(existingList);
l.add(item);
return Collections.unmodifiableList(l);
- }
+ }
}
private static class URLSegmentsExchange {
@@ -2734,4 +2893,81 @@
return this;
}
}
+
+ private static class UnsupportedAuthenticationClientFactory
+ implements AuthenticationClientFactory {
+
+ @Override
+ public AuthenticationSoap newSharePointFormsAuthentication(
+ String virtualServer, String username, String password)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SamlHandshakeManager newAdfsAuthentication(String virtualServer,
+ String username, String password, String stsendpoint, String stsrelam,
+ String login, String trustlocation) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SamlHandshakeManager newLiveAuthentication(String virtualServer,
+ String username, String password) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ private static class MockAuthenticationClientFactoryForms
+ extends UnsupportedAuthenticationClientFactory {
+ @Override
+ public AuthenticationSoap newSharePointFormsAuthentication(
+ String virtualServer, String username, String password)
+ throws IOException {
+ return new MockAuthenticationSoap();
+ }
+ }
+
+ private static class MockAuthenticationClientFactoryAdfs
+ extends UnsupportedAuthenticationClientFactory {
+ @Override
+ public SamlHandshakeManager newAdfsAuthentication(
+ String virtualServer, String username, String password,
+ String stsendpoint, String stsrelam, String login,
+ String trustlocation) throws IOException {
+ return new MockSamlHandshakeManager("Token", "rtf=authenticationCookie;");
+ }
+ }
+
+ private static class MockAuthenticationClientFactoryLive
+ extends UnsupportedAuthenticationClientFactory {
+ @Override
+ public SamlHandshakeManager newLiveAuthentication(
+ String virtualServer, String username, String password)
+ throws IOException {
+ return new MockSamlHandshakeManager("Token", "rtf=authenticationCookie;");
+ }
+ }
+
+ private static class MockSamlHandshakeManager
+ implements SamlHandshakeManager {
+ private String token;
+ private String cookie;
+ MockSamlHandshakeManager(String token, String cookie) {
+ this.token = token;
+ this.cookie = cookie;
+ }
+
+ @Override
+ public String requestToken() {
+ return token;
+ }
+
+ @Override
+ public String getAuthenticationCookie(String token) throws IOException {
+ return cookie;
+ }
+ }
+
}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointFormsAuthenticationHandlerTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointFormsAuthenticationHandlerTest.java
index fb9251f..2782a51 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointFormsAuthenticationHandlerTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointFormsAuthenticationHandlerTest.java
@@ -20,6 +20,8 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import com.google.enterprise.adaptor.sharepoint.FormsAuthenticationHandlerTest.UnsupportedScheduledExecutor;
+
import com.microsoft.schemas.sharepoint.soap.authentication.AuthenticationMode;
import com.microsoft.schemas.sharepoint.soap.authentication.AuthenticationSoap;
import com.microsoft.schemas.sharepoint.soap.authentication.LoginErrorCode;
@@ -35,6 +37,10 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
@@ -92,41 +98,46 @@
}
@Test
- public void testConstructor() {
- new SharePointFormsAuthenticationHandler (
- new UnsupportedAuthenticationSoap(), "username", "password");
+ public void testBuilder() {
+ new SharePointFormsAuthenticationHandler.Builder("username", "password",
+ new UnsupportedScheduledExecutor(),
+ new UnsupportedAuthenticationSoap()).build();
}
@Test
public void testNullUserName() {
thrown.expect(NullPointerException.class);
- new SharePointFormsAuthenticationHandler (
- new UnsupportedAuthenticationSoap(), null, "password");
+ new SharePointFormsAuthenticationHandler.Builder(null, "password",
+ new UnsupportedScheduledExecutor(),
+ new UnsupportedAuthenticationSoap()).build();
}
@Test
public void testNullPassword() {
thrown.expect(NullPointerException.class);
- new SharePointFormsAuthenticationHandler (
- new UnsupportedAuthenticationSoap(), "username", null);
+ new SharePointFormsAuthenticationHandler.Builder("username", null,
+ new UnsupportedScheduledExecutor(),
+ new UnsupportedAuthenticationSoap()).build();
}
@Test
public void testNullAuthenticationClient() {
thrown.expect(NullPointerException.class);
- new SharePointFormsAuthenticationHandler ( null, "username", "password");
+ new SharePointFormsAuthenticationHandler.Builder("username", "password",
+ new UnsupportedScheduledExecutor(), null).build();
}
@Test
public void testSharePointWithWindowsAuthentication() throws IOException{
SharePointFormsAuthenticationHandler authenHandler
- = new SharePointFormsAuthenticationHandler(
+ = new SharePointFormsAuthenticationHandler.Builder("username",
+ "password", new UnsupportedScheduledExecutor(),
new MockFormsAuthenticationSoap(){
@Override public AuthenticationMode mode()
{
return AuthenticationMode.WINDOWS;
}
- }, "username", "password");
+ }).build();
assertFalse(authenHandler.isFormsAuthentication());
AuthenticationResult ar = authenHandler.authenticate();
@@ -139,7 +150,8 @@
@Test
public void testSharePointWithFormsPasswordMismatch() throws IOException {
SharePointFormsAuthenticationHandler authenHandler
- = new SharePointFormsAuthenticationHandler(
+ = new SharePointFormsAuthenticationHandler.Builder("username",
+ "password", new UnsupportedScheduledExecutor(),
new MockFormsAuthenticationSoap(){
@Override public LoginResult login(
String username, String password) {
@@ -147,7 +159,7 @@
lr.setErrorCode(LoginErrorCode.PASSWORD_NOT_MATCH);
return lr;
}
- }, "username", "password");
+ }).build();
assertTrue(authenHandler.isFormsAuthentication());
AuthenticationResult ar = authenHandler.authenticate();
@@ -160,8 +172,9 @@
@Test
public void testSharePointWithFormsAuthentication() throws IOException {
SharePointFormsAuthenticationHandler authenHandler
- = new SharePointFormsAuthenticationHandler(
- new MockFormsAuthenticationSoap() {
+ = new SharePointFormsAuthenticationHandler.Builder("username",
+ "password", new UnsupportedScheduledExecutor(),
+ new MockFormsAuthenticationSoap(){
@Override public LoginResult login(
String username, String password) {
LoginResult lr = new LoginResult();
@@ -180,7 +193,7 @@
Collections.unmodifiableMap(responseHeaders));
return Collections.unmodifiableMap(responseContext);
}
- }, "username", "password");
+ }).build();
assertTrue(authenHandler.isFormsAuthentication());
AuthenticationResult ar = authenHandler.authenticate();
assertNotNull(ar);
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java
index a69f72b..7b2bd1d 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java
@@ -25,6 +25,7 @@
import com.google.enterprise.adaptor.DocId;
import com.google.enterprise.adaptor.GroupPrincipal;
+import com.google.enterprise.adaptor.sharepoint.SamlAuthenticationHandler.SamlHandshakeManager;
import com.google.enterprise.adaptor.sharepoint.SharePointUserProfileAdaptor.UserProfileServiceClient;
import com.google.enterprise.adaptor.sharepoint.SharePointUserProfileAdaptor.UserProfileServiceFactory;
import com.google.enterprise.adaptor.sharepoint.SharePointUserProfileAdaptor.UserProfileServiceWS;
@@ -76,6 +77,8 @@
private Config config;
private SharePointUserProfileAdaptor adaptor;
private final Charset charset = Charset.forName("UTF-8");
+ private AuthenticationClientFactory authenticationFactory
+ = new MockAuthenticationClientFactoryForms();
@Before
public void setup() {
@@ -130,7 +133,8 @@
assertEquals(adaptorConfig.getValue("sharepoint.password"), "");
MockUserProfileServiceFactoryImpl serviceFactory =
new MockUserProfileServiceFactoryImpl(null);
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(adaptorConfig, pusher));
}
@@ -161,7 +165,8 @@
// since profile properties are null
serviceFactory.addUserProfileToCollection(5, 6, "user4", null, null);
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
assertEquals(0, pusher.getRecords().size());
@@ -174,7 +179,8 @@
throws IOException, InterruptedException {
MockUserProfileServiceFactoryImpl serviceFactory =
new MockUserProfileServiceFactoryImpl(null);
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
assertEquals(0, pusher.getRecords().size());
@@ -229,7 +235,8 @@
serviceFactory.addUserProfileToCollection(1, 2, "domain\\user1",
profile, colleaguesData);
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory
+ ,authenticationFactory);
config.overrideKey("adaptor.namespace", "ns1");
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
@@ -308,7 +315,8 @@
public void testGetDocContentNotFound() throws IOException {
MockUserProfileServiceFactoryImpl serviceFactory =
new MockUserProfileServiceFactoryImpl(null);
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
@@ -330,7 +338,8 @@
SharePointUserProfileAdaptor.PROFILE_ACCOUNTNAME_PROPERTY,
new String[] {"user1"});
serviceFactory.addUserProfileToCollection(1, 2, "user1", profile, null);
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
@@ -349,7 +358,8 @@
MockUserProfileServiceFactoryImpl serviceFactory =
new MockUserProfileServiceFactoryImpl(
"change token on mock repository");
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
adaptor.setUserProfileChangeToken(null);
@@ -366,7 +376,8 @@
MockUserProfileServiceFactoryImpl serviceFactory =
new MockUserProfileServiceFactoryImpl(
"same current token");
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
adaptor.setUserProfileChangeToken("same current token");
@@ -383,7 +394,8 @@
MockUserProfileServiceFactoryImpl serviceFactory =
new MockUserProfileServiceFactoryImpl(
"new token");
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
adaptor.setUserProfileChangeToken("old token");
@@ -420,7 +432,8 @@
//batch 5 -user6
serviceFactory.addChangeLogForUser("user6");
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
adaptor.setUserProfileChangeToken("old token");
@@ -437,7 +450,8 @@
MockUserProfileServiceFactoryImpl serviceFactory =
new MockUserProfileServiceFactoryImpl(
"sp token");
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
adaptor.setUserProfileChangeToken("invalid");
@@ -452,7 +466,8 @@
MockUserProfileServiceFactoryImpl serviceFactory =
new MockUserProfileServiceFactoryImpl(
"sp token");
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
UserProfileServiceClient client = adaptor.new UserProfileServiceClient(null);
ArrayOfContactData colleaguesData = new ArrayOfContactData();
@@ -484,7 +499,8 @@
MockUserProfileServiceFactoryImpl serviceFactory =
new MockUserProfileServiceFactoryImpl(
"sp token");
- adaptor = new SharePointUserProfileAdaptor(serviceFactory);
+ adaptor = new SharePointUserProfileAdaptor(serviceFactory,
+ authenticationFactory);
UserProfileServiceClient client =
adaptor.new UserProfileServiceClient(null);
// Get an instance of factory
@@ -648,11 +664,6 @@
public void addChangeLogForUser(String userName) {
proxy.addChangeLogForUser(userName);
}
-
- @Override
- public AuthenticationSoap newAuthentication(String endpoint) {
- return new MockAuthenticationSoap();
- }
}
private static class MockAuthenticationSoap implements AuthenticationSoap {
@@ -666,4 +677,39 @@
return AuthenticationMode.WINDOWS;
}
}
+
+ private static class UnsupportedAuthenticationClientFactory
+ implements AuthenticationClientFactory {
+
+ @Override
+ public AuthenticationSoap newSharePointFormsAuthentication(
+ String virtualServer, String username, String password)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SamlHandshakeManager newAdfsAuthentication(String virtualServer,
+ String username, String password, String stsendpoint, String stsrelam,
+ String login, String trustlocation) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SamlHandshakeManager newLiveAuthentication(String virtualServer,
+ String username, String password) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ private static class MockAuthenticationClientFactoryForms
+ extends UnsupportedAuthenticationClientFactory {
+ @Override
+ public AuthenticationSoap newSharePointFormsAuthentication(
+ String virtualServer, String username, String password)
+ throws IOException {
+ return new MockAuthenticationSoap();
+ }
+ }
}