mirror of https://github.com/usbharu/Hideout.git
feat: 自動で鍵を作成するように
This commit is contained in:
parent
f0383e3a95
commit
aebf0862e0
|
@ -0,0 +1,5 @@
|
||||||
|
package dev.usbharu.hideout.domain.model.hideout.entity
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
data class Jwt(val kid: UUID, val privateKey: String, val publicKey: String)
|
|
@ -7,7 +7,10 @@ import com.auth0.jwt.JWT
|
||||||
import com.auth0.jwt.algorithms.Algorithm
|
import com.auth0.jwt.algorithms.Algorithm
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
||||||
import dev.usbharu.hideout.property
|
import dev.usbharu.hideout.property
|
||||||
|
import dev.usbharu.hideout.repository.IMetaRepository
|
||||||
import dev.usbharu.hideout.service.IUserAuthService
|
import dev.usbharu.hideout.service.IUserAuthService
|
||||||
|
import dev.usbharu.hideout.util.JsonWebKeyUtil
|
||||||
|
import dev.usbharu.hideout.util.RsaUtil
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.auth.*
|
import io.ktor.server.auth.*
|
||||||
|
@ -15,19 +18,27 @@ import io.ktor.server.auth.jwt.*
|
||||||
import io.ktor.server.request.*
|
import io.ktor.server.request.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.security.KeyFactory
|
import java.security.KeyFactory
|
||||||
import java.security.interfaces.RSAPrivateKey
|
import java.security.interfaces.RSAPrivateKey
|
||||||
import java.security.interfaces.RSAPublicKey
|
|
||||||
import java.security.spec.PKCS8EncodedKeySpec
|
import java.security.spec.PKCS8EncodedKeySpec
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
const val TOKEN_AUTH = "jwt-auth"
|
const val TOKEN_AUTH = "jwt-auth"
|
||||||
|
|
||||||
fun Application.configureSecurity(userAuthService: IUserAuthService) {
|
fun Application.configureSecurity(userAuthService: IUserAuthService, metaRepository: IMetaRepository) {
|
||||||
|
|
||||||
val privateKeyString = property("jwt.privateKey")
|
val privateKeyString = runBlocking {
|
||||||
val issuer = property("jwt.issuer")
|
requireNotNull(metaRepository.get()).jwt.privateKey
|
||||||
|
}
|
||||||
|
val publicKey = runBlocking {
|
||||||
|
val publicKey = requireNotNull(metaRepository.get()).jwt.publicKey
|
||||||
|
println(publicKey)
|
||||||
|
RsaUtil.decodeRsaPublicKey(Base64.getDecoder().decode(publicKey))
|
||||||
|
}
|
||||||
|
println(privateKeyString)
|
||||||
|
val issuer = property("hideout.url")
|
||||||
// val audience = property("jwt.audience")
|
// val audience = property("jwt.audience")
|
||||||
val myRealm = property("jwt.realm")
|
val myRealm = property("jwt.realm")
|
||||||
val jwkProvider = JwkProviderBuilder(issuer)
|
val jwkProvider = JwkProviderBuilder(issuer)
|
||||||
|
@ -57,8 +68,6 @@ fun Application.configureSecurity(userAuthService: IUserAuthService) {
|
||||||
if (check.not()) {
|
if (check.not()) {
|
||||||
return@post call.respond(HttpStatusCode.Unauthorized)
|
return@post call.respond(HttpStatusCode.Unauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
val publicKey = jwkProvider.get("6f8856ed-9189-488f-9011-0ff4b6c08edc").publicKey
|
|
||||||
val keySpecPKCS8 = PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString))
|
val keySpecPKCS8 = PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString))
|
||||||
val privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpecPKCS8)
|
val privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpecPKCS8)
|
||||||
val token = JWT.create()
|
val token = JWT.create()
|
||||||
|
@ -66,22 +75,16 @@ fun Application.configureSecurity(userAuthService: IUserAuthService) {
|
||||||
// .withIssuer(issuer)
|
// .withIssuer(issuer)
|
||||||
.withClaim("username", user.username)
|
.withClaim("username", user.username)
|
||||||
.withExpiresAt(Date(System.currentTimeMillis() + 60000))
|
.withExpiresAt(Date(System.currentTimeMillis() + 60000))
|
||||||
.sign(Algorithm.RSA256(publicKey as RSAPublicKey, privateKey as RSAPrivateKey))
|
.sign(Algorithm.RSA256(publicKey, privateKey as RSAPrivateKey))
|
||||||
return@post call.respond(hashSetOf("token" to token))
|
return@post call.respond(hashSetOf("token" to token))
|
||||||
}
|
}
|
||||||
|
|
||||||
get("/.well-known/jwks.json"){
|
get("/.well-known/jwks.json") {
|
||||||
//language=JSON
|
//language=JSON
|
||||||
call.respondText(contentType = ContentType.Application.Json,text = """{
|
call.respondText(
|
||||||
"keys": [
|
contentType = ContentType.Application.Json,
|
||||||
{
|
text = JsonWebKeyUtil.publicKeyToJwk(requireNotNull(metaRepository.get()).jwt.publicKey)
|
||||||
"kty": "RSA",
|
)
|
||||||
"e": "AQAB",
|
|
||||||
"kid": "6f8856ed-9189-488f-9011-0ff4b6c08edc",
|
|
||||||
"n":"tfJaLrzXILUg1U3N1KV8yJr92GHn5OtYZR7qWk1Mc4cy4JGjklYup7weMjBD9f3bBVoIsiUVX6xNcYIr0Ie0AQ"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}""")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,8 @@ class ServerInitialiseServiceImpl(private val metaRepository: IMetaRepository) :
|
||||||
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
||||||
val jwt = Jwt(
|
val jwt = Jwt(
|
||||||
UUID.randomUUID(),
|
UUID.randomUUID(),
|
||||||
Base64.getEncoder().encodeToString(generateKeyPair.public.encoded),
|
Base64.getEncoder().encodeToString(generateKeyPair.private.encoded),
|
||||||
Base64.getEncoder().encodeToString(generateKeyPair.private.encoded)
|
Base64.getEncoder().encodeToString(generateKeyPair.public.encoded)
|
||||||
)
|
)
|
||||||
val meta = Meta(implementationVersion, jwt)
|
val meta = Meta(implementationVersion, jwt)
|
||||||
metaRepository.save(meta)
|
metaRepository.save(meta)
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package dev.usbharu.hideout.util
|
||||||
|
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.security.KeyFactory
|
||||||
|
import java.security.interfaces.RSAPublicKey
|
||||||
|
import java.security.spec.X509EncodedKeySpec
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
object JsonWebKeyUtil {
|
||||||
|
|
||||||
|
fun publicKeyToJwk(publicKey: String): String {
|
||||||
|
val x509EncodedKeySpec = X509EncodedKeySpec(Base64.getDecoder().decode(publicKey))
|
||||||
|
val generatePublic = KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec)
|
||||||
|
return publicKeyToJwk(generatePublic as RSAPublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun publicKeyToJwk(publicKey: RSAPublicKey): String {
|
||||||
|
val e = encodeBase64UInt(publicKey.publicExponent)
|
||||||
|
val n = encodeBase64UInt(publicKey.modulus)
|
||||||
|
return """{"e":"$e","n":"$n","use":"sig","kty":"RSA"}"""
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun encodeBase64UInt(bigInteger: BigInteger, minLength: Int = -1): String {
|
||||||
|
if(bigInteger.signum() < 0){
|
||||||
|
throw IllegalArgumentException("Cannot encode negative numbers")
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = bigInteger.toByteArray()
|
||||||
|
if (bigInteger.bitLength() % 8 == 0 && (bytes[0] == 0.toByte()) && bytes.size > 1){
|
||||||
|
bytes = Arrays.copyOfRange(bytes, 1, bytes.size)
|
||||||
|
}
|
||||||
|
if (minLength != -1){
|
||||||
|
if (bytes.size < minLength){
|
||||||
|
val array = ByteArray(minLength)
|
||||||
|
System.arraycopy(bytes, 0, array, minLength - bytes.size, bytes.size)
|
||||||
|
bytes = array
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package dev.usbharu.hideout.util
|
||||||
|
|
||||||
|
import java.security.KeyFactory
|
||||||
|
import java.security.interfaces.RSAPrivateKey
|
||||||
|
import java.security.interfaces.RSAPublicKey
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec
|
||||||
|
import java.security.spec.X509EncodedKeySpec
|
||||||
|
|
||||||
|
object RsaUtil {
|
||||||
|
fun decodeRsaPublicKey(byteArray: ByteArray):RSAPublicKey{
|
||||||
|
val x509EncodedKeySpec = X509EncodedKeySpec(byteArray)
|
||||||
|
return KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec) as RSAPublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decodeRsaPrivateKey(byteArray: ByteArray):RSAPrivateKey{
|
||||||
|
val pkcS8EncodedKeySpec = PKCS8EncodedKeySpec(byteArray)
|
||||||
|
return KeyFactory.getInstance("RSA").generatePrivate(pkcS8EncodedKeySpec) as RSAPrivateKey
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue