Skip to content

Commit

Permalink
Merge pull request #252 from VAuthenticator/mfa-on-postgres
Browse files Browse the repository at this point in the history
mfa storage on postgres
  • Loading branch information
mrFlick72 authored Oct 27, 2024
2 parents 6c7f6cd + 2383795 commit c1cf4b8
Show file tree
Hide file tree
Showing 106 changed files with 817 additions and 615 deletions.
225 changes: 225 additions & 0 deletions src/main/kotlin/com/vauthenticator/server/account/AccountConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
package com.vauthenticator.server.account

import com.fasterxml.jackson.databind.ObjectMapper
import com.hubspot.jinjava.Jinjava
import com.vauthenticator.document.repository.DocumentRepository
import com.vauthenticator.server.account.adapter.CachedAccountRepository
import com.vauthenticator.server.account.adapter.dynamodb.DynamoDbAccountRepository
import com.vauthenticator.server.account.adapter.jdbc.JdbcAccountRepository
import com.vauthenticator.server.account.domain.AccountCacheContentConverter
import com.vauthenticator.server.account.domain.AccountRepository
import com.vauthenticator.server.account.domain.AccountUpdateAdminAction
import com.vauthenticator.server.account.domain.SaveAccount
import com.vauthenticator.server.account.domain.emailverification.SendVerifyEMailChallenge
import com.vauthenticator.server.account.domain.emailverification.SendVerifyEMailChallengeUponSignUpEventConsumer
import com.vauthenticator.server.account.domain.emailverification.VerifyEMailChallenge
import com.vauthenticator.server.account.domain.signup.SignUpUse
import com.vauthenticator.server.account.domain.welcome.SayWelcome
import com.vauthenticator.server.account.domain.welcome.SendWelcomeMailUponSignUpEventConsumer
import com.vauthenticator.server.cache.CacheOperation
import com.vauthenticator.server.cache.RedisCacheOperation
import com.vauthenticator.server.communication.NoReplyEMailConfiguration
import com.vauthenticator.server.communication.adapter.JinJavaTemplateResolver
import com.vauthenticator.server.communication.adapter.javamail.JavaEMailSenderService
import com.vauthenticator.server.communication.domain.EMailSenderService
import com.vauthenticator.server.communication.domain.EMailType
import com.vauthenticator.server.communication.domain.SimpleEMailMessageFactory
import com.vauthenticator.server.events.VAuthenticatorEventsDispatcher
import com.vauthenticator.server.mfa.domain.MfaMethodsEnrollment
import com.vauthenticator.server.mfa.domain.MfaMethodsEnrollmentAssociation
import com.vauthenticator.server.oauth2.clientapp.domain.ClientApplicationRepository
import com.vauthenticator.server.password.domain.PasswordPolicy
import com.vauthenticator.server.password.domain.VAuthenticatorPasswordEncoder
import com.vauthenticator.server.role.domain.RoleRepository
import com.vauthenticator.server.ticket.domain.TicketRepository
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Profile
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.mail.javamail.JavaMailSender
import software.amazon.awssdk.services.dynamodb.DynamoDbClient
import java.time.Duration

@Configuration(proxyBeanMethods = false)
class AccountConfig {

@Bean
fun changeAccountEnabling(accountRepository: AccountRepository): AccountUpdateAdminAction =
AccountUpdateAdminAction(accountRepository)

@Bean
fun saveAccount(accountRepository: AccountRepository): SaveAccount =
SaveAccount(accountRepository)


@Bean("accountRepository")
@Profile("experimental_database_persistence")
fun jdbcAccountRepository(
jdbcTemplate: JdbcTemplate
) = JdbcAccountRepository(jdbcTemplate)


@Bean("accountRepository")
@ConditionalOnProperty(
name = ["vauthenticator.dynamo-db.account.cache.enabled"],
havingValue = "false",
matchIfMissing = true
)
@Profile("!experimental_database_persistence")
fun dynamoDbAccountRepository(
mapper: ObjectMapper,
dynamoDbClient: DynamoDbClient,
roleRepository: RoleRepository,
@Value("\${vauthenticator.dynamo-db.account.table-name}") accountTableName: String,
@Value("\${vauthenticator.dynamo-db.account.role.table-name}") accountRoleTableName: String
) =
DynamoDbAccountRepository(dynamoDbClient, accountTableName, roleRepository)


@Bean("accountRepository")
@ConditionalOnProperty(
name = ["vauthenticator.dynamo-db.account.cache.enabled"],
havingValue = "true",
matchIfMissing = false
)
@Profile("!experimental_database_persistence")
fun cachedDynamoDbAccountRepository(
mapper: ObjectMapper,
dynamoDbClient: DynamoDbClient,
accountCacheOperation: CacheOperation<String, String>,
roleRepository: RoleRepository,
@Value("\${vauthenticator.dynamo-db.account.table-name}") accountTableName: String,
@Value("\${vauthenticator.dynamo-db.account.role.table-name}") accountRoleTableName: String
) =
CachedAccountRepository(
AccountCacheContentConverter(mapper),
accountCacheOperation,
DynamoDbAccountRepository(dynamoDbClient, accountTableName, roleRepository),
)

@Bean
@ConditionalOnProperty(
name = ["vauthenticator.dynamo-db.account.cache.enabled"],
havingValue = "true",
matchIfMissing = false
)
@Profile("!experimental_database_persistence")
fun accountCacheOperation(
redisTemplate: RedisTemplate<*, *>,
@Value("\${vauthenticator.dynamo-db.account.cache.ttl}") ttl: Duration,
@Value("\${vauthenticator.dynamo-db.account.cache.name}") cacheRegionName: String,
) = RedisCacheOperation<String, String>(
cacheName = cacheRegionName,
ttl = ttl,
redisTemplate = redisTemplate as RedisTemplate<String, String>
)
}


@Configuration(proxyBeanMethods = false)
class WelcomeConfig {

@Bean
fun sayWelcome(
accountRepository: AccountRepository,
welcomeMailSender: EMailSenderService
) = SayWelcome(accountRepository, welcomeMailSender)

@Bean
fun welcomeMailSender(
javaMailSender: JavaMailSender,
documentRepository: DocumentRepository,
noReplyEMailConfiguration: NoReplyEMailConfiguration
) =
JavaEMailSenderService(
documentRepository,
javaMailSender,
JinJavaTemplateResolver(Jinjava()),
SimpleEMailMessageFactory(
noReplyEMailConfiguration.from,
noReplyEMailConfiguration.welcomeEMailSubject,
EMailType.WELCOME
)
)

@Bean
fun sendWelcomeMailUponSignUpEventConsumer(sayWelcome: SayWelcome) =
SendWelcomeMailUponSignUpEventConsumer(sayWelcome)
}


@Configuration(proxyBeanMethods = false)
class EMailVerificationConfig {

@Bean
fun sendVerifyMailChallenge(
clientAccountRepository: ClientApplicationRepository,
accountRepository: AccountRepository,
mfaMethodsEnrollment: MfaMethodsEnrollment,
verificationMailSender: EMailSenderService,
@Value("\${vauthenticator.host}") frontChannelBaseUrl: String
) =
SendVerifyEMailChallenge(
accountRepository,
mfaMethodsEnrollment,
verificationMailSender,
frontChannelBaseUrl
)

@Bean
fun verifyMailChallengeSent(
accountRepository: AccountRepository,
ticketRepository: TicketRepository,
mfaMethodsEnrollmentAssociation: MfaMethodsEnrollmentAssociation
) =
VerifyEMailChallenge(
ticketRepository,
accountRepository,
mfaMethodsEnrollmentAssociation
)

@Bean
fun verificationMailSender(
javaMailSender: JavaMailSender,
documentRepository: DocumentRepository,
noReplyEMailConfiguration: NoReplyEMailConfiguration
) =
JavaEMailSenderService(
documentRepository,
javaMailSender,
JinJavaTemplateResolver(Jinjava()),
SimpleEMailMessageFactory(
noReplyEMailConfiguration.from,
noReplyEMailConfiguration.welcomeEMailSubject,
EMailType.EMAIL_VERIFICATION
)
)

@Bean
fun sendVerifyMailChallengeUponSignUpEventConsumer(mailChallenge: SendVerifyEMailChallenge) =
SendVerifyEMailChallengeUponSignUpEventConsumer(mailChallenge)
}


@Configuration(proxyBeanMethods = false)
class SingUpConfig {

@Bean
fun signUpUseCase(
passwordPolicy: PasswordPolicy,
clientAccountRepository: ClientApplicationRepository,
accountRepository: AccountRepository,
vAuthenticatorPasswordEncoder: VAuthenticatorPasswordEncoder,
vAuthenticatorEventsDispatcher : VAuthenticatorEventsDispatcher
): SignUpUse =
SignUpUse(
passwordPolicy,
accountRepository,
vAuthenticatorPasswordEncoder,
vAuthenticatorEventsDispatcher
)

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.vauthenticator.server.account.repository
package com.vauthenticator.server.account.adapter

import com.vauthenticator.server.account.Account
import com.vauthenticator.server.account.domain.Account
import com.vauthenticator.server.account.domain.AccountRepository
import com.vauthenticator.server.cache.CacheContentConverter
import com.vauthenticator.server.cache.CacheOperation
import java.util.*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.vauthenticator.server.account.repository.dynamodb
package com.vauthenticator.server.account.adapter.dynamodb

import com.vauthenticator.server.account.*
import com.vauthenticator.server.account.domain.*
import com.vauthenticator.server.extentions.asDynamoAttribute
import com.vauthenticator.server.extentions.valueAsBoolFor
import com.vauthenticator.server.extentions.valueAsStringFor
Expand All @@ -22,10 +22,24 @@ object DynamoAccountConverter {
firstName = dynamoPayload.valueAsStringFor("firstName"),
lastName = dynamoPayload.valueAsStringFor("lastName"),
authorities = dynamoPayload.valueAsStringSetFor("authorities"),
birthDate = Date.isoDateFor(dynamoPayload.valueAsStringFor("birthDate")),
phone = Phone.phoneFor(dynamoPayload.valueAsStringFor("phone")),
locale = UserLocale.localeFrom(dynamoPayload.valueAsStringFor("locale")),
mandatoryAction = AccountMandatoryAction.valueOf(dynamoPayload.valueAsStringFor("mandatory_action"))
birthDate = Date.isoDateFor(
dynamoPayload.valueAsStringFor(
"birthDate"
)
),
phone = Phone.phoneFor(
dynamoPayload.valueAsStringFor(
"phone"
)
),
locale = UserLocale.localeFrom(
dynamoPayload.valueAsStringFor(
"locale"
)
),
mandatoryAction = AccountMandatoryAction.valueOf(
dynamoPayload.valueAsStringFor("mandatory_action")
)
)

fun fromDomainToDynamo(account: Account) =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.vauthenticator.server.account.repository.dynamodb
package com.vauthenticator.server.account.adapter.dynamodb

import com.vauthenticator.server.account.Account
import com.vauthenticator.server.account.adapter.dynamodb.DynamoAccountConverter.fromDomainToDynamo
import com.vauthenticator.server.account.domain.Account
import com.vauthenticator.server.extentions.asDynamoAttribute
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest
Expand All @@ -19,7 +20,7 @@ object DynamoAccountQueryFactory {
fun storeAccountQueryFor(account: Account, table: String, withUpsert: Boolean = true): PutItemRequest =
PutItemRequest.builder()
.tableName(table)
.item(DynamoAccountConverter.fromDomainToDynamo(account))
.item(fromDomainToDynamo(account))
.let {
if (withUpsert)
it
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.vauthenticator.server.account.repository.dynamodb

import com.vauthenticator.server.account.Account
import com.vauthenticator.server.account.repository.AccountRegistrationException
import com.vauthenticator.server.account.repository.AccountRepository
import com.vauthenticator.server.account.repository.dynamodb.DynamoAccountConverter.fromDynamoToDomain
import com.vauthenticator.server.account.repository.dynamodb.DynamoAccountQueryFactory.findAccountQueryForUserName
import com.vauthenticator.server.account.repository.dynamodb.DynamoAccountQueryFactory.storeAccountQueryFor
package com.vauthenticator.server.account.adapter.dynamodb

import com.vauthenticator.server.account.adapter.dynamodb.DynamoAccountConverter.fromDynamoToDomain
import com.vauthenticator.server.account.adapter.dynamodb.DynamoAccountQueryFactory.findAccountQueryForUserName
import com.vauthenticator.server.account.adapter.dynamodb.DynamoAccountQueryFactory.storeAccountQueryFor
import com.vauthenticator.server.account.domain.Account
import com.vauthenticator.server.account.domain.AccountRegistrationException
import com.vauthenticator.server.account.domain.AccountRepository
import com.vauthenticator.server.extentions.filterEmptyMetadata
import com.vauthenticator.server.role.domain.RoleRepository
import software.amazon.awssdk.services.dynamodb.DynamoDbClient
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.vauthenticator.server.account.repository.jdbc
package com.vauthenticator.server.account.adapter.jdbc

import com.vauthenticator.server.account.*
import com.vauthenticator.server.account.Date
import com.vauthenticator.server.account.repository.AccountRegistrationException
import com.vauthenticator.server.account.repository.AccountRepository
import com.vauthenticator.server.account.domain.*
import com.vauthenticator.server.account.domain.Date
import org.springframework.dao.DuplicateKeyException
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.transaction.annotation.Transactional
Expand Down Expand Up @@ -106,10 +104,18 @@ class JdbcAccountRepository(private val jdbcTemplate: JdbcTemplate) : AccountRep
firstName = rs.getString("first_name"),
lastName = rs.getString("last_name"),
authorities = authorities,
birthDate = Date.isoDateFor(rs.getString("birth_date").orEmpty()),
birthDate = Date.isoDateFor(
rs.getString("birth_date").orEmpty()
),
phone = Phone.phoneFor(rs.getString("phone")),
locale = UserLocale.localeFrom(rs.getString("locale")),
mandatoryAction = AccountMandatoryAction.valueOf(rs.getString("mandatory_action"))
locale = UserLocale.localeFrom(
rs.getString(
"locale"
)
),
mandatoryAction = AccountMandatoryAction.valueOf(
rs.getString("mandatory_action")
)
)
}, username)
return Optional.ofNullable(queryResult.firstOrNull())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.vauthenticator.server.account.api

import com.vauthenticator.server.account.*
import com.vauthenticator.server.account.AccountMandatoryAction.NO_ACTION
import com.vauthenticator.server.account.Date
import com.vauthenticator.server.account.domain.AccountMandatoryAction.NO_ACTION
import com.vauthenticator.server.account.api.SignUpAccountConverter.fromRepresentationToSignedUpAccount
import com.vauthenticator.server.account.signup.SignUpUse
import com.vauthenticator.server.account.domain.*
import com.vauthenticator.server.account.domain.Date
import com.vauthenticator.server.account.domain.signup.SignUpUse
import com.vauthenticator.server.extentions.clientAppId
import com.vauthenticator.server.extentions.oauth2ClientId
import com.vauthenticator.server.oauth2.clientapp.domain.ClientAppId
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package com.vauthenticator.server.account.api

import com.vauthenticator.server.account.Account
import com.vauthenticator.server.account.AccountMandatoryAction
import com.vauthenticator.server.account.AccountUpdateAdminAction
import com.vauthenticator.server.account.AdminAccountApiRequest
import com.vauthenticator.server.account.repository.AccountRepository
import com.vauthenticator.server.account.domain.*
import org.springframework.http.ResponseEntity.noContent
import org.springframework.http.ResponseEntity.ok
import org.springframework.security.core.Authentication
Expand Down
Loading

0 comments on commit c1cf4b8

Please sign in to comment.