You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2022/11/28 00:50:19 UTC
svn commit: r1905560 - in /db/derby/code/branches/10.16: ./ build.xml java/org.apache.derby.engine/org/apache/derby/impl/jdbc/authentication/LDAPAuthenticationSchemeImpl.java tools/release/notices/tomcat.txt
Author: rhillegas
Date: Mon Nov 28 00:50:19 2022
New Revision: 1905560
URL: http://svn.apache.org/viewvc?rev=1905560&view=rev
Log:
DERBY-7147: Port 1905442 and 1905550 from the trunk to the 10.16 branch.
Added:
db/derby/code/branches/10.16/tools/release/notices/tomcat.txt
- copied unchanged from r1905550, db/derby/code/trunk/tools/release/notices/tomcat.txt
Modified:
db/derby/code/branches/10.16/ (props changed)
db/derby/code/branches/10.16/build.xml
db/derby/code/branches/10.16/java/org.apache.derby.engine/org/apache/derby/impl/jdbc/authentication/LDAPAuthenticationSchemeImpl.java
Propchange: db/derby/code/branches/10.16/
------------------------------------------------------------------------------
Merged /db/derby/code/trunk:r1905442,1905550
Modified: db/derby/code/branches/10.16/build.xml
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.16/build.xml?rev=1905560&r1=1905559&r2=1905560&view=diff
==============================================================================
--- db/derby/code/branches/10.16/build.xml (original)
+++ db/derby/code/branches/10.16/build.xml Mon Nov 28 00:50:19 2022
@@ -2668,6 +2668,7 @@
<antcall target="appendnotice"><param name="sourcefile" value="felix.txt"/></antcall>
<antcall target="appendnotice"><param name="sourcefile" value="lucene.txt"/></antcall>
<antcall target="appendnotice"><param name="sourcefile" value="simpleJson.txt"/></antcall>
+ <antcall target="appendnotice"><param name="sourcefile" value="tomcat.txt"/></antcall>
<antcall target="checkinfile">
<param name="checkinComment" value="Check in NOTICE as part of building a release."/>
Modified: db/derby/code/branches/10.16/java/org.apache.derby.engine/org/apache/derby/impl/jdbc/authentication/LDAPAuthenticationSchemeImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.16/java/org.apache.derby.engine/org/apache/derby/impl/jdbc/authentication/LDAPAuthenticationSchemeImpl.java?rev=1905560&r1=1905559&r2=1905560&view=diff
==============================================================================
--- db/derby/code/branches/10.16/java/org.apache.derby.engine/org/apache/derby/impl/jdbc/authentication/LDAPAuthenticationSchemeImpl.java (original)
+++ db/derby/code/branches/10.16/java/org.apache.derby.engine/org/apache/derby/impl/jdbc/authentication/LDAPAuthenticationSchemeImpl.java Mon Nov 28 00:50:19 2022
@@ -61,131 +61,176 @@ import org.apache.derby.iapi.util.String
*/
public final class LDAPAuthenticationSchemeImpl
-extends JNDIAuthenticationSchemeBase
+ extends JNDIAuthenticationSchemeBase
{
- private static final String dfltLDAPURL = "ldap://";
+ private static final String dfltLDAPURL = "ldap://";
- private String searchBaseDN;
+ private String searchBaseDN;
- private String leftSearchFilter; // stick in uid in between
- private String rightSearchFilter;
- private boolean useUserPropertyAsDN;
-
- // Search Auth DN & Password if anonymous search not allowed
- private String searchAuthDN;
- private String searchAuthPW;
- // we only want the user's full DN in return
- private static final String[] attrDN = {"dn"}; ;
-
- //
- // Derby LDAP Configuration properties
- //
- private static final String LDAP_SEARCH_BASE =
- "derby.authentication.ldap.searchBase";
- private static final String LDAP_SEARCH_FILTER =
- "derby.authentication.ldap.searchFilter";
- private static final String LDAP_SEARCH_AUTH_DN =
- "derby.authentication.ldap.searchAuthDN";
- private static final String LDAP_SEARCH_AUTH_PW =
- "derby.authentication.ldap.searchAuthPW";
- private static final String LDAP_LOCAL_USER_DN =
- "derby.user";
- private static final String LDAP_SEARCH_FILTER_USERNAME =
- "%USERNAME%";
-
- public LDAPAuthenticationSchemeImpl(JNDIAuthenticationService as, Properties dbProperties) {
-
- super(as, dbProperties);
- }
-
- /**
- * Authenticate the passed-in user's credentials.
- *
- * We authenticate against a LDAP Server.
- *
- *
- * @param userName The user's name used to connect to JBMS system
- * @param userPassword The user's password used to connect to JBMS system
- * @param databaseName The database which the user wants to connect to.
- * @param info Additional jdbc connection info.
- */
- public boolean authenticateUser(String userName,
- String userPassword,
- String databaseName,
- Properties info
- )
- throws java.sql.SQLException
- {
- if ( ((userName == null) || (userName.length() == 0)) ||
- ((userPassword == null) || (userPassword.length() == 0)) )
- {
- // We don't tolerate 'guest' user for now as well as
- // null password.
- // If a null password is passed upon authenticating a user
- // through LDAP, then the LDAP server might consider this as
- // anonymous bind and therefore no authentication will be done
- // at all.
- return false;
- }
-
-
- Exception e;
- try {
- Properties env = (Properties) initDirContextEnv.clone();
- String userDN = null;
- //
- // Retrieve the user's DN (Distinguished Name)
- // If we're asked to look it up locally, do it first
- // and if we don't find it, we go against the LDAP
- // server for a look-up (search)
- //
- if (useUserPropertyAsDN)
- userDN =
- authenticationService.getProperty(
- org.apache.derby.shared.common.reference.Property.USER_PROPERTY_PREFIX);
-
- if (userDN == (String) null) {
- userDN = getDNFromUID(userName);
- }
+ private String leftSearchFilter; // stick in uid in between
+ private String rightSearchFilter;
+ private boolean useUserPropertyAsDN;
+
+ // Search Auth DN & Password if anonymous search not allowed
+ private String searchAuthDN;
+ private String searchAuthPW;
+ // we only want the user's full DN in return
+ private static final String[] attrDN = {"dn"}; ;
+
+ //
+ // Derby LDAP Configuration properties
+ //
+ private static final String LDAP_SEARCH_BASE =
+ "derby.authentication.ldap.searchBase";
+ private static final String LDAP_SEARCH_FILTER =
+ "derby.authentication.ldap.searchFilter";
+ private static final String LDAP_SEARCH_AUTH_DN =
+ "derby.authentication.ldap.searchAuthDN";
+ private static final String LDAP_SEARCH_AUTH_PW =
+ "derby.authentication.ldap.searchAuthPW";
+ private static final String LDAP_LOCAL_USER_DN =
+ "derby.user";
+ private static final String LDAP_SEARCH_FILTER_USERNAME =
+ "%USERNAME%";
+
+ public LDAPAuthenticationSchemeImpl(JNDIAuthenticationService as, Properties dbProperties) {
+
+ super(as, dbProperties);
+ }
+
+ /**
+ * Authenticate the passed-in user's credentials.
+ *
+ * We authenticate against a LDAP Server.
+ *
+ *
+ * @param userName The user's name used to connect to JBMS system
+ * @param userPassword The user's password used to connect to JBMS system
+ * @param databaseName The database which the user wants to connect to.
+ * @param info Additional jdbc connection info.
+ */
+ public boolean authenticateUser(String userName,
+ String userPassword,
+ String databaseName,
+ Properties info
+ )
+ throws java.sql.SQLException {
+ if ( ((userName == null) || (userName.length() == 0)) ||
+ ((userPassword == null) || (userPassword.length() == 0)) )
+ {
+ // We don't tolerate 'guest' user for now as well as
+ // null password.
+ // If a null password is passed upon authenticating a user
+ // through LDAP, then the LDAP server might consider this as
+ // anonymous bind and therefore no authentication will be done
+ // at all.
+ return false;
+ }
+
+
+ Exception e;
+ try {
+ Properties env = (Properties) initDirContextEnv.clone();
+ String userDN = null;
+ //
+ // Retrieve the user's DN (Distinguished Name)
+ // If we're asked to look it up locally, do it first
+ // and if we don't find it, we go against the LDAP
+ // server for a look-up (search)
+ //
+ if (useUserPropertyAsDN)
+ userDN =
+ authenticationService.getProperty(
+ org.apache.derby.shared.common.reference.Property.USER_PROPERTY_PREFIX);
+
+ if (userDN == (String) null) {
+ userDN = getDNFromUID(userName);
+ }
- if (SanityManager.DEBUG)
- {
- if (SanityManager.DEBUG_ON(
- AuthenticationServiceBase.AuthenticationTrace)) {
- SanityManager.DEBUG(AuthenticationServiceBase.AuthenticationTrace,
+ if (SanityManager.DEBUG)
+ {
+ if (SanityManager.DEBUG_ON(
+ AuthenticationServiceBase.AuthenticationTrace)) {
+ SanityManager.DEBUG(AuthenticationServiceBase.AuthenticationTrace,
"User DN = ["+ userDN+"]\n");
- }
- }
+ }
+ }
- env.put(Context.SECURITY_PRINCIPAL, userDN);
- env.put(Context.SECURITY_CREDENTIALS, userPassword);
+ env.put(Context.SECURITY_PRINCIPAL, userDN);
+ env.put(Context.SECURITY_CREDENTIALS, userPassword);
- // Connect & authenticate (bind) to the LDAP server now
+ // Connect & authenticate (bind) to the LDAP server now
- // it is happening right here
+ // it is happening right here
DirContext ctx = privInitialDirContext(env);
- // if the above was successfull, then username and
- // password must be correct
- return true;
+ // if the above was successfull, then username and
+ // password must be correct
+ return true;
- } catch (javax.naming.AuthenticationException jndiae) {
- return false;
+ } catch (javax.naming.AuthenticationException jndiae) {
+ return false;
- } catch (javax.naming.NameNotFoundException jndinnfe) {
- return false;
+ } catch (javax.naming.NameNotFoundException jndinnfe) {
+ return false;
- } catch (javax.naming.NamingException jndine) {
- e = jndine;
- }
+ } catch (javax.naming.NamingException jndine) {
+ e = jndine;
+ }
- throw getLoginSQLException(e);
- }
+ throw getLoginSQLException(e);
+ }
-
+ /**
+ * Given an LDAP search string, returns the string with certain characters
+ * escaped according to RFC 2254 guidelines. Cribbed from org.apache.catalina.realm.JNDIRealm.
+ *
+ * The character mapping is as follows:
+ * char -> Replacement
+ * ---------------------------
+ * * -> \2a
+ * ( -> \28
+ * ) -> \29
+ * \ -> \5c
+ * \0 -> \00
+ *
+ * @param inString string to escape according to RFC 2254 guidelines
+ *
+ * @return String the escaped/encoded result
+ */
+ protected String doFilterEscaping(String inString) {
+ if (inString == null) {
+ return null;
+ }
+ StringBuilder buf = new StringBuilder(inString.length());
+ for (int i = 0; i < inString.length(); i++) {
+ char c = inString.charAt(i);
+ switch (c) {
+ case '\\':
+ buf.append("\\5c");
+ break;
+ case '*':
+ buf.append("\\2a");
+ break;
+ case '(':
+ buf.append("\\28");
+ break;
+ case ')':
+ buf.append("\\29");
+ break;
+ case '\0':
+ buf.append("\\00");
+ break;
+ default:
+ buf.append(c);
+ break;
+ }
+ }
+ return buf.toString();
+ }
/**
* Call new InitialDirContext in a privilege block
@@ -201,8 +246,7 @@ extends JNDIAuthenticationSchemeBase
* for the JNDI provider scheme (here it is LDAP).
*
**/
- protected void setJNDIProviderProperties()
- {
+ protected void setJNDIProviderProperties() {
// check if we're told to use a different initial context factory
if (initDirContextEnv.getProperty(
@@ -381,87 +425,91 @@ extends JNDIAuthenticationSchemeBase
}
- /**
- * Search for the full user's DN in the LDAP server.
- * LDAP server bind may or not be anonymous.
- *
- * If the admin does not want us to do anonymous bind/search, then we
- * must have been given principal/credentials in order to successfully
- * bind to perform the user's DN search.
- *
- * @exception NamingException if could not retrieve the user DN.
- **/
- private String getDNFromUID(String uid)
- throws javax.naming.NamingException
- {
- //
- // We bind to the LDAP server here
- // Note that this bind might be anonymous (if anonymous searches
- // are allowed in the LDAP server, or authenticated if we were
- // told/configured to.
- //
- Properties env = null;
- if (this.searchAuthDN != (String) null) {
- env = (Properties) initDirContextEnv.clone();
- env.put(Context.SECURITY_PRINCIPAL, this.searchAuthDN);
- env.put(Context.SECURITY_CREDENTIALS, this.searchAuthPW);
- }
- else
- env = initDirContextEnv;
-
- DirContext ctx = privInitialDirContext(env);
-
- // Construct Search Filter
- SearchControls ctls = new SearchControls();
- // Set-up a LDAP subtree search scope
- ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-
- // Just retrieve the DN
- ctls.setReturningAttributes(attrDN);
-
- String searchFilter =
- this.leftSearchFilter + uid + this.rightSearchFilter;
- NamingEnumeration results =
- ctx.search(searchBaseDN, searchFilter, ctls);
+ /**
+ * Search for the full user's DN in the LDAP server.
+ * LDAP server bind may or not be anonymous.
+ *
+ * If the admin does not want us to do anonymous bind/search, then we
+ * must have been given principal/credentials in order to successfully
+ * bind to perform the user's DN search.
+ *
+ * @exception NamingException if could not retrieve the user DN.
+ **/
+ private String getDNFromUID(String uid)
+ throws javax.naming.NamingException {
+
+ // Escape the uid as a defense against LDAP injection. See DERBY-7147.
+ uid = doFilterEscaping(uid);
+
+ //
+ // We bind to the LDAP server here
+ // Note that this bind might be anonymous (if anonymous searches
+ // are allowed in the LDAP server, or authenticated if we were
+ // told/configured to.
+ //
+ Properties env = null;
+ if (this.searchAuthDN != (String) null) {
+ env = (Properties) initDirContextEnv.clone();
+ env.put(Context.SECURITY_PRINCIPAL, this.searchAuthDN);
+ env.put(Context.SECURITY_CREDENTIALS, this.searchAuthPW);
+ }
+ else
+ env = initDirContextEnv;
+
+ DirContext ctx = privInitialDirContext(env);
+
+ // Construct Search Filter
+ SearchControls ctls = new SearchControls();
+ // Set-up a LDAP subtree search scope
+ ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+ // Just retrieve the DN
+ ctls.setReturningAttributes(attrDN);
+
+ String searchFilter =
+ this.leftSearchFilter + uid + this.rightSearchFilter;
+
+ NamingEnumeration results =
+ ctx.search(searchBaseDN, searchFilter, ctls);
- // If we did not find anything then login failed
- if (results == null || !results.hasMore())
- throw new NameNotFoundException();
+ // If we did not find anything then login failed
+ if (results == null || !results.hasMore())
+ throw new NameNotFoundException();
- SearchResult result = (SearchResult)results.next();
+ SearchResult result = (SearchResult)results.next();
- if (results.hasMore())
- {
- // This is a login failure as we cannot assume the first one
- // is the valid one.
- if (SanityManager.DEBUG)
- {
- if (SanityManager.DEBUG_ON(
- AuthenticationServiceBase.AuthenticationTrace)) {
-
- java.io.PrintWriter iDbgStream =
- SanityManager.GET_DEBUG_STREAM();
-
- iDbgStream.println(
- " - LDAP Authentication request failure: "+
- "search filter [" + searchFilter + "]"+
- ", retrieve more than one occurence in "+
- "LDAP server [" + this.providerURL + "]");
- }
- }
- throw new NameNotFoundException();
- }
-
- NameParser parser = ctx.getNameParser(searchBaseDN);
- Name userDN = parser.parse(searchBaseDN);
-
- if (userDN == (Name) null)
- // This should not happen in theory
- throw new NameNotFoundException();
- else
- userDN.addAll(parser.parse(result.getName()));
+ if (results.hasMore())
+ {
+ // This is a login failure as we cannot assume the first one
+ // is the valid one.
+ if (SanityManager.DEBUG)
+ {
+ if (SanityManager.DEBUG_ON(
+ AuthenticationServiceBase.AuthenticationTrace)) {
+
+ java.io.PrintWriter iDbgStream =
+ SanityManager.GET_DEBUG_STREAM();
+
+ iDbgStream.println(
+ " - LDAP Authentication request failure: "+
+ "search filter [" + searchFilter + "]"+
+ ", retrieve more than one occurence in "+
+ "LDAP server [" + this.providerURL + "]");
+ }
+ }
+ throw new NameNotFoundException();
+ }
+
+ NameParser parser = ctx.getNameParser(searchBaseDN);
+ Name userDN = parser.parse(searchBaseDN);
+
+ if (userDN == (Name) null)
+ // This should not happen in theory
+ throw new NameNotFoundException();
+ else
+ userDN.addAll(parser.parse(result.getName()));
- // Return the full user's DN
- return userDN.toString();
- }
+ // Return the full user's DN
+ return userDN.toString();
+ }
}