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 oy...@apache.org on 2007/09/12 11:50:44 UTC

svn commit: r574870 - in /db/derby/code/trunk/java: drda/org/apache/derby/impl/drda/DRDAConnThread.java engine/org/apache/derby/impl/jdbc/EmbedConnection.java engine/org/apache/derby/jdbc/InternalDriver.java

Author: oysteing
Date: Wed Sep 12 02:50:43 2007
New Revision: 574870

URL: http://svn.apache.org/viewvc?rev=574870&view=rev
Log:
DERBY-3060: Network Server incorrectly assumes that all SQLExceptions
            with error code 08004 are caused by an authentication failure.
Contributed by Jørgen Løland

Modified:
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
    db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?rev=574870&r1=574869&r2=574870&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Wed Sep 12 02:50:43 2007
@@ -1192,17 +1192,86 @@
 	private int getRdbAccessErrorCodePoint()
 	{
 		String sqlState = databaseAccessException.getSQLState();
-		if (sqlState.regionMatches(0,SQLState.DATABASE_NOT_FOUND,0,5) |
-			sqlState.regionMatches(0,SQLState.NO_SUCH_DATABASE,0,5))
+		// These tests are ok since DATABASE_NOT_FOUND,
+		// NO_SUCH_DATABASE and AUTH_INVALID_USER_NAME are not
+		// ambigious error codes (on the first five characters) in
+		// SQLState. If they were, we would have to perform a similar
+		// check as done in method isAuthenticationException
+		if (sqlState.regionMatches(0,SQLState.DATABASE_NOT_FOUND,0,5) ||
+			sqlState.regionMatches(0,SQLState.NO_SUCH_DATABASE,0,5)) {
+			// RDB not found codepoint
 			return CodePoint.RDBNFNRM;
-		else
-			if (sqlState.regionMatches(0,SQLState.LOGIN_FAILED,0,5) ||
-				sqlState.regionMatches(0,SQLState.AUTH_INVALID_USER_NAME,0,5))
+		} else {
+			if (isAuthenticationException(databaseAccessException) ||
+				sqlState.regionMatches(0,SQLState.AUTH_INVALID_USER_NAME,0,5)) {
+				// Not Authorized To RDB reply message codepoint
 				return CodePoint.RDBATHRM;
-		else
+			} else {
+				// RDB Access Failed Reply Message codepoint
 				return CodePoint.RDBAFLRM;
+            }
+        }
 	}
 
+    /**
+     * There are multiple reasons for not getting a connection, and
+     * all these should throw SQLExceptions with SQL state 08004
+     * according to the SQL standard. Since only one of these SQL
+     * states indicate that an authentication error has occurred, it
+     * is not enough to check that the SQL state is 08004 and conclude
+     * that authentication caused the exception to be thrown.
+     *
+     * This method tries to cast the exception to an EmbedSQLException
+     * and use getMessageId on that object to check for authentication
+     * error instead of the SQL state we get from
+     * SQLExceptions#getSQLState. getMessageId returns the entire id
+     * as defined in SQLState (e.g. 08004.C.1), while getSQLState only
+     * return the 5 first characters (i.e. 08004 instead of 08004.C.1)
+     *
+     * If the cast to EmbedSQLException is not successful, the
+     * assumption that SQL State 08004 is caused by an authentication
+     * failure is followed even though this is not correct. This was
+     * the pre DERBY-3060 way of solving the issue.
+     *
+     * @param sqlException The exception that is checked to see if
+     * this is really caused by an authentication failure
+     * @return true if sqlException is (or has to be assumed to be)
+     * caused by an authentication failure, false otherwise.
+     * @see SQLState
+     */
+    private boolean isAuthenticationException (SQLException sqlException) {
+        boolean authFail = false;
+
+        // get exception which carries Derby messageID and args
+        SQLException se = Util.getExceptionFactory().
+            getArgumentFerry(sqlException);
+
+        if (se instanceof EmbedSQLException) {
+            // DERBY-3060: if this is an EmbedSQLException, we can
+            // check the messageId to find out what caused the
+            // exception.
+
+            String msgId = ((EmbedSQLException)se).getMessageId();
+
+            // Of the 08004.C.x messages, only
+            // SQLState.NET_CONNECT_AUTH_FAILED is an authentication
+            // exception
+            if (msgId.equals(SQLState.NET_CONNECT_AUTH_FAILED)) {
+                authFail = true;
+            }
+        } else {
+            String sqlState = se.getSQLState();
+            if (sqlState.regionMatches(0,SQLState.LOGIN_FAILED,0,5)) {
+                // Unchanged by DERBY-3060: This is not an
+                // EmbedSQLException, so we cannot check the
+                // messageId. As before DERBY-3060, we assume that all
+                // 08004 error codes are due to an authentication
+                // failure, even though this ambigious
+                authFail = true;
+            }
+        }
+        return authFail;
+    }
 
 	/**
 	 * Verify userId and password
@@ -1275,9 +1344,7 @@
 			database.makeConnection(p);
 	  	} catch (SQLException se) {
 			String sqlState = se.getSQLState();
-			// need to set the security check code based on the reason the connection     
-			// was denied, Derby doesn't say whether the userid or password caused
-			// the problem, so we will just return userid invalid
+
 			databaseAccessException = se;
 			for (; se != null; se = se.getNextException())
 			{
@@ -1286,10 +1353,15 @@
 	 			println2Log(database.dbName, session.drdaID, se.getMessage());
 			}
 
-			if (sqlState.regionMatches(0,SQLState.LOGIN_FAILED,0,5))
+			if (isAuthenticationException(databaseAccessException)) {
+				// need to set the security check code based on the
+				// reason the connection was denied, Derby doesn't say
+				// whether the userid or password caused the problem,
+				// so we will just return userid invalid
 				return CodePoint.SECCHKCD_USERIDINVALID;
-
-			return 0;
+			} else {
+				return 0;
+			}
 		}
 		catch (Exception e)
 		{

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java?rev=574870&r1=574869&r2=574870&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java Wed Sep 12 02:50:43 2007
@@ -585,7 +585,8 @@
 											   userInfo
 											   )) {
 
-			throw newSQLException(SQLState.LOGIN_FAILED, MessageService.getTextMessage(MessageId.AUTH_INVALID));
+			throw newSQLException(SQLState.NET_CONNECT_AUTH_FAILED,
+                     MessageService.getTextMessage(MessageId.AUTH_INVALID));
 
 		}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java?rev=574870&r1=574869&r2=574870&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java Wed Sep 12 02:50:43 2007
@@ -197,7 +197,9 @@
 
 						// not a valid user
 						throw Util.generateCsSQLException(
-                                  SQLState.LOGIN_FAILED, MessageService.getTextMessage(MessageId.AUTH_INVALID));
+                                    SQLState.NET_CONNECT_AUTH_FAILED,
+                                    MessageService.
+                                    getTextMessage(MessageId.AUTH_INVALID));
 					}
 
 					Monitor.getMonitor().shutdown();