Skip to content

Commit

Permalink
WIP jdbc implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mrFlick72 committed Oct 22, 2024
1 parent ae703fd commit 4e90dd3
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package com.vauthenticator.server.keys.adapter.jdbc

import com.vauthenticator.server.keys.domain.*
import org.slf4j.LoggerFactory
import org.springframework.jdbc.core.JdbcTemplate
import java.time.Duration

class JdbcKeyStorage : KeyStorage {
class JdbcKeyStorage(private val jdbcTemplate: JdbcTemplate) : KeyStorage {

private val logger = LoggerFactory.getLogger(JdbcKeyStorage::class.java)

Expand All @@ -15,15 +16,53 @@ class JdbcKeyStorage : KeyStorage {
keyType: KeyType,
keyPurpose: KeyPurpose
) {
TODO()
jdbcTemplate.update(
"""
INSERT INTO KEY (
key_id
master_key_id,
key_purpose,
key_type,
encrypted_private_key,
public_key,
enabled,
key_expiration_date_timestamp
) VALUES (?,?,?,?,?,?,?,?)
""".trimIndent(),
kid.content(),
masterKid.content(),
dataKey.encryptedPrivateKeyAsString(),
dataKey.publicKeyAsString(),
keyPurpose.name,
true,
Duration.ofSeconds(0).toSeconds()
)
}

override fun signatureKeys(): Keys {
TODO()
}

override fun findOne(kid: Kid, keyPurpose: KeyPurpose): Key {
TODO()
return jdbcTemplate.query(
"""
SELECT * FROM KEY WHERE key_id = ? AND key_purpose = ?;
""".trimIndent(), { rs, _ ->
Key(
kid = Kid(rs.getString("key_id")),
masterKid = MasterKid(rs.getString("master_key_id")),
keyPurpose = KeyPurpose.valueOf(rs.getString("key_purpose")),
enabled = rs.getBoolean("enabled"),
type = KeyType.valueOf(rs.getString("key_type")),
expirationDateTimestamp = rs.getLong("key_expiration_date_timestamp"),
dataKey = DataKey.from(
rs.getString("encrypted_private_key"),
rs.getString("public_key"),
)
)
},
kid.content(), keyPurpose.name
).first()
}

override fun justDeleteKey(kid: Kid, keyPurpose: KeyPurpose) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class KeyRepository(
return keyStorage.signatureKeys()
}

// todo would be better return an optional?
fun keyFor(kid: Kid, keyPurpose: KeyPurpose): Key {
return keyStorage.findOne(kid, keyPurpose)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface KeyStorage {

fun signatureKeys(): Keys

// todo would be better return an optional?
fun findOne(kid: Kid, keyPurpose: KeyPurpose): Key

fun justDeleteKey(kid: Kid, keyPurpose: KeyPurpose)
Expand Down
15 changes: 15 additions & 0 deletions src/main/resources/data/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ CREATE TABLE ACCOUNT_ROLE
FOREIGN KEY (role_name) REFERENCES ROLE (name) on delete cascade
);

CREATE TABLE KEY
(
key_id varchar(255) not null primary key,
master_key_id varchar(255) not null,
key_purpose varchar(255) not null,
key_type varchar(255) not null,
encrypted_private_key text,
public_key text,
enabled not null default false,
key_expiration_date_timestamp bigint_field not null default 0,

);

CREATE INDEX keys_key_purpose ON KEY (key_purpose);

CREATE TABLE CLIENT_APPLICATION
(
client_app_id varchar(255) not null PRIMARY KEY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package com.vauthenticator.server.keys.adapter

import com.vauthenticator.server.extentions.encoder
import com.vauthenticator.server.extentions.valueAsStringFor
import com.vauthenticator.server.keys.adapter.dynamo.DynamoDbKeyStorage
import com.vauthenticator.server.keys.domain.KeyPurpose
import com.vauthenticator.server.keys.domain.KeyPurpose.MFA
import com.vauthenticator.server.keys.domain.KeyPurpose.SIGNATURE
import com.vauthenticator.server.keys.domain.KeyStorage
import com.vauthenticator.server.keys.domain.KeyType.ASYMMETRIC
import com.vauthenticator.server.keys.domain.KeyType.SYMMETRIC
import com.vauthenticator.server.keys.domain.Keys
import com.vauthenticator.server.keys.domain.Kid
import com.vauthenticator.server.support.DynamoDbUtils.dynamoDbClient
import com.vauthenticator.server.support.DynamoDbUtils.dynamoMfaKeysTableName
import com.vauthenticator.server.support.DynamoDbUtils.dynamoSignatureKeysTableName
import com.vauthenticator.server.support.KeysUtils.aKeyFor
Expand All @@ -21,8 +24,10 @@ import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import software.amazon.awssdk.services.dynamodb.model.AttributeValue
import java.time.Clock
import java.time.Duration
import java.time.Instant
import java.time.ZoneId
import kotlin.test.assertNotNull

abstract class AbstractKeyStorageTest {
Expand All @@ -34,8 +39,9 @@ abstract class AbstractKeyStorageTest {

abstract fun initKeyStorage(): KeyStorage
abstract fun resetDatabase()
abstract fun getActual(kid: Kid, tableName: String): MutableMap<String, AttributeValue>
abstract fun getActual(kid: Kid, keyPurpose: KeyPurpose): MutableMap<String, AttributeValue>

fun clock(): Clock = Clock.fixed(now, ZoneId.systemDefault())

@BeforeEach
fun setUp() {
Expand All @@ -47,7 +53,7 @@ abstract class AbstractKeyStorageTest {
fun `when store a new data key pair`() {
uut.store(masterKid, aKid, aSignatureDataKey, ASYMMETRIC, SIGNATURE)

val actual = getActual(aKid, dynamoSignatureKeysTableName)
val actual = getActual(aKid, SIGNATURE)
assertEquals(aKid.content(), actual.valueAsStringFor("key_id"))
assertEquals(masterKid.content(), actual.valueAsStringFor("master_key_id"))
assertEquals(
Expand All @@ -64,7 +70,7 @@ abstract class AbstractKeyStorageTest {
fun `when store a new data key for mfa`() {
uut.store(masterKid, aKid, aSimmetricDataKey, SYMMETRIC, MFA)

val actual = getActual(aKid, dynamoMfaKeysTableName)
val actual = getActual(aKid, MFA)
assertEquals(aKid.content(), actual.valueAsStringFor("key_id"))
assertEquals(masterKid.content(), actual.valueAsStringFor("master_key_id"))
assertEquals(
Expand Down Expand Up @@ -110,7 +116,7 @@ abstract class AbstractKeyStorageTest {
assertNotNull(storedKey)

uut.justDeleteKey(aKid, SIGNATURE)
val actual = getActual(aKid, dynamoSignatureKeysTableName)
val actual = getActual(aKid, SIGNATURE)
assertEquals(emptyMap<String, AttributeValue>(), actual)
}

Expand All @@ -123,7 +129,7 @@ abstract class AbstractKeyStorageTest {
val ttl = Duration.ofSeconds(1)
uut.keyDeleteJodPlannedFor(aKid, ttl, SIGNATURE)

val actual = getActual(aKid, dynamoSignatureKeysTableName)
val actual = getActual(aKid, SIGNATURE)
val expectedTTl = now.epochSecond + 1
assertEquals(false, (actual["enabled"] as AttributeValue).bool())
assertEquals(expectedTTl, (actual["key_expiration_date_timestamp"] as AttributeValue).n().toLong())
Expand All @@ -137,14 +143,14 @@ abstract class AbstractKeyStorageTest {

uut.keyDeleteJodPlannedFor(aKid, Duration.ofSeconds(1), SIGNATURE)

val actual = getActual(aKid, dynamoSignatureKeysTableName)
val actual = getActual(aKid, SIGNATURE)
val expectedTTl = now.epochSecond + 1
assertEquals(false, (actual["enabled"] as AttributeValue).bool())
assertEquals(expectedTTl, (actual["key_expiration_date_timestamp"] as AttributeValue).n().toLong())

uut.keyDeleteJodPlannedFor(aKid, Duration.ofSeconds(10), SIGNATURE)

val actualAfterReplanning = getActual(aKid, dynamoSignatureKeysTableName)
val actualAfterReplanning = getActual(aKid, SIGNATURE)
val expectedTTlAfterReplanning = now.epochSecond + 1
assertEquals(false, (actualAfterReplanning["enabled"] as AttributeValue).bool())
assertEquals(expectedTTlAfterReplanning, (actualAfterReplanning["key_expiration_date_timestamp"] as AttributeValue).n().toLong())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.vauthenticator.server.keys.adapter.dynamodb
import com.vauthenticator.server.extentions.asDynamoAttribute
import com.vauthenticator.server.keys.adapter.AbstractKeyStorageTest
import com.vauthenticator.server.keys.adapter.dynamo.DynamoDbKeyStorage
import com.vauthenticator.server.keys.domain.KeyPurpose
import com.vauthenticator.server.keys.domain.KeyStorage
import com.vauthenticator.server.keys.domain.Kid
import com.vauthenticator.server.support.DynamoDbUtils.dynamoDbClient
Expand All @@ -17,10 +18,8 @@ import java.time.ZoneId

class DynamoDbKeyStorageTest : AbstractKeyStorageTest() {

private val now = Instant.now()

override fun initKeyStorage(): KeyStorage = DynamoDbKeyStorage(
Clock.fixed(now, ZoneId.systemDefault()),
clock(),
dynamoDbClient,
dynamoSignatureKeysTableName,
dynamoMfaKeysTableName
Expand All @@ -30,14 +29,20 @@ class DynamoDbKeyStorageTest : AbstractKeyStorageTest() {
resetDynamoDb()
}

override fun getActual(kid: Kid, tableName: String): MutableMap<String, AttributeValue> =
override fun getActual(kid: Kid, keyPurpose: KeyPurpose): MutableMap<String, AttributeValue> =
dynamoDbClient.getItem(
GetItemRequest.builder().tableName(tableName)
GetItemRequest.builder().tableName(tableNameFor(keyPurpose))
.key(
mapOf(
"key_id" to kid.content().asDynamoAttribute()
)
)
.build()
).item()


private fun tableNameFor(keyPurpose: KeyPurpose) = when (keyPurpose) {
KeyPurpose.MFA -> dynamoMfaKeysTableName
KeyPurpose.SIGNATURE -> dynamoSignatureKeysTableName
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
package com.vauthenticator.server.keys.adapter.jdbc

import org.junit.jupiter.api.Assertions.*
import com.vauthenticator.server.keys.adapter.AbstractKeyStorageTest
import com.vauthenticator.server.keys.domain.KeyPurpose
import com.vauthenticator.server.keys.domain.KeyStorage
import com.vauthenticator.server.keys.domain.Kid
import com.vauthenticator.server.support.JdbcUtils.jdbcTemplate
import com.vauthenticator.server.support.JdbcUtils.resetDb
import software.amazon.awssdk.services.dynamodb.model.AttributeValue

class JdbcKeyStorageTest
class JdbcKeyStorageTest : AbstractKeyStorageTest() {

override fun initKeyStorage(): KeyStorage = JdbcKeyStorage(jdbcTemplate)

override fun resetDatabase() {
resetDb()
}

override fun getActual(kid: Kid, keyPurpose: KeyPurpose): MutableMap<String, AttributeValue> {
TODO("Not yet implemented")
}


}

0 comments on commit 4e90dd3

Please sign in to comment.