mirror of https://github.com/usbharu/Hideout.git
feat: HTTP Signatureの署名器を実装
This commit is contained in:
parent
16d0b555f7
commit
8e611aaf4f
|
@ -0,0 +1,16 @@
|
|||
package dev.usbharu.hideout.service.signature
|
||||
|
||||
import io.ktor.http.*
|
||||
|
||||
interface HttpSignatureSigner {
|
||||
suspend fun sign(
|
||||
url: String,
|
||||
method: HttpMethod,
|
||||
headers: Headers,
|
||||
requestBody: String,
|
||||
keyPair: Key,
|
||||
signHeaders: List<String>
|
||||
): SignedRequest
|
||||
|
||||
suspend fun signRaw(signString: String, keyPair: Key, signHeaders: List<String>): Sign
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package dev.usbharu.hideout.service.signature
|
||||
|
||||
import dev.usbharu.hideout.util.Base64Util
|
||||
import io.ktor.http.*
|
||||
import io.ktor.util.*
|
||||
import org.springframework.stereotype.Component
|
||||
import java.net.URL
|
||||
import java.security.Signature
|
||||
|
||||
@Component
|
||||
class HttpSignatureSignerImpl : HttpSignatureSigner {
|
||||
override suspend fun sign(
|
||||
url: String,
|
||||
method: HttpMethod,
|
||||
headers: Headers,
|
||||
requestBody: String,
|
||||
keyPair: Key,
|
||||
signHeaders: List<String>
|
||||
): SignedRequest {
|
||||
val sign = signRaw(
|
||||
signString = buildSignString(
|
||||
url = URL(url),
|
||||
method = method,
|
||||
headers = headers,
|
||||
signHeaders = signHeaders
|
||||
),
|
||||
keyPair = keyPair,
|
||||
signHeaders = signHeaders
|
||||
)
|
||||
return SignedRequest(
|
||||
url = url,
|
||||
method = method,
|
||||
headers = headers,
|
||||
requestBody = requestBody,
|
||||
sign = sign
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun signRaw(signString: String, keyPair: Key, signHeaders: List<String>): Sign {
|
||||
val signer = Signature.getInstance("SHA256withRSA")
|
||||
signer.initSign(keyPair.privateKey)
|
||||
signer.update(signString.toByteArray())
|
||||
val sign = signer.sign()
|
||||
val signature = Base64Util.encode(sign)
|
||||
return Sign(
|
||||
signature,
|
||||
"""keyId="${keyPair.keyId}",algorithm="${signHeaders.joinToString(" ")}",signature="$signature""""
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildSignString(
|
||||
url: URL,
|
||||
method: HttpMethod,
|
||||
headers: Headers,
|
||||
signHeaders: List<String>
|
||||
): String {
|
||||
headers.toMap().map { it.key.lowercase() to it.value }.toMap()
|
||||
val result = signHeaders.map {
|
||||
if (it.startsWith("(")) {
|
||||
specialHeader(it, url, method)
|
||||
} else {
|
||||
generalHeader(it, headers.get(it)!!)
|
||||
}
|
||||
}.joinToString("\n")
|
||||
return result
|
||||
}
|
||||
|
||||
private fun specialHeader(fieldName: String, url: URL, method: HttpMethod): String {
|
||||
if (fieldName != "(request-target)") {
|
||||
throw IllegalArgumentException(fieldName + "is unsupported type")
|
||||
}
|
||||
return "(request-target): ${method.value.lowercase()} ${url.path}"
|
||||
}
|
||||
|
||||
private fun generalHeader(fieldName: String, value: String): String {
|
||||
return "$fieldName: $value"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package dev.usbharu.hideout.service.signature
|
||||
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
|
||||
data class Key(
|
||||
val keyId: String,
|
||||
val privateKey: PrivateKey,
|
||||
val publicKey: PublicKey
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
package dev.usbharu.hideout.service.signature
|
||||
|
||||
data class Sign(
|
||||
val signature: String,
|
||||
val signatureHeader: String
|
||||
)
|
|
@ -0,0 +1,23 @@
|
|||
package dev.usbharu.hideout.service.signature
|
||||
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.http.*
|
||||
|
||||
data class SignedRequest(
|
||||
val url: String,
|
||||
val method: HttpMethod,
|
||||
val headers: Headers,
|
||||
val requestBody: String,
|
||||
val sign: Sign
|
||||
) {
|
||||
fun toRequestBuilder(): HttpRequestBuilder {
|
||||
val httpRequestBuilder = HttpRequestBuilder()
|
||||
httpRequestBuilder.url(this.url)
|
||||
httpRequestBuilder.method = this.method
|
||||
httpRequestBuilder.headers {
|
||||
this.appendAll(headers)
|
||||
}
|
||||
httpRequestBuilder.setBody(requestBody)
|
||||
return httpRequestBuilder
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue