Skip to content

Commit

Permalink
add mfa jdbc repository
Browse files Browse the repository at this point in the history
  • Loading branch information
mrFlick72 committed Oct 26, 2024
1 parent 1f6dd96 commit 7b299f0
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.vauthenticator.server.mfa.adapter.jdbc

import com.vauthenticator.server.keys.domain.*
import com.vauthenticator.server.mfa.domain.MfaAccountMethod
import com.vauthenticator.server.mfa.domain.MfaAccountMethodsRepository
import com.vauthenticator.server.mfa.domain.MfaDeviceId
import com.vauthenticator.server.mfa.domain.MfaMethod
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.transaction.annotation.Transactional
import java.sql.ResultSet
import java.util.*

@Transactional
class JdbcMfaAccountMethodsRepository(
private val jdbcTemplate: JdbcTemplate,
private val keyRepository: KeyRepository,
private val masterKid: MasterKid,
private val mfaDeviceIdGenerator: () -> MfaDeviceId
) : MfaAccountMethodsRepository {
override fun findBy(userName: String, mfaMfaMethod: MfaMethod, mfaChannel: String): Optional<MfaAccountMethod> =
Optional.ofNullable(
jdbcTemplate.query(
"SELECT * FROM MFA_ACCOUNT_METHODS WHERE user_name=? AND mfa_method=? AND mfa_channel=?",
{ rs, _ -> mfaAccountMethodFrom(rs) },
userName, mfaMfaMethod.name, mfaChannel
).firstOrNull()
)


override fun findBy(deviceId: MfaDeviceId): Optional<MfaAccountMethod> =
Optional.ofNullable(
jdbcTemplate.query(
"SELECT * FROM MFA_ACCOUNT_METHODS WHERE mfa_device_id=?",
{ rs, _ -> mfaAccountMethodFrom(rs) },
deviceId.content
).firstOrNull()
)

override fun findAll(userName: String): List<MfaAccountMethod> =
jdbcTemplate.query("SELECT * FROM MFA_ACCOUNT_METHODS")
{ rs, _ -> mfaAccountMethodFrom(rs) }


override fun save(
userName: String,
mfaMfaMethod: MfaMethod,
mfaChannel: String,
associated: Boolean
): MfaAccountMethod {
val kid = keyRepository.createKeyFrom(masterKid, KeyType.SYMMETRIC, KeyPurpose.MFA)
val mfaDeviceId = mfaDeviceIdGenerator.invoke()

jdbcTemplate.update(
"INSERT INTO MFA_ACCOUNT_METHODS (user_name, mfa_device_id, mfa_method, mfa_channel, key_id, associated) VALUES (?,?,?,?,?,?)",
userName, mfaDeviceId.content, mfaMfaMethod.name, mfaChannel, kid.content(), associated
)

return MfaAccountMethod(userName, mfaDeviceId, kid, mfaMfaMethod, mfaChannel, associated)
}


override fun setAsDefault(userName: String, deviceId: MfaDeviceId) {
Optional.ofNullable(
jdbcTemplate.query(
"SELECT mfa_device_id FROM MFA_ACCOUNT_METHODS WHERE user_name=? AND default_mfa_method=true",
{ rs, _ -> MfaDeviceId(rs.getString("mfa_device_id")) },
userName
).firstOrNull()
).ifPresent {
jdbcTemplate.update(
"UPDATE MFA_ACCOUNT_METHODS SET default_mfa_method = false WHERE user_name=? AND mfa_device_id=?",
userName, it.content
)
}

jdbcTemplate.update(
"UPDATE MFA_ACCOUNT_METHODS SET default_mfa_method = true WHERE user_name=? AND mfa_device_id=?",
userName, deviceId.content
)
}

override fun getDefaultDevice(userName: String): Optional<MfaDeviceId> =
Optional.ofNullable(
jdbcTemplate.query(
"SELECT mfa_device_id FROM MFA_ACCOUNT_METHODS WHERE user_name=? AND default_mfa_method=true",
{ rs, _ -> MfaDeviceId(rs.getString("mfa_device_id")) },
userName
).firstOrNull()
)

private fun mfaAccountMethodFrom(rs: ResultSet) = MfaAccountMethod(
userName = rs.getString("user_name"),
mfaDeviceId = MfaDeviceId(rs.getString("mfa_device_id")),
key = Kid(rs.getString("key_id")),
mfaMethod = MfaMethod.valueOf(rs.getString("mfa_method")),
mfaChannel = rs.getString("mfa_channel"),
associated = rs.getBoolean("associated"),
)

}
20 changes: 17 additions & 3 deletions src/main/resources/data/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,27 @@ CREATE TABLE TICKET

CREATE TABLE PASSWORD_HISTORY
(
user_name varchar(255) not null ,
created_at bigint not null default 0,
password varchar(255) not null,
user_name varchar(255) not null,
created_at bigint not null default 0,
password varchar(255) not null,

primary key (user_name, password)
);

CREATE TABLE MFA_ACCOUNT_METHODS
(
user_name varchar(255) not null,
mfa_device_id varchar(255) not null,
mfa_method varchar(255) not null,
mfa_channel varchar(255) not null,
key_id varchar(255) not null,
associated varchar(255) not null,
default_mfa_method boolean default false,

primary key (user_name, mfa_channel)
);

CREATE INDEX mfa_account_methods_mfa_device_id ON MFA_ACCOUNT_METHODS (mfa_device_id);

CREATE TABLE CLIENT_APPLICATION
(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ abstract class AbstractMfaAccountMethodsRepositoryTest {

@Test
fun `when decide what mfa use as default`() {
every { keyRepository.createKeyFrom(masterKid, KeyType.SYMMETRIC, KeyPurpose.MFA) } returns key
uut.save(email, MfaMethod.EMAIL_MFA_METHOD, email, true)

val expected = Optional.of(mfaDeviceId)
uut.setAsDefault(email, mfaDeviceId)
val defaultDevice = uut.getDefaultDevice(email)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@ import io.mockk.junit5.MockKExtension
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(MockKExtension::class)
class DynamoMfaAccountMethodsRepositoryTest : AbstractMfaAccountMethodsRepositoryTest(){
class DynamoMfaAccountMethodsRepositoryTest : AbstractMfaAccountMethodsRepositoryTest() {

override fun initMfaAccountMethodsRepository(): MfaAccountMethodsRepository {
return DynamoMfaAccountMethodsRepository(
override fun initMfaAccountMethodsRepository() =
DynamoMfaAccountMethodsRepository(
dynamoMfaAccountMethodsTableName,
dynamoDefaultMfaAccountMethodsTableName,
dynamoDbClient,
keyRepository,
masterKid
) { mfaDeviceId }
}

override fun resetDatabase() {
resetDynamoDb()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.vauthenticator.server.mfa.adapter.jdbc

import com.vauthenticator.server.mfa.adapter.AbstractMfaAccountMethodsRepositoryTest
import com.vauthenticator.server.support.JdbcUtils.jdbcTemplate
import com.vauthenticator.server.support.JdbcUtils.resetDb
import io.mockk.junit5.MockKExtension
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(MockKExtension::class)
class JdbcMfaAccountMethodsRepositoryTest : AbstractMfaAccountMethodsRepositoryTest() {
override fun initMfaAccountMethodsRepository() = JdbcMfaAccountMethodsRepository(
jdbcTemplate,
keyRepository,
masterKid
) { mfaDeviceId }


override fun resetDatabase() {
resetDb()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ object JdbcUtils {
jdbcTemplate.execute("DROP TABLE IF EXISTS KEYS;")
jdbcTemplate.execute("DROP TABLE IF EXISTS TICKET;")
jdbcTemplate.execute("DROP TABLE IF EXISTS PASSWORD_HISTORY;")
jdbcTemplate.execute("DROP TABLE IF EXISTS MFA_ACCOUNT_METHODS;")
jdbcTemplate.execute("DROP TABLE IF EXISTS oauth2_authorization;")
jdbcTemplate.execute(Files.readString(Paths.get("src/main/resources/data/schema.sql")))
} catch (e: java.lang.Exception) {
Expand Down

0 comments on commit 7b299f0

Please sign in to comment.