feat: Signature-InputとSignatureヘッダーのパースができるように
This commit is contained in:
parent
ebe864fd10
commit
87e40bead2
|
@ -11,6 +11,7 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.greenbytes.http:structured-fields:0.4")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.8.1")
|
||||
testImplementation("org.mockito:mockito-inline:5.2.0")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package dev.usbharu.httpsignature.v2
|
||||
|
||||
import org.greenbytes.http.sfv.*
|
||||
|
||||
class DefaultHttpSignatureHeaderParser() : HttpSignatureHeaderParser {
|
||||
override fun parse(signatureInputs: List<String>, signatures: List<String>): Map<String, Signature> {
|
||||
val signatureInputString = signatureInputs.joinToString(", ")
|
||||
|
||||
val signatureString = signatures.joinToString(", ")
|
||||
|
||||
val parseSignatureInputs = parseSignatureInputs(signatureInputString)
|
||||
|
||||
val parseSignatures = parseSignatures(signatureString)
|
||||
|
||||
require(parseSignatureInputs.size == parseSignatures.size)
|
||||
|
||||
return parseSignatureInputs.map {
|
||||
val signatureInput = parseSignatureInputs.getValue(it.key)
|
||||
it.key to Signature(
|
||||
it.key,
|
||||
signatureInput.first,
|
||||
parseSignatures.getValue(it.key),
|
||||
signatureInput.third,
|
||||
signatureInput.second
|
||||
)
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
private fun parseSignatureInputs(signatureInput: String): Map<String, Triple<String, List<String>, List<SignatureParameter>>> {
|
||||
val parser = Parser(signatureInput)
|
||||
val map = parser.parseDictionary()
|
||||
.get()
|
||||
.mapValues {
|
||||
val innerList = it.value as InnerList
|
||||
Triple(
|
||||
it.value.serialize(),
|
||||
innerList.get().map { it.get().toString() },
|
||||
innerList.params.map { param ->
|
||||
when (val value = param.value) {
|
||||
is IntegerItem -> LongSignatureParameter(param.key, value.asLong)
|
||||
is NumberItem -> LongSignatureParameter(param.key, value.asLong)
|
||||
is StringItem -> StringSignatureParameter(param.key, value.get())
|
||||
else -> error("Unknown parameter: $param")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
|
||||
private fun parseSignatures(signature: String): Map<String, String> {
|
||||
val parser = Parser(signature)
|
||||
val map = parser.parseDictionary().get()
|
||||
|
||||
return map.map { it.key to it.value.get().toString() }.toMap()
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package dev.usbharu.httpsignature.v2
|
||||
|
||||
class HttpMessageSignatureSigner {
|
||||
fun sign(material: Material, signatureParameters: List<SignatureParameter>, signer: SignatureSigner): Signatures {
|
||||
fun sign(material: Material, signatureParameters: List<SignatureParameter>, signer: SignatureSigner): Signature {
|
||||
|
||||
val signatureBase = material.signatureBase.generateSignatureBase(signatureParameters)
|
||||
val signatureInput =
|
||||
|
@ -9,6 +9,12 @@ class HttpMessageSignatureSigner {
|
|||
|
||||
val signature = signer.sign(signatureBase.toByteArray(Charsets.UTF_8), material.privateKey)
|
||||
|
||||
return Signatures(signatureInput, signature)
|
||||
return Signature(
|
||||
material.label,
|
||||
signatureInput,
|
||||
signature,
|
||||
signatureParameters,
|
||||
material.signatureBase.coveredComponents()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package dev.usbharu.httpsignature.v2
|
||||
|
||||
interface HttpSignatureHeaderParser {
|
||||
fun parse(signatureInputs: List<String>, signatures: List<String>): Map<String, Signature>
|
||||
}
|
|
@ -2,7 +2,7 @@ package dev.usbharu.httpsignature.v2
|
|||
|
||||
import java.time.Instant
|
||||
|
||||
class InstantSignatureParameter(private val instantName: String, val instant: Instant) : SignatureParameter {
|
||||
data class InstantSignatureParameter(private val instantName: String, val instant: Instant) : SignatureParameter {
|
||||
override val name: String
|
||||
get() = instantName
|
||||
override val value: String
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package dev.usbharu.httpsignature.v2
|
||||
|
||||
data class LongSignatureParameter(val longName: String, val longValue: Long) : SignatureParameter {
|
||||
override val name: String
|
||||
get() = longName
|
||||
override val value: String
|
||||
get() = longValue.toString()
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package dev.usbharu.httpsignature.v2
|
||||
|
||||
data class Signature(
|
||||
val label: String,
|
||||
val signatureInput: String,
|
||||
val signature: String,
|
||||
val signatureParameters: List<SignatureParameter>,
|
||||
val coveredComponents: List<String>
|
||||
)
|
|
@ -32,4 +32,8 @@ class SignatureBase() {
|
|||
)
|
||||
) + signatureParameters.map { "${it.name}=${it.value}" }).joinToString(";")
|
||||
}
|
||||
|
||||
fun coveredComponents(): List<String> {
|
||||
return list.map { it.key }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package dev.usbharu.httpsignature.v2
|
||||
|
||||
data class Signatures(
|
||||
val signatureInput: String,
|
||||
val signature: String
|
||||
)
|
|
@ -1,6 +1,7 @@
|
|||
package dev.usbharu.httpsignature.v2
|
||||
|
||||
class StringSignatureParameter(private val stringName: String, private val stringValue: String) : SignatureParameter {
|
||||
data class StringSignatureParameter(private val stringName: String, private val stringValue: String) :
|
||||
SignatureParameter {
|
||||
override val name: String
|
||||
get() = stringName
|
||||
override val value: String
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package dev.usbharu.httpsignature.v2
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class DefaultHttpSignatureHeaderParserTest {
|
||||
@Test
|
||||
fun name() {
|
||||
val defaultHttpSignatureHeaderParser = DefaultHttpSignatureHeaderParser()
|
||||
defaultHttpSignatureHeaderParser.parse(
|
||||
listOf(
|
||||
"sig1=(\"@method\" \"@target-uri\" \"@authority\" " +
|
||||
" \"content-digest\" \"cache-control\");" +
|
||||
" created=1618884475;keyid=\"test-key-rsa-pss\""
|
||||
), listOf()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test2() {
|
||||
val parse = DefaultHttpSignatureHeaderParser().parse(
|
||||
listOf(
|
||||
"sig1=(\"@method\" \"@authority\" \"@path\" " +
|
||||
"\"content-digest\" \"content-type\" \"content-length\")" +
|
||||
";created=1618884475;keyid=\"test-key-ecc-p256\", " +
|
||||
"proxy_sig=(\"@method\" \"@authority\" \"@path\" \"content-digest\" " +
|
||||
"\"content-type\" \"content-length\" \"forwarded\")" +
|
||||
";created=1618884480;keyid=\"test-key-rsa\";alg=\"rsa-v1_5-sha256\"" +
|
||||
";expires=1618884540"
|
||||
), listOf(
|
||||
"sig1=:X5spyd6CFnAG5QnDyHfqoSNICd+BUP4LYMz2Q0JXlb//4Ijpzp" +
|
||||
"+kve2w4NIyqeAuM7jTDX+sNalzA8ESSaHD3A==:, " +
|
||||
"proxy_sig=:S6ZzPXSdAMOPjN/6KXfXWNO/f7V6cHm7BXYUh3YD/fRad4BCaRZxP+" +
|
||||
"JH+8XY1I6+8Cy+CM5g92iHgxtRPz+MjniOaYmdkDcnL9cCpXJleXsOckpURl49G" +
|
||||
"wiyUpZ10KHgOEe11sx3G2gxI8S0jnxQB+Pu68U9vVcasqOWAEObtNKKZd8tSFu7" +
|
||||
"LB5YAv0RAGhB8tmpv7sFnIm9y+7X5kXQfi8NMaZaA8i2ZHwpBdg7a6CMfwnnrtf" +
|
||||
"lzvZdXAsD3LH2TwevU+/PBPv0B6NMNk93wUs/vfJvye+YuI87HU38lZHowtznbL" +
|
||||
"Vdp770I6VHR6WfgS9ddzirrswsE1w5o0LV/g==:"
|
||||
)
|
||||
)
|
||||
|
||||
println(parse)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue