diff --git a/node/src/integration-test/kotlin/net/corda/node/flows/FlowWithClientIdTest.kt b/node/src/integration-test/kotlin/net/corda/node/flows/FlowWithClientIdTest.kt index 17b4f36320..7e80b7d9a5 100644 --- a/node/src/integration-test/kotlin/net/corda/node/flows/FlowWithClientIdTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/flows/FlowWithClientIdTest.kt @@ -61,6 +61,38 @@ class FlowWithClientIdTest { } } + @Test(timeout = 300_000) + fun `start flow with client id permissions`() { + val user = User("TonyStark", "I AM IRONMAN", setOf("StartFlow.net.corda.node.flows.FlowWithClientIdTest\$ResultFlow")) + driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = emptySet())) { + val nodeA = startNode(rpcUsers = listOf(user)).getOrThrow() + nodeA.rpc.startFlowWithClientId(UUID.randomUUID().toString(), ::ResultFlow, 5).returnValue.getOrThrow(20.seconds) + nodeA.rpc.startFlowDynamicWithClientId( + UUID.randomUUID().toString(), + ResultFlow::class.java, + 5 + ).returnValue.getOrThrow(20.seconds) + } + } + + @Test(timeout = 300_000) + fun `start flow with client id without permissions`() { + val user = User("TonyStark", "I AM IRONMAN", setOf()) + driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = emptySet())) { + val nodeA = startNode(rpcUsers = listOf(user)).getOrThrow() + assertFailsWith { + nodeA.rpc.startFlowWithClientId(UUID.randomUUID().toString(), ::ResultFlow, 5).returnValue.getOrThrow(20.seconds) + } + assertFailsWith { + nodeA.rpc.startFlowDynamicWithClientId( + UUID.randomUUID().toString(), + ResultFlow::class.java, + 5 + ).returnValue.getOrThrow(20.seconds) + } + } + } + @Test(timeout = 300_000) fun `remove client id`() { val clientId = UUID.randomUUID().toString() diff --git a/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/AuthenticatedRpcOpsProxy.kt b/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/AuthenticatedRpcOpsProxy.kt index 1e0caa50a2..fcf8793779 100644 --- a/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/AuthenticatedRpcOpsProxy.kt +++ b/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/AuthenticatedRpcOpsProxy.kt @@ -5,6 +5,7 @@ import net.corda.core.flows.FlowLogic import net.corda.core.internal.messaging.InternalCordaRPCOps import net.corda.core.messaging.CordaRPCOps import net.corda.core.internal.utilities.InvocationHandlerTemplate +import net.corda.core.messaging.FlowHandleWithClientId import net.corda.node.services.rpc.RpcAuthContext import net.corda.node.services.rpc.rpcContext import java.lang.reflect.Method @@ -32,6 +33,16 @@ internal class AuthenticatedRpcOpsProxy(private val delegate: InternalCordaRPCOp delegate.startTrackedFlowDynamic(logicType, *args) } + // Need overriding to pass additional `listOf(logicType)` argument for polymorphic `startFlow` permissions. + @Suppress("SpreadOperator") + override fun startFlowDynamicWithClientId( + clientId: String, + logicType: Class>, + vararg args: Any? + ): FlowHandleWithClientId = guard("startFlowDynamic", listOf(logicType), ::rpcContext) { + delegate.startFlowDynamicWithClientId(clientId, logicType, *args) + } + private companion object { private fun proxy(delegate: InternalCordaRPCOps, context: () -> RpcAuthContext): InternalCordaRPCOps { val handler = PermissionsEnforcingInvocationHandler(delegate, context)