Skip to content

Commit 83fc06d

Browse files
authored
Merge pull request #592 from gjwatts/490-connection-error-path-handling
Implement proper handling and messages for connection error paths
2 parents 0cfe1ee + 996de3e commit 83fc06d

File tree

4 files changed

+123
-7
lines changed

4 files changed

+123
-7
lines changed

vertx-db2-client/src/main/java/io/vertx/db2client/impl/codec/DB2Decoder.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.netty.handler.codec.ByteToMessageDecoder;
2525
import io.vertx.core.impl.logging.Logger;
2626
import io.vertx.core.impl.logging.LoggerFactory;
27+
import io.vertx.db2client.DB2Exception;
2728
import io.vertx.sqlclient.impl.command.CommandResponse;
2829

2930
class DB2Decoder extends ByteToMessageDecoder {
@@ -74,6 +75,9 @@ private void decodePayload(ByteBuf payload, int payloadLength) {
7475
if (LOG.isDebugEnabled())
7576
LOG.debug("<<< DECODE " + ctx + " (" + payloadLength + " bytes)");
7677
ctx.decodePayload(payload, payloadLength);
78+
} catch (DB2Exception connex) {
79+
// A common connection error occurred, so don't bother with a hex dump and generic error message
80+
ctx.completionHandler.handle(CommandResponse.failure(connex));
7781
} catch (Throwable t) {
7882
int i = payload.readerIndex();
7983
payload.readerIndex(startIndex);

vertx-db2-client/src/main/java/io/vertx/db2client/impl/drda/DRDAConnectResponse.java

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package io.vertx.db2client.impl.drda;
1717

18-
import java.nio.charset.StandardCharsets;
1918
import java.sql.Connection;
2019
import java.util.ArrayList;
2120
import java.util.List;
@@ -1057,13 +1056,13 @@ private void parseSECCHKreply() {
10571056
// 0x03 - OBJDSS sent when not allowed.
10581057
//parseSECTKN (true);
10591058
parseSECTKN(false);
1060-
}
1059+
}
10611060
}
10621061

10631062
// The Security Check (SECCHKRM) Reply Message indicates the acceptability
10641063
// of the security information.
1065-
// this method returns the security check code. it is up to the caller to check
1066-
// the value of this return code and take the appropriate action.
1064+
// This method throws an exception if the connection was not established
1065+
// It is up to the caller to catch this exception and take the appropriate action.
10671066
//
10681067
// Returned from Server:
10691068
// SVRCOD - required (0 - INFO, 8 - ERROR, 16 -SEVERE)
@@ -1132,10 +1131,30 @@ private void parseSECCHKRM() {
11321131
if (!secchkcdReceived)
11331132
throw new IllegalStateException("Did not receive SECCHKCD codepoint");
11341133
// checkRequiredObjects(svrcodReceived, secchkcdReceived);
1135-
11361134
// netConnection.securityCheckComplete(svrcod, secchkcd);
1137-
if (secchkcd != CodePoint.SECCHKCD_00) {
1138-
throw new IllegalArgumentException("Authentication failed");
1135+
1136+
switch (secchkcd) {
1137+
// Security information accepted
1138+
case CodePoint.SECCHKCD_00:
1139+
break;
1140+
// Missing userid - TODO We should catch and handle this issue *before* the call to the DB2 server
1141+
case CodePoint.SECCHKCD_12:
1142+
// Using SQL error code and state values from JDBC
1143+
throw new DB2Exception("Missing userid, verify a user value was supplied", SqlCode.MISSING_CREDENTIALS, SQLState.CONNECT_USERID_ISNULL);
1144+
// Missing password - TODO We should catch and handle this issue *before* the call to the DB2 server
1145+
case CodePoint.SECCHKCD_10:
1146+
// Using SQL error code and state values from similar JDBC reponse
1147+
throw new DB2Exception("Missing password, verify a password value was supplied", SqlCode.MISSING_CREDENTIALS, SQLState.CONNECT_PASSWORD_ISNULL);
1148+
// Invalid credentials
1149+
case CodePoint.SECCHKCD_0E:
1150+
case CodePoint.SECCHKCD_0F:
1151+
case CodePoint.SECCHKCD_13:
1152+
case CodePoint.SECCHKCD_14:
1153+
case CodePoint.SECCHKCD_15:
1154+
// Using SQL error code and state values from similar JDBC response for consistency
1155+
throw new DB2Exception("Invalid credentials, verify the user and password values supplied are correct", SqlCode.INVALID_CREDENTIALS, SQLState.NET_CONNECT_AUTH_FAILED);
1156+
default:
1157+
throw new IllegalArgumentException("Authentication failed");
11391158
}
11401159
}
11411160

vertx-db2-client/src/main/java/io/vertx/db2client/impl/drda/SqlCode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public class SqlCode {
2626

2727
public static final int CONNECTION_REFUSED = -4499;
2828
public static final int RDB_NOT_FOUND = -30061;
29+
public static final int INVALID_CREDENTIALS = -4214;
30+
public static final int MISSING_CREDENTIALS = -4461;
2931

3032
private int code_;
3133

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright (C) 2020 IBM Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.vertx.db2client;
17+
18+
import org.junit.Ignore;
19+
import org.junit.Test;
20+
import org.junit.runner.RunWith;
21+
22+
import io.vertx.db2client.impl.drda.SQLState;
23+
import io.vertx.db2client.impl.drda.SqlCode;
24+
import io.vertx.ext.unit.TestContext;
25+
import io.vertx.ext.unit.junit.VertxUnitRunner;
26+
27+
@RunWith(VertxUnitRunner.class)
28+
public class DB2ErrorMessageTest extends DB2TestBase {
29+
30+
@Test
31+
@Ignore // TODO - Need to figure out why this is blowing up in parseACCSECreply()
32+
public void testConnectInvalidDatabase(TestContext ctx) {
33+
options.setDatabase("DOES_NOT_EXIST");
34+
DB2Connection.connect(vertx, options, ctx.asyncAssertFailure(err -> {
35+
ctx.assertTrue(err instanceof DB2Exception, "The error message returned is of the wrong type. It should be a DB2Exception, but it was of type " + err.getClass().getSimpleName());
36+
// DB2Exception ex = (DB2Exception) err;
37+
// ctx.assertTrue(ex.getMessage().contains("Invalid database"), "The SQL error message returned is not correct. It should have contained \"Invalid database\", but instead it said \"" + ex.getMessage() + "\"");
38+
}));
39+
}
40+
41+
@Test
42+
public void testConnectInvalidUsername(TestContext ctx) {
43+
options.setUser("INVALID_USER_FOR_TESTING");
44+
DB2Connection.connect(vertx, options, ctx.asyncAssertFailure(err -> {
45+
ctx.assertTrue(err instanceof DB2Exception, "The error message returned is of the wrong type. It should be a DB2Exception, but it was of type " + err.getClass().getSimpleName());
46+
DB2Exception ex = (DB2Exception) err;
47+
ctx.assertTrue(ex.getMessage().contains("Invalid credentials"), "The SQL error message returned is not correct. It should have contained \"Invalid credentials\", but instead it said \"" + ex.getMessage() + "\"");
48+
ctx.assertEquals(SqlCode.INVALID_CREDENTIALS, ex.getErrorCode());
49+
ctx.assertEquals(SQLState.NET_CONNECT_AUTH_FAILED, ex.getSqlState());
50+
System.out.println(err.getMessage());
51+
}));
52+
}
53+
54+
@Test
55+
public void testConnectInvalidPassword(TestContext ctx) {
56+
options.setPassword("INVALID_PASSWORD_FOR_TESTING");
57+
DB2Connection.connect(vertx, options, ctx.asyncAssertFailure(err -> {
58+
ctx.assertTrue(err instanceof DB2Exception, "The error message returned is of the wrong type. It should be a DB2Exception, but it was of type " + err.getClass().getSimpleName());
59+
DB2Exception ex = (DB2Exception) err;
60+
ctx.assertTrue(ex.getMessage().contains("Invalid credentials"), "The SQL error message returned is not correct. It should have contained \"Invalid credentials\", but instead it said \"" + ex.getMessage() + "\"");
61+
ctx.assertEquals(SqlCode.INVALID_CREDENTIALS, ex.getErrorCode());
62+
ctx.assertEquals(SQLState.NET_CONNECT_AUTH_FAILED, ex.getSqlState());
63+
System.out.println(err.getMessage());
64+
}));
65+
}
66+
67+
@Test
68+
@Ignore // TODO - @GJW I want to validate we would always want to fail a test for a blank user name. If so, we want to catch this *before* we connect to the DB2 server
69+
public void testConnectBlankUsername(TestContext ctx) {
70+
options.setUser("");
71+
DB2Connection.connect(vertx, options, ctx.asyncAssertFailure(err -> {
72+
ctx.assertTrue(err instanceof DB2Exception, "The error message returned is of the wrong type. It should be a DB2Exception, but it was of type " + err.getClass().getSimpleName());
73+
ctx.assertTrue("Missing userid, verify a user value was supplied".equalsIgnoreCase(err.getMessage()), "The text of the returned error message is incorrect. It should say \"Missing userid, verify a user value was supplied\", but instead, it says \"" + err.getMessage() + "\"");
74+
}));
75+
}
76+
77+
@Test
78+
@Ignore // TODO - @GJW I want to validate we would always want to fail a test for a blank password. If so, we want to catch this *before* we connect to the DB2 server
79+
public void testConnectBlankPassword(TestContext ctx) {
80+
options.setPassword("");
81+
DB2Connection.connect(vertx, options, ctx.asyncAssertFailure(err -> {
82+
ctx.assertTrue(err instanceof DB2Exception, "The error message returned is of the wrong type. It should be a DB2Exception, but it was of type " + err.getClass().getSimpleName());
83+
ctx.assertTrue("Missing password, verify a password value was supplied".equalsIgnoreCase(err.getMessage()), "The text of the returned error message is incorrect. It should say \"Missing password, verify a password value was supplied\", but instead, it says \"" + err.getMessage() + "\"");
84+
}));
85+
}
86+
87+
@Test
88+
@Ignore // TODO - complete
89+
public void testConnectInvalidQuery(TestContext ctx) {
90+
}
91+
}

0 commit comments

Comments
 (0)