mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
MOB-710: LDAP queries now performed with RFC 2696 paging and a configurable page size, defaulting to 1000 (the AD default maximum)
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14648 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -18,7 +18,7 @@
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
@@ -26,6 +26,7 @@ package org.alfresco.repo.security.authentication.ldap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.InitialDirContext;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
@@ -44,6 +45,19 @@ public interface LDAPInitialDirContextFactory
|
||||
*/
|
||||
public void setInitialDirContextEnvironment(Map<String, String> environment);
|
||||
|
||||
/**
|
||||
* Use the environment properties and connect to the LDAP server, optionally configuring RFC 2696 paged results.
|
||||
* Used to obtain read only access to the LDAP server.
|
||||
*
|
||||
* @param pageSize
|
||||
* if a positive value, indicates that a LDAP v3 RFC 2696 paged results control should be used. The
|
||||
* results of a search operation should be returned by the LDAP server in batches of the specified size.
|
||||
* @return the default intial dir context
|
||||
* @throws AuthenticationException
|
||||
* the authentication exception
|
||||
*/
|
||||
public InitialDirContext getDefaultIntialDirContext(int pageSize) throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Use the environment properties and connect to the LDAP server.
|
||||
* Used to obtain read only access to the LDAP server.
|
||||
@@ -53,6 +67,19 @@ public interface LDAPInitialDirContextFactory
|
||||
*/
|
||||
public InitialDirContext getDefaultIntialDirContext() throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Determines whether there is another page to fetch from the last search to be run in this context. Also prepares
|
||||
* the request controls so that the appropriate cookie will be passed in the next search.
|
||||
*
|
||||
* @param ctx
|
||||
* the context
|
||||
* @param pageSize
|
||||
* if a positive value, indicates that a LDAP v3 RFC 2696 paged results control should be used. The
|
||||
* results of a search operation should be returned by the LDAP server in batches of the specified size.
|
||||
* @return true, if is ready for next page
|
||||
*/
|
||||
public boolean hasNextPage(DirContext ctx, int pageSize);
|
||||
|
||||
/**
|
||||
* Augment the connection environment with the identity and credentials and bind to the ldap server.
|
||||
* Mainly used to validate a user's credentials during authentication.
|
||||
|
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
@@ -35,7 +36,13 @@ import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttribute;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.InitialDirContext;
|
||||
import javax.naming.ldap.Control;
|
||||
import javax.naming.ldap.InitialLdapContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
import javax.naming.ldap.PagedResultsControl;
|
||||
import javax.naming.ldap.PagedResultsResponseControl;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
@@ -71,18 +78,37 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
}
|
||||
|
||||
public InitialDirContext getDefaultIntialDirContext() throws AuthenticationException
|
||||
{
|
||||
return getDefaultIntialDirContext(0);
|
||||
}
|
||||
|
||||
public InitialDirContext getDefaultIntialDirContext(int pageSize) throws AuthenticationException
|
||||
{
|
||||
Hashtable<String, String> env = new Hashtable<String, String>(initialDirContextEnvironment.size());
|
||||
env.putAll(initialDirContextEnvironment);
|
||||
env.put("javax.security.auth.useSubjectCredsOnly", "false");
|
||||
return buildInitialDirContext(env);
|
||||
return buildInitialDirContext(env, pageSize);
|
||||
}
|
||||
|
||||
private InitialDirContext buildInitialDirContext(Hashtable<String, String> env) throws AuthenticationException
|
||||
private InitialDirContext buildInitialDirContext(Hashtable<String, String> env, int pageSize)
|
||||
throws AuthenticationException
|
||||
{
|
||||
try
|
||||
{
|
||||
return new InitialDirContext(env);
|
||||
// If a page size has been requested, use LDAP v3 paging
|
||||
if (pageSize > 0)
|
||||
{
|
||||
InitialLdapContext ctx = new InitialLdapContext(env, null);
|
||||
ctx.setRequestControls(new Control[]
|
||||
{
|
||||
new PagedResultsControl(pageSize, Control.CRITICAL)
|
||||
});
|
||||
return ctx;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new InitialDirContext(env);
|
||||
}
|
||||
}
|
||||
catch (javax.naming.AuthenticationException ax)
|
||||
{
|
||||
@@ -92,6 +118,54 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
{
|
||||
throw new AuthenticationException("Unable to connect to LDAP Server; check LDAP configuration", nx);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new AuthenticationException("Unable to encode LDAP v3 request controls; check LDAP configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasNextPage(DirContext ctx, int pageSize)
|
||||
{
|
||||
if (pageSize > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
LdapContext ldapContext = (LdapContext) ctx;
|
||||
Control[] controls = ldapContext.getResponseControls();
|
||||
|
||||
// Retrieve the paged result cookie if there is one
|
||||
if (controls != null)
|
||||
{
|
||||
for (Control control : controls)
|
||||
{
|
||||
if (control instanceof PagedResultsResponseControl)
|
||||
{
|
||||
byte[] cookie = ((PagedResultsResponseControl) control).getCookie();
|
||||
if (cookie != null)
|
||||
{
|
||||
// Prepare for next page
|
||||
ldapContext.setRequestControls(new Control[]
|
||||
{
|
||||
new PagedResultsControl(pageSize, cookie, Control.CRITICAL)
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
throw new AuthenticationException("Unable to connect to LDAP Server; check LDAP configuration", nx);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new AuthenticationException(
|
||||
"Unable to encode LDAP v3 request controls; check LDAP configuration", e);
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public InitialDirContext getInitialDirContext(String principal, String credentials) throws AuthenticationException
|
||||
@@ -100,7 +174,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
{
|
||||
throw new AuthenticationException("Null user name provided.");
|
||||
}
|
||||
|
||||
|
||||
if (principal.length() == 0)
|
||||
{
|
||||
throw new AuthenticationException("Empty user name provided.");
|
||||
@@ -110,18 +184,18 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
{
|
||||
throw new AuthenticationException("No credentials provided.");
|
||||
}
|
||||
|
||||
|
||||
if (credentials.length() == 0)
|
||||
{
|
||||
throw new AuthenticationException("Empty credentials provided.");
|
||||
}
|
||||
|
||||
|
||||
Hashtable<String, String> env = new Hashtable<String, String>(initialDirContextEnvironment.size());
|
||||
env.putAll(initialDirContextEnvironment);
|
||||
env.put(Context.SECURITY_PRINCIPAL, principal);
|
||||
env.put(Context.SECURITY_CREDENTIALS, credentials);
|
||||
|
||||
return buildInitialDirContext(env);
|
||||
return buildInitialDirContext(env, 0);
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
@@ -214,7 +288,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
// Check Anonymous bind
|
||||
|
||||
|
||||
Hashtable<String, String> env = new Hashtable<String, String>(initialDirContextEnvironment.size());
|
||||
env.putAll(initialDirContextEnvironment);
|
||||
env.remove(Context.SECURITY_PRINCIPAL);
|
||||
@@ -229,18 +303,18 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
{
|
||||
|
||||
}
|
||||
catch(AuthenticationNotSupportedException e)
|
||||
catch (AuthenticationNotSupportedException e)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
catch (NamingException nx)
|
||||
{
|
||||
logger.error("Unable to connect to LDAP Server; check LDAP configuration", nx);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Simple DN and password
|
||||
|
||||
|
||||
env = new Hashtable<String, String>(initialDirContextEnvironment.size());
|
||||
env.putAll(initialDirContextEnvironment);
|
||||
env.put(Context.SECURITY_PRINCIPAL, "daftAsABrush");
|
||||
@@ -259,7 +333,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch(AuthenticationNotSupportedException e)
|
||||
catch (AuthenticationNotSupportedException e)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
@@ -267,9 +341,9 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
{
|
||||
logger.info("LDAP server does not support simple string user ids and invalid credentials at "+ env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
|
||||
|
||||
// DN and password
|
||||
|
||||
|
||||
env = new Hashtable<String, String>(initialDirContextEnvironment.size());
|
||||
env.putAll(initialDirContextEnvironment);
|
||||
env.put(Context.SECURITY_PRINCIPAL, "cn=daftAsABrush,dc=woof");
|
||||
@@ -288,7 +362,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch(AuthenticationNotSupportedException e)
|
||||
catch (AuthenticationNotSupportedException e)
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
@@ -298,13 +372,13 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
}
|
||||
|
||||
// Check more if we have a real principal we expect to work
|
||||
|
||||
|
||||
env = new Hashtable<String, String>(initialDirContextEnvironment.size());
|
||||
env.putAll(initialDirContextEnvironment);
|
||||
if(env.get(Context.SECURITY_PRINCIPAL) != null)
|
||||
if (env.get(Context.SECURITY_PRINCIPAL) != null)
|
||||
{
|
||||
// Correct principal invalid password
|
||||
|
||||
|
||||
env = new Hashtable<String, String>(initialDirContextEnvironment.size());
|
||||
env.putAll(initialDirContextEnvironment);
|
||||
env.put(Context.SECURITY_CREDENTIALS, "sdasdasdasdasd123123123");
|
||||
@@ -322,7 +396,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
|
||||
{
|
||||
logger.info("LDAP server does not fall back to anonymous bind for known principal and invalid credentials at " + env.get(Context.PROVIDER_URL));
|
||||
}
|
||||
catch(AuthenticationNotSupportedException e)
|
||||
catch (AuthenticationNotSupportedException e)
|
||||
{
|
||||
logger.info("LDAP server does not support the required authentication mechanism");
|
||||
}
|
||||
|
Reference in New Issue
Block a user