Package org.apache.manifoldcf.crawler.connectors.cmis

Source Code of org.apache.manifoldcf.crawler.connectors.cmis.CmisAuthorityConnector

/* $Id: CmisAuthorityConnector.java 1327112 2012-04-17 14:28:14Z ridder $ */

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.manifoldcf.crawler.connectors.cmis;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Locale;

import org.apache.commons.lang.StringUtils;
import org.apache.manifoldcf.authorities.authorities.BaseAuthorityConnector;
import org.apache.manifoldcf.authorities.interfaces.AuthorizationResponse;
import org.apache.manifoldcf.core.interfaces.CacheManagerFactory;
import org.apache.manifoldcf.core.interfaces.ConfigParams;
import org.apache.manifoldcf.core.interfaces.ICacheCreateHandle;
import org.apache.manifoldcf.core.interfaces.ICacheDescription;
import org.apache.manifoldcf.core.interfaces.ICacheHandle;
import org.apache.manifoldcf.core.interfaces.ICacheManager;
import org.apache.manifoldcf.core.interfaces.IHTTPOutput;
import org.apache.manifoldcf.core.interfaces.IPostParameters;
import org.apache.manifoldcf.core.interfaces.IThreadContext;
import org.apache.manifoldcf.core.interfaces.ManifoldCFException;
import org.apache.manifoldcf.core.interfaces.StringSet;
import org.apache.manifoldcf.crawler.system.Logging;
import org.apache.manifoldcf.ui.util.Encoder;

/**
*
* The CMIS Authority Connector is based only on a regular expression checker, because the CMIS specification
* (and the Apache Chemistry implementation) doesn't have any exposed method to get info about users.
*
* For the configuration we can assume that we could have different users for any CMIS repository that
* could have the same endpoint. That's why for this connector is required the Repository ID.
*
* @author Piergiorgio Lucidi
*
*/
public class CmisAuthorityConnector extends BaseAuthorityConnector {

  public static final String CONFIG_PARAM_USERNAME = "username";
  public static final String CONFIG_PARAM_PASSWORD = "password";
  public static final String CONFIG_PARAM_ENDPOINT = "endpoint";
  public static final String CONFIG_PARAM_REPOSITORY_ID = "repositoryId";
 
  /** User name mapping parameter */
  protected static final String CONFIG_PARAM_USERMAPPING = "usermapping";
 
  protected static final String CONFIG_PARAM_USERNAME_REGEXP = "usernameregexp";
  protected static final String CONFIG_PARAM_USER_TRANSLATION = "usertranslation";
 
  private static final String DEFAULT_VALUE_ENDPOINT = "http://localhost:8080/cmis/";
  private static final String DEFAULT_VALUE_REPOSITORY_ID = "uuid";

  protected String endpoint = null;
  protected String repositoryId = null;

  protected Map<String, String> parameters = new HashMap<String, String>();
 
  /** The cache manager. */
  protected ICacheManager cacheManager = null;
 
  /** Match map for username mapping */
  protected MatchMap matchMap = null;
 
  protected static long responseLifetime = 60000L;
  protected static int LRUsize = 1000;
  protected static StringSet emptyStringSet = new StringSet();
 
  /** This is the active directory global deny token.  This should be ingested with all documents. */
  public static final String GLOBAL_DENY_TOKEN = "DEAD_AUTHORITY";
 
  /** Unreachable CMIS */
  private static final AuthorizationResponse unreachableResponse = new AuthorizationResponse(
    new String[]{GLOBAL_DENY_TOKEN},AuthorizationResponse.RESPONSE_UNREACHABLE);
 
  /** User not found */
  private static final AuthorizationResponse userNotFoundResponse = new AuthorizationResponse(
    new String[]{GLOBAL_DENY_TOKEN},AuthorizationResponse.RESPONSE_USERNOTFOUND);

  /** Set thread context.
   */
   @Override
   public void setThreadContext(IThreadContext tc)
     throws ManifoldCFException {
     super.setThreadContext(tc);
     cacheManager = CacheManagerFactory.make(tc);
   }
  
   /** Clear thread context.
   */
   @Override
   public void clearThreadContext() {
     super.clearThreadContext();
     cacheManager = null;
   }
 
  public CmisAuthorityConnector() {
    super();
  }
 
 
  /**
   * Output the configuration body section. This method is called in the body
   * section of the authority connector's configuration page. Its purpose is to
   * present the required form elements for editing. The coder can presume that
   * the HTML that is output from this configuration will be within appropriate
   * <html>, <body>, and <form> tags. The name of the form is "editconnection".
   *
   * @param threadContext
   *          is the local thread context.
   * @param out
   *          is the output to which any HTML should be sent.
   * @param parameters
   *          are the configuration parameters, as they currently exist, for
   *          this connection being configured.
   * @param tabName
   *          is the current tab name.
   */
  @Override
  public void outputConfigurationBody(IThreadContext threadContext,
      IHTTPOutput out, Locale locale, ConfigParams parameters, String tabName)
      throws ManifoldCFException, IOException {

    String endpoint = parameters.getParameter(CONFIG_PARAM_ENDPOINT);
    String repositoryId = parameters.getParameter(CONFIG_PARAM_REPOSITORY_ID);
   
    if(StringUtils.isEmpty(endpoint))
      endpoint = DEFAULT_VALUE_ENDPOINT;
    if(StringUtils.isEmpty(repositoryId))
      repositoryId = DEFAULT_VALUE_REPOSITORY_ID;
   
    String userMappingString = parameters.getParameter(CONFIG_PARAM_USERMAPPING);
    MatchMap localMap;
    if (StringUtils.isNotEmpty(userMappingString)){
      localMap = new MatchMap(userMappingString);
    } else {
      localMap = new MatchMap();
      localMap.appendMatchPair("(.*)","$(1)");
    }
    String usernameRegexp = localMap.getMatchString(0);
    String userTranslation = localMap.getReplaceString(0);
   
    if (tabName.equals(Messages.getString(locale,"CmisAuthorityConnector.Repository")))
    {
    out.print("<table class=\"displaytable\">\n"
        + "  <tr><td class=\"separator\" colspan=\"2\"><hr/></td></tr>\n");
    out.print("<tr><td class=\"description\"><nobr>" + Messages.getBodyString(locale,"CmisAuthorityConnector.Endpoint") + "</nobr></td>" +
        "<td class=\"value\"><input type=\"text\" name=\""
        + CONFIG_PARAM_ENDPOINT + "\" value=\""+Encoder.attributeEscape(endpoint)+"\" size=\"50\"/></td></tr>\n");
    out.print("<tr><td class=\"description\"><nobr>" + Messages.getBodyString(locale,"CmisAuthorityConnector.RepositoryID") + "</nobr></td>" +
        "<td class=\"value\"><input type=\"text\" name=\""
        + CONFIG_PARAM_REPOSITORY_ID + "\" value=\""+Encoder.attributeEscape(repositoryId)+"\"/></td></tr>\n");
    out.print("</table>\n");
    }
    else
    {
      out.print("<input type=\"hidden\" name=\""+CONFIG_PARAM_ENDPOINT+"\" value=\""+Encoder.attributeEscape(endpoint)+"\"/>\n");
      out.print("<input type=\"hidden\" name=\""+CONFIG_PARAM_REPOSITORY_ID+"\" value=\""+Encoder.attributeEscape(repositoryId)+"\"/>\n");
    }
   
    if (tabName.equals(Messages.getString(locale,"CmisAuthorityConnector.UserMapping")))
    {
      out.print(
"<table class=\"displaytable\">\n"+
"  <tr><td class=\"separator\" colspan=\"2\"><hr/></td></tr>\n"+
"  <tr>\n"+
"    <td class=\"description\"><nobr>" + Messages.getBodyString(locale,"CmisAuthorityConnector.UserMapping") + "</nobr></td>\n"+
"    <td class=\"value\">\n"+
"      <input type=\"text\" size=\"32\" name=\""+CONFIG_PARAM_USERNAME_REGEXP+"\" value=\""+
  Encoder.attributeEscape(usernameRegexp)+"\"/> ==&gt; \n"+
"      <input type=\"text\" size=\"32\" name=\""+CONFIG_PARAM_USER_TRANSLATION+"\" value=\""+
  Encoder.attributeEscape(userTranslation)+"\"/>\n"+
"    </td>\n"+
"  </tr>\n"+
"</table>\n"
      );
    }
    else
    {
      out.print(
"<input type=\"hidden\" name=\"usernameregexp\" value=\""+
  Encoder.attributeEscape(usernameRegexp)+"\"/>\n"+
"<input type=\"hidden\" name=\"usertranslation\" value=\""+
  Encoder.attributeEscape(userTranslation)+"\"/>\n"
      );
    }

  }

  /**
   * Output the configuration header section. This method is called in the head
   * section of the connector's configuration page. Its purpose is to add the
   * required tabs to the list, and to output any javascript methods that might
   * be needed by the configuration editing HTML.
   *
   * @param threadContext
   *          is the local thread context.
   * @param out
   *          is the output to which any HTML should be sent.
   * @param parameters
   *          are the configuration parameters, as they currently exist, for
   *          this connection being configured.
   * @param tabsArray
   *          is an array of tab names. Add to this array any tab names that are
   *          specific to the connector.
   */
  @Override
  public void outputConfigurationHeader(IThreadContext threadContext,
      IHTTPOutput out, Locale locale, ConfigParams parameters, List<String> tabsArray)
      throws ManifoldCFException, IOException {
   
    tabsArray.add(Messages.getString(locale,"CmisAuthorityConnector.Repository"));
    tabsArray.add(Messages.getString(locale,"CmisAuthorityConnector.UserMapping"));
   
    out.print("<script type=\"text/javascript\">\n" + "<!--\n"
        + "function checkConfig()\n" + "{\n"
        + "  if (editconnection.endpoint.value == \"\")\n" + "  {\n"
        + "    alert(\"" + Messages.getBodyJavascriptString(locale,"CmisAuthorityConnector.TheEndpointMustBeNotNull") + "\");\n"
        + "    editconnection.endpoint.focus();\n" + "    return false;\n"
        + "  }\n" + "\n" + "  return true;\n" + "}\n" + " \n"
        + "function checkConfigForSave()\n" + "{\n"
        + "  if (editconnection.endpoint.value == \"\")\n" + "  {\n"
        + "    alert(\"" + Messages.getBodyJavascriptString(locale,"CmisAuthorityConnector.TheEndpointMustBeNotNull") + "\");\n"
        + "    editconnection.endpoint.focus();\n" + "    return false;\n"
        + "  }\n" + "  if (editconnection.repositoryId.value == \"\")\n" + "  {\n"
        + "    alert(\"" + Messages.getBodyJavascriptString(locale,"CmisAuthorityConnector.TheEndpointMustBeNotNull") + "\");\n"
        + "    editconnection.repositoryId.focus();\n" + "    return false;\n"
        + "  }\n" + "  return true;\n" + "}\n" + "\n" + "//-->\n"
        + "</script>\n");
  }

  /**
   * Process a configuration post. This method is called at the start of the
   * connector's configuration page, whenever there is a possibility that form
   * data for a connection has been posted. Its purpose is to gather form
   * information and modify the configuration parameters accordingly. The name
   * of the posted form is "editconnection".
   *
   * @param threadContext
   *          is the local thread context.
   * @param variableContext
   *          is the set of variables available from the post, including binary
   *          file post information.
   * @param parameters
   *          are the configuration parameters, as they currently exist, for
   *          this connection being configured.
   * @return null if all is well, or a string error message if there is an error
   *         that should prevent saving of the connection (and cause a
   *         redirection to an error page).
   */
  @Override
  public String processConfigurationPost(IThreadContext threadContext,
      IPostParameters variableContext, Locale locale, ConfigParams parameters)
      throws ManifoldCFException {

    //Repository
    String endpoint = variableContext.getParameter(CONFIG_PARAM_ENDPOINT);
    if (StringUtils.isNotEmpty(endpoint) && endpoint.length() > 0)
      parameters.setParameter(CONFIG_PARAM_ENDPOINT, endpoint);

    String repositoryId = variableContext
        .getParameter(CONFIG_PARAM_REPOSITORY_ID);
    if (StringUtils.isNotEmpty(repositoryId))
      parameters.setParameter(CONFIG_PARAM_REPOSITORY_ID, repositoryId);
   
    //User Mapping
    String usernameRegexp = variableContext.getParameter(CONFIG_PARAM_USERNAME_REGEXP);
    String userTranslation = variableContext.getParameter(CONFIG_PARAM_USER_TRANSLATION);
    if (StringUtils.isNotEmpty(usernameRegexp) && StringUtils.isNotEmpty(userTranslation))
    {
      MatchMap localMap = new MatchMap();
      localMap.appendMatchPair(usernameRegexp,userTranslation);
      parameters.setParameter(CONFIG_PARAM_USERMAPPING,localMap.toString());
    }

    return null;

  }
 
  /**
   * View configuration. This method is called in the body section of the
   * connector's view configuration page. Its purpose is to present the
   * connection information to the user. The coder can presume that the HTML that
   * is output from this configuration will be within appropriate <html> and
   * <body> tags.
   *
   * @param threadContext
   *          is the local thread context.
   * @param out
   *          is the output to which any HTML should be sent.
   * @param parameters
   *          are the configuration parameters, as they currently exist, for
   *          this connection being configured.
   */
  @Override
  public void viewConfiguration(IThreadContext threadContext, IHTTPOutput out,
      Locale locale, ConfigParams parameters) throws ManifoldCFException, IOException {
    out.print("<table class=\"displaytable\">\n"
        + "  <tr>\n"
        + "    <td class=\"description\" colspan=\"1\"><nobr>" + Messages.getBodyString(locale,"CmisAuthorityConnector.Parameters") + "</nobr></td>\n"
        + "    <td class=\"value\" colspan=\"3\">\n");
    Iterator iter = parameters.listParameters();
    while (iter.hasNext()) {
      String param = (String) iter.next();
      String value = parameters.getParameter(param);
        out.print("      <nobr>"
            + org.apache.manifoldcf.ui.util.Encoder.bodyEscape(param) + "="
            + org.apache.manifoldcf.ui.util.Encoder.bodyEscape(value)
            + "</nobr><br/>\n");
    }
    out.print("</td>\n" + "  </tr>\n" + "</table>\n");
  }
 
  /** Obtain the default access tokens for a given user name.
   *@param userName is the user name or identifier.
   *@return the default response tokens, presuming that the connect method fails.
   */
   @Override
   public AuthorizationResponse getDefaultAuthorizationResponse(String userName)
   {
     return unreachableResponse;
   }
  
   /** Uncached version of the getAuthorizationResponse method.
    *@param userName is the user name or identifier.
    *@return the response tokens (according to the current authority).
    * (Should throws an exception only when a condition cannot be properly described within the authorization response object.)
    */
    protected AuthorizationResponse getAuthorizationResponseUncached(String userName)
      throws ManifoldCFException
    {
      if (Logging.connectors.isDebugEnabled())
        Logging.connectors.debug("CMIS: Calculating response access tokens for user '"+userName+"'");

      // Map the user to the final value
      String verifiedUserName = StringUtils.EMPTY;
      try {
        verifiedUserName = matchMap.translate(userName);
      } catch (Exception e) {
          return userNotFoundResponse;
      }

      if (Logging.connectors.isDebugEnabled())
        Logging.connectors.debug("CMIS: Mapped user name is '"+verifiedUserName+"'");
     
      String[] tokens = new String[1];
      tokens[0] = verifiedUserName;
      return new AuthorizationResponse(tokens,AuthorizationResponse.RESPONSE_OK);

    }
 
  /** Obtain the access tokens for a given user name.
   *@param userName is the user name or identifier.
   *@return the response tokens (according to the current authority).
   * (Should throws an exception only when a condition cannot be properly described within the authorization response object.)
   */
   @Override
   public AuthorizationResponse getAuthorizationResponse(String userName)
     throws ManifoldCFException
   {
     if (Logging.connectors.isDebugEnabled())
       Logging.connectors.debug("CMIS: Received request for user '"+userName+"'");
    
     ICacheDescription objectDescription = new AuthorizationResponseDescription(userName,endpoint,repositoryId,matchMap.toString());
    
     // Enter the cache
     ICacheHandle ch = cacheManager.enterCache(new ICacheDescription[]{objectDescription},null,null);
     try
     {
       ICacheCreateHandle createHandle = cacheManager.enterCreateSection(ch);
       try
       {
         // Lookup the object
         AuthorizationResponse response = (AuthorizationResponse)cacheManager.lookupObject(createHandle,objectDescription);
         if (response != null)
           return response;
         // Create the object.
         response = getAuthorizationResponseUncached(userName);
         // Save it in the cache
         cacheManager.saveObject(createHandle,objectDescription,response);
         // And return it...
         return response;
       }
       finally
       {
         cacheManager.leaveCreateSection(createHandle);
       }
     }
     finally
     {
       cacheManager.leaveCache(ch);
     }
   }
  
   /** This is the cache object descriptor for cached access tokens from
    * this connector.
    */
    protected static class AuthorizationResponseDescription extends org.apache.manifoldcf.core.cachemanager.BaseDescription
    {
      /** The user name associated with the access tokens */
      protected String userName;
      /** The repository endpoint */
      protected String endpoint;
      /** The repository id */
      protected String repositoryId;
      /** The user mapping */
      protected String userMapping;
      /** The expiration time */
      protected long expirationTime = -1;
     
      /** Constructor. */
      public AuthorizationResponseDescription(String userName, String endpoint, String repositoryId, String userMapping)
      {
        super("CMISAuthority",LRUsize);
        this.userName = userName;
        this.endpoint = endpoint;
        this.repositoryId = repositoryId;
        this.userMapping = userMapping;
      }

      /** Return the invalidation keys for this object. */
      public StringSet getObjectKeys()
      {
        return emptyStringSet;
      }

      /** Get the critical section name, used for synchronizing the creation of the object */
      public String getCriticalSectionName()
      {
        return getClass().getName() + "-" + userName + "-" + endpoint +
          "-" + repositoryId + "_" + userMapping;
      }

      /** Return the object expiration interval */
      public long getObjectExpirationTime(long currentTime)
      {
        if (expirationTime == -1)
          expirationTime = currentTime + responseLifetime;
        return expirationTime;
      }

      public int hashCode()
      {
        return userName.hashCode() + endpoint.hashCode() + repositoryId.hashCode() + userMapping.hashCode();
      }
     
      public boolean equals(Object o)
      {
        if (!(o instanceof AuthorizationResponseDescription))
          return false;
        AuthorizationResponseDescription ard = (AuthorizationResponseDescription)o;
        return ard.userName.equals(userName) && ard.endpoint.equals(endpoint) &&
          repositoryId.equals(repositoryId) && ard.userMapping.equals(userMapping);
      }
     
    }
   
}
TOP

Related Classes of org.apache.manifoldcf.crawler.connectors.cmis.CmisAuthorityConnector

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.