blob: 37f314ef961bd1b0205654002360d4deb1365fb0 [file] [log] [blame]
// 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.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.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;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.handler.MessageContext;
/**
* AuthenticationHandler implementation for SharePoint forms authentication
* using Authentication.asmx web service.
*/
public class SharePointFormsAuthenticationHandler
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 SharePointFormsAuthenticationHandler(String username, String password,
ScheduledExecutorService executor,
AuthenticationSoap authenticationClient) {
super(username, password, executor);
this.authenticationClient = authenticationClient;
}
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,
LoginErrorCode.NOT_IN_FORMS_AUTHENTICATION_MODE.toString());
}
LoginResult result;
try {
result = authenticationClient.login(username, password);
} catch (WebServiceException ex) {
log.log(Level.WARNING,
"Forms authentication failed.", ex);
log.log(Level.INFO, "Possible SharePoint environment configured to use "
+ "claims based windows integrated authentication. "
+ "Adaptor will fallback to use windows integrated authentication.");
return new AuthenticationResult(null, DEFAULT_COOKIE_TIMEOUT_SECONDS,
LoginErrorCode.NOT_IN_FORMS_AUTHENTICATION_MODE.toString());
}
log.log(Level.FINE,
"Login Cookie Expiration in = {0}", result.getTimeoutSeconds());
if (result.getErrorCode() != LoginErrorCode.NO_ERROR) {
log.log(Level.WARNING, "Forms authentication failed with error code {0}. "
+ "Possible SharePoint environment with multiple claims providers. "
+ "Adaptor will fallback to use windows integrated authentication.",
result.getErrorCode());
return new AuthenticationResult(null, DEFAULT_COOKIE_TIMEOUT_SECONDS,
result.getErrorCode().toString());
}
@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);
if(!responseHeaders.containsKey("Set-cookie")) {
throw new IOException("Unable to extract authentication cookie.");
}
@SuppressWarnings("unchecked")
List<String> cookies = (List<String>) responseHeaders.get("Set-cookie");
if (cookies == null || cookies.isEmpty()) {
throw new IOException("Unable to extract authentication cookie.");
}
int cookieTimeout;
// On SP2007 result.getTimeoutSeconds() can be null
if (result.getTimeoutSeconds() == null) {
log.log(Level.FINE,
"Login cookie timeout is null. Using default cookie timeout.");
cookieTimeout = DEFAULT_COOKIE_TIMEOUT_SECONDS;
} else {
cookieTimeout = result.getTimeoutSeconds() > 0
? result.getTimeoutSeconds() : DEFAULT_COOKIE_TIMEOUT_SECONDS;
}
log.log(Level.FINE,
"Login Cookie Expiration in = {0} seconds", cookieTimeout);
return new AuthenticationResult(cookies.get(0), cookieTimeout,
result.getErrorCode().toString());
}
public boolean isFormsAuthentication() throws IOException {
if (authenticationMode == null) {
// Cache authentication mode value to avoid repetitive web service
// calls to get authentication mode.
setAuthenticationMode(authenticationClient.mode());
log.log(Level.FINE, "Authentication Mode {0}", authenticationMode);
}
return authenticationMode == AuthenticationMode.FORMS;
}
private synchronized void setAuthenticationMode(AuthenticationMode mode) {
authenticationMode = mode;
}
}