Fix another non-serializable exception, add docs, fix a possible security issue. (#2707)

* Fix another non-serializable exception, add docs, fix a possible security issue.

* Update API definition to reflect methods added to make more exceptions serializable
This commit is contained in:
Mike Hearn 2018-03-02 15:10:54 +01:00 committed by GitHub
parent 799d90b350
commit 80c00b920b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 14 deletions

View File

@ -563,15 +563,20 @@ public final class net.corda.core.contracts.TransactionStateKt extends java.lang
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$ConflictingAttachmentsRejection extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash, String)
@org.jetbrains.annotations.NotNull public final String getContractClass()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$ContractConstraintRejection extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash, String)
@org.jetbrains.annotations.NotNull public final String getContractClass()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$ContractCreationError extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash, String, Throwable)
@org.jetbrains.annotations.NotNull public final String getContractClass()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$ContractRejection extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash, String, Throwable)
public <init>(net.corda.core.crypto.SecureHash, net.corda.core.contracts.Contract, Throwable)
@org.jetbrains.annotations.NotNull public final String getContractClass()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$Direction extends java.lang.Enum
protected <init>(String, int)
@ -594,12 +599,17 @@ public final class net.corda.core.contracts.TransactionStateKt extends java.lang
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$NotaryChangeInWrongTransactionType extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.identity.Party)
@org.jetbrains.annotations.NotNull public final net.corda.core.identity.Party getOutputNotary()
@org.jetbrains.annotations.NotNull public final net.corda.core.identity.Party getTxNotary()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$SignersMissing extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash, List)
@org.jetbrains.annotations.NotNull public final List getMissing()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.contracts.TransactionVerificationException$TransactionMissingEncumbranceException extends net.corda.core.contracts.TransactionVerificationException
public <init>(net.corda.core.crypto.SecureHash, int, net.corda.core.contracts.TransactionVerificationException$Direction)
@org.jetbrains.annotations.NotNull public final net.corda.core.contracts.TransactionVerificationException$Direction getInOut()
public final int getMissing()
##
@net.corda.core.serialization.CordaSerializable public abstract class net.corda.core.contracts.TypeOnlyCommandData extends java.lang.Object implements net.corda.core.contracts.CommandData
public <init>()
@ -1327,6 +1337,8 @@ public static final class net.corda.core.flows.FlowStackSnapshot$Frame extends j
##
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.flows.IllegalFlowLogicException extends java.lang.IllegalArgumentException
public <init>(Class, String)
public <init>(String, String)
@org.jetbrains.annotations.NotNull public final String getType()
##
public @interface net.corda.core.flows.InitiatedBy
public abstract Class value()

View File

@ -6,6 +6,6 @@ package net.corda.core
* These fields are only meant to be used by Corda internally, and are not intended to be part of the public API.
*/
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Target(AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FUNCTION)
@MustBeDocumented
annotation class CordaInternal

View File

@ -1,10 +1,12 @@
package net.corda.core.flows
import net.corda.core.CordaInternal
import net.corda.core.DoNotImplement
import net.corda.core.serialization.CordaSerializable
/**
* The public factory interface for creating validated FlowLogicRef instances as part of the scheduling framework.
* The public factory interface for creating validated [FlowLogicRef] instances as part of the scheduling framework.
*
* Typically this would be used from within the nextScheduledActivity method of a QueryableState to specify
* the flow to run at the scheduled time.
*/
@ -14,20 +16,40 @@ interface FlowLogicRefFactory {
* Construct a FlowLogicRef. This is intended for cases where the calling code has the relevant class already
* and can provide it directly.
*/
@Deprecated("This should be avoided, and the version which takes a class name used instead to avoid requiring the class on the classpath to deserialize calling code")
fun create(flowClass: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef
/**
* Construct a FlowLogicRef. This is intended for cases where the calling code does not want to require the flow
* class on the classpath for all cases where the calling code is loaded.
*/
fun create(flowClassName: String, vararg args: Any?): FlowLogicRef
/**
* @suppress
* This is an internal method and should not be used: use [create] instead, which checks for the
* [SchedulableFlow] annotation.
*/
@CordaInternal
fun createForRPC(flowClass: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef
/**
* Converts a [FlowLogicRef] object that was obtained from the calls above into a [FlowLogic], after doing some
* validation to ensure it points to a legitimate flow class.
*/
fun toFlowLogic(ref: FlowLogicRef): FlowLogic<*>
}
/**
* Thrown if the structure of a class implementing a flow is not correct. There can be several causes for this such as
* not inheriting from [FlowLogic], not having a valid constructor and so on.
*
* @property type the fully qualified name of the class that failed checks.
*/
@CordaSerializable
class IllegalFlowLogicException(type: Class<*>, msg: String) : IllegalArgumentException(
"${FlowLogicRef::class.java.simpleName} cannot be constructed for ${FlowLogic::class.java.simpleName} of type ${type.name} $msg")
class IllegalFlowLogicException(val type: String, msg: String) :
IllegalArgumentException("A FlowLogicRef cannot be constructed for FlowLogic of type $type: $msg") {
constructor(type: Class<*>, msg: String) : this(type.name, msg)
}
/**
* A handle interface representing a [FlowLogic] instance which would be possible to safely pass out of the contract sandbox.

View File

@ -41,15 +41,21 @@ class FlowLogicRefFactoryImpl(private val classloader: ClassLoader) : SingletonS
}
override fun create(flowClassName: String, vararg args: Any?): FlowLogicRef {
val flowClass = Class.forName(flowClassName, true, classloader).asSubclass(FlowLogic::class.java)
if (flowClass == null) {
throw IllegalArgumentException("The class $flowClassName is not a subclass of FlowLogic.")
} else {
if (!flowClass.isAnnotationPresent(SchedulableFlow::class.java)) {
throw IllegalFlowLogicException(flowClass, "because it's not a schedulable flow")
}
return createForRPC(flowClass, *args)
val flowClass = validatedFlowClassFromName(flowClassName)
if (!flowClass.isAnnotationPresent(SchedulableFlow::class.java)) {
throw IllegalFlowLogicException(flowClass, "because it's not a schedulable flow")
}
return createForRPC(flowClass, *args)
}
private fun validatedFlowClassFromName(flowClassName: String): Class<out FlowLogic<*>> {
val forName = try {
Class.forName(flowClassName, true, classloader)
} catch (e: ClassNotFoundException) {
throw IllegalFlowLogicException(flowClassName, "Flow not found: $flowClassName")
}
return forName.asSubclass(FlowLogic::class.java) ?:
throw IllegalFlowLogicException(flowClassName, "The class $flowClassName is not a subclass of FlowLogic.")
}
override fun createForRPC(flowClass: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef {
@ -93,7 +99,9 @@ class FlowLogicRefFactoryImpl(private val classloader: ClassLoader) : SingletonS
override fun toFlowLogic(ref: FlowLogicRef): FlowLogic<*> {
if (ref !is FlowLogicRefImpl) throw IllegalFlowLogicException(ref.javaClass, "FlowLogicRef was not created via correct FlowLogicRefFactory interface")
val klass = Class.forName(ref.flowLogicClassName, true, classloader).asSubclass(FlowLogic::class.java)
// We re-validate here because a FlowLogicRefImpl could have arrived via deserialization and therefore the
// class name could point to anything at all.
val klass = validatedFlowClassFromName(ref.flowLogicClassName)
return createConstructor(klass, ref.args)()
}