Package com.google.enterprise.connector.adgroups

Source Code of com.google.enterprise.connector.adgroups.AdGroupsAuthenticationManager

// 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.adgroups;

import com.google.common.base.Strings;
import com.google.enterprise.connector.adgroups.AdConstants.Method;
import com.google.enterprise.connector.adgroups.AdDbUtil.Query;
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 java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.naming.CommunicationException;
import javax.naming.NamingException;

/**
* 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://code.google.com/apis/searchappliance
* /documentation/connectors/110/connector_dev/cdg_authentication.html
*
* @author nitendra_thakur
*/
public class AdGroupsAuthenticationManager implements AuthenticationManager {
  private static final Logger LOGGER =
      Logger.getLogger(AdGroupsAuthenticationManager.class.getName());

  private final AdDbUtil db;
  private final String globalNamespace;
  private final boolean includeBuiltinGroups;
  private final String databaseType;

  /**
   * @param connector an instance of an {@link AdGroupsConnector}
   */
  public AdGroupsAuthenticationManager(AdGroupsConnector connector)
      throws RepositoryException {
    db = new AdDbUtil(connector.getDataSource(), connector.getDatabaseType());
    globalNamespace = connector.getGoogleGlobalNamespace();
    includeBuiltinGroups = connector.isIncludeBuiltinGroups();
    databaseType = connector.getDatabaseType();
  }

  /**
    * Authenticates the user against Active Directory server. Each instance of
    * the connector must be able to authenticate users regardless of which
    * domain he belongs to. The necessary data where to connect to have to
    * be stored in the database.
    *
    * @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
    */
  @Override
  public AuthenticationResponse authenticate(
      final AuthenticationIdentity identity)
      throws RepositoryLoginException, RepositoryException {
    final String username = identity.getUsername();
    final String password = identity.getPassword();
    final String domain = identity.getDomain();

    long startAuthN = System.currentTimeMillis();

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

    HashMap<String, Object> sqlIdentity = new HashMap<String, Object>();
    sqlIdentity.put(AdConstants.DB_SAMACCOUNTNAME, username.toLowerCase());
    Query query;
    if (Strings.isNullOrEmpty(domain)) {
      query = Query.SELECT_USER_BY_SAMACCOUNTNAME;
    } else {
      //TODO: rename the DB bound variable to domain
      sqlIdentity.put(AdConstants.DB_NETBIOSNAME, domain);
      query = Query.SELECT_USER_BY_DOMAIN_SAMACCOUNTNAME;
    }

    try {
      List<HashMap<String, Object>> users = db.select(query, sqlIdentity);
      if (users.size() == 0) {
        LOGGER.warning("User not found in the database ["
            + username + "] domain [" + domain + "]");
        return new AuthenticationResponse(false, "", null);
      } else if (users.size() > 1) {
        StringBuffer sb = new StringBuffer("Multiple users found in the "
            + "database matching [" + domain + "]\\[" + username + "]: ");
        for (HashMap<String, Object> u : users) {
          sb.append("[").append(u.get("dn")).append("] ");
        }
        LOGGER.warning(sb.toString());
        return new AuthenticationResponse(false, "", null);
      }
      HashMap<String, Object>user = users.get(0);
      List<Principal> groups =
          getAllGroupsForTheUser((Number) user.get(AdConstants.DB_ENTITYID));
      if (password != null && !authenticateUser(
              (String) user.get(AdConstants.DB_DNSROOT),
              (String) user.get(AdConstants.DB_NETBIOSNAME)
                  + AdConstants.BACKSLASH
                  + (String) user.get(AdConstants.DB_SAMACCOUNTNAME),
              password)) {
        return new AuthenticationResponse(false, "", null);
      }
      if (LOGGER.isLoggable(Level.INFO)) {
        StringBuffer sb = new StringBuffer("Resolved ").append(groups.size())
            .append(" AD group(s) for user [").append(username).append("]")
            .append(" domain [").append(domain).append("]: ");
        for (Principal group : groups) {
          sb.append("[").append(group.getName()).append("] ");
        }
        LOGGER.info(sb.toString());
      }
      if (identity instanceof MutableIdentity) {
        MutableIdentity mutable = (MutableIdentity) identity;
        mutable.setDomain((String) user.get(AdConstants.DB_NETBIOSNAME));
        mutable.setUsername((String) user.get(AdConstants.DB_SAMACCOUNTNAME));
        LOGGER.fine("New identity: [" + domain + "\\" + username
            + "] Active Directory: [" + identity.getDomain()
            + "\\" + identity.getUsername() + "]");
      }
      LOGGER.log(Level.INFO, "Elapsed time for Active Directory authentication "
          + "of user [{0}\\{1}] = [{2}ms]"new Object[] {domain, username,
            System.currentTimeMillis() - startAuthN});
      return new AuthenticationResponse(true, "", groups);
    } catch (SQLException e) {
      LOGGER.log(Level.WARNING,
          "Failed to retrieve information about user from database ["
          + username + "] domain [" + domain + "].", e);
      return new AuthenticationResponse(false, "", null);
    }
  }

  /**
   * Connects to specified AD domain with users principal and password.
   *
   * @param dnsRoot hostname of the domain
   * @param principal userPrincipalName of the user
   * @param password password
   * @return if authentication was successful
   */
  boolean authenticateUser(String dnsRoot, String principal, String password) {
    // Authenticate via SSL
    try {
      new AdServer(Method.SSL, dnsRoot, 636, principal, password).connect();
      // No exception thrown - authentication succeeded
      LOGGER.info("Successfully authenticated user [" + principal + "]");
      return true;
    } catch (CommunicationException e) {
      // network or SSL related, continue without SSL
      LOGGER.log(Level.FINE, "SSL Authentication failed", e);
    } catch (NamingException e) {
      // NamingException - authentication failed
      LOGGER.log(Level.INFO,
          "SSL Authenticated failed for user [" + principal + "]", e);
      return false;
    }

    try {
      new AdServer(Method.STANDARD, dnsRoot, 389, principal, password).connect();
      // No exception thrown - authentication succeeded
      LOGGER.info("Successfully authenticated user [" + principal + "]");
      return true;
    } catch (CommunicationException e) {
      // network related exception
      LOGGER.log(Level.INFO,
          "Plain Authentication failed for user [" + principal + "]", e);
      return false;
    } catch (Exception e) {
      // any other exception - authentication failed
      LOGGER.log(Level.FINE,
          "Authentication failed for user [ " + principal + " ]", e);
      return false;
    }
  }

  Principal formatGroup(HashMap<String, Object> entity) {
    String netbiosName = (String) entity.get(AdConstants.DB_NETBIOSNAME);
    String samAccountName = (String) entity.get(AdConstants.DB_SAMACCOUNTNAME);

    String principalName;
    if (netbiosName != null) {
      principalName = netbiosName + AdConstants.BACKSLASH + samAccountName;
    } else {
      principalName = samAccountName;
    }
    return new Principal(PrincipalType.UNKNOWN, globalNamespace, principalName);
  }

  List<Principal> getAllGroupsForTheUser(Number entityId) throws SQLException {
    List<Principal> groups = new ArrayList<Principal>();
    List<Number> entities = new ArrayList<Number>();
    entities.add(entityId);
   
    boolean useRecursiveQuery = databaseType.equalsIgnoreCase("SQLSERVER")
        || databaseType.equalsIgnoreCase("ORACLE");

    // Add current user to all implicit well known entities
    for (HashMap<String, Object> wellKnown :
             db.select(Query.SELECT_WELLKNOWN_MEMBERSHIPS, null)) {
      groups.add(formatGroup(wellKnown));
      // when using recursive query no need to process
      // wellknown entities individually.
      if (!useRecursiveQuery) {
        entities.add((Number) wellKnown.get(AdConstants.DB_ENTITYID));
      }
    }

    HashMap<String, Object> params = new HashMap<String, Object>();
    // The loop goes over the entities list appending newly found groups
    // at the end of the list this way we will resolve each group only once
    for (int i = 0; i < entities.size(); ++i) {
      params.put(AdConstants.DB_ENTITYID, entities.get(i));
      List<HashMap<String, Object>> results =
          db.select(Query.SELECT_MEMBERSHIPS_BY_ENTITYID, params);
      for (HashMap<String, Object> result : results) {
        Number groupId = (Number) result.get(AdConstants.DB_ENTITYID);
        if (!entities.contains(groupId)) {
          String netbiosName = (String) result.get(AdConstants.DB_NETBIOSNAME);
          if (includeBuiltinGroups
              || !netbiosName.equalsIgnoreCase("BUILTIN")) {
            groups.add(formatGroup(result));
          }
          entities.add(groupId);
        }
      }
      // Using recursive query we need only one iteration of group resolution
      if (useRecursiveQuery) {
        break;
      }
    }
    return groups;
  }
}
TOP

Related Classes of com.google.enterprise.connector.adgroups.AdGroupsAuthenticationManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.