add PrivateKeyProvider
This commit is contained in:
@@ -17,6 +17,10 @@ tab_width = 2
|
|||||||
[*.bat]
|
[*.bat]
|
||||||
end_of_line = crlf
|
end_of_line = crlf
|
||||||
|
|
||||||
|
[*.pem]
|
||||||
|
max_line_length = 64
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
# noinspection EditorConfigKeyCorrectness
|
# noinspection EditorConfigKeyCorrectness
|
||||||
[*.{kt,kts}]
|
[*.{kt,kts}]
|
||||||
ij_kotlin_packages_to_use_import_on_demand = unset
|
ij_kotlin_packages_to_use_import_on_demand = unset
|
||||||
|
|||||||
23
src/main/kotlin/ltd/hlaeja/exception/KeyProviderException.kt
Normal file
23
src/main/kotlin/ltd/hlaeja/exception/KeyProviderException.kt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package ltd.hlaeja.exception
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class KeyProviderException : RuntimeException {
|
||||||
|
|
||||||
|
constructor() : super()
|
||||||
|
|
||||||
|
constructor(message: String) : super(message)
|
||||||
|
|
||||||
|
constructor(cause: Throwable) : super(cause)
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
message: String,
|
||||||
|
cause: Throwable,
|
||||||
|
) : super(message, cause)
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
message: String,
|
||||||
|
cause: Throwable,
|
||||||
|
enableSuppression: Boolean,
|
||||||
|
writableStackTrace: Boolean,
|
||||||
|
) : super(message, cause, enableSuppression, writableStackTrace)
|
||||||
|
}
|
||||||
35
src/main/kotlin/ltd/hlaeja/util/PrivateKeyProvider.kt
Normal file
35
src/main/kotlin/ltd/hlaeja/util/PrivateKeyProvider.kt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package ltd.hlaeja.util
|
||||||
|
|
||||||
|
import java.security.KeyFactory
|
||||||
|
import java.security.interfaces.RSAPrivateKey
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec
|
||||||
|
import java.util.Base64.getDecoder
|
||||||
|
import ltd.hlaeja.exception.KeyProviderException
|
||||||
|
|
||||||
|
object PrivateKeyProvider {
|
||||||
|
|
||||||
|
fun load(
|
||||||
|
pemFile: String,
|
||||||
|
): RSAPrivateKey = readPrivatePemFile(pemFile)
|
||||||
|
.let(::makePrivateKey)
|
||||||
|
|
||||||
|
private fun makePrivateKey(
|
||||||
|
privateKeyBytes: ByteArray,
|
||||||
|
): RSAPrivateKey = KeyFactory.getInstance("RSA")
|
||||||
|
.generatePrivate(PKCS8EncodedKeySpec(privateKeyBytes)) as RSAPrivateKey
|
||||||
|
|
||||||
|
private fun readPrivatePemFile(
|
||||||
|
privateKey: String,
|
||||||
|
): ByteArray = javaClass.classLoader
|
||||||
|
.getResource(privateKey)
|
||||||
|
?.readText()
|
||||||
|
?.let(::getPrivateKeyByteArray)
|
||||||
|
?: throw KeyProviderException("Could not load private key")
|
||||||
|
|
||||||
|
private fun getPrivateKeyByteArray(
|
||||||
|
keyText: String,
|
||||||
|
): ByteArray = keyText.replace(Regex("[\r\n]+"), "")
|
||||||
|
.removePrefix("-----BEGIN PRIVATE KEY-----")
|
||||||
|
.removeSuffix("-----END PRIVATE KEY-----")
|
||||||
|
.let { getDecoder().decode(it) }
|
||||||
|
}
|
||||||
51
src/test/kotlin/ltd/hlaeja/util/PrivateKeyProviderTest.kt
Normal file
51
src/test/kotlin/ltd/hlaeja/util/PrivateKeyProviderTest.kt
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package ltd.hlaeja.util
|
||||||
|
|
||||||
|
import java.security.interfaces.RSAPrivateKey
|
||||||
|
import ltd.hlaeja.exception.KeyProviderException
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.assertThrows
|
||||||
|
|
||||||
|
class PrivateKeyProviderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `load private key - success`() {
|
||||||
|
// given
|
||||||
|
val pemFilePath = "keys/valid-private-key.pem"
|
||||||
|
|
||||||
|
// when
|
||||||
|
val privateKey: RSAPrivateKey = PrivateKeyProvider.load(pemFilePath)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(privateKey).isNotNull
|
||||||
|
assertThat(privateKey.algorithm).isEqualTo("RSA")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `load private key - file does not exist`() {
|
||||||
|
// given
|
||||||
|
val nonExistentPemFilePath = "keys/non-existent.pem"
|
||||||
|
|
||||||
|
// when exception
|
||||||
|
val exception = assertThrows<KeyProviderException> {
|
||||||
|
PrivateKeyProvider.load(nonExistentPemFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(exception.message).isEqualTo("Could not load private key")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `load private key - file is invalid`() {
|
||||||
|
// given
|
||||||
|
val invalidPemFilePath = "keys/invalid-private-key.pem"
|
||||||
|
|
||||||
|
// when exception
|
||||||
|
val exception = assertThrows<IllegalArgumentException> {
|
||||||
|
PrivateKeyProvider.load(invalidPemFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(exception.message).contains("Input byte array has wrong 4-byte ending unit")
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/test/resources/keys/invalid-private-key.pem
Normal file
28
src/test/resources/keys/invalid-private-key.pem
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
VEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBK
|
||||||
|
VU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMg
|
||||||
|
SVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBU
|
||||||
|
SElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpV
|
||||||
|
TksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJ
|
||||||
|
UyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRI
|
||||||
|
SVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVO
|
||||||
|
SyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElT
|
||||||
|
IEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJ
|
||||||
|
UyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5L
|
||||||
|
IFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMg
|
||||||
|
SlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElT
|
||||||
|
IElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksg
|
||||||
|
VEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBK
|
||||||
|
VU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMg
|
||||||
|
SVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBU
|
||||||
|
SElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpV
|
||||||
|
TksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJ
|
||||||
|
UyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRI
|
||||||
|
SVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVO
|
||||||
|
SyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElT
|
||||||
|
IEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJ
|
||||||
|
UyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5L
|
||||||
|
IFRISVMgSVMgSlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMg
|
||||||
|
SlVOSyBUSElTIElTIEpVTksgVEhJUyBJUyBKVU5LIFRISVMgSVMgSlVOSyBUSElT
|
||||||
|
IElTIEpVTksg==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
28
src/test/resources/keys/valid-private-key.pem
Normal file
28
src/test/resources/keys/valid-private-key.pem
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj
|
||||||
|
MzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu
|
||||||
|
NMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ
|
||||||
|
qgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg
|
||||||
|
p2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR
|
||||||
|
ZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi
|
||||||
|
VuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV
|
||||||
|
laAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8
|
||||||
|
sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H
|
||||||
|
mQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY
|
||||||
|
dgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw
|
||||||
|
ta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ
|
||||||
|
DM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T
|
||||||
|
N0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t
|
||||||
|
0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv
|
||||||
|
t8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU
|
||||||
|
AhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk
|
||||||
|
48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL
|
||||||
|
DY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK
|
||||||
|
xt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA
|
||||||
|
mNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh
|
||||||
|
2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz
|
||||||
|
et6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr
|
||||||
|
VBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD
|
||||||
|
TQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc
|
||||||
|
dn/RsYEONbwQSjIfMPkvxF+8HQ==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
Reference in New Issue
Block a user