| // 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; |
| } |
| } |