This is an automated email from the ASF dual-hosted git repository.

terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new fcccba479b6 Add basic Firebird exception mapper (#38812)
fcccba479b6 is described below

commit fcccba479b609ddd064c8dad0b126860f698caea
Author: Maxim Sentyabrskiy <[email protected]>
AuthorDate: Sat Jun 6 08:28:14 2026 +0300

    Add basic Firebird exception mapper (#38812)
    
    Co-authored-by: makssent <[email protected]>
---
 bom/pom.xml                                        |  5 ++
 .../dialect/firebird/pom.xml                       | 15 +----
 .../mapper/FirebirdDialectExceptionMapper.java     | 54 ++++++++++++++++
 .../exception/firebird/sqlstate/FirebirdState.java | 36 +++++++++++
 .../firebird/vendor/FirebirdVendorError.java       | 53 ++++++++++++++++
 ...exception.core.mapper.SQLDialectExceptionMapper | 18 ++++++
 .../mapper/FirebirdDialectExceptionMapperTest.java | 64 +++++++++++++++++++
 database/exception/dialect/pom.xml                 |  1 +
 database/protocol/dialect/firebird/pom.xml         |  5 ++
 .../firebird/err/FirebirdStatusVector.java         |  8 ++-
 .../firebird/err/FirebirdStatusVectorTest.java     | 25 ++++++++
 .../FirebirdAuthenticationEngine.java              | 11 ++--
 .../FirebirdAuthenticationEngineTest.java          | 71 +++++++++++++++++++++-
 .../err/FirebirdErrorPacketFactoryTest.java        | 16 +++++
 14 files changed, 359 insertions(+), 23 deletions(-)

diff --git a/bom/pom.xml b/bom/pom.xml
index 19dc5ae6237..5f5cc79172c 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -370,6 +370,11 @@
                 
<artifactId>shardingsphere-database-exception-postgresql</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.shardingsphere</groupId>
+                
<artifactId>shardingsphere-database-exception-firebird</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.shardingsphere</groupId>
                 <artifactId>shardingsphere-database-protocol-core</artifactId>
diff --git a/database/protocol/dialect/firebird/pom.xml 
b/database/exception/dialect/firebird/pom.xml
similarity index 74%
copy from database/protocol/dialect/firebird/pom.xml
copy to database/exception/dialect/firebird/pom.xml
index 2b84ba05c4d..df11220b81e 100644
--- a/database/protocol/dialect/firebird/pom.xml
+++ b/database/exception/dialect/firebird/pom.xml
@@ -20,29 +20,18 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.shardingsphere</groupId>
-        <artifactId>shardingsphere-database-protocol-dialect</artifactId>
+        <artifactId>shardingsphere-database-exception-dialect</artifactId>
         <version>5.5.4-SNAPSHOT</version>
     </parent>
-    <artifactId>shardingsphere-protocol-firebird</artifactId>
+    <artifactId>shardingsphere-database-exception-firebird</artifactId>
     <name>${project.artifactId}</name>
     
     <dependencies>
-        <dependency>
-            <groupId>org.apache.shardingsphere</groupId>
-            <artifactId>shardingsphere-database-protocol-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.shardingsphere</groupId>
-            <artifactId>shardingsphere-database-connector-firebird</artifactId>
-            <version>${project.version}</version>
-        </dependency>
         <dependency>
             <groupId>org.apache.shardingsphere</groupId>
             <artifactId>shardingsphere-database-exception-core</artifactId>
             <version>${project.version}</version>
         </dependency>
-        
         <dependency>
             <groupId>org.firebirdsql.jdbc</groupId>
             <artifactId>jaybird</artifactId>
diff --git 
a/database/exception/dialect/firebird/src/main/java/org/apache/shardingsphere/database/exception/firebird/mapper/FirebirdDialectExceptionMapper.java
 
b/database/exception/dialect/firebird/src/main/java/org/apache/shardingsphere/database/exception/firebird/mapper/FirebirdDialectExceptionMapper.java
new file mode 100644
index 00000000000..fbfe347cf05
--- /dev/null
+++ 
b/database/exception/dialect/firebird/src/main/java/org/apache/shardingsphere/database/exception/firebird/mapper/FirebirdDialectExceptionMapper.java
@@ -0,0 +1,54 @@
+/*
+ * 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.shardingsphere.database.exception.firebird.mapper;
+
+import 
org.apache.shardingsphere.database.exception.core.exception.SQLDialectException;
+import 
org.apache.shardingsphere.database.exception.core.exception.connection.AccessDeniedException;
+import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
+import 
org.apache.shardingsphere.database.exception.core.mapper.SQLDialectExceptionMapper;
+import 
org.apache.shardingsphere.database.exception.firebird.vendor.FirebirdVendorError;
+import 
org.apache.shardingsphere.infra.exception.external.sql.vendor.VendorError;
+import org.apache.shardingsphere.infra.exception.generic.UnknownSQLException;
+
+import java.sql.SQLException;
+
+/**
+ * Firebird dialect exception mapper.
+ */
+public final class FirebirdDialectExceptionMapper implements 
SQLDialectExceptionMapper {
+    
+    @Override
+    public SQLException convert(final SQLDialectException sqlDialectException) 
{
+        if (sqlDialectException instanceof UnknownDatabaseException) {
+            return toSQLException(FirebirdVendorError.UNAVAILABLE_DATABASE, 
((UnknownDatabaseException) sqlDialectException).getDatabaseName());
+        }
+        if (sqlDialectException instanceof AccessDeniedException) {
+            return toSQLException(FirebirdVendorError.LOGIN_FAILED);
+        }
+        return new UnknownSQLException(sqlDialectException).toSQLException();
+    }
+    
+    private SQLException toSQLException(final VendorError vendorError, final 
Object... messageArgs) {
+        return new SQLException(String.format(vendorError.getReason(), 
messageArgs), vendorError.getSqlState().getValue(), 
vendorError.getVendorCode());
+    }
+    
+    @Override
+    public String getDatabaseType() {
+        return "Firebird";
+    }
+}
diff --git 
a/database/exception/dialect/firebird/src/main/java/org/apache/shardingsphere/database/exception/firebird/sqlstate/FirebirdState.java
 
b/database/exception/dialect/firebird/src/main/java/org/apache/shardingsphere/database/exception/firebird/sqlstate/FirebirdState.java
new file mode 100644
index 00000000000..f00a726c59e
--- /dev/null
+++ 
b/database/exception/dialect/firebird/src/main/java/org/apache/shardingsphere/database/exception/firebird/sqlstate/FirebirdState.java
@@ -0,0 +1,36 @@
+/*
+ * 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.shardingsphere.database.exception.firebird.sqlstate;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import 
org.apache.shardingsphere.infra.exception.external.sql.sqlstate.SQLState;
+
+/**
+ * Firebird SQL state.
+ *
+ * <p>Holds SQL states that Jaybird derives from a GDSCODE but that are not 
defined in {@code XOpenSQLState}.</p>
+ */
+@RequiredArgsConstructor
+@Getter
+public enum FirebirdState implements SQLState {
+    
+    UNAVAILABLE_DATABASE("08001");
+    
+    private final String value;
+}
diff --git 
a/database/exception/dialect/firebird/src/main/java/org/apache/shardingsphere/database/exception/firebird/vendor/FirebirdVendorError.java
 
b/database/exception/dialect/firebird/src/main/java/org/apache/shardingsphere/database/exception/firebird/vendor/FirebirdVendorError.java
new file mode 100644
index 00000000000..2c5280ee850
--- /dev/null
+++ 
b/database/exception/dialect/firebird/src/main/java/org/apache/shardingsphere/database/exception/firebird/vendor/FirebirdVendorError.java
@@ -0,0 +1,53 @@
+/*
+ * 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.shardingsphere.database.exception.firebird.vendor;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import 
org.apache.shardingsphere.database.exception.firebird.sqlstate.FirebirdState;
+import 
org.apache.shardingsphere.infra.exception.external.sql.sqlstate.SQLState;
+import 
org.apache.shardingsphere.infra.exception.external.sql.sqlstate.XOpenSQLState;
+import 
org.apache.shardingsphere.infra.exception.external.sql.vendor.VendorError;
+import org.firebirdsql.gds.ISCConstants;
+
+/**
+ * Firebird vendor error.
+ *
+ * <p>The vendor code carries the native Firebird GDSCODE, which the client 
(Jaybird) uses to look up both the message
+ * template and the SQL state from its own catalog. The status vector 
transmits the GDSCODE plus a single string
+ * argument, so the reason here holds only that argument. With Jaybird's 
current message rendering a {@code {0}}
+ * placeholder is filled by the argument and a template without placeholders 
is followed by the argument; an empty reason
+ * sends no argument, leaving the catalog message as-is. GDSCODEs whose 
templates require multiple arguments are avoided
+ * until the status vector can carry them.</p>
+ *
+ * @see <a 
href="https://www.firebirdsql.org/file/documentation/chunk/en/refdocs/fblangref40/fblangref40-appx02-sqlcodes.html";>SQLCODE
 and GDSCODE Error Codes</a>
+ */
+@RequiredArgsConstructor
+@Getter
+public enum FirebirdVendorError implements VendorError {
+    
+    UNAVAILABLE_DATABASE(FirebirdState.UNAVAILABLE_DATABASE, 
ISCConstants.isc_unavailable, "%s"),
+    
+    LOGIN_FAILED(XOpenSQLState.INVALID_AUTHORIZATION_SPECIFICATION, 
ISCConstants.isc_login, "");
+    
+    private final SQLState sqlState;
+    
+    private final int vendorCode;
+    
+    private final String reason;
+}
diff --git 
a/database/exception/dialect/firebird/src/main/resources/META-INF/services/org.apache.shardingsphere.database.exception.core.mapper.SQLDialectExceptionMapper
 
b/database/exception/dialect/firebird/src/main/resources/META-INF/services/org.apache.shardingsphere.database.exception.core.mapper.SQLDialectExceptionMapper
new file mode 100644
index 00000000000..4b26c68316e
--- /dev/null
+++ 
b/database/exception/dialect/firebird/src/main/resources/META-INF/services/org.apache.shardingsphere.database.exception.core.mapper.SQLDialectExceptionMapper
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.shardingsphere.database.exception.firebird.mapper.FirebirdDialectExceptionMapper
diff --git 
a/database/exception/dialect/firebird/src/test/java/org/apache/shardingsphere/database/exception/firebird/mapper/FirebirdDialectExceptionMapperTest.java
 
b/database/exception/dialect/firebird/src/test/java/org/apache/shardingsphere/database/exception/firebird/mapper/FirebirdDialectExceptionMapperTest.java
new file mode 100644
index 00000000000..7593ebbd061
--- /dev/null
+++ 
b/database/exception/dialect/firebird/src/test/java/org/apache/shardingsphere/database/exception/firebird/mapper/FirebirdDialectExceptionMapperTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.shardingsphere.database.exception.firebird.mapper;
+
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.database.exception.core.exception.SQLDialectException;
+import 
org.apache.shardingsphere.database.exception.core.exception.connection.AccessDeniedException;
+import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
+import 
org.apache.shardingsphere.database.exception.core.mapper.SQLDialectExceptionMapper;
+import 
org.apache.shardingsphere.database.exception.firebird.vendor.FirebirdVendorError;
+import 
org.apache.shardingsphere.infra.exception.external.sql.vendor.VendorError;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.junit.jupiter.api.Test;
+
+import java.sql.SQLException;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.mock;
+
+class FirebirdDialectExceptionMapperTest {
+    
+    private final DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "Firebird");
+    
+    private final SQLDialectExceptionMapper mapper = 
DatabaseTypedSPILoader.getService(SQLDialectExceptionMapper.class, 
databaseType);
+    
+    @Test
+    void assertConvertWithUnknownDatabase() {
+        assertSQLException(mapper.convert(new 
UnknownDatabaseException("logic_db")), 
FirebirdVendorError.UNAVAILABLE_DATABASE, "logic_db");
+    }
+    
+    @Test
+    void assertConvertWithAccessDenied() {
+        assertSQLException(mapper.convert(new AccessDeniedException("root", 
"127.0.0.1", true)), FirebirdVendorError.LOGIN_FAILED);
+    }
+    
+    @Test
+    void assertConvertWithUnknownException() {
+        SQLException actual = mapper.convert(mock(SQLDialectException.class));
+        assertThat(actual.getSQLState(), is("HY000"));
+    }
+    
+    private void assertSQLException(final SQLException actual, final 
VendorError vendorError, final Object... messageArgs) {
+        assertThat(actual.getSQLState(), 
is(vendorError.getSqlState().getValue()));
+        assertThat(actual.getErrorCode(), is(vendorError.getVendorCode()));
+        assertThat(actual.getMessage(), 
is(String.format(vendorError.getReason(), messageArgs)));
+    }
+}
diff --git a/database/exception/dialect/pom.xml 
b/database/exception/dialect/pom.xml
index 17f2584c363..35cd99a8e70 100644
--- a/database/exception/dialect/pom.xml
+++ b/database/exception/dialect/pom.xml
@@ -30,5 +30,6 @@
     <modules>
         <module>mysql</module>
         <module>postgresql</module>
+        <module>firebird</module>
     </modules>
 </project>
diff --git a/database/protocol/dialect/firebird/pom.xml 
b/database/protocol/dialect/firebird/pom.xml
index 2b84ba05c4d..98765c6fd80 100644
--- a/database/protocol/dialect/firebird/pom.xml
+++ b/database/protocol/dialect/firebird/pom.xml
@@ -42,6 +42,11 @@
             <artifactId>shardingsphere-database-exception-core</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-database-exception-firebird</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         
         <dependency>
             <groupId>org.firebirdsql.jdbc</groupId>
diff --git 
a/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/err/FirebirdStatusVector.java
 
b/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/err/FirebirdStatusVector.java
index 2ef6c55093a..a443e201fa3 100644
--- 
a/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/err/FirebirdStatusVector.java
+++ 
b/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/err/FirebirdStatusVector.java
@@ -36,7 +36,7 @@ public final class FirebirdStatusVector extends 
FirebirdPacket {
     
     public FirebirdStatusVector(final SQLException ex) {
         gdsCode = ex.getErrorCode() >= ISCConstants.isc_arith_except ? 
ex.getErrorCode() : ISCConstants.isc_random;
-        String rawMessage = ex.getMessage();
+        String rawMessage = null == ex.getMessage() ? "" : ex.getMessage();
         int idx = rawMessage.indexOf(';');
         String message = idx >= 0 ? rawMessage.substring(idx + 1).trim() : 
rawMessage;
         int stateIdx = message.indexOf(" [SQLState:");
@@ -50,8 +50,10 @@ public final class FirebirdStatusVector extends 
FirebirdPacket {
     protected void write(final FirebirdPacketPayload payload) {
         payload.writeInt4(ISCConstants.isc_arg_gds);
         payload.writeInt4(gdsCode);
-        payload.writeInt4(ISCConstants.isc_arg_string);
-        payload.writeString(errorMessage);
+        if (!errorMessage.isEmpty()) {
+            payload.writeInt4(ISCConstants.isc_arg_string);
+            payload.writeString(errorMessage);
+        }
         payload.writeInt4(ISCConstants.isc_arg_end);
     }
 }
diff --git 
a/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/err/FirebirdStatusVectorTest.java
 
b/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/err/FirebirdStatusVectorTest.java
index 9760e664082..82aaa361496 100644
--- 
a/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/err/FirebirdStatusVectorTest.java
+++ 
b/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/err/FirebirdStatusVectorTest.java
@@ -54,6 +54,31 @@ class FirebirdStatusVectorTest {
         verifyNoMoreInteractions(payload);
     }
     
+    @Test
+    void assertWriteOmitsArgumentWhenMessageIsEmpty() {
+        SQLException emptyMessage = new SQLException("", "28000", 
ISCConstants.isc_login);
+        FirebirdStatusVector vector = new FirebirdStatusVector(emptyMessage);
+        vector.write(payload);
+        InOrder inOrder = inOrder(payload);
+        inOrder.verify(payload).writeInt4(ISCConstants.isc_arg_gds);
+        inOrder.verify(payload).writeInt4(ISCConstants.isc_login);
+        inOrder.verify(payload).writeInt4(ISCConstants.isc_arg_end);
+        verifyNoMoreInteractions(payload);
+    }
+    
+    @Test
+    void assertWriteWithNullMessage() {
+        SQLException nullMessage = new SQLException(null, "28000", 
ISCConstants.isc_login);
+        FirebirdStatusVector vector = new FirebirdStatusVector(nullMessage);
+        assertThat(vector.getErrorMessage(), is(""));
+        vector.write(payload);
+        InOrder inOrder = inOrder(payload);
+        inOrder.verify(payload).writeInt4(ISCConstants.isc_arg_gds);
+        inOrder.verify(payload).writeInt4(ISCConstants.isc_login);
+        inOrder.verify(payload).writeInt4(ISCConstants.isc_arg_end);
+        verifyNoMoreInteractions(payload);
+    }
+    
     @Test
     void assertWriteUsesRandomCodeWhenErrorCodeIsLowerThanArithExcept() {
         SQLException plainMessage = new SQLException("plain", "00000", 
ISCConstants.isc_arith_except - 1);
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngine.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngine.java
index cbd172e794f..8357a139d9c 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngine.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngine.java
@@ -17,7 +17,6 @@
 
 package org.apache.shardingsphere.proxy.frontend.firebird.authentication;
 
-import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import io.netty.channel.ChannelHandlerContext;
 import org.apache.shardingsphere.authentication.AuthenticatorFactory;
@@ -25,6 +24,7 @@ import 
org.apache.shardingsphere.authentication.AuthenticatorType;
 import org.apache.shardingsphere.authentication.result.AuthenticationResult;
 import 
org.apache.shardingsphere.authentication.result.AuthenticationResultBuilder;
 import org.apache.shardingsphere.authority.rule.AuthorityRule;
+import 
org.apache.shardingsphere.database.exception.core.exception.connection.AccessDeniedException;
 import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
 import org.apache.shardingsphere.database.protocol.constant.CommonConstants;
 import 
org.apache.shardingsphere.database.protocol.firebird.constant.FirebirdAuthenticationMethod;
@@ -109,9 +109,10 @@ public final class FirebirdAuthenticationEngine implements 
AuthenticationEngine
                 Strings.isNullOrEmpty(databaseName) || 
ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().containsDatabase(databaseName),
                 () -> new UnknownDatabaseException(databaseName));
         Grantee grantee = new Grantee(username, "");
-        Optional<ShardingSphereUser> user = rule.findUser(grantee);
-        user.ifPresent(shardingSphereUser -> new 
AuthenticatorFactory<>(FirebirdAuthenticatorType.class, rule)
-                
.newInstance(shardingSphereUser).authenticate(shardingSphereUser, new 
Object[]{attachPacket.getEncPassword(), authData, attachPacket.getAuthData()}));
+        ShardingSphereUser user = rule.findUser(grantee).orElseThrow(() -> new 
AccessDeniedException(username, "", true));
+        boolean authenticated = new 
AuthenticatorFactory<>(FirebirdAuthenticatorType.class, rule)
+                .newInstance(user).authenticate(user, new 
Object[]{attachPacket.getEncPassword(), authData, attachPacket.getAuthData()});
+        ShardingSpherePreconditions.checkState(authenticated, () -> new 
AccessDeniedException(username, "", true));
     }
     
     private AuthenticationResult processConnect(final ChannelHandlerContext 
context, final FirebirdPacketPayload payload, final AuthorityRule rule) {
@@ -123,7 +124,7 @@ public final class FirebirdAuthenticationEngine implements 
AuthenticationEngine
         String username = connectPacket.getLogin();
         Grantee grantee = new Grantee(username, "");
         Optional<ShardingSphereUser> user = rule.findUser(grantee);
-        Preconditions.checkState(user.isPresent());
+        ShardingSpherePreconditions.checkState(user.isPresent(), () -> new 
AccessDeniedException(username, connectPacket.getHost(), true));
         FirebirdAuthenticationMethod plugin = 
FirebirdAuthenticationMethod.valueOf(getPluginName(rule, user.get()));
         FirebirdAuthenticationMethod userPlugin = connectPacket.getPlugin();
         if (plugin != userPlugin) {
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngineTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngineTest.java
index e72fcbcdee4..25356587f5b 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngineTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngineTest.java
@@ -24,6 +24,7 @@ import 
org.apache.shardingsphere.authentication.AuthenticatorFactory;
 import org.apache.shardingsphere.authentication.result.AuthenticationResult;
 import 
org.apache.shardingsphere.authentication.result.AuthenticationResultBuilder;
 import org.apache.shardingsphere.authority.rule.AuthorityRule;
+import 
org.apache.shardingsphere.database.exception.core.exception.connection.AccessDeniedException;
 import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
 import org.apache.shardingsphere.database.protocol.constant.CommonConstants;
 import 
org.apache.shardingsphere.database.protocol.firebird.constant.FirebirdAuthenticationMethod;
@@ -231,6 +232,7 @@ class FirebirdAuthenticationEngineTest {
         
Plugins.getMemberAccessor().set(FirebirdAuthenticationEngine.class.getDeclaredField("authData"),
 authenticationEngine, authData);
         FirebirdPacketPayload payload = 
mockFirebirdPayload(FirebirdCommandPacketType.ATTACH);
         FirebirdAuthenticator authenticator = 
mock(FirebirdAuthenticator.class);
+        lenient().when(authenticator.authenticate(any(), 
any())).thenReturn(true);
         if (expectException) {
             try (MockedConstruction<FirebirdAttachPacket> ignored = 
mockConstruction(FirebirdAttachPacket.class, (attachPacket, construction) -> {
                 when(attachPacket.getEncoding()).thenReturn(encoding);
@@ -266,6 +268,72 @@ class FirebirdAuthenticationEngineTest {
         }
     }
     
+    @Test
+    void assertAuthenticateConnectWithUnknownUser() {
+        AuthorityRule rule = mock(AuthorityRule.class);
+        when(rule.findUser(any(Grantee.class))).thenReturn(Optional.empty());
+        mockProxyContext(rule, true);
+        Attribute<Charset> charsetAttr = mock(Attribute.class);
+        Attribute<FirebirdProtocolVersion> protocolVersionAttr = 
mock(Attribute.class);
+        
when(context.channel().attr(CommonConstants.CHARSET_ATTRIBUTE_KEY)).thenReturn(charsetAttr);
+        
when(context.channel().attr(FirebirdConstant.CONNECTION_PROTOCOL_VERSION)).thenReturn(protocolVersionAttr);
+        FirebirdProtocol protocol = mock(FirebirdProtocol.class);
+        
when(protocol.getVersion()).thenReturn(FirebirdProtocolVersion.PROTOCOL_VERSION10);
+        List<FirebirdProtocol> userProtocols = new 
ArrayList<>(Collections.singletonList(protocol));
+        FirebirdPacketPayload payload = 
mockFirebirdPayload(FirebirdCommandPacketType.CONNECT);
+        try (MockedConstruction<FirebirdConnectPacket> ignored = 
mockConstruction(FirebirdConnectPacket.class, (mockConnect, construction) -> {
+            when(mockConnect.getUserProtocols()).thenReturn(userProtocols);
+            when(mockConnect.getLogin()).thenReturn("absent");
+            when(mockConnect.getHost()).thenReturn("host");
+        })) {
+            assertThrows(AccessDeniedException.class, () -> 
authenticationEngine.authenticate(context, payload));
+        }
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    @Test
+    void assertAuthenticateAttachWithUnknownUser() {
+        AuthorityRule rule = mock(AuthorityRule.class);
+        when(rule.findUser(any(Grantee.class))).thenReturn(Optional.empty());
+        mockProxyContext(rule, true);
+        Attribute<Charset> charsetAttr = mock(Attribute.class);
+        
when(context.channel().attr(CommonConstants.CHARSET_ATTRIBUTE_KEY)).thenReturn(charsetAttr);
+        
Plugins.getMemberAccessor().set(FirebirdAuthenticationEngine.class.getDeclaredField("currentAuthResult"),
 authenticationEngine,
+                AuthenticationResultBuilder.continued("absent", "", "db"));
+        FirebirdPacketPayload payload = 
mockFirebirdPayload(FirebirdCommandPacketType.ATTACH);
+        try (MockedConstruction<FirebirdAttachPacket> ignored = 
mockConstruction(FirebirdAttachPacket.class, (attachPacket, construction) -> 
when(attachPacket.getEncoding()).thenReturn("UTF8"))) {
+            assertThrows(AccessDeniedException.class, () -> 
authenticationEngine.authenticate(context, payload));
+        }
+    }
+    
+    @SuppressWarnings("rawtypes")
+    @SneakyThrows(ReflectiveOperationException.class)
+    @Test
+    void assertAuthenticateAttachWithWrongPassword() {
+        AuthorityRule rule = mock(AuthorityRule.class);
+        ShardingSphereUser user = new ShardingSphereUser("root", "pwd", "");
+        when(rule.findUser(any(Grantee.class))).thenReturn(Optional.of(user));
+        mockProxyContext(rule, true);
+        Attribute<Charset> charsetAttr = mock(Attribute.class);
+        
when(context.channel().attr(CommonConstants.CHARSET_ATTRIBUTE_KEY)).thenReturn(charsetAttr);
+        
Plugins.getMemberAccessor().set(FirebirdAuthenticationEngine.class.getDeclaredField("currentAuthResult"),
 authenticationEngine,
+                AuthenticationResultBuilder.continued("root", "", "db"));
+        FirebirdSRPAuthenticationData authData = 
mock(FirebirdSRPAuthenticationData.class);
+        
Plugins.getMemberAccessor().set(FirebirdAuthenticationEngine.class.getDeclaredField("authData"),
 authenticationEngine, authData);
+        FirebirdAuthenticator authenticator = 
mock(FirebirdAuthenticator.class);
+        when(authenticator.authenticate(any(), any())).thenReturn(false);
+        FirebirdPacketPayload payload = 
mockFirebirdPayload(FirebirdCommandPacketType.ATTACH);
+        try (MockedConstruction<FirebirdAttachPacket> ignoredPacket = 
mockConstruction(FirebirdAttachPacket.class, (attachPacket, construction) -> {
+            when(attachPacket.getEncoding()).thenReturn("UTF8");
+            when(attachPacket.getEncPassword()).thenReturn("cipher_pwd");
+            when(attachPacket.getAuthData()).thenReturn("client_auth");
+        });
+                MockedConstruction<AuthenticatorFactory> ignoredFactory = 
mockConstruction(AuthenticatorFactory.class,
+                        (factory, construction) -> 
when(factory.newInstance(user)).thenReturn(authenticator))) {
+            assertThrows(AccessDeniedException.class, () -> 
authenticationEngine.authenticate(context, payload));
+        }
+    }
+    
     private FirebirdPacketPayload mockFirebirdPayload(final 
FirebirdCommandPacketType commandPacketType) {
         FirebirdPacketPayload result = mock(FirebirdPacketPayload.class, 
RETURNS_DEEP_STUBS);
         when(result.readInt4()).thenReturn(commandPacketType.getValue());
@@ -294,8 +362,7 @@ class FirebirdAuthenticationEngineTest {
     private static Stream<Arguments> attachArguments() {
         return Stream.of(
                 Arguments.of("attachWithUser", true, new 
ShardingSphereUser("root", "pwd", ""), "root", "db", "UTF8", false, true, true, 
"db", "root", "cipher_pwd", "client_auth"),
-                Arguments.of("attachWithoutUser", true, null, "absent", "db", 
"NONE", false, false, true, "db", "absent", null, null),
                 Arguments.of("attachUnknownDatabase", false, new 
ShardingSphereUser("root", "pwd", ""), "root", "missing_db", "UTF8", true, 
false, false, "", "root", null, null),
-                Arguments.of("attachEmptyDatabase", false, null, "root", "", 
"NONE", false, false, true, "", "root", null, null));
+                Arguments.of("attachEmptyDatabase", false, new 
ShardingSphereUser("root", "pwd", ""), "root", "", "NONE", false, true, true, 
"", "root", "cipher_pwd", "client_auth"));
     }
 }
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/err/FirebirdErrorPacketFactoryTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/err/FirebirdErrorPacketFactoryTest.java
index 741345b8c47..5bf1fae1753 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/err/FirebirdErrorPacketFactoryTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/err/FirebirdErrorPacketFactoryTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.proxy.frontend.firebird.err;
 
+import 
org.apache.shardingsphere.database.exception.core.exception.connection.AccessDeniedException;
+import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdGenericResponsePacket;
 import org.junit.jupiter.api.Test;
 
@@ -41,6 +43,20 @@ class FirebirdErrorPacketFactoryTest {
         assertThat(actual.getErrorMessage(), is("Table not found"));
     }
     
+    @Test
+    void assertNewInstanceWithUnknownDatabaseException() {
+        FirebirdGenericResponsePacket actual = (FirebirdGenericResponsePacket) 
FirebirdErrorPacketFactory.newInstance(new 
UnknownDatabaseException("logic_db"));
+        assertThat(actual.getErrorCode(), is(335544375));
+        assertThat(actual.getErrorMessage(), is("logic_db"));
+    }
+    
+    @Test
+    void assertNewInstanceWithAccessDeniedException() {
+        FirebirdGenericResponsePacket actual = (FirebirdGenericResponsePacket) 
FirebirdErrorPacketFactory.newInstance(new AccessDeniedException("root", 
"127.0.0.1", true));
+        assertThat(actual.getErrorCode(), is(335544472));
+        assertThat(actual.getErrorMessage(), is(""));
+    }
+    
     @Test
     void assertNewInstanceWithNonFirebirdErrorCode() {
         FirebirdGenericResponsePacket actual = (FirebirdGenericResponsePacket) 
FirebirdErrorPacketFactory.newInstance(new SQLException("Invalid error", 
"HY000", 123));


Reply via email to