Separate SharePoint claim space authority into an AD authority and a SharePoint Native authority.

git-svn-id: https://svn.apache.org/repos/asf/manifoldcf/branches/CONNECTORS-754-2@1536145 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/build.xml b/build.xml
index cb2c5bd..98d0de5 100644
--- a/build.xml
+++ b/build.xml
@@ -2414,7 +2414,12 @@
         </antcall>
         <antcall target="general-add-authority-connector">
             <param name="connector-name" value="sharepoint"/>
-            <param name="connector-label" value="SharePoint"/>
+            <param name="connector-label" value="SharePoint/ActiveDirectory"/>
+            <param name="connector-class" value="org.apache.manifoldcf.authorities.authorities.sharepoint.SharePointADAuthority"/>
+        </antcall>
+        <antcall target="general-add-authority-connector">
+            <param name="connector-name" value="sharepoint"/>
+            <param name="connector-label" value="SharePoint/Native"/>
             <param name="connector-class" value="org.apache.manifoldcf.authorities.authorities.sharepoint.SharePointAuthority"/>
         </antcall>
     </target>
diff --git a/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointADAuthority.java b/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointADAuthority.java
new file mode 100644
index 0000000..474a066
--- /dev/null
+++ b/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointADAuthority.java
@@ -0,0 +1,1107 @@
+/* $Id$ */
+
+/**
+* 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.authorities.authorities.sharepoint;
+
+import org.apache.manifoldcf.core.interfaces.*;
+import org.apache.manifoldcf.agents.interfaces.*;
+import org.apache.manifoldcf.authorities.interfaces.*;
+import org.apache.manifoldcf.authorities.system.Logging;
+import org.apache.manifoldcf.authorities.system.ManifoldCF;
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import java.util.concurrent.TimeUnit;
+import javax.naming.*;
+import javax.naming.ldap.*;
+import javax.naming.directory.*;
+
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.conn.PoolingClientConnectionManager;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.NTCredentials;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.DefaultRedirectStrategy;
+import org.apache.http.util.EntityUtils;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.protocol.HttpContext;
+
+
+/** This is the Active Directory implementation of the IAuthorityConnector interface, as used
+* by SharePoint in Claim Space.  It is meant to be used in conjunction with other SharePoint authorities,
+* and should ONLY be used if SharePoint native authorization is being performed in ClaimSpace mode.
+*/
+public class SharePointADAuthority extends org.apache.manifoldcf.authorities.authorities.BaseAuthorityConnector
+{
+  public static final String _rcsid = "@(#)$Id$";
+
+  // Data from the parameters
+  
+  /** The list of suffixes and the associated domain controllers */
+  private List<DCRule> dCRules = null;
+  /** How to create a connection for a DC, keyed by DC name */
+  private Map<String,DCConnectionParameters> dCConnectionParameters = null;
+  
+  private boolean hasSessionParameters = false;
+  private String cacheLifetime = null;
+  private String cacheLRUsize = null;
+  private long responseLifetime = 60000L;
+  private int LRUsize = 1000;
+
+  /** Session information for all DC's we talk with. */
+  private Map<String,DCSessionInfo> sessionInfo = null;
+  
+  /** Cache manager. */
+  private ICacheManager cacheManager = null;
+  
+  /** The length of time in milliseconds that an connection remains idle before expiring.  Currently 5 minutes. */
+  private static final long ADExpirationInterval = 300000L;
+  
+  /** Constructor.
+  */
+  public SharePointADAuthority()
+  {
+  }
+
+  /** 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;
+  }
+  
+  /** Connect.  The configuration parameters are included.
+  *@param configParams are the configuration parameters for this connection.
+  */
+  @Override
+  public void connect(ConfigParams configParams)
+  {
+    super.connect(configParams);
+
+
+    // Allocate the session data, currently empty
+    sessionInfo = new HashMap<String,DCSessionInfo>();
+    
+    // Set up the DC param set, and the rules
+    dCRules = new ArrayList<DCRule>();
+    dCConnectionParameters = new HashMap<String,DCConnectionParameters>();
+    // Read DC info from the config parameters
+    for (int i = 0; i < params.getChildCount(); i++)
+    {
+      ConfigNode cn = params.getChild(i);
+      if (cn.getType().equals(SharePointConfig.NODE_DOMAINCONTROLLER))
+      {
+        // Domain controller name is the actual key...
+        String dcName = cn.getAttributeValue(SharePointConfig.ATTR_DOMAINCONTROLLER);
+        // Set up the parameters for the domain controller
+        dCConnectionParameters.put(dcName,new DCConnectionParameters(cn.getAttributeValue(SharePointConfig.ATTR_USERNAME),
+          deobfuscate(cn.getAttributeValue(SharePointConfig.ATTR_PASSWORD)),
+          cn.getAttributeValue(SharePointConfig.ATTR_AUTHENTICATION),
+          cn.getAttributeValue(SharePointConfig.ATTR_USERACLsUSERNAME)));
+        // Order-based rule, as well
+        dCRules.add(new DCRule(cn.getAttributeValue(SharePointConfig.ATTR_SUFFIX),dcName));
+      }
+    }
+    
+    cacheLifetime = params.getParameter(SharePointConfig.PARAM_CACHELIFETIME);
+    if (cacheLifetime == null)
+      cacheLifetime = "1";
+    cacheLRUsize = params.getParameter(SharePointConfig.PARAM_CACHELRUSIZE);
+    if (cacheLRUsize == null)
+      cacheLRUsize = "1000";    
+  }
+
+  protected static String deobfuscate(String input)
+  {
+    if (input == null)
+      return null;
+    try
+    {
+      return ManifoldCF.deobfuscate(input);
+    }
+    catch (ManifoldCFException e)
+    {
+      return "";
+    }
+  }
+  
+  // All methods below this line will ONLY be called if a connect() call succeeded
+  // on this instance!
+
+  /** Check connection for sanity.
+  */
+  @Override
+  public String check()
+    throws ManifoldCFException
+  {
+    // Set up the basic AD session...
+    getSessionParameters();
+    // Clear the DC session info, so we're forced to redo it
+    for (Map.Entry<String,DCSessionInfo> sessionEntry : sessionInfo.entrySet())
+    {
+      sessionEntry.getValue().closeConnection();
+    }
+    // Loop through all domain controllers and attempt to establish a session with each one.
+    for (String domainController : dCConnectionParameters.keySet())
+    {
+      createDCSession(domainController);
+    }
+    
+    return super.check();
+  }
+
+  /** Create or lookup a session for a domain controller.
+  */
+  protected LdapContext createDCSession(String domainController)
+    throws ManifoldCFException
+  {
+    getSessionParameters();
+    DCConnectionParameters parms = dCConnectionParameters.get(domainController);
+    // Find the session in the hash, if it exists
+    DCSessionInfo session = sessionInfo.get(domainController);
+    if (session == null)
+    {
+      session = new DCSessionInfo();
+      sessionInfo.put(domainController,session);
+    }
+    return session.getADSession(domainController,parms);
+  }
+  
+  /** Poll.  The connection should be closed if it has been idle for too long.
+  */
+  @Override
+  public void poll()
+    throws ManifoldCFException
+  {
+    long currentTime = System.currentTimeMillis();
+    for (Map.Entry<String,DCSessionInfo> sessionEntry : sessionInfo.entrySet())
+    {
+      sessionEntry.getValue().closeIfExpired(currentTime);
+    }
+    super.poll();
+  }
+  
+  /** Close the connection.  Call this before discarding the repository connector.
+  */
+  @Override
+  public void disconnect()
+    throws ManifoldCFException
+  {
+    // Clean up caching parameters
+    
+    cacheLifetime = null;
+    cacheLRUsize = null;
+    
+    // Clean up AD parameters
+    
+    hasSessionParameters = false;
+
+    // Close all connections
+    for (Map.Entry<String,DCSessionInfo> sessionEntry : sessionInfo.entrySet())
+    {
+      sessionEntry.getValue().closeConnection();
+    }
+    sessionInfo = null;
+    
+    super.disconnect();
+  }
+
+  /** 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
+  {
+    // This sets up parameters we need to construct the response description
+    getSessionParameters();
+
+    // Construct a cache description object
+    ICacheDescription objectDescription = new AuthorizationResponseDescription(userName,
+      dCConnectionParameters,dCRules,this.responseLifetime,this.LRUsize);
+    
+    // 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);
+    }
+  }
+  
+  /** Obtain the access tokens for a given user name, uncached.
+  *@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
+  {
+    //String searchBase = "CN=Administrator,CN=Users,DC=qa-ad-76,DC=metacarta,DC=com";
+    int index = userName.indexOf("@");
+    if (index == -1)
+      throw new ManifoldCFException("Username is in unexpected form (no @): '"+userName+"'");
+
+    String userPart = userName.substring(0,index);
+    String domainPart = userName.substring(index+1);
+
+    try
+    {
+      List<String> adTokens = getADTokens(userPart,domainPart,userName);
+      if (adTokens == null)
+        return RESPONSE_USERNOTFOUND_ADDITIVE;
+      return new AuthorizationResponse(adTokens.toArray(new String[0]),AuthorizationResponse.RESPONSE_OK);
+    }
+    catch (NameNotFoundException e)
+    {
+      // This means that the user doesn't exist
+      return RESPONSE_USERNOTFOUND_ADDITIVE;
+    }
+    catch (NamingException e)
+    {
+      // Unreachable
+      return RESPONSE_UNREACHABLE_ADDITIVE;
+    }
+    
+  }
+
+  /** 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)
+  {
+    // The default response if the getConnection method fails
+    return RESPONSE_UNREACHABLE_ADDITIVE;
+  }
+
+  /** Get the AD-derived access tokens for a user and domain */
+  protected List<String> getADTokens(String userPart, String domainPart, String userName)
+    throws NameNotFoundException, NamingException, ManifoldCFException
+  {
+    // Now, look through the rules for the matching domain controller
+    String domainController = null;
+    for (DCRule rule : dCRules)
+    {
+      String suffix = rule.getSuffix();
+      if (suffix.length() == 0 || domainPart.toLowerCase(Locale.ROOT).endsWith(suffix.toLowerCase(Locale.ROOT)) &&
+        (suffix.length() == domainPart.length() || domainPart.charAt((domainPart.length()-suffix.length())-1) == '.'))
+      {
+        domainController = rule.getDomainControllerName();
+        break;
+      }
+    }
+    
+    if (domainController == null)
+      // No AD user
+      return null;
+    
+    // Look up connection parameters
+    DCConnectionParameters dcParams = dCConnectionParameters.get(domainController);
+    if (dcParams == null)
+      // No AD user
+      return null;
+        
+    // Use the complete fqn if the field is the "userPrincipalName"
+    String userBase;
+    String userACLsUsername = dcParams.getUserACLsUsername();
+    if (userACLsUsername != null && userACLsUsername.equals("userPrincipalName")){
+      userBase = userName;
+    }
+    else
+    {
+      userBase = userPart;
+    }
+        
+    //Build the DN searchBase from domain part
+    StringBuilder domainsb = new StringBuilder();
+    int j = 0;
+    while (true)
+    {
+      if (j > 0)
+        domainsb.append(",");
+
+      int k = domainPart.indexOf(".",j);
+      if (k == -1)
+      {
+        domainsb.append("DC=").append(ldapEscape(domainPart.substring(j)));
+        break;
+      }
+      domainsb.append("DC=").append(ldapEscape(domainPart.substring(j,k)));
+      j = k+1;
+    }
+
+    // Establish a session with the selected domain controller
+    LdapContext ctx = createDCSession(domainController);  
+        
+    //Get DistinguishedName (for this method we are using DomainPart as a searchBase ie: DC=qa-ad-76,DC=metacarta,DC=com")
+    String searchBase = getDistinguishedName(ctx, userBase, domainsb.toString(), userACLsUsername);
+    if (searchBase == null)
+      return null;
+
+    //specify the LDAP search filter
+    String searchFilter = "(objectClass=user)";
+
+    //Create the search controls for finding the access tokens	
+    SearchControls searchCtls = new SearchControls();
+
+    //Specify the search scope, must be base level search for tokenGroups
+    searchCtls.setSearchScope(SearchControls.OBJECT_SCOPE);
+       
+    //Specify the attributes to return
+    String returnedAtts[]={"tokenGroups","objectSid"};
+    searchCtls.setReturningAttributes(returnedAtts);
+
+    //Search for tokens.  Since every user *must* have a SID, the "no user" detection should be safe.
+    NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
+
+    List<String> theGroups = new ArrayList<String>();
+    String userToken = userTokenFromLoginName(domainPart + "\\" + userPart);
+    if (userToken != null)
+      theGroups.add(userToken);
+    
+    //Loop through the search results
+    while (answer.hasMoreElements())
+    {
+      SearchResult sr = (SearchResult)answer.next();
+     
+      //the sr.GetName should be null, as it is relative to the base object
+            
+      Attributes attrs = sr.getAttributes();
+      if (attrs != null)
+      {
+        try
+        {
+          for (NamingEnumeration ae = attrs.getAll();ae.hasMore();) 
+          {
+            Attribute attr = (Attribute)ae.next();
+            for (NamingEnumeration e = attr.getAll();e.hasMore();)
+            {
+              String sid = sid2String((byte[])e.next());
+              String token = attr.getID().equals("objectSid")?userTokenFromSID(sid):groupTokenFromSID(sid);
+              theGroups.add(token);
+            }
+          }
+        }	 
+        catch (NamingException e)
+        {
+          throw new ManifoldCFException(e.getMessage(),e);
+        }
+      }
+    }
+
+    if (theGroups.size() == 0)
+      return null;
+    
+    // User is in AD, so add the 'everyone' group
+    theGroups.add(everyoneGroup());
+    return theGroups;
+  }
+
+  protected static String everyoneGroup()
+  {
+    return "c:0!.s|windows";
+  }
+  
+  protected static String groupTokenFromSID(String SID)
+  {
+    return "c:0+.w|"+SID.toLowerCase(Locale.ROOT);
+  }
+
+  protected static String userTokenFromSID(String SID)
+  {
+    return "i:0+.w|"+SID.toLowerCase(Locale.ROOT);
+  }
+  
+  protected static String userTokenFromLoginName(String loginName)
+  {
+    try
+    {
+      return "i:0#.w|"+URLEncoder.encode(loginName,"utf-8");
+    }
+    catch (UnsupportedEncodingException e)
+    {
+      throw new RuntimeException("Utf-8 encoding unrecognized");
+    }
+  }
+  
+  // UI support methods.
+  //
+  // These support methods are involved in setting up authority connection configuration information. The configuration methods cannot assume that the
+  // current authority object is connected.  That is why they receive a thread context argument.
+    
+  /** 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,"SharePointAuthority.DomainController"));
+    tabsArray.add(Messages.getString(locale,"SharePointAuthority.Cache"));
+    Messages.outputResourceWithVelocity(out,locale,"editADConfiguration.js",null);
+  }
+  
+  /** 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
+  {
+    Map<String,Object> velocityContext = new HashMap<String,Object>();
+    velocityContext.put("TabName",tabName);
+    fillInDomainControllerTab(velocityContext,out,parameters);
+    fillInCacheTab(velocityContext,out,parameters);
+    Messages.outputResourceWithVelocity(out,locale,"editADConfiguration_DomainController.html",velocityContext);
+    Messages.outputResourceWithVelocity(out,locale,"editADConfiguration_Cache.html",velocityContext);
+  }
+
+  protected static void fillInDomainControllerTab(Map<String,Object> velocityContext, IPasswordMapperActivity mapper, ConfigParams parameters)
+  {
+    List<Map<String,String>> domainControllers = new ArrayList<Map<String,String>>();
+    
+    // Go through nodes looking for DC nodes
+    for (int i = 0; i < parameters.getChildCount(); i++)
+    {
+      ConfigNode cn = parameters.getChild(i);
+      if (cn.getType().equals(SharePointConfig.NODE_DOMAINCONTROLLER))
+      {
+        // Grab the info
+        String dcSuffix = cn.getAttributeValue(SharePointConfig.ATTR_SUFFIX);
+        String dcDomainController = cn.getAttributeValue(SharePointConfig.ATTR_DOMAINCONTROLLER);
+        String dcUserName = cn.getAttributeValue(SharePointConfig.ATTR_USERNAME);
+        String dcPassword = deobfuscate(cn.getAttributeValue(SharePointConfig.ATTR_PASSWORD));
+        String dcAuthentication = cn.getAttributeValue(SharePointConfig.ATTR_AUTHENTICATION);
+        String dcUserACLsUsername = cn.getAttributeValue(SharePointConfig.ATTR_USERACLsUSERNAME);
+        domainControllers.add(createDomainControllerMap(mapper,dcSuffix,dcDomainController,dcUserName,dcPassword,dcAuthentication,dcUserACLsUsername));
+      }
+    }
+    velocityContext.put("DOMAINCONTROLLERS",domainControllers);
+  }
+
+  protected static Map<String,String> createDomainControllerMap(IPasswordMapperActivity mapper, String suffix, String domainControllerName,
+    String userName, String password, String authentication, String userACLsUsername)
+  {
+    Map<String,String> defaultMap = new HashMap<String,String>();
+    if (suffix != null)
+      defaultMap.put("SUFFIX",suffix);
+    if (domainControllerName != null)
+      defaultMap.put("DOMAINCONTROLLER",domainControllerName);
+    if (userName != null)
+      defaultMap.put("USERNAME",userName);
+    if (password != null)
+      defaultMap.put("PASSWORD",mapper.mapPasswordToKey(password));
+    if (authentication != null)
+      defaultMap.put("AUTHENTICATION",authentication);
+    if (userACLsUsername != null)
+      defaultMap.put("USERACLsUSERNAME",userACLsUsername);
+    return defaultMap;
+  }
+  
+  protected static void fillInCacheTab(Map<String,Object> velocityContext, IPasswordMapperActivity mapper, ConfigParams parameters)
+  {
+    String cacheLifetime = parameters.getParameter(SharePointConfig.PARAM_CACHELIFETIME);
+    if (cacheLifetime == null)
+      cacheLifetime = "1";
+    velocityContext.put("CACHELIFETIME",cacheLifetime);
+    String cacheLRUsize = parameters.getParameter(SharePointConfig.PARAM_CACHELRUSIZE);
+    if (cacheLRUsize == null)
+      cacheLRUsize = "1000";
+    velocityContext.put("CACHELRUSIZE",cacheLRUsize);
+  }
+  
+  /** Process a configuration post.
+  * This method is called at the start of the authority 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
+  {
+    String x = variableContext.getParameter("dcrecord_count");
+    if (x != null)
+    {
+      // Delete old nodes
+      int i = 0;
+      while (i < parameters.getChildCount())
+      {
+        ConfigNode cn = parameters.getChild(i);
+        if (cn.getType().equals(SharePointConfig.NODE_DOMAINCONTROLLER))
+          parameters.removeChild(i);
+        else
+          i++;
+      }
+      // Scan form fields and apply operations
+      int count = Integer.parseInt(x);
+      i = 0;
+      String op;
+      
+      Set<String> seenDomains = new HashSet<String>();
+      
+      while (i < count)
+      {
+        op = variableContext.getParameter("dcrecord_op_"+i);
+        if (op != null && op.equals("Insert"))
+        {
+          // Insert a new record right here
+          addDomainController(seenDomains,parameters,
+            variableContext.getParameter("dcrecord_suffix"),
+            variableContext.getParameter("dcrecord_domaincontrollername"),
+            variableContext.getParameter("dcrecord_username"),
+            variableContext.mapKeyToPassword(variableContext.getParameter("dcrecord_password")),
+            variableContext.getParameter("dcrecord_authentication"),
+            variableContext.getParameter("dcrecord_userACLsUsername"));
+        }
+        if (op == null || !op.equals("Delete"))
+        {
+          // Add this record back in
+          addDomainController(seenDomains,parameters,
+            variableContext.getParameter("dcrecord_suffix_"+i),
+            variableContext.getParameter("dcrecord_domaincontrollername_"+i),
+            variableContext.getParameter("dcrecord_username_"+i),
+            variableContext.mapKeyToPassword(variableContext.getParameter("dcrecord_password_"+i)),
+            variableContext.getParameter("dcrecord_authentication_"+i),
+            variableContext.getParameter("dcrecord_userACLsUsername_"+i));
+        }
+        i++;
+      }
+      op = variableContext.getParameter("dcrecord_op");
+      if (op != null && op.equals("Add"))
+      {
+        // Insert a new record right here
+        addDomainController(seenDomains,parameters,
+          variableContext.getParameter("dcrecord_suffix"),
+          variableContext.getParameter("dcrecord_domaincontrollername"),
+          variableContext.getParameter("dcrecord_username"),
+          variableContext.getParameter("dcrecord_password"),
+          variableContext.getParameter("dcrecord_authentication"),
+          variableContext.getParameter("dcrecord_userACLsUsername"));
+      }
+    }
+
+    // Cache parameters
+    
+    String cacheLifetime = variableContext.getParameter("cachelifetime");
+    if (cacheLifetime != null)
+      parameters.setParameter(SharePointConfig.PARAM_CACHELIFETIME,cacheLifetime);
+    String cacheLRUsize = variableContext.getParameter("cachelrusize");
+    if (cacheLRUsize != null)
+      parameters.setParameter(SharePointConfig.PARAM_CACHELRUSIZE,cacheLRUsize);
+    
+    return null;
+  }
+  
+  protected static void addDomainController(Set<String> seenDomains, ConfigParams parameters,
+    String suffix, String domainControllerName, String userName, String password, String authentication,
+    String userACLsUsername)
+    throws ManifoldCFException
+  {
+    if (!seenDomains.contains(domainControllerName))
+    {
+      ConfigNode cn = new ConfigNode(SharePointConfig.NODE_DOMAINCONTROLLER);
+      cn.setAttribute(SharePointConfig.ATTR_SUFFIX,suffix);
+      cn.setAttribute(SharePointConfig.ATTR_DOMAINCONTROLLER,domainControllerName);
+      cn.setAttribute(SharePointConfig.ATTR_USERNAME,userName);
+      cn.setAttribute(SharePointConfig.ATTR_PASSWORD,ManifoldCF.obfuscate(password));
+      cn.setAttribute(SharePointConfig.ATTR_AUTHENTICATION,authentication);
+      cn.setAttribute(SharePointConfig.ATTR_USERACLsUSERNAME,userACLsUsername);
+      parameters.addChild(parameters.getChildCount(),cn);
+      seenDomains.add(domainControllerName);
+    }
+  }
+  
+  /** View configuration.
+  * This method is called in the body section of the authority 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
+  {
+    Map<String,Object> velocityContext = new HashMap<String,Object>();
+    fillInDomainControllerTab(velocityContext,out,parameters);
+    fillInCacheTab(velocityContext,out,parameters);
+    Messages.outputResourceWithVelocity(out,locale,"viewADConfiguration.html",velocityContext);
+  }
+
+  // Protected methods
+
+  /** Get parameters needed for caching.
+  */
+  protected void getSessionParameters()
+    throws ManifoldCFException
+  {
+    if (!hasSessionParameters)
+    {
+      try
+      {
+        responseLifetime = Long.parseLong(this.cacheLifetime) * 60L * 1000L;
+        LRUsize = Integer.parseInt(this.cacheLRUsize);
+      }
+      catch (NumberFormatException e)
+      {
+        throw new ManifoldCFException("Cache lifetime or Cache LRU size must be an integer: "+e.getMessage(),e);
+      }
+      hasSessionParameters = true;
+    }
+  }
+  
+  /** Obtain the DistinguishedName for a given user logon name.
+  *@param ctx is the ldap context to use.
+  *@param userName (Domain Logon Name) is the user name or identifier.
+  *@param searchBase (Full Domain Name for the search ie: DC=qa-ad-76,DC=metacarta,DC=com)
+  *@return DistinguishedName for given domain user logon name. 
+  * (Should throws an exception if user is not found.)
+  */
+  protected String getDistinguishedName(LdapContext ctx, String userName, String searchBase, String userACLsUsername)
+    throws ManifoldCFException
+  {
+    String returnedAtts[] = {"distinguishedName"};
+    String searchFilter = "(&(objectClass=user)(" + userACLsUsername + "=" + userName + "))";
+    SearchControls searchCtls = new SearchControls();
+    searchCtls.setReturningAttributes(returnedAtts);
+    //Specify the search scope  
+    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+    searchCtls.setReturningAttributes(returnedAtts);
+
+    try
+    {
+      NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
+      while (answer.hasMoreElements())
+      {
+        SearchResult sr = (SearchResult)answer.next();
+        Attributes attrs = sr.getAttributes();
+        if (attrs != null)
+        {
+          String dn = attrs.get("distinguishedName").get().toString();
+          return dn;
+        }
+      }
+      return null;
+    }
+    catch (NamingException e)
+    {
+      throw new ManifoldCFException(e.getMessage(),e);
+    }
+  }
+   
+  /** LDAP escape a string.
+  */
+  protected static String ldapEscape(String input)
+  {
+    //Add escape sequence to all commas
+    StringBuilder sb = new StringBuilder();
+    int index = 0;
+    while (true)
+    {
+      int oldIndex = index;
+      index = input.indexOf(",",oldIndex);
+      if (index == -1)
+      {
+        sb.append(input.substring(oldIndex));
+        break;
+      }
+      sb.append(input.substring(oldIndex,index)).append("\\,");
+      index++;
+    }
+    return sb.toString();
+  }
+    	
+  /** Convert a binary SID to a string */
+  protected static String sid2String(byte[] SID)
+  {
+    StringBuilder strSID = new StringBuilder("S");
+    long version = SID[0];
+    strSID.append("-").append(Long.toString(version));
+    long authority = SID[4];
+    for (int i = 0;i<4;i++)
+    {
+      authority <<= 8;
+      authority += SID[4+i] & 0xFF;
+    }
+    strSID.append("-").append(Long.toString(authority));
+    long count = SID[2];
+    count <<= 8;
+    count += SID[1] & 0xFF;
+    for (int j=0;j<count;j++)
+    {
+      long rid = SID[11 + (j*4)] & 0xFF;
+      for (int k=1;k<4;k++)
+      {
+        rid <<= 8;
+        rid += SID[11-k + (j*4)] & 0xFF;
+      }
+      strSID.append("-").append(Long.toString(rid));
+    }
+    return strSID.toString();
+  }
+
+  /** Class representing the session information for a specific domain controller
+  * connection.
+  */
+  protected static class DCSessionInfo
+  {
+    /** The initialized LDAP context (which functions as a session) */
+    private LdapContext ctx = null;
+    /** The time of last access to this ctx object */
+    private long expiration = -1L;
+    
+    public DCSessionInfo()
+    {
+    }
+
+    /** Initialize the session. */
+    public LdapContext getADSession(String domainControllerName, DCConnectionParameters params)
+      throws ManifoldCFException
+    {
+      String authentication = params.getAuthentication();
+      String userName = params.getUserName();
+      String password = params.getPassword();
+      
+      while (true)
+      {
+        if (ctx == null)
+        {
+          // Calculate the ldap url first
+          String ldapURL = "ldap://" + domainControllerName + ":389";
+          
+          Hashtable env = new Hashtable();
+          env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
+          env.put(Context.SECURITY_AUTHENTICATION,authentication);      
+          env.put(Context.SECURITY_PRINCIPAL,userName);
+          env.put(Context.SECURITY_CREDENTIALS,password);
+                                    
+          //connect to my domain controller
+          env.put(Context.PROVIDER_URL,ldapURL);
+                    
+          //specify attributes to be returned in binary format
+          env.put("java.naming.ldap.attributes.binary","tokenGroups objectSid");
+     
+          // Now, try the connection...
+          try
+          {
+            ctx = new InitialLdapContext(env,null);
+            // If successful, break
+            break;
+          }
+          catch (AuthenticationException e)
+          {
+            // This means we couldn't authenticate!
+            throw new ManifoldCFException("Authentication problem authenticating admin user '"+userName+"': "+e.getMessage(),e);
+          }
+          catch (CommunicationException e)
+          {
+            // This means we couldn't connect, most likely
+            throw new ManifoldCFException("Couldn't communicate with domain controller '"+domainControllerName+"': "+e.getMessage(),e);
+          }
+          catch (NamingException e)
+          {
+            throw new ManifoldCFException(e.getMessage(),e);
+          }
+        }
+        else
+        {
+          // Attempt to reconnect.  I *hope* this is efficient and doesn't do unnecessary work.
+          try
+          {
+            ctx.reconnect(null);
+            // Break on apparent success
+            break;
+          }
+          catch (AuthenticationException e)
+          {
+            // This means we couldn't authenticate!  Log it and retry creating a whole new context.
+            Logging.authorityConnectors.warn("Reconnect: Authentication problem authenticating admin user '"+userName+"': "+e.getMessage(),e);
+          }
+          catch (CommunicationException e)
+          {
+            // This means we couldn't connect, most likely.  Log it and retry creating a whole new context.
+            Logging.authorityConnectors.warn("Reconnect: Couldn't communicate with domain controller '"+domainControllerName+"': "+e.getMessage(),e);
+          }
+          catch (NamingException e)
+          {
+            Logging.authorityConnectors.warn("Reconnect: Naming exception: "+e.getMessage(),e);
+          }
+          
+          // So we have no chance of leaking resources, attempt to close the context.
+          closeConnection();
+          // Loop back around to try our luck with a fresh connection.
+
+        }
+      }
+      
+      // Set the expiration time anew
+      expiration = System.currentTimeMillis() + ADExpirationInterval;
+      return ctx;
+    }
+    
+    /** Close the connection handle. */
+    protected void closeConnection()
+    {
+      if (ctx != null)
+      {
+        try
+        {
+          ctx.close();
+        }
+        catch (NamingException e)
+        {
+          // Eat this error
+        }
+        ctx = null;
+        expiration = -1L;
+      }
+    }
+
+    /** Close connection if it has expired. */
+    protected void closeIfExpired(long currentTime)
+    {
+      if (expiration != -1L && currentTime > expiration)
+        closeConnection();
+    }
+
+  }
+
+  /** Class describing a domain suffix and corresponding domain controller name rule.
+  */
+  protected static class DCRule
+  {
+    private String suffix;
+    private String domainControllerName;
+    
+    public DCRule(String suffix, String domainControllerName)
+    {
+      this.suffix = suffix;
+      this.domainControllerName = domainControllerName;
+    }
+    
+    public String getSuffix()
+    {
+      return suffix;
+    }
+    
+    public String getDomainControllerName()
+    {
+      return domainControllerName;
+    }
+  }
+  
+  /** Class describing the connection parameters to a domain controller.
+  */
+  protected static class DCConnectionParameters
+  {
+    private String userName;
+    private String password;
+    private String authentication;
+    private String userACLsUsername;
+
+    public DCConnectionParameters(String userName, String password, String authentication, String userACLsUsername)
+    {
+      this.userName = userName;
+      this.password = password;
+      this.authentication = authentication;
+      this.userACLsUsername = userACLsUsername;
+    }
+    
+    public String getUserName()
+    {
+      return userName;
+    }
+    
+    public String getPassword()
+    {
+      return password;
+    }
+    
+    public String getAuthentication()
+    {
+      return authentication;
+    }
+    
+    public String getUserACLsUsername()
+    {
+      return userACLsUsername;
+    }
+  }
+  
+  protected static StringSet emptyStringSet = new StringSet();
+  
+  /** 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 */
+    protected String userName;
+    /** Connection parameters */
+    protected Map<String,DCConnectionParameters> dcConnectionParams;
+    /** Rules */
+    protected List<DCRule> dcRules;
+    /** The response lifetime */
+    protected long responseLifetime;
+    /** The expiration time */
+    protected long expirationTime = -1;
+    
+    /** Constructor. */
+    public AuthorizationResponseDescription(String userName, Map<String,DCConnectionParameters> dcConnectionParams,
+      List<DCRule> dcRules, long responseLifetime, int LRUsize)
+    {
+      super("SharePointADAuthority",LRUsize);
+      this.userName = userName;
+      this.dcConnectionParams = dcConnectionParams;
+      this.dcRules = dcRules;
+      this.responseLifetime = responseLifetime;
+    }
+
+    /** 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()
+    {
+      StringBuilder sb = new StringBuilder(getClass().getName());
+      sb.append("-").append(userName);
+      for (DCRule rule : dcRules)
+      {
+        sb.append("-").append(rule.getSuffix());
+        String domainController = rule.getDomainControllerName();
+        DCConnectionParameters params = dcConnectionParams.get(domainController);
+        sb.append("-").append(domainController).append("-").append(params.getUserName()).append("-").append(params.getPassword());
+      }
+      return sb.toString();
+    }
+
+    /** Return the object expiration interval */
+    public long getObjectExpirationTime(long currentTime)
+    {
+      if (expirationTime == -1)
+        expirationTime = currentTime + responseLifetime;
+      return expirationTime;
+    }
+
+    public int hashCode()
+    {
+      int rval = userName.hashCode();
+      for (DCRule rule : dcRules)
+      {
+        String domainController = rule.getDomainControllerName();
+        DCConnectionParameters params = dcConnectionParams.get(domainController);
+        rval += rule.getSuffix().hashCode() + domainController.hashCode() + params.getUserName().hashCode() + params.getPassword().hashCode();
+      }
+      return rval;
+    }
+    
+    public boolean equals(Object o)
+    {
+      if (!(o instanceof AuthorizationResponseDescription))
+        return false;
+      AuthorizationResponseDescription ard = (AuthorizationResponseDescription)o;
+      if (!ard.userName.equals(userName))
+        return false;
+      if (ard.dcRules.size() != dcRules.size())
+        return false;
+      for (int i = 0 ; i < dcRules.size() ; i++)
+      {
+        DCRule rule = dcRules.get(i);
+        DCRule ardRule = ard.dcRules.get(i);
+        if (!rule.getSuffix().equals(ardRule.getSuffix()) || !rule.getDomainControllerName().equals(ardRule.getDomainControllerName()))
+          return false;
+        String domainController = rule.getDomainControllerName();
+        DCConnectionParameters params = dcConnectionParams.get(domainController);
+        DCConnectionParameters ardParams = ard.dcConnectionParams.get(domainController);
+        if (!params.getUserName().equals(ardParams.getUserName()) || !params.getPassword().equals(ardParams.getPassword()))
+          return false;
+      }
+      return true;
+    }
+    
+  }
+  
+}
+
+
diff --git a/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointAuthority.java b/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointAuthority.java
index 0e24e63..fd59e68 100644
--- a/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointAuthority.java
+++ b/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointAuthority.java
@@ -54,10 +54,7 @@
 import org.apache.http.protocol.HttpContext;
 
 
-/** This is the Active Directory implementation of the IAuthorityConnector interface.
-* Access tokens for this connector are simple SIDs, except for the "global deny" token, which
-* is designed to allow the authority to shut off access to all authorized documents when the
-* user is unrecognized or the domain controller does not respond.
+/** This is the native SharePoint implementation of the IAuthorityConnector interface.
 */
 public class SharePointAuthority extends org.apache.manifoldcf.authorities.authorities.BaseAuthorityConnector
 {
@@ -65,56 +62,46 @@
 
   // Data from the parameters
   
-  /** The list of suffixes and the associated domain controllers */
-  private List<DCRule> dCRules = null;
-  /** How to create a connection for a DC, keyed by DC name */
-  private Map<String,DCConnectionParameters> dCConnectionParameters = null;
-  
-  private boolean hasSessionParameters = false;
-  private String cacheLifetime = null;
-  private String cacheLRUsize = null;
-  private long responseLifetime = 60000L;
-  private int LRUsize = 1000;
-
-  /** Session information for all DC's we talk with. */
-  private Map<String,DCSessionInfo> sessionInfo = null;
-  
   /** Cache manager. */
   private ICacheManager cacheManager = null;
   
-  /** The length of time in milliseconds that an connection remains idle before expiring.  Currently 5 minutes. */
-  private static final long ADExpirationInterval = 300000L;
+  private boolean hasSessionParameters = false;
   
   /** Length of time that a SharePoint session can remain idle */
   private static final long SharePointExpirationInterval = 300000L;
   
   // SharePoint server parameters
-  
+  // These are needed for caching, so they are set at connect() time
   private String serverProtocol = null;
   private String serverUrl = null;
   private String fileBaseUrl = null;
-  private String userName = null;
-  private String strippedUserName = null;
+  private String serverUserName = null;
   private String password = null;
   private String ntlmDomain = null;
   private String serverName = null;
+  private String serverPortString = null;
   private String serverLocation = null;
+  private String strippedUserName = null;
   private String encodedServerLocation = null;
-  private int serverPort = -1;
-
-  private SPSProxyHelper proxy = null;
-
-  private boolean isClaimSpace = false;
+  private String keystoreData = null;
   
+  private String cacheLRUsize = null;
+  private String cacheLifetime = null;
+  
+  // These are calculated when the session is set up
+  private int serverPort = -1;
+  private SPSProxyHelper proxy = null;
   private long sharepointSessionTimeout;
   
-  // SSL support
-  private String keystoreData = null;
+  private long responseLifetime = -1L;
+  private int LRUsize = -1;
+  
   private IKeystoreManager keystoreManager = null;
   
   private ClientConnectionManager connectionManager = null;
   private HttpClient httpClient = null;
 
+
   // Current host name
   private static String currentHost = null;
   static
@@ -165,53 +152,53 @@
   {
     super.connect(configParams);
 
-
-    // Allocate the session data, currently empty
-    sessionInfo = new HashMap<String,DCSessionInfo>();
-    
-    // Set up the DC param set, and the rules
-    dCRules = new ArrayList<DCRule>();
-    dCConnectionParameters = new HashMap<String,DCConnectionParameters>();
-    // Read DC info from the config parameters
-    for (int i = 0; i < params.getChildCount(); i++)
-    {
-      ConfigNode cn = params.getChild(i);
-      if (cn.getType().equals(SharePointConfig.NODE_DOMAINCONTROLLER))
-      {
-        // Domain controller name is the actual key...
-        String dcName = cn.getAttributeValue(SharePointConfig.ATTR_DOMAINCONTROLLER);
-        // Set up the parameters for the domain controller
-        dCConnectionParameters.put(dcName,new DCConnectionParameters(cn.getAttributeValue(SharePointConfig.ATTR_USERNAME),
-          deobfuscate(cn.getAttributeValue(SharePointConfig.ATTR_PASSWORD)),
-          cn.getAttributeValue(SharePointConfig.ATTR_AUTHENTICATION),
-          cn.getAttributeValue(SharePointConfig.ATTR_USERACLsUSERNAME)));
-        // Order-based rule, as well
-        dCRules.add(new DCRule(cn.getAttributeValue(SharePointConfig.ATTR_SUFFIX),dcName));
-      }
-    }
-    
-    cacheLifetime = params.getParameter(SharePointConfig.PARAM_CACHELIFETIME);
+    // Pick up all the parameters that go into the cache key here
+    cacheLifetime = configParams.getParameter(SharePointConfig.PARAM_CACHELIFETIME);
     if (cacheLifetime == null)
       cacheLifetime = "1";
-    cacheLRUsize = params.getParameter(SharePointConfig.PARAM_CACHELRUSIZE);
+    cacheLRUsize = configParams.getParameter(SharePointConfig.PARAM_CACHELRUSIZE);
     if (cacheLRUsize == null)
-      cacheLRUsize = "1000";    
+      cacheLRUsize = "1000";
+    
+    String serverVersion = configParams.getParameter( SharePointConfig.PARAM_SERVERVERSION );
+    if (serverVersion == null)
+      serverVersion = "2.0";
+    // Authority needs to do nothing with SharePoint version right now.
+      
+    serverProtocol = configParams.getParameter( SharePointConfig.PARAM_SERVERPROTOCOL );
+    if (serverProtocol == null)
+      serverProtocol = "http";
+      
+    serverName = configParams.getParameter( SharePointConfig.PARAM_SERVERNAME );
+    serverPortString = configParams.getParameter( SharePointConfig.PARAM_SERVERPORT );
+    serverLocation = configParams.getParameter(SharePointConfig.PARAM_SERVERLOCATION);
+    if (serverLocation == null)
+      serverLocation = "";
+    if (serverLocation.endsWith("/"))
+      serverLocation = serverLocation.substring(0,serverLocation.length()-1);
+    if (serverLocation.length() > 0 && !serverLocation.startsWith("/"))
+      serverLocation = "/" + serverLocation;
+    encodedServerLocation = serverLocation;
+    serverLocation = decodePath(serverLocation);
+
+    serverUserName = configParams.getParameter(SharePointConfig.PARAM_SERVERUSERNAME);
+    password = configParams.getObfuscatedParameter(SharePointConfig.PARAM_SERVERPASSWORD);
+    int index = serverUserName.indexOf("\\");
+    if (index != -1)
+    {
+      strippedUserName = serverUserName.substring(index+1);
+      ntlmDomain = serverUserName.substring(0,index);
+    }
+    else
+    {
+      strippedUserName = null;
+      ntlmDomain = null;
+    }
+    
+    keystoreData = params.getParameter(SharePointConfig.PARAM_SERVERKEYSTORE);
+
   }
 
-  protected static String deobfuscate(String input)
-  {
-    if (input == null)
-      return null;
-    try
-    {
-      return ManifoldCF.deobfuscate(input);
-    }
-    catch (ManifoldCFException e)
-    {
-      return "";
-    }
-  }
-  
   // All methods below this line will ONLY be called if a connect() call succeeded
   // on this instance!
 
@@ -221,20 +208,6 @@
   public String check()
     throws ManifoldCFException
   {
-    // Set up the basic AD session...
-    getSessionParameters();
-    // Clear the DC session info, so we're forced to redo it
-    for (Map.Entry<String,DCSessionInfo> sessionEntry : sessionInfo.entrySet())
-    {
-      sessionEntry.getValue().closeConnection();
-    }
-    // Loop through all domain controllers and attempt to establish a session with each one.
-    for (String domainController : dCConnectionParameters.keySet())
-    {
-      createDCSession(domainController);
-    }
-    
-    // SharePoint check
     getSharePointSession();
     try
     {
@@ -257,23 +230,6 @@
     return super.check();
   }
 
-  /** Create or lookup a session for a domain controller.
-  */
-  protected LdapContext createDCSession(String domainController)
-    throws ManifoldCFException
-  {
-    getSessionParameters();
-    DCConnectionParameters parms = dCConnectionParameters.get(domainController);
-    // Find the session in the hash, if it exists
-    DCSessionInfo session = sessionInfo.get(domainController);
-    if (session == null)
-    {
-      session = new DCSessionInfo();
-      sessionInfo.put(domainController,session);
-    }
-    return session.getADSession(domainController,parms);
-  }
-  
   /** Poll.  The connection should be closed if it has been idle for too long.
   */
   @Override
@@ -281,10 +237,6 @@
     throws ManifoldCFException
   {
     long currentTime = System.currentTimeMillis();
-    for (Map.Entry<String,DCSessionInfo> sessionEntry : sessionInfo.entrySet())
-    {
-      sessionEntry.getValue().closeIfExpired(currentTime);
-    }
     if (proxy != null && System.currentTimeMillis() >= sharepointSessionTimeout)
       expireSharePointSession();
     if (connectionManager != null)
@@ -303,22 +255,11 @@
     cacheLifetime = null;
     cacheLRUsize = null;
     
-    // Clean up AD parameters
-    
-    hasSessionParameters = false;
-
-    // Close all connections
-    for (Map.Entry<String,DCSessionInfo> sessionEntry : sessionInfo.entrySet())
-    {
-      sessionEntry.getValue().closeConnection();
-    }
-    sessionInfo = null;
-    
     // Clean up SharePoint parameters
     
     serverUrl = null;
     fileBaseUrl = null;
-    userName = null;
+    serverUserName = null;
     strippedUserName = null;
     password = null;
     ntlmDomain = null;
@@ -336,6 +277,8 @@
       connectionManager.shutdown();
     connectionManager = null;
 
+    hasSessionParameters = false;
+    
     super.disconnect();
   }
 
@@ -348,12 +291,11 @@
   public AuthorizationResponse getAuthorizationResponse(String userName)
     throws ManifoldCFException
   {
-    // This sets up parameters we need to construct the response description
     getSessionParameters();
-
     // Construct a cache description object
     ICacheDescription objectDescription = new AuthorizationResponseDescription(userName,
-      dCConnectionParameters,dCRules,this.responseLifetime,this.LRUsize);
+      serverName,serverPortString,serverLocation,serverProtocol,serverUserName,password,
+      this.responseLifetime,this.LRUsize);
     
     // Enter the cache
     ICacheHandle ch = cacheManager.enterCache(new ICacheDescription[]{objectDescription},null,null);
@@ -400,38 +342,13 @@
     String userPart = userName.substring(0,index);
     String domainPart = userName.substring(index+1);
 
-    List<String> theGroups = new ArrayList<String>();
-    
     // First, look up user in SharePoint.
     getSharePointSession();
     List<String> sharePointTokens = proxy.getAccessTokens("/", domainPart + "\\" + userPart);
     if (sharePointTokens == null)
-      return RESPONSE_USERNOTFOUND;
-    theGroups.addAll(sharePointTokens);
+      return RESPONSE_USERNOTFOUND_ADDITIVE;
     
-    // Use AD only if Claim Space
-    if (isClaimSpace)
-    {
-      try
-      {
-        List<String> adTokens = getADTokens(userPart,domainPart,userName);
-        // User not present in AD is perfectly OK provided the user exists in SharePoint
-        if (adTokens != null)
-          theGroups.addAll(adTokens);
-      }
-      catch (NameNotFoundException e)
-      {
-        // This means that the user doesn't exist
-        return RESPONSE_USERNOTFOUND;
-      }
-      catch (NamingException e)
-      {
-        // Unreachable
-        return RESPONSE_UNREACHABLE;
-      }
-    }
-    
-    return new AuthorizationResponse(theGroups.toArray(new String[0]),AuthorizationResponse.RESPONSE_OK);
+    return new AuthorizationResponse(sharePointTokens.toArray(new String[0]),AuthorizationResponse.RESPONSE_OK);
   }
 
   /** Obtain the default access tokens for a given user name.
@@ -442,164 +359,9 @@
   public AuthorizationResponse getDefaultAuthorizationResponse(String userName)
   {
     // The default response if the getConnection method fails
-    return RESPONSE_UNREACHABLE;
+    return RESPONSE_UNREACHABLE_ADDITIVE;
   }
 
-  /** Get the AD-derived access tokens for a user and domain */
-  protected List<String> getADTokens(String userPart, String domainPart, String userName)
-    throws NameNotFoundException, NamingException, ManifoldCFException
-  {
-    // Now, look through the rules for the matching domain controller
-    String domainController = null;
-    for (DCRule rule : dCRules)
-    {
-      String suffix = rule.getSuffix();
-      if (suffix.length() == 0 || domainPart.toLowerCase(Locale.ROOT).endsWith(suffix.toLowerCase(Locale.ROOT)) &&
-        (suffix.length() == domainPart.length() || domainPart.charAt((domainPart.length()-suffix.length())-1) == '.'))
-      {
-        domainController = rule.getDomainControllerName();
-        break;
-      }
-    }
-    
-    if (domainController == null)
-      // No AD user
-      return null;
-    
-    // Look up connection parameters
-    DCConnectionParameters dcParams = dCConnectionParameters.get(domainController);
-    if (dcParams == null)
-      // No AD user
-      return null;
-        
-    // Use the complete fqn if the field is the "userPrincipalName"
-    String userBase;
-    String userACLsUsername = dcParams.getUserACLsUsername();
-    if (userACLsUsername != null && userACLsUsername.equals("userPrincipalName")){
-      userBase = userName;
-    }
-    else
-    {
-      userBase = userPart;
-    }
-        
-    //Build the DN searchBase from domain part
-    StringBuilder domainsb = new StringBuilder();
-    int j = 0;
-    while (true)
-    {
-      if (j > 0)
-        domainsb.append(",");
-
-      int k = domainPart.indexOf(".",j);
-      if (k == -1)
-      {
-        domainsb.append("DC=").append(ldapEscape(domainPart.substring(j)));
-        break;
-      }
-      domainsb.append("DC=").append(ldapEscape(domainPart.substring(j,k)));
-      j = k+1;
-    }
-
-    // Establish a session with the selected domain controller
-    LdapContext ctx = createDCSession(domainController);  
-        
-    //Get DistinguishedName (for this method we are using DomainPart as a searchBase ie: DC=qa-ad-76,DC=metacarta,DC=com")
-    String searchBase = getDistinguishedName(ctx, userBase, domainsb.toString(), userACLsUsername);
-    if (searchBase == null)
-      return null;
-
-    //specify the LDAP search filter
-    String searchFilter = "(objectClass=user)";
-
-    //Create the search controls for finding the access tokens	
-    SearchControls searchCtls = new SearchControls();
-
-    //Specify the search scope, must be base level search for tokenGroups
-    searchCtls.setSearchScope(SearchControls.OBJECT_SCOPE);
-       
-    //Specify the attributes to return
-    String returnedAtts[]={"tokenGroups","objectSid"};
-    searchCtls.setReturningAttributes(returnedAtts);
-
-    //Search for tokens.  Since every user *must* have a SID, the "no user" detection should be safe.
-    NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
-
-    List<String> theGroups = new ArrayList<String>();
-    String userToken = userTokenFromLoginName(domainPart + "\\" + userPart);
-    if (userToken != null)
-      theGroups.add(userToken);
-    
-    //Loop through the search results
-    while (answer.hasMoreElements())
-    {
-      SearchResult sr = (SearchResult)answer.next();
-     
-      //the sr.GetName should be null, as it is relative to the base object
-            
-      Attributes attrs = sr.getAttributes();
-      if (attrs != null)
-      {
-        try
-        {
-          for (NamingEnumeration ae = attrs.getAll();ae.hasMore();) 
-          {
-            Attribute attr = (Attribute)ae.next();
-            for (NamingEnumeration e = attr.getAll();e.hasMore();)
-            {
-              String sid = sid2String((byte[])e.next());
-              String token = attr.getID().equals("objectSid")?userTokenFromSID(sid):groupTokenFromSID(sid);
-              theGroups.add(token);
-            }
-          }
-        }	 
-        catch (NamingException e)
-        {
-          throw new ManifoldCFException(e.getMessage(),e);
-        }
-      }
-    }
-
-    if (theGroups.size() == 0)
-      return null;
-    
-    // User is in AD, so add the 'everyone' group
-    theGroups.add(everyoneGroup());
-    return theGroups;
-  }
-
-  protected String everyoneGroup()
-  {
-    if (isClaimSpace)
-      return "c:0!.s|windows";
-    else
-      return "S-1-1-0";
-  }
-  
-  protected String groupTokenFromSID(String SID)
-  {
-    if (isClaimSpace)
-      return "c:0+.w|"+SID.toLowerCase(Locale.ROOT);
-    else
-      return SID;
-  }
-
-  protected String userTokenFromSID(String SID)
-  {
-    if (isClaimSpace)
-      return "i:0+.w|"+SID.toLowerCase(Locale.ROOT);
-    else
-      return SID;
-  }
-  
-  protected String userTokenFromLoginName(String loginName)
-  {
-    if (isClaimSpace)
-      return "i:0#.w|"+URLEncoder.encode(loginName);
-    else
-      return null;
-  }
-  
   // UI support methods.
   //
   // These support methods are involved in setting up authority connection configuration information. The configuration methods cannot assume that the
@@ -617,9 +379,7 @@
   public void outputConfigurationHeader(IThreadContext threadContext, IHTTPOutput out, Locale locale, ConfigParams parameters, List<String> tabsArray)
     throws ManifoldCFException, IOException
   {
-    tabsArray.add(Messages.getString(locale,"SharePointAuthority.DomainController"));
     tabsArray.add(Messages.getString(locale,"SharePointAuthority.Server"));
-    tabsArray.add(Messages.getString(locale,"SharePointAuthority.AuthorizationModel"));
     tabsArray.add(Messages.getString(locale,"SharePointAuthority.Cache"));
     Messages.outputResourceWithVelocity(out,locale,"editConfiguration.js",null);
   }
@@ -639,25 +399,10 @@
   {
     Map<String,Object> velocityContext = new HashMap<String,Object>();
     velocityContext.put("TabName",tabName);
-    fillInDomainControllerTab(velocityContext,out,parameters);
     fillInCacheTab(velocityContext,out,parameters);
     fillInServerTab(velocityContext,out,parameters);
-    fillInAuthorizationModelTab(velocityContext,out,parameters);
-    Messages.outputResourceWithVelocity(out,locale,"editConfiguration_DomainController.html",velocityContext);
     Messages.outputResourceWithVelocity(out,locale,"editConfiguration_Cache.html",velocityContext);
     Messages.outputResourceWithVelocity(out,locale,"editConfiguration_Server.html",velocityContext);
-    Messages.outputResourceWithVelocity(out,locale,"editConfiguration_AuthorizationModel.html",velocityContext);
-  }
-
-  protected static void fillInAuthorizationModelTab(Map<String,Object> velocityContext, IHTTPOutput out, ConfigParams parameters)
-    throws ManifoldCFException
-  {
-    String authorizationModel = parameters.getParameter(SharePointConfig.PARAM_AUTHORIZATIONMODEL);
-    if (authorizationModel == null)
-      authorizationModel = "Classic";
-    
-    // Fill in context
-    velocityContext.put("AUTHORIZATIONMODEL", authorizationModel);
   }
 
   protected static void fillInServerTab(Map<String,Object> velocityContext, IHTTPOutput out, ConfigParams parameters)
@@ -728,48 +473,6 @@
     
   }
 
-  protected static void fillInDomainControllerTab(Map<String,Object> velocityContext, IPasswordMapperActivity mapper, ConfigParams parameters)
-  {
-    List<Map<String,String>> domainControllers = new ArrayList<Map<String,String>>();
-    
-    // Go through nodes looking for DC nodes
-    for (int i = 0; i < parameters.getChildCount(); i++)
-    {
-      ConfigNode cn = parameters.getChild(i);
-      if (cn.getType().equals(SharePointConfig.NODE_DOMAINCONTROLLER))
-      {
-        // Grab the info
-        String dcSuffix = cn.getAttributeValue(SharePointConfig.ATTR_SUFFIX);
-        String dcDomainController = cn.getAttributeValue(SharePointConfig.ATTR_DOMAINCONTROLLER);
-        String dcUserName = cn.getAttributeValue(SharePointConfig.ATTR_USERNAME);
-        String dcPassword = deobfuscate(cn.getAttributeValue(SharePointConfig.ATTR_PASSWORD));
-        String dcAuthentication = cn.getAttributeValue(SharePointConfig.ATTR_AUTHENTICATION);
-        String dcUserACLsUsername = cn.getAttributeValue(SharePointConfig.ATTR_USERACLsUSERNAME);
-        domainControllers.add(createDomainControllerMap(mapper,dcSuffix,dcDomainController,dcUserName,dcPassword,dcAuthentication,dcUserACLsUsername));
-      }
-    }
-    velocityContext.put("DOMAINCONTROLLERS",domainControllers);
-  }
-
-  protected static Map<String,String> createDomainControllerMap(IPasswordMapperActivity mapper, String suffix, String domainControllerName,
-    String userName, String password, String authentication, String userACLsUsername)
-  {
-    Map<String,String> defaultMap = new HashMap<String,String>();
-    if (suffix != null)
-      defaultMap.put("SUFFIX",suffix);
-    if (domainControllerName != null)
-      defaultMap.put("DOMAINCONTROLLER",domainControllerName);
-    if (userName != null)
-      defaultMap.put("USERNAME",userName);
-    if (password != null)
-      defaultMap.put("PASSWORD",mapper.mapPasswordToKey(password));
-    if (authentication != null)
-      defaultMap.put("AUTHENTICATION",authentication);
-    if (userACLsUsername != null)
-      defaultMap.put("USERACLsUSERNAME",userACLsUsername);
-    return defaultMap;
-  }
-  
   protected static void fillInCacheTab(Map<String,Object> velocityContext, IPasswordMapperActivity mapper, ConfigParams parameters)
   {
     String cacheLifetime = parameters.getParameter(SharePointConfig.PARAM_CACHELIFETIME);
@@ -795,67 +498,6 @@
   public String processConfigurationPost(IThreadContext threadContext, IPostParameters variableContext, Locale locale, ConfigParams parameters)
     throws ManifoldCFException
   {
-    String x = variableContext.getParameter("dcrecord_count");
-    if (x != null)
-    {
-      // Delete old nodes
-      int i = 0;
-      while (i < parameters.getChildCount())
-      {
-        ConfigNode cn = parameters.getChild(i);
-        if (cn.getType().equals(SharePointConfig.NODE_DOMAINCONTROLLER))
-          parameters.removeChild(i);
-        else
-          i++;
-      }
-      // Scan form fields and apply operations
-      int count = Integer.parseInt(x);
-      i = 0;
-      String op;
-      
-      Set<String> seenDomains = new HashSet<String>();
-      
-      while (i < count)
-      {
-        op = variableContext.getParameter("dcrecord_op_"+i);
-        if (op != null && op.equals("Insert"))
-        {
-          // Insert a new record right here
-          addDomainController(seenDomains,parameters,
-            variableContext.getParameter("dcrecord_suffix"),
-            variableContext.getParameter("dcrecord_domaincontrollername"),
-            variableContext.getParameter("dcrecord_username"),
-            variableContext.mapKeyToPassword(variableContext.getParameter("dcrecord_password")),
-            variableContext.getParameter("dcrecord_authentication"),
-            variableContext.getParameter("dcrecord_userACLsUsername"));
-        }
-        if (op == null || !op.equals("Delete"))
-        {
-          // Add this record back in
-          addDomainController(seenDomains,parameters,
-            variableContext.getParameter("dcrecord_suffix_"+i),
-            variableContext.getParameter("dcrecord_domaincontrollername_"+i),
-            variableContext.getParameter("dcrecord_username_"+i),
-            variableContext.mapKeyToPassword(variableContext.getParameter("dcrecord_password_"+i)),
-            variableContext.getParameter("dcrecord_authentication_"+i),
-            variableContext.getParameter("dcrecord_userACLsUsername_"+i));
-        }
-        i++;
-      }
-      op = variableContext.getParameter("dcrecord_op");
-      if (op != null && op.equals("Add"))
-      {
-        // Insert a new record right here
-        addDomainController(seenDomains,parameters,
-          variableContext.getParameter("dcrecord_suffix"),
-          variableContext.getParameter("dcrecord_domaincontrollername"),
-          variableContext.getParameter("dcrecord_username"),
-          variableContext.getParameter("dcrecord_password"),
-          variableContext.getParameter("dcrecord_authentication"),
-          variableContext.getParameter("dcrecord_userACLsUsername"));
-      }
-    }
-
     // Cache parameters
     
     String cacheLifetime = variableContext.getParameter("cachelifetime");
@@ -956,33 +598,9 @@
       }
     }
     
-    // Authorization model
-    String authorizationModel = variableContext.getParameter("authorizationModel");
-    if (authorizationModel != null)
-      parameters.setParameter(SharePointConfig.PARAM_AUTHORIZATIONMODEL,authorizationModel);
-
     return null;
   }
   
-  protected static void addDomainController(Set<String> seenDomains, ConfigParams parameters,
-    String suffix, String domainControllerName, String userName, String password, String authentication,
-    String userACLsUsername)
-    throws ManifoldCFException
-  {
-    if (!seenDomains.contains(domainControllerName))
-    {
-      ConfigNode cn = new ConfigNode(SharePointConfig.NODE_DOMAINCONTROLLER);
-      cn.setAttribute(SharePointConfig.ATTR_SUFFIX,suffix);
-      cn.setAttribute(SharePointConfig.ATTR_DOMAINCONTROLLER,domainControllerName);
-      cn.setAttribute(SharePointConfig.ATTR_USERNAME,userName);
-      cn.setAttribute(SharePointConfig.ATTR_PASSWORD,ManifoldCF.obfuscate(password));
-      cn.setAttribute(SharePointConfig.ATTR_AUTHENTICATION,authentication);
-      cn.setAttribute(SharePointConfig.ATTR_USERACLsUSERNAME,userACLsUsername);
-      parameters.addChild(parameters.getChildCount(),cn);
-      seenDomains.add(domainControllerName);
-    }
-  }
-  
   /** View configuration.
   * This method is called in the body section of the authority 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.
@@ -995,10 +613,8 @@
     throws ManifoldCFException, IOException
   {
     Map<String,Object> velocityContext = new HashMap<String,Object>();
-    fillInDomainControllerTab(velocityContext,out,parameters);
     fillInCacheTab(velocityContext,out,parameters);
     fillInServerTab(velocityContext,out,parameters);
-    fillInAuthorizationModelTab(velocityContext,out,parameters);
     Messages.outputResourceWithVelocity(out,locale,"viewConfiguration.html",velocityContext);
   }
 
@@ -1029,24 +645,10 @@
   {
     if (proxy == null)
     {
-      String serverVersion = params.getParameter( SharePointConfig.PARAM_SERVERVERSION );
-      if (serverVersion == null)
-        serverVersion = "2.0";
-      // Authority needs to do nothing with SharePoint version right now.
-      
-      String authorizationModel = params.getParameter( SharePointConfig.PARAM_AUTHORIZATIONMODEL );
-      isClaimSpace = (authorizationModel != null &&authorizationModel.equals("ClaimSpace"));
-
-      serverProtocol = params.getParameter( SharePointConfig.PARAM_SERVERPROTOCOL );
-      if (serverProtocol == null)
-        serverProtocol = "http";
-      
-      serverName = params.getParameter( SharePointConfig.PARAM_SERVERNAME );
-
+      // Set up server URL
       try
       {
-        String serverPort = params.getParameter( SharePointConfig.PARAM_SERVERPORT );
-        if (serverPort == null || serverPort.length() == 0)
+        if (serverPortString == null || serverPortString.length() == 0)
         {
           if (serverProtocol.equals("https"))
             this.serverPort = 443;
@@ -1054,36 +656,13 @@
             this.serverPort = 80;
         }
         else
-          this.serverPort = Integer.parseInt(serverPort);
+          this.serverPort = Integer.parseInt(serverPortString);
       }
       catch (NumberFormatException e)
       {
         throw new ManifoldCFException(e.getMessage(),e);
       }
-      serverLocation = params.getParameter(SharePointConfig.PARAM_SERVERLOCATION);
-      if (serverLocation == null)
-        serverLocation = "";
-      if (serverLocation.endsWith("/"))
-        serverLocation = serverLocation.substring(0,serverLocation.length()-1);
-      if (serverLocation.length() > 0 && !serverLocation.startsWith("/"))
-        serverLocation = "/" + serverLocation;
-      encodedServerLocation = serverLocation;
-      serverLocation = decodePath(serverLocation);
-
-      userName = params.getParameter(SharePointConfig.PARAM_SERVERUSERNAME);
-      password = params.getObfuscatedParameter(SharePointConfig.PARAM_SERVERPASSWORD);
-      int index = userName.indexOf("\\");
-      if (index != -1)
-      {
-        strippedUserName = userName.substring(index+1);
-        ntlmDomain = userName.substring(0,index);
-      }
-      else
-      {
-        strippedUserName = null;
-        ntlmDomain = null;
-      }
-
+      
       serverUrl = serverProtocol + "://" + serverName;
       if (serverProtocol.equals("https"))
       {
@@ -1097,7 +676,6 @@
       }
 
       // Set up ssl if indicated
-      keystoreData = params.getParameter(SharePointConfig.PARAM_SERVERKEYSTORE);
 
       PoolingClientConnectionManager localConnectionManager = new PoolingClientConnectionManager();
       localConnectionManager.setMaxTotal(1);
@@ -1142,7 +720,7 @@
 
       httpClient = localHttpClient;
       
-      proxy = new SPSProxyHelper( serverUrl, encodedServerLocation, serverLocation, userName, password,
+      proxy = new SPSProxyHelper( serverUrl, encodedServerLocation, serverLocation, serverUserName, password,
         org.apache.manifoldcf.sharepoint.CommonsHTTPSender.class, "sharepoint-client-config.wsdd",
         httpClient );
       
@@ -1153,19 +731,10 @@
   protected void expireSharePointSession()
     throws ManifoldCFException
   {
+    serverPort = -1;
     serverUrl = null;
     fileBaseUrl = null;
-    userName = null;
-    strippedUserName = null;
-    password = null;
-    ntlmDomain = null;
-    serverLocation = null;
-    encodedServerLocation = null;
-    serverPort = -1;
-
-    keystoreData = null;
     keystoreManager = null;
-
     proxy = null;
     httpClient = null;
     if (connectionManager != null)
@@ -1173,222 +742,6 @@
     connectionManager = null;
   }
 
-  /** Obtain the DistinguishedName for a given user logon name.
-  *@param ctx is the ldap context to use.
-  *@param userName (Domain Logon Name) is the user name or identifier.
-  *@param searchBase (Full Domain Name for the search ie: DC=qa-ad-76,DC=metacarta,DC=com)
-  *@return DistinguishedName for given domain user logon name. 
-  * (Should throws an exception if user is not found.)
-  */
-  protected String getDistinguishedName(LdapContext ctx, String userName, String searchBase, String userACLsUsername)
-    throws ManifoldCFException
-  {
-    String returnedAtts[] = {"distinguishedName"};
-    String searchFilter = "(&(objectClass=user)(" + userACLsUsername + "=" + userName + "))";
-    SearchControls searchCtls = new SearchControls();
-    searchCtls.setReturningAttributes(returnedAtts);
-    //Specify the search scope  
-    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-    searchCtls.setReturningAttributes(returnedAtts);
-
-    try
-    {
-      NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
-      while (answer.hasMoreElements())
-      {
-        SearchResult sr = (SearchResult)answer.next();
-        Attributes attrs = sr.getAttributes();
-        if (attrs != null)
-        {
-          String dn = attrs.get("distinguishedName").get().toString();
-          return dn;
-        }
-      }
-      return null;
-    }
-    catch (NamingException e)
-    {
-      throw new ManifoldCFException(e.getMessage(),e);
-    }
-  }
-   
-  /** LDAP escape a string.
-  */
-  protected static String ldapEscape(String input)
-  {
-    //Add escape sequence to all commas
-    StringBuilder sb = new StringBuilder();
-    int index = 0;
-    while (true)
-    {
-      int oldIndex = index;
-      index = input.indexOf(",",oldIndex);
-      if (index == -1)
-      {
-        sb.append(input.substring(oldIndex));
-        break;
-      }
-      sb.append(input.substring(oldIndex,index)).append("\\,");
-      index++;
-    }
-    return sb.toString();
-  }
-    	
-  /** Convert a binary SID to a string */
-  protected static String sid2String(byte[] SID)
-  {
-    StringBuilder strSID = new StringBuilder("S");
-    long version = SID[0];
-    strSID.append("-").append(Long.toString(version));
-    long authority = SID[4];
-    for (int i = 0;i<4;i++)
-    {
-      authority <<= 8;
-      authority += SID[4+i] & 0xFF;
-    }
-    strSID.append("-").append(Long.toString(authority));
-    long count = SID[2];
-    count <<= 8;
-    count += SID[1] & 0xFF;
-    for (int j=0;j<count;j++)
-    {
-      long rid = SID[11 + (j*4)] & 0xFF;
-      for (int k=1;k<4;k++)
-      {
-        rid <<= 8;
-        rid += SID[11-k + (j*4)] & 0xFF;
-      }
-      strSID.append("-").append(Long.toString(rid));
-    }
-    return strSID.toString();
-  }
-
-  /** Class representing the session information for a specific domain controller
-  * connection.
-  */
-  protected static class DCSessionInfo
-  {
-    /** The initialized LDAP context (which functions as a session) */
-    private LdapContext ctx = null;
-    /** The time of last access to this ctx object */
-    private long expiration = -1L;
-    
-    public DCSessionInfo()
-    {
-    }
-
-    /** Initialize the session. */
-    public LdapContext getADSession(String domainControllerName, DCConnectionParameters params)
-      throws ManifoldCFException
-    {
-      String authentication = params.getAuthentication();
-      String userName = params.getUserName();
-      String password = params.getPassword();
-      
-      while (true)
-      {
-        if (ctx == null)
-        {
-          // Calculate the ldap url first
-          String ldapURL = "ldap://" + domainControllerName + ":389";
-          
-          Hashtable env = new Hashtable();
-          env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
-          env.put(Context.SECURITY_AUTHENTICATION,authentication);      
-          env.put(Context.SECURITY_PRINCIPAL,userName);
-          env.put(Context.SECURITY_CREDENTIALS,password);
-                                    
-          //connect to my domain controller
-          env.put(Context.PROVIDER_URL,ldapURL);
-                    
-          //specify attributes to be returned in binary format
-          env.put("java.naming.ldap.attributes.binary","tokenGroups objectSid");
-     
-          // Now, try the connection...
-          try
-          {
-            ctx = new InitialLdapContext(env,null);
-            // If successful, break
-            break;
-          }
-          catch (AuthenticationException e)
-          {
-            // This means we couldn't authenticate!
-            throw new ManifoldCFException("Authentication problem authenticating admin user '"+userName+"': "+e.getMessage(),e);
-          }
-          catch (CommunicationException e)
-          {
-            // This means we couldn't connect, most likely
-            throw new ManifoldCFException("Couldn't communicate with domain controller '"+domainControllerName+"': "+e.getMessage(),e);
-          }
-          catch (NamingException e)
-          {
-            throw new ManifoldCFException(e.getMessage(),e);
-          }
-        }
-        else
-        {
-          // Attempt to reconnect.  I *hope* this is efficient and doesn't do unnecessary work.
-          try
-          {
-            ctx.reconnect(null);
-            // Break on apparent success
-            break;
-          }
-          catch (AuthenticationException e)
-          {
-            // This means we couldn't authenticate!  Log it and retry creating a whole new context.
-            Logging.authorityConnectors.warn("Reconnect: Authentication problem authenticating admin user '"+userName+"': "+e.getMessage(),e);
-          }
-          catch (CommunicationException e)
-          {
-            // This means we couldn't connect, most likely.  Log it and retry creating a whole new context.
-            Logging.authorityConnectors.warn("Reconnect: Couldn't communicate with domain controller '"+domainControllerName+"': "+e.getMessage(),e);
-          }
-          catch (NamingException e)
-          {
-            Logging.authorityConnectors.warn("Reconnect: Naming exception: "+e.getMessage(),e);
-          }
-          
-          // So we have no chance of leaking resources, attempt to close the context.
-          closeConnection();
-          // Loop back around to try our luck with a fresh connection.
-
-        }
-      }
-      
-      // Set the expiration time anew
-      expiration = System.currentTimeMillis() + ADExpirationInterval;
-      return ctx;
-    }
-    
-    /** Close the connection handle. */
-    protected void closeConnection()
-    {
-      if (ctx != null)
-      {
-        try
-        {
-          ctx.close();
-        }
-        catch (NamingException e)
-        {
-          // Eat this error
-        }
-        ctx = null;
-        expiration = -1L;
-      }
-    }
-
-    /** Close connection if it has expired. */
-    protected void closeIfExpired(long currentTime)
-    {
-      if (expiration != -1L && currentTime > expiration)
-        closeConnection();
-    }
-
-  }
-
   /** Decode a path item.
   */
   public static String pathItemDecode(String pathItem)
@@ -1462,68 +815,6 @@
     return sb.toString();
   }
 
-  /** Class describing a domain suffix and corresponding domain controller name rule.
-  */
-  protected static class DCRule
-  {
-    private String suffix;
-    private String domainControllerName;
-    
-    public DCRule(String suffix, String domainControllerName)
-    {
-      this.suffix = suffix;
-      this.domainControllerName = domainControllerName;
-    }
-    
-    public String getSuffix()
-    {
-      return suffix;
-    }
-    
-    public String getDomainControllerName()
-    {
-      return domainControllerName;
-    }
-  }
-  
-  /** Class describing the connection parameters to a domain controller.
-  */
-  protected static class DCConnectionParameters
-  {
-    private String userName;
-    private String password;
-    private String authentication;
-    private String userACLsUsername;
-
-    public DCConnectionParameters(String userName, String password, String authentication, String userACLsUsername)
-    {
-      this.userName = userName;
-      this.password = password;
-      this.authentication = authentication;
-      this.userACLsUsername = userACLsUsername;
-    }
-    
-    public String getUserName()
-    {
-      return userName;
-    }
-    
-    public String getPassword()
-    {
-      return password;
-    }
-    
-    public String getAuthentication()
-    {
-      return authentication;
-    }
-    
-    public String getUserACLsUsername()
-    {
-      return userACLsUsername;
-    }
-  }
-  
   protected static StringSet emptyStringSet = new StringSet();
   
   /** This is the cache object descriptor for cached access tokens from
@@ -1532,25 +823,33 @@
   protected static class AuthorizationResponseDescription extends org.apache.manifoldcf.core.cachemanager.BaseDescription
   {
     /** The user name */
-    protected String userName;
-    /** Connection parameters */
-    protected Map<String,DCConnectionParameters> dcConnectionParams;
-    /** Rules */
-    protected List<DCRule> dcRules;
+    protected final String userName;
     /** The response lifetime */
-    protected long responseLifetime;
+    protected final long responseLifetime;
     /** The expiration time */
     protected long expirationTime = -1;
+    // Parameters designed to guarantee cache key uniqueness
+    protected final String serverName;
+    protected final String serverPortString;
+    protected final String serverLocation;
+    protected final String serverProtocol;
+    protected final String serverUserName;
+    protected final String password;
     
     /** Constructor. */
-    public AuthorizationResponseDescription(String userName, Map<String,DCConnectionParameters> dcConnectionParams,
-      List<DCRule> dcRules, long responseLifetime, int LRUsize)
+    public AuthorizationResponseDescription(String userName,
+      String serverName, String serverPortString, String serverLocation, String serverProtocol, String serverUserName, String password,
+      long responseLifetime, int LRUsize)
     {
       super("SharePointAuthority",LRUsize);
       this.userName = userName;
-      this.dcConnectionParams = dcConnectionParams;
-      this.dcRules = dcRules;
       this.responseLifetime = responseLifetime;
+      this.serverName = serverName;
+      this.serverPortString = serverPortString;
+      this.serverLocation = serverLocation;
+      this.serverProtocol = serverProtocol;
+      this.serverUserName = serverUserName;
+      this.password = password;
     }
 
     /** Return the invalidation keys for this object. */
@@ -1564,13 +863,12 @@
     {
       StringBuilder sb = new StringBuilder(getClass().getName());
       sb.append("-").append(userName);
-      for (DCRule rule : dcRules)
-      {
-        sb.append("-").append(rule.getSuffix());
-        String domainController = rule.getDomainControllerName();
-        DCConnectionParameters params = dcConnectionParams.get(domainController);
-        sb.append("-").append(domainController).append("-").append(params.getUserName()).append("-").append(params.getPassword());
-      }
+      sb.append("-").append(serverName);
+      sb.append("-").append(serverPortString);
+      sb.append("-").append(serverLocation);
+      sb.append("-").append(serverProtocol);
+      sb.append("-").append(serverUserName);
+      sb.append("-").append(password);
       return sb.toString();
     }
 
@@ -1585,12 +883,12 @@
     public int hashCode()
     {
       int rval = userName.hashCode();
-      for (DCRule rule : dcRules)
-      {
-        String domainController = rule.getDomainControllerName();
-        DCConnectionParameters params = dcConnectionParams.get(domainController);
-        rval += rule.getSuffix().hashCode() + domainController.hashCode() + params.getUserName().hashCode() + params.getPassword().hashCode();
-      }
+      rval += serverName.hashCode();
+      rval += serverPortString.hashCode();
+      rval += serverLocation.hashCode();
+      rval += serverProtocol.hashCode();
+      rval += serverUserName.hashCode();
+      rval += password.hashCode();
       return rval;
     }
     
@@ -1601,20 +899,18 @@
       AuthorizationResponseDescription ard = (AuthorizationResponseDescription)o;
       if (!ard.userName.equals(userName))
         return false;
-      if (ard.dcRules.size() != dcRules.size())
+      if (!ard.serverName.equals(serverName))
         return false;
-      for (int i = 0 ; i < dcRules.size() ; i++)
-      {
-        DCRule rule = dcRules.get(i);
-        DCRule ardRule = ard.dcRules.get(i);
-        if (!rule.getSuffix().equals(ardRule.getSuffix()) || !rule.getDomainControllerName().equals(ardRule.getDomainControllerName()))
-          return false;
-        String domainController = rule.getDomainControllerName();
-        DCConnectionParameters params = dcConnectionParams.get(domainController);
-        DCConnectionParameters ardParams = ard.dcConnectionParams.get(domainController);
-        if (!params.getUserName().equals(ardParams.getUserName()) || !params.getPassword().equals(ardParams.getPassword()))
-          return false;
-      }
+      if (!ard.serverPortString.equals(serverPortString))
+        return false;
+      if (!ard.serverLocation.equals(serverLocation))
+        return false;
+      if (!ard.serverProtocol.equals(serverProtocol))
+        return false;
+      if (!ard.serverUserName.equals(serverUserName))
+        return false;
+      if (!ard.password.equals(password))
+        return false;
       return true;
     }
     
diff --git a/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointConfig.java b/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointConfig.java
index b5f1c00..c97308d 100644
--- a/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointConfig.java
+++ b/connectors/sharepoint/connector/src/main/java/org/apache/manifoldcf/authorities/authorities/sharepoint/SharePointConfig.java
@@ -49,9 +49,6 @@
   /** SharePoint server certificate store */
   public static final String PARAM_SERVERKEYSTORE = "keystore";
 
-  /** SharePoint authorization model */
-  public static final String PARAM_AUTHORIZATIONMODEL = "authorizationModel";
-  
   // Nodes
   
   /** Domain controller node */
diff --git a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editADConfiguration.js b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editADConfiguration.js
new file mode 100644
index 0000000..d3fd88e
--- /dev/null
+++ b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editADConfiguration.js
@@ -0,0 +1,134 @@
+<!--
+ 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.
+-->
+
+<script type="text/javascript">
+<!--
+function checkConfig()
+{
+  var i = 0;
+  var count = editconnection.dcrecord_count.value;
+  while (i < count)
+  {
+    var username = eval("editconnection.dcrecord_username_"+i+".value");
+    if (username == "")
+    {
+      alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AdministrativeUserNameCannotBeNull'))");
+      eval("editconnection.dcrecord_username_"+i+".focus()");
+      return false;
+    }
+    var authentication = eval("editconnection.dcrecord_authentication_"+i+".value");
+    if (authentication == "")
+    {
+      alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AuthenticationCannotBeNull'))");
+      eval("editconnection.dcrecord_authentication_"+i+".focus()");
+      return false;
+    }
+    i += 1;
+  }
+  return true;
+}
+
+function checkConfigForSave()
+{
+  if (editconnection.cachelifetime.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.CacheLifetimeCannotBeNull'))");
+    SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.Cache'))");
+    editconnection.cachelifetime.focus();
+    return false;
+  }
+  if (editconnection.cachelifetime.value != "" && !isInteger(editconnection.cachelifetime.value))
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.CacheLifetimeMustBeAnInteger'))");
+    SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.Cache'))");
+    editconnection.cachelifetime.focus();
+    return false;
+  }
+  if (editconnection.cachelrusize.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.CacheLRUSizeCannotBeNull'))");
+    SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.Cache'))");
+    editconnection.cachelrusize.focus();
+    return false;
+  }
+  if (editconnection.cachelrusize.value != "" && !isInteger(editconnection.cachelrusize.value))
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.CacheLRUSizeMustBeAnInteger'))");
+    SelectTab("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.Cache'))");
+    editconnection.cachelrusize.focus();
+    return false;
+  }
+  return true;
+}
+
+function deleteDC(i)
+{
+  eval("editconnection.dcrecord_op_"+i+".value=\"Delete\"");
+  postFormSetAnchor("dcrecord");
+}
+
+function insertDC(i)
+{
+  if (editconnection.dcrecord_domaincontrollername.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.EnterADomainControllerServerName'))");
+    editconnection.dcrecord_domaincontrollername.focus();
+    return;
+  }
+  if (editconnection.dcrecord_username.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AdministrativeUserNameCannotBeNull'))");
+    editconnection.dcrecord_username.focus();
+    return;
+  }
+  if (editconnection.dcrecord_authentication.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AuthenticationCannotBeNull'))");
+    editconnection.dcrecord_authentication.focus();
+    return;
+  }
+  eval("editconnection.dcrecord_op_"+i+".value=\"Insert\"");
+  postFormSetAnchor("dcrecord_"+i);
+}
+
+function addDC()
+{
+  if (editconnection.dcrecord_domaincontrollername.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.EnterADomainControllerServerName'))");
+    editconnection.dcrecord_domaincontrollername.focus();
+    return;
+  }
+  if (editconnection.dcrecord_username.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AdministrativeUserNameCannotBeNull'))");
+    editconnection.dcrecord_username.focus();
+    return;
+  }
+  if (editconnection.dcrecord_authentication.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AuthenticationCannotBeNull'))");
+    editconnection.dcrecord_authentication.focus();
+    return;
+  }
+  editconnection.dcrecord_op.value="Add";
+  postFormSetAnchor("dcrecord");
+}
+
+//-->
+</script>
+
diff --git a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editADConfiguration_Cache.html b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editADConfiguration_Cache.html
new file mode 100644
index 0000000..384abd1
--- /dev/null
+++ b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editADConfiguration_Cache.html
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+#if($TabName == $ResourceBundle.getString('SharePointAuthority.Cache'))
+
+<table class="displaytable">
+  <tr><td class="separator" colspan="2"><hr/></td></tr>
+  <tr>
+    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.CacheLifetime'))</nobr></td>
+    <td class="value"><input type="text" size="5" name="cachelifetime" value="$Encoder.attributeEscape($CACHELIFETIME)"/> $Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.minutes'))</td>
+  </tr>
+  <tr>
+    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.CacheLRUSize'))</nobr></td>
+    <td class="value"><input type="text" size="5" name="cachelrusize" value="$Encoder.attributeEscape($CACHELRUSIZE)"/></td>
+  </tr>
+</table>
+
+#else
+
+<input type="hidden" name="cachelifetime" value="$Encoder.attributeEscape($CACHELIFETIME)"/>
+<input type="hidden" name="cachelrusize" value="$Encoder.attributeEscape($CACHELRUSIZE)"/>
+
+#end
diff --git a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editConfiguration_DomainController.html b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editADConfiguration_DomainController.html
similarity index 100%
rename from connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editConfiguration_DomainController.html
rename to connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editADConfiguration_DomainController.html
diff --git a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editConfiguration.js b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editConfiguration.js
index 3006a73..9fed1f9 100644
--- a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editConfiguration.js
+++ b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editConfiguration.js
@@ -19,26 +19,6 @@
 <!--
 function checkConfig()
 {
-  var i = 0;
-  var count = editconnection.dcrecord_count.value;
-  while (i < count)
-  {
-    var username = eval("editconnection.dcrecord_username_"+i+".value");
-    if (username == "")
-    {
-      alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AdministrativeUserNameCannotBeNull'))");
-      eval("editconnection.dcrecord_username_"+i+".focus()");
-      return false;
-    }
-    var authentication = eval("editconnection.dcrecord_authentication_"+i+".value");
-    if (authentication == "")
-    {
-      alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AuthenticationCannotBeNull'))");
-      eval("editconnection.dcrecord_authentication_"+i+".focus()");
-      return false;
-    }
-    i += 1;
-  }
   if (editconnection.serverPort.value != "" && !isInteger(editconnection.serverPort.value))
   {
     alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.PleaseSupplyAValidNumber'))");
@@ -149,60 +129,6 @@
   return true;
 }
 
-function deleteDC(i)
-{
-  eval("editconnection.dcrecord_op_"+i+".value=\"Delete\"");
-  postFormSetAnchor("dcrecord");
-}
-
-function insertDC(i)
-{
-  if (editconnection.dcrecord_domaincontrollername.value == "")
-  {
-    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.EnterADomainControllerServerName'))");
-    editconnection.dcrecord_domaincontrollername.focus();
-    return;
-  }
-  if (editconnection.dcrecord_username.value == "")
-  {
-    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AdministrativeUserNameCannotBeNull'))");
-    editconnection.dcrecord_username.focus();
-    return;
-  }
-  if (editconnection.dcrecord_authentication.value == "")
-  {
-    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AuthenticationCannotBeNull'))");
-    editconnection.dcrecord_authentication.focus();
-    return;
-  }
-  eval("editconnection.dcrecord_op_"+i+".value=\"Insert\"");
-  postFormSetAnchor("dcrecord_"+i);
-}
-
-function addDC()
-{
-  if (editconnection.dcrecord_domaincontrollername.value == "")
-  {
-    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.EnterADomainControllerServerName'))");
-    editconnection.dcrecord_domaincontrollername.focus();
-    return;
-  }
-  if (editconnection.dcrecord_username.value == "")
-  {
-    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AdministrativeUserNameCannotBeNull'))");
-    editconnection.dcrecord_username.focus();
-    return;
-  }
-  if (editconnection.dcrecord_authentication.value == "")
-  {
-    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('SharePointAuthority.AuthenticationCannotBeNull'))");
-    editconnection.dcrecord_authentication.focus();
-    return;
-  }
-  editconnection.dcrecord_op.value="Add";
-  postFormSetAnchor("dcrecord");
-}
-
 function ShpDeleteCertificate(aliasName)
 {
   editconnection.shpkeystorealias.value = aliasName;
diff --git a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editConfiguration_AuthorizationModel.html b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editConfiguration_AuthorizationModel.html
deleted file mode 100644
index 4d112e6..0000000
--- a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/editConfiguration_AuthorizationModel.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!--
- 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.
--->
-
-#if($TabName == $ResourceBundle.getString('SharePointAuthority.AuthorizationModel'))
-
-<table class="displaytable">
-  <tr><td class="separator" colspan="2"><hr/></td></tr>
-  <tr>
-    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.AuthorizationModelColon'))</nobr></td>
-    <td class="value">
-  #if($AUTHORIZATIONMODEL == 'Classic')
-      <input type="radio" name="authorizationModel" value="Classic" checked="true"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.Classic'))</nobr></input>
-  #else
-      <input type="radio" name="authorizationModel" value="Classic"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.Classic'))</nobr></input>
-  #end
-  #if($AUTHORIZATIONMODEL == 'ClaimSpace')
-      <input type="radio" name="authorizationModel" value="ClaimSpace" checked="true"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.ClaimSpace'))</nobr></input>
-  #else
-      <input type="radio" name="authorizationModel" value="ClaimSpace"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.ClaimSpace'))</nobr></input>
-  #end
-    </td>
-  </tr>
-</table>
-
-#else
-
-<input type="hidden" name="authorizationModel" value="$AUTHORIZATIONMODEL"/>
-
-#end
diff --git a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/viewADConfiguration.html b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/viewADConfiguration.html
new file mode 100644
index 0000000..666c2e3
--- /dev/null
+++ b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/viewADConfiguration.html
@@ -0,0 +1,62 @@
+<!--
+ 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.
+-->
+
+<table class="displaytable">
+  <tr>
+    <td class="description">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.DomainControllers'))</td>
+    <td class="boxcell">
+      <table class="formtable">
+        <tr class="formheaderrow">
+          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.DomainControllerName'))</td>
+          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.DomainSuffix'))</td>
+          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.AdministrativeUserName'))</td>
+          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.AdministrativePassword'))</td>
+          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.Authentication'))</td>
+          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.LoginNameADAttribute'))</td>
+        </tr>
+#set($dccounter = 0)
+#foreach($domaincontroller in $DOMAINCONTROLLERS)
+  #if(($dccounter % 2) == 0)
+        <tr class="evenformrow">
+  #else
+        <tr class="oddformrow">
+  #end
+          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('DOMAINCONTROLLER'))</nobr></td>
+          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('SUFFIX'))</nobr></td>
+          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('USERNAME'))</nobr></td>
+          <td class="formcolumncell"><nobr>******</nobr></td>
+          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('AUTHENTICATION'))</nobr></td>
+          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('USERACLsUSERNAME'))</nobr></td>
+        </tr>
+  #set($dccounter = $dccounter + 1)
+#end
+      </table>
+    </td>
+  </tr>
+  
+  <tr><td class="separator" colspan="2"><hr/></td></tr>
+  
+  <tr>
+    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.CacheLifetime'))</nobr></td>
+    <td class="value"><nobr>$Encoder.bodyEscape($CACHELIFETIME)</nobr> $Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.minutes'))</td>
+  </tr>
+  <tr>
+    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.CacheLRUSize'))</nobr></td>
+    <td class="value"><nobr>$Encoder.bodyEscape($CACHELRUSIZE)</nobr></td>
+  </tr>
+  
+</table>
diff --git a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/viewConfiguration.html b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/viewConfiguration.html
index 65b0060..d70017a 100644
--- a/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/viewConfiguration.html
+++ b/connectors/sharepoint/connector/src/main/resources/org/apache/manifoldcf/authorities/authorities/sharepoint/viewConfiguration.html
@@ -17,51 +17,6 @@
 
 <table class="displaytable">
   <tr>
-    <td class="description">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.DomainControllers'))</td>
-    <td class="boxcell">
-      <table class="formtable">
-        <tr class="formheaderrow">
-          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.DomainControllerName'))</td>
-          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.DomainSuffix'))</td>
-          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.AdministrativeUserName'))</td>
-          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.AdministrativePassword'))</td>
-          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.Authentication'))</td>
-          <td class="formcolumnheader">$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.LoginNameADAttribute'))</td>
-        </tr>
-#set($dccounter = 0)
-#foreach($domaincontroller in $DOMAINCONTROLLERS)
-  #if(($dccounter % 2) == 0)
-        <tr class="evenformrow">
-  #else
-        <tr class="oddformrow">
-  #end
-          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('DOMAINCONTROLLER'))</nobr></td>
-          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('SUFFIX'))</nobr></td>
-          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('USERNAME'))</nobr></td>
-          <td class="formcolumncell"><nobr>******</nobr></td>
-          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('AUTHENTICATION'))</nobr></td>
-          <td class="formcolumncell"><nobr>$Encoder.bodyEscape($domaincontroller.get('USERACLsUSERNAME'))</nobr></td>
-        </tr>
-  #set($dccounter = $dccounter + 1)
-#end
-      </table>
-    </td>
-  </tr>
-  
-  <tr><td class="separator" colspan="2"><hr/></td></tr>
-  
-  <tr>
-    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.CacheLifetime'))</nobr></td>
-    <td class="value"><nobr>$Encoder.bodyEscape($CACHELIFETIME)</nobr> $Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.minutes'))</td>
-  </tr>
-  <tr>
-    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.CacheLRUSize'))</nobr></td>
-    <td class="value"><nobr>$Encoder.bodyEscape($CACHELRUSIZE)</nobr></td>
-  </tr>
-  
-  <tr><td class="separator" colspan="2"><hr/></td></tr>
-  
-  <tr>
     <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.ServerSharePointVersion'))</nobr></td>
     <td class="value">
   #if($SERVERVERSION == '2.0')
@@ -145,4 +100,15 @@
     </td>
   </tr>
 
+  <tr><td class="separator" colspan="2"><hr/></td></tr>
+
+  <tr>
+    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.CacheLifetime'))</nobr></td>
+    <td class="value"><nobr>$Encoder.bodyEscape($CACHELIFETIME)</nobr> $Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.minutes'))</td>
+  </tr>
+  <tr>
+    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('SharePointAuthority.CacheLRUSize'))</nobr></td>
+    <td class="value"><nobr>$Encoder.bodyEscape($CACHELRUSIZE)</nobr></td>
+  </tr>
+  
 </table>
diff --git a/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/authorities/BaseAuthorityConnector.java b/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/authorities/BaseAuthorityConnector.java
index 7c74027..304c919 100644
--- a/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/authorities/BaseAuthorityConnector.java
+++ b/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/authorities/BaseAuthorityConnector.java
@@ -34,6 +34,7 @@
 {
   public static final String _rcsid = "@(#)$Id: BaseAuthorityConnector.java 988245 2010-08-23 18:39:35Z kwright $";
 
+  // For repositories that have the ability to deny access based on a user's access tokens
   protected static final AuthorizationResponse RESPONSE_UNREACHABLE = new AuthorizationResponse(new String[]{GLOBAL_DENY_TOKEN},
     AuthorizationResponse.RESPONSE_UNREACHABLE);
   protected static final AuthorizationResponse RESPONSE_USERNOTFOUND = new AuthorizationResponse(new String[]{GLOBAL_DENY_TOKEN},
@@ -41,6 +42,14 @@
   protected static final AuthorizationResponse RESPONSE_USERUNAUTHORIZED = new AuthorizationResponse(new String[]{GLOBAL_DENY_TOKEN},
     AuthorizationResponse.RESPONSE_USERUNAUTHORIZED);
 
+  // For repositories that DO NOT have the ability to deny access based on a user's access tokens
+  protected static final AuthorizationResponse RESPONSE_UNREACHABLE_ADDITIVE = new AuthorizationResponse(new String[0],
+    AuthorizationResponse.RESPONSE_UNREACHABLE);
+  protected static final AuthorizationResponse RESPONSE_USERNOTFOUND_ADDITIVE = new AuthorizationResponse(new String[0],
+    AuthorizationResponse.RESPONSE_USERNOTFOUND);
+  protected static final AuthorizationResponse RESPONSE_USERUNAUTHORIZED_ADDITIVE = new AuthorizationResponse(new String[0],
+    AuthorizationResponse.RESPONSE_USERUNAUTHORIZED);
+
   /** 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).