From e0eac8fa0de6a2a8b0dbda37dea70e5834f69df0 Mon Sep 17 00:00:00 2001 From: Ryan Fowler Date: Tue, 7 Jan 2020 11:35:45 +0000 Subject: [PATCH] Corda 3513 rpc flow without permission (#5828) * CORDA-3513: Don't try to reconnect for PermissionExceptions * CORDA-3513: Don't try to reconnect for PermissionExceptions * CORDA-3513: Add test for not reconnecting for PermissionExceptions * CORDA-3513: Update exception message and test --- .../rpc/internal/ReconnectingCordaRPCOps.kt | 13 ++++++++++--- .../net/corda/node/flows/FlowRetryTest.kt | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ReconnectingCordaRPCOps.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ReconnectingCordaRPCOps.kt index afe09497a7..9db2ef8600 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ReconnectingCordaRPCOps.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ReconnectingCordaRPCOps.kt @@ -303,9 +303,7 @@ class ReconnectingCordaRPCOps private constructor( * A negative number for [maxNumberOfAttempts] means an unlimited number of retries will be performed. */ private fun doInvoke(method: Method, args: Array?, maxNumberOfAttempts: Int): Any? { - if (reconnectingRPCConnection.isClosed()) { - throw RPCException("Cannot execute RPC command after client has shut down.") - } + checkIfClosed() var remainingAttempts = maxNumberOfAttempts var lastException: Throwable? = null while (remainingAttempts != 0) { @@ -331,6 +329,9 @@ class ReconnectingCordaRPCOps private constructor( Thread.sleep(1000) // TODO - explain why this sleep is necessary checkIfIsStartFlow(method, e) } + is PermissionException -> { + throw RPCException("User does not have permission to perform operation ${method.name}.", e) + } else -> { log.warn("Failed to perform operation ${method.name}. Unknown error. Retrying....", e) reconnectingRPCConnection.reconnectOnError(e) @@ -345,6 +346,12 @@ class ReconnectingCordaRPCOps private constructor( throw MaxRpcRetryException(maxNumberOfAttempts, lastException) } + private fun checkIfClosed() { + if (reconnectingRPCConnection.isClosed()) { + throw RPCException("Cannot execute RPC command after client has shut down.") + } + } + override fun invoke(proxy: Any, method: Method, args: Array?): Any? { return when (method.returnType) { DataFeed::class.java -> { diff --git a/node/src/integration-test/kotlin/net/corda/node/flows/FlowRetryTest.kt b/node/src/integration-test/kotlin/net/corda/node/flows/FlowRetryTest.kt index cfe19709c9..9a2a23a7f1 100644 --- a/node/src/integration-test/kotlin/net/corda/node/flows/FlowRetryTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/flows/FlowRetryTest.kt @@ -184,6 +184,23 @@ class FlowRetryTest { } } } + + @Test + fun `Permission exceptions are not retried and propagate`() { + val user = User("mark", "dadada", setOf()) + driver(DriverParameters(isDebug = true, startNodesInProcess = isQuasarAgentSpecified())) { + + val nodeAHandle = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() + + CordaRPCClient(nodeAHandle.rpcAddress).start(user.username, user.password).use { + assertThatExceptionOfType(CordaRuntimeException::class.java).isThrownBy { + it.proxy.startFlow(::AsyncRetryFlow).returnValue.getOrThrow() + }.withMessageStartingWith("User not authorized to perform RPC call") + // This stays at -1 since the flow never even got called + assertEquals(-1, GeneralExternalFailureFlow.retryCount) + } + } + } } fun isQuasarAgentSpecified(): Boolean {