com.google.enterprise.connector.sharepoint.spiimpl.SharepointAuthenticationManager.java Source code

Java tutorial

Introduction

Here is the source code for com.google.enterprise.connector.sharepoint.spiimpl.SharepointAuthenticationManager.java

Source

// Copyright 2007 Google Inc.
//
// 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.connector.sharepoint.spiimpl;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.enterprise.connector.adgroups.AdGroupsAuthenticationManager;
import com.google.enterprise.connector.adgroups.MutableIdentity;
import com.google.enterprise.connector.sharepoint.client.BulkAuthorizationHelper;
import com.google.enterprise.connector.sharepoint.client.SPConstants;
import com.google.enterprise.connector.sharepoint.client.SharepointClientContext;
import com.google.enterprise.connector.sharepoint.client.Util;
import com.google.enterprise.connector.sharepoint.dao.UserGroupMembership;
import com.google.enterprise.connector.sharepoint.ldap.LdapService;
import com.google.enterprise.connector.sharepoint.ldap.UserGroupsService;
import com.google.enterprise.connector.sharepoint.ldap.UserGroupsService.LdapConnectionSettings;
import com.google.enterprise.connector.sharepoint.wsclient.client.ClientFactory;
import com.google.enterprise.connector.spi.AuthenticationIdentity;
import com.google.enterprise.connector.spi.AuthenticationManager;
import com.google.enterprise.connector.spi.AuthenticationResponse;
import com.google.enterprise.connector.spi.Principal;
import com.google.enterprise.connector.spi.RepositoryException;
import com.google.enterprise.connector.spi.RepositoryLoginException;
import com.google.enterprise.connector.spi.SpiConstants.PrincipalType;

import org.apache.commons.lang.StringEscapeUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class provides an implementation of AuthenticationManager SPI provided
 * by CM for authenticating the search users. To understand how this module fits
 * into the Connector Manager framework refer to
 * http://google-enterprise-connector-manager.googlecode.com/svn/docs/devguide/2.4.0/cdg_authentication.html
 */
public class SharepointAuthenticationManager implements AuthenticationManager {
    private static final Logger LOGGER = Logger.getLogger(SharepointAuthenticationManager.class.getName());

    private final ClientFactory clientFactory;
    private final SharepointClientContext sharepointClientContext;
    @VisibleForTesting
    final LdapService ldapService;
    private final AdGroupsAuthenticationManager adGroupsAuthenticationManager;

    /**
     * @param inSharepointClientContext Context Information is required to create
     *          the instance of this class
     */
    public SharepointAuthenticationManager(final ClientFactory clientFactory,
            final SharepointClientContext inSharepointClientContext,
            final AdGroupsAuthenticationManager inAdGroupsAuthenticationManager) throws SharepointException {
        if (inSharepointClientContext == null) {
            throw new SharepointException("SharePointClientContext can not be null");
        }
        adGroupsAuthenticationManager = inAdGroupsAuthenticationManager;
        this.clientFactory = clientFactory;
        sharepointClientContext = (SharepointClientContext) inSharepointClientContext.clone();
        if (sharepointClientContext.isPushAcls()) {
            LdapConnectionSettings ldapConnectionSettings = sharepointClientContext.getLdapConnectionSettings();
            if (!Strings.isNullOrEmpty(ldapConnectionSettings.getHostname())) {
                ldapService = new UserGroupsService(inSharepointClientContext);
            } else {
                ldapService = null;
            }
        } else {
            ldapService = null;
        }
    }

    @Override
    public AuthenticationResponse authenticate(final AuthenticationIdentity identity)
            throws RepositoryLoginException, RepositoryException {
        if (adGroupsAuthenticationManager != null) {
            return authenticateAgainstActiveDirectory(new MutableIdentity(identity));
        } else {
            return authenticateAgainstSharepoint(identity);
        }
    }

    /**
     * Returns the search user name after changing its format to the user name
     * format specified by the connector administrator during connector
     * configuration.
     *
     * @param userName
     * @param domain
     */
    private String addUserNameFormatForTheSearchUser(final String userName, final String domain) {
        String format = this.sharepointClientContext.getUsernameFormatInAce();
        LOGGER.config("Username format in ACE : " + format);
        String domainToUse = (Strings.isNullOrEmpty(domain)) ? this.sharepointClientContext.getDomain() : domain;
        LOGGER.log(Level.FINE, "domainToUse [ " + domainToUse + " ], input domain [ " + domain + " ]. ");
        if (format.indexOf(SPConstants.AT) != -1) {
            return Util.getUserNameAtDomain(userName, domainToUse);
        } else if (format.indexOf(SPConstants.BACKSLASH) != -1) {
            return Util.getUserNameWithDomain(userName, domainToUse);
        } else {
            return userName;
        }
    }

    //TODO: make this claims aware - authorize against Sharepoint and resolve
    //groups against AD only if necessary
    private AuthenticationResponse authenticateAgainstActiveDirectory(final AuthenticationIdentity identity)
            throws RepositoryLoginException, RepositoryException {
        long startAuthN = System.currentTimeMillis();
        AuthenticationResponse adAuthResult = adGroupsAuthenticationManager.authenticate(identity);
        if (!adAuthResult.isValid()) {
            return adAuthResult;
        }

        long startSharePoint = System.currentTimeMillis();
        @SuppressWarnings("unchecked")
        Collection<Principal> adGroups = (Collection<Principal>) adAuthResult.getGroups();
        String strUserName = addUserNameFormatForTheSearchUser(identity.getUsername(), identity.getDomain());
        Set<Principal> spGroups = sharepointClientContext.getUserDataStoreDAO()
                .getSharePointGroupsForSearchUserAndLdapGroups(sharepointClientContext.getGoogleLocalNamespace(),
                        adGroups, strUserName);

        Collection<Principal> groups = new ArrayList<Principal>();
        groups.addAll(adGroups);
        groups.addAll(spGroups);
        LOGGER.log(Level.INFO,
                "Authentication Duration [{0}] : Total = [{1}ms] " + "SharePoint = [{2}ms] AD = [{3}ms]",
                new Object[] { strUserName, (System.currentTimeMillis() - startAuthN),
                        (System.currentTimeMillis() - startSharePoint), (startSharePoint - startAuthN) });

        return new AuthenticationResponse(adAuthResult.isValid(), adAuthResult.getData(), groups);
    }

    /**
     * Authenticates the user against the SharePoint server where Crawl URL
     * specified during connector configuration is hosted
     *
     * @param identity AuthenticationIdentity object created by CM while
     *          delegating authentication to the connector. This corresponds to
     *          one specific search user
     * @return AuthenticationResponse Contains the authentication status for the
     *         incoming identity
     */
    private AuthenticationResponse authenticateAgainstSharepoint(final AuthenticationIdentity identity)
            throws RepositoryLoginException, RepositoryException {
        if (sharepointClientContext == null) {
            LOGGER.warning("SharePointClientContext is null. Authentication Failed.");
            return null;
        }

        final String user = identity.getUsername();
        final String password = identity.getPassword();
        String domain = identity.getDomain();

        LOGGER.log(Level.INFO, "Received authN request for Username [ " + user + " ], domain [ " + domain + " ]. ");

        LOGGER.log(Level.INFO, "Received authN request for Username [ " + user + " ], domain [ " + domain + " ]. ");

        // If domain is not received as part of the authentication request, use
        // the one from SharePointClientContext
        if ((domain == null) || (domain.length() == 0)) {
            domain = sharepointClientContext.getDomain();
        }

        if (!Strings.isNullOrEmpty(password)) {
            final String userName = Util.getUserNameWithDomain(user, domain);
            LOGGER.log(Level.INFO, "Authenticating User: " + userName);
            sharepointClientContext.setUsername(userName);
            sharepointClientContext.setPassword(password);
            BulkAuthorizationHelper bulkAuth = new BulkAuthorizationHelper(sharepointClientContext);

            /*
             * If you can make a call to Web Service with the given credential, the
             * user is valid user. This should not be assumed as a valid SharePoint
             * user. A valid user is any user who is identified on the SharePoint
             * server.The Google Services deployed on the SharePoint server can be
             * called with such user credentials.
             *
             * If Authentication is successful get groups information from
             * UserDataStore data base for a given user and add it to
             * AuthenticationResponse. *
             */
            if (SPConstants.CONNECTIVITY_SUCCESS.equalsIgnoreCase(bulkAuth.checkConnectivity())) {
                LOGGER.log(Level.INFO,
                        "Authentication succeeded for the user : " + user + " with identity : " + userName);
                if (sharepointClientContext.isPushAcls() && null != this.ldapService) {
                    return getAllGroupsForTheUser(user);
                } else {
                    // Handle the cases when connector should just return true
                    // indicating successfull authN
                    LOGGER.config("No group resolution has been attempted as connector is not set to feed ACL");
                    return new AuthenticationResponse(true, "", null);
                }
            }
        } else {
            LOGGER.config("AuthN was not attempted as password is empty and groups are being returned.");
            return getAllGroupsForTheUser(user);
        }
        LOGGER.log(Level.WARNING, "Authentication failed for " + user);
        return new AuthenticationResponse(false, "", null);
    }

    /**
     * This method makes a call to {@link LdapService} to get all AD groups and SP
     * groups of which he/she is a direct or indirect member of and returns
     * {@link AuthenticationResponse}.
     *
     * @param searchUser to fetch all SharePoint groups and Directory groups to
     *          which he/she is a direct or indirect member of.
     * @return {@link AuthenticationResponse}
     * @throws SharepointException
     */
    @VisibleForTesting
    AuthenticationResponse getAllGroupsForTheUser(String searchUser) throws SharepointException {
        LOGGER.info("Attempting group resolution for user : " + searchUser);
        Set<Principal> allSearchUserGroups = ldapService.getAllGroupsForSearchUser(sharepointClientContext,
                searchUser);
        if (null != allSearchUserGroups && allSearchUserGroups.size() > 0) {
            // Should return true if there is at least one group returned by
            // LDAP service.
            LOGGER.log(Level.INFO, "Group resolution returned following groups " + "for the search user: {0}\n{1}",
                    new Object[] { searchUser, allSearchUserGroups.toString() });
            return new AuthenticationResponse(true, "", allSearchUserGroups);
        } else {
            LOGGER.info("Group resolution returned no groups for the search user: " + searchUser);
            // Should return true with null groups.
            return new AuthenticationResponse(true, "", null);
        }
    }
}