:wave: hi, ya'll! i'm new to kotlin and spring; i ...
# spring
a
👋 hi, ya'll! i'm new to kotlin and spring; i have a REST controller that will be receiving webhooks. we want to validate these webhooks with a signature that gets sent over. we currently have a
@RequestBody body: MyDataClass
to get a deserialized object of the payload. but my problem is that i need to pass in the body as a String to validate the signature properly. Is there a proper way to handle this? or do i just update to
@RequestBody body: String
, then do validation, and finally do a manual
ObjectMapper
to
MyDataClass
?
t
How about an interceptor validating the signature, for example if the method has a certain annotation?
t
Copy code
import javax.validation.Valid
import javax.validation.ConstraintValidator
import javax.validation.ConstraintValidatorContext

class Controller {
  @PostMapping //or get, or whatever method your webhook uses
  fun webhook(@Valid @RequestBody body: MyDataClass)
}

class MyDataClass(
  @get:ValidSignature
  val signature: String
)

@Constraint(validatedBy = [ValidSignatureValidator::class])
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class ValidSignature(
  val message: String = "Some error message",
  val groups: Array<KClass<*>> = [],
  val payload: Array<KClass<*>> = []
)

class ValidSignatureValidator : ConstraintValidator<ValidSignature, String> {

  override fun isValid(value: String, context: ConstraintValidatorContext): Boolean =
    ...
this uses javax validation which I really really like since it gives you all violations at once (should have more) and automatically pinpoints the exact cause of the error. javax validation is a specification, so you need an implementation as well. usually I go with hibernate validator, but there are also kotlin ones which might be more idiomatic (but I never tried them). for instance in gradle
Copy code
implementation "org.hibernate.validator:hibernate-validator"
👓 3
if you are using spring boot all necessary beans are created automatically, I think
this would be a pretty bare bone implementation, you can do a lot more (like message with parameters, error translation, etc) but that requires more configuration ofc
a
hi, ya'll! thank you for the responses! 🙏
@thanksforallthefish: for your example, would it matter if i'm getting the signature in an HTTP header? currently getting it like so
@RequestHeader(value = "X-XYZCorp-Signature") signature: String,
also, love the slack handle! loved that book! 🐬
t
@ValidSignature @RequestHeader(value = "X-XYZCorp-Signature") signature: String,
should work in that case
maybe you would also
@Valid
and/or
Copy code
@Validated
class Controller
I am never sure there
a
i see. brilliant. let me give that a go 👍
k
I don't think this will solve your problem, if I understand it correctly
you have payload and some signature of this payload represented as string
and you need to hook before spring translates this string into object
to be able to verify signature
a
hello, jakub 👋 yes, that's a good summary of what i'd like to do. i'm new to kotlin + spring boot, but the recommendation here won't work?
yes, the signature is HmacSHA256 of payload + secret. that's correct. in case that helps clear up anything
k
well first, this is not really related to kotlin but spring, so probably you would get better info in springs gitter chat
secondly, I can't imagine how would javax.validation help in this context
so yeah either accept is as a string and do conversion manually after check
or I would look into filters/interceptors and hook some interceptor before messageconversion
a
I have solved this by requiring that the JSON fields be in a specific order You can do this by adding these two Jackson annotations to the
@RequestBody
Object: ``
Copy code
@JsonInclude(JsonInclude.Include.ALWAYS)
@JsonPropertyOrder("name", "type", "value")
Then you can simply convert the object to a JSON string, validate and dispose the String. This method also allows to you leave the
@Validated
annotation intact so that Spring can take care of that for you as well
k
but this would need to be honored by client too, right?
and formatting
t
javax validation also offers cross parameter validation, so it should be possible, but yeah, I did not understand the problem correctly
k
but parameters have to be on the same object, no?
a
got it, thank you all for the feedback! 🙏 i think for now, i will just accept the body as a String and manually convert.
i'm all ears though, if there is a better solution! 👍
t
@kqr no, there is https://www.baeldung.com/javax-validation-method-constraints#2-using-cross-parameter-constraints personally I find it relatively ugly, the validator receives an array and you access those positionally, but it is a possibility
k
thx TIL