Skip to content

Commit

Permalink
mfa association via ticket to support the mail verification feature a…
Browse files Browse the repository at this point in the history
…nd with code to support the association api
  • Loading branch information
mrFlick72 committed Jul 25, 2024
1 parent 7966588 commit 40d3ffb
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.vauthenticator.server.email.EMailSenderService
import com.vauthenticator.server.mfa.domain.MfaMethod
import com.vauthenticator.server.mfa.domain.MfaMethodsEnrollment
import com.vauthenticator.server.oauth2.clientapp.ClientAppId
import com.vauthenticator.server.ticket.Ticket
import com.vauthenticator.server.ticket.Ticket.Companion.MFA_AUTO_ASSOCIATION_CONTEXT_VALUE
import com.vauthenticator.server.ticket.TicketId
import org.slf4j.LoggerFactory

Expand All @@ -20,24 +22,23 @@ class SendVerifyEMailChallenge(

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

fun sendVerifyMail(email: String) {
accountRepository.accountFor(email)
.map { account ->
val verificationTicket =
mfaMethodsEnrollment.enroll(
account,
MfaMethod.EMAIL_MFA_METHOD,
account.email,
ClientAppId.empty(),
false
)
val mailContext = mailContextFrom(verificationTicket)
mailVerificationMailSender.sendFor(account, mailContext)
}.orElseThrow {
logger.warn("account not found")
AccountNotFoundException("account not found")
}
}
fun sendVerifyMail(email: String): Unit = accountRepository.accountFor(email)
.map { account ->
val verificationTicket =
mfaMethodsEnrollment.enroll(
account,
MfaMethod.EMAIL_MFA_METHOD,
account.email,
ClientAppId.empty(),
false,
mapOf(Ticket.MFA_AUTO_ASSOCIATION_CONTEXT_KEY to MFA_AUTO_ASSOCIATION_CONTEXT_VALUE)
)
val mailContext = mailContextFrom(verificationTicket)
mailVerificationMailSender.sendFor(account, mailContext)
}.orElseThrow {
logger.warn("account not found")
AccountNotFoundException("account not found")
}

private fun mailContextFrom(ticketId: TicketId): Map<String, String> {
val verificationLink = "$frontChannelBaseUrl/email-verify/${ticketId.content}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class VerifyEMailChallenge(
fun verifyMail(ticket: String) {
ticketRepository.loadFor(TicketId(ticket))
.map {
mfaMethodsEnrollmentAssociation.associate(ticket, associationRequest.code)
mfaMethodsEnrollmentAssociation.associate(ticket)
enableAccountFrom(it.userName)
}
.orElseThrow { throw InvalidTicketException("The ticket $ticket is not a valid ticket, it seems to be expired") }
Expand Down
7 changes: 4 additions & 3 deletions src/main/kotlin/com/vauthenticator/server/mfa/MfaConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ class MfaConfig {
@Bean
fun mfaMethodsEnrolmentAssociation(
ticketRepository: TicketRepository,
mfaAccountMethodsRepository: MfaAccountMethodsRepository
mfaAccountMethodsRepository: MfaAccountMethodsRepository,
otpMfaVerifier: OtpMfaVerifier
) =
MfaMethodsEnrollmentAssociation(ticketRepository, mfaAccountMethodsRepository)
MfaMethodsEnrollmentAssociation(ticketRepository, mfaAccountMethodsRepository, otpMfaVerifier)

@Bean
fun mfaMethodsEnrollment(
mfaSender : OtpMfaSender,
mfaSender: OtpMfaSender,
ticketCreator: TicketCreator,
mfaAccountMethodsRepository: MfaAccountMethodsRepository
) = MfaMethodsEnrollment(ticketCreator, mfaSender, mfaAccountMethodsRepository)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,32 @@ import com.vauthenticator.server.account.Account
import com.vauthenticator.server.mfa.repository.MfaAccountMethodsRepository
import com.vauthenticator.server.oauth2.clientapp.ClientAppId
import com.vauthenticator.server.ticket.*
import com.vauthenticator.server.ticket.Ticket.Companion.MFA_AUTO_ASSOCIATION_CONTEXT_KEY
import com.vauthenticator.server.ticket.Ticket.Companion.MFA_AUTO_ASSOCIATION_CONTEXT_VALUE
import com.vauthenticator.server.ticket.Ticket.Companion.MFA_CHANNEL_CONTEXT_KEY
import com.vauthenticator.server.ticket.Ticket.Companion.MFA_METHOD_CONTEXT_KEY

class MfaMethodsEnrollmentAssociation(
private val ticketRepository: TicketRepository,
private val mfaAccountMethodsRepository: MfaAccountMethodsRepository
private val mfaAccountMethodsRepository: MfaAccountMethodsRepository,
private val otpMfaVerifier: OtpMfaVerifier
) {

fun associate(ticket: kotlin.String, code: kotlin.String) {
fun associate(ticket: String) {
associate(ticket) {
it.context.content[MFA_AUTO_ASSOCIATION_CONTEXT_KEY] === MFA_AUTO_ASSOCIATION_CONTEXT_VALUE
}

}

fun associate(ticket: String, code: String) {
associate(ticket) { otpMfaVerifier.verifyMfaChallengeFor(it.userName, MfaChallenge(code)) }
}

private fun associate(ticket: String, verifier: (ticket: Ticket) -> Unit) {
ticketRepository.loadFor(TicketId(ticket))
.map { ticket ->
verifier.invoke(ticket)
revoke(ticket)
}
.orElseThrow { throw InvalidTicketException("The ticket $ticket is not a valid ticket, it seems to be expired") }
Expand All @@ -36,7 +51,8 @@ class MfaMethodsEnrollment(
mfaMethod: MfaMethod,
mfaChannel: String,
clientAppId: ClientAppId,
sendChallengeCode: Boolean = true
sendChallengeCode: Boolean = true,
ticketContextAdditionalProperties: Map<String, String> = emptyMap()
): TicketId {
val email = account.email

Expand All @@ -54,7 +70,7 @@ class MfaMethodsEnrollment(
mapOf(
MFA_CHANNEL_CONTEXT_KEY to mfaChannel,
MFA_METHOD_CONTEXT_KEY to mfaMethod.name
)
) + ticketContextAdditionalProperties
)
)
}
Expand Down
6 changes: 4 additions & 2 deletions src/main/kotlin/com/vauthenticator/server/ticket/Ticket.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ data class Ticket(
val context: TicketContext = TicketContext.empty(),
) {
companion object {
val MFA_CHANNEL_CONTEXT_KEY = "mfaChannel"
val MFA_METHOD_CONTEXT_KEY = "mfaMethod"
const val MFA_CHANNEL_CONTEXT_KEY = "mfaChannel"
const val MFA_METHOD_CONTEXT_KEY = "mfaMethod"
const val MFA_AUTO_ASSOCIATION_CONTEXT_KEY = "auto-association"
const val MFA_AUTO_ASSOCIATION_CONTEXT_VALUE = "true"
}
}

Expand Down

0 comments on commit 40d3ffb

Please sign in to comment.