blob: 6ab0290251d7f270184a34d9f1a593285f9b6774 [file] [log] [blame]
// Copyright 2012 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.microsoft.schemas.sharepoint.soap.authentication.AuthenticationMode;
import com.microsoft.schemas.sharepoint.soap.authentication.AuthenticationSoap;
import com.microsoft.schemas.sharepoint.soap.authentication.LoginErrorCode;
import com.microsoft.schemas.sharepoint.soap.authentication.LoginResult;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.handler.MessageContext;
/**
* Helper class to handle forms authentication.
*/
class FormsAuthenticationHandler {
/** SharePoint's namespace. */
private static final String XMLNS
= "http://schemas.microsoft.com/sharepoint/soap/";
private static final Logger log
= Logger.getLogger(FormsAuthenticationHandler.class.getName());
// 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;
private final ScheduledExecutorService executor;
private final Runnable refreshRunnable = new RefreshRunnable();
private final List<String> authenticationCookiesList
= new CopyOnWriteArrayList<String>();
private AuthenticationMode authenticationMode;
private final AuthenticationSoap authenticationClient;
@VisibleForTesting
FormsAuthenticationHandler(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 List<String> getAuthenticationCookies() {
return Collections.unmodifiableList(authenticationCookiesList);
}
public boolean isFormsAuthentication() {
return authenticationMode == AuthenticationMode.FORMS;
}
private void refreshCookies() throws IOException {
log.log(Level.FINE, "AuthenticationMode = {0}", authenticationMode);
if (authenticationMode != AuthenticationMode.FORMS) {
return;
}
LoginResult result;
try {
result = authenticationClient.login(userName, password);
} catch (WebServiceException ex) {
log.log(Level.WARNING,
"Possible SP2013 environment with windows authentication", ex);
authenticationMode = AuthenticationMode.WINDOWS;
return;
}
log.log(Level.FINE,
"Login Cookie Expiration in = {0}", result.getTimeoutSeconds());
if (result.getErrorCode() != LoginErrorCode.NO_ERROR) {
throw new IOException("Forms authentication failed with authentication "
+ "web service with Error Code " + result.getErrorCode());
}
@SuppressWarnings("unchecked")
Map<String, Object> responseHeaders
= (Map<String, Object>) ((BindingProvider) authenticationClient)
.getResponseContext().get(MessageContext.HTTP_RESPONSE_HEADERS);
log.log(Level.FINEST, "Response headers: {0}", responseHeaders);
@SuppressWarnings("unchecked")
String cookies = ((List<String>) responseHeaders.get("Set-cookie")).get(0);
if (authenticationCookiesList.isEmpty()) {
authenticationCookiesList.add(cookies);
} else {
authenticationCookiesList.set(0, cookies);
}
long cookieTimeOut = (result.getTimeoutSeconds() == null) ?
DEFAULT_COOKIE_TIMEOUT_SECONDS : result.getTimeoutSeconds();
long rerunAfter = (cookieTimeOut + 1) / 2;
executor.schedule(refreshRunnable, rerunAfter, TimeUnit.SECONDS);
log.log(Level.FINEST,
"Authentication Cookie is {0}", authenticationCookiesList);
}
public void start() throws IOException {
authenticationMode = authenticationClient.mode();
refreshCookies();
}
private class RefreshRunnable implements Runnable {
@Override
public void run() {
try {
refreshCookies();
} catch(IOException ex) {
log.log(Level.WARNING,
"Error refreshing forms authentication cookies", ex);
executor.schedule(this, 5, TimeUnit.MINUTES);
}
}
}
}