Skip to content

Commit

Permalink
fix the test suite
Browse files Browse the repository at this point in the history
  • Loading branch information
mrFlick72 committed Jul 26, 2024
1 parent ac5f4b1 commit 9aaa715
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 73 deletions.
1 change: 0 additions & 1 deletion local-environment/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ and key.master-key=`MASTER_KEY`

p.s. `MASTER_KEY` is shown in the std out of the mrflick72/vauthenticator-local-tenant-installer:tag execution like below:

docker build -t vauthenticator-local-tenant-installer:mfa-enrolment-of-more-email-as-mfa -f tenant-installer.Dockerfile .
```shell
....

Expand Down
16 changes: 8 additions & 8 deletions local-environment/request.http
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Content-Type: application/json
Authorization: Bearer {{auth_token}}

{
"email": "user1@email.com",
"email": "user2@email.com",
"password": "secret!",
"firstName": "Admin",
"lastName": "",
Expand All @@ -43,7 +43,7 @@ Content-Type: application/json
Authorization: Bearer {{auth_token}}

{
"email": "admin2@email.com"
"email": "user2@email.com"
}


Expand Down Expand Up @@ -72,21 +72,21 @@ Authorization: Bearer {{auth_token}}

POST {{host}}/api/mfa/enrollment
Content-Type: application/json
Authorization: Bearer eyJraWQiOiJkYTFiNzAwMS05NjlkLTQyNzQtYTM5Yy0wYTI2ZjMzODg2NmIiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbkBlbWFpbC5jb20iLCJhdWQiOiJ1c2VyLWludHJvc3BlY3Rpb24iLCJuYmYiOjE3MjE4OTM1NDIsInVzZXJfbmFtZSI6ImFkbWluQGVtYWlsLmNvbSIsInNjb3BlIjpbIm9wZW5pZCIsImVtYWlsIiwicHJvZmlsZSJdLCJpc3MiOiJodHRwOi8vbG9jYWwuYXBpLnZhdXRoZW50aWNhdG9yLmNvbTo5MDkwIiwiZXhwIjoxNzIxODkzOTAyLCJpYXQiOjE3MjE4OTM1NDIsImp0aSI6ImU2ZDYyMWQzLTJjZmUtNDE1ZC04NGM4LTE0NjEwNGNiZTM2NiIsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiIsIlZBVVRIRU5USUNBVE9SX0FETUlOIl19.zwd43a7ZZvBizh4ebW6r36aQRmhSj8oHt21HRScGU2mHn0mOR1OEHMhw-0QPRwW75XfcwhpnLk05k9C2VDd-Nx4d_GZn13qgmnTFK-BPBxm620hbWR3arW8sXYSMzDZTZDGQRPDCUBqJigDS51hVZfyA5LvoFdzfbOQsyKXvd-ZDgjfBNFJSt20V9GlS11gqX_Vd9hSSecPONOdLzJbtVZb9iYwc8pb7VCmI47C9WVf4B40xto6uPfPkMGRI1P055HCQoVW6mFwru_N3BZenIl0Mypb-TdLmQatifPQMNFkdozdlhY6v5VQklxqf5l-MH7pDledow3JULAG1ed-cyQ
Authorization: Bearer eyJraWQiOiJkYTFiNzAwMS05NjlkLTQyNzQtYTM5Yy0wYTI2ZjMzODg2NmIiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMkBlbWFpbC5jb20iLCJhdWQiOiJ1c2VyLWludHJvc3BlY3Rpb24iLCJuYmYiOjE3MjIwMTI4NzEsInVzZXJfbmFtZSI6InVzZXIyQGVtYWlsLmNvbSIsInNjb3BlIjpbIm9wZW5pZCIsImVtYWlsIiwicHJvZmlsZSJdLCJpc3MiOiJodHRwOi8vbG9jYWwuYXBpLnZhdXRoZW50aWNhdG9yLmNvbTo5MDkwIiwiZXhwIjoxNzIyMDEzMjMxLCJpYXQiOjE3MjIwMTI4NzEsImp0aSI6ImY5ODQ0ZjYyLTllZDQtNDVmOS1iODJlLWJiZGU4ZGRmNDdmZSIsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiIsIlZBVVRIRU5USUNBVE9SX0FETUlOIl19.f8_LjNZ60y-2vT7kxc63fL0OHVTachIWZcL3aBLhJQZeylwKGWR67ENf474jBPfVX9QqdY-rllQwPp_l0tcVtSoQGXHd-181fPFiKry9AWUZ6jfQPB3EvvTiHmtthebYvZCvgh8EvuJHDr8F1Zf_qpcUMbZgUHE_IxSjX7isWjfWI0lJDK7S7wfKtU4Q_-5dCQq6l26IpOHhE_LXwhVFoBlnGxh_VhGg1fVesVgDX9he-QQxB0LKKJkL9UIKd0BPjgLUZGTSxHhLInhU7wumbPO2Z9TB5bDayOr77ilo5eAPma8c8zUem_BGhcGi3JuiPMfUuqmjPMyYGy_E1XmblQ

{
"mfaMethod": "EMAIL_MFA_METHOD",
"mfaChannel" : "admin11@email.com"
"mfaChannel" : "user2_123@email.com"
}


### associate new email

POST {{host}}/api/mfa/associate?ticket=
POST {{host}}/api/mfa/associate
Content-Type: application/json
Authorization: Bearer eyJraWQiOiJkYTFiNzAwMS05NjlkLTQyNzQtYTM5Yy0wYTI2ZjMzODg2NmIiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbkBlbWFpbC5jb20iLCJhdWQiOiJ1c2VyLWludHJvc3BlY3Rpb24iLCJuYmYiOjE3MjE4OTM1NDIsInVzZXJfbmFtZSI6ImFkbWluQGVtYWlsLmNvbSIsInNjb3BlIjpbIm9wZW5pZCIsImVtYWlsIiwicHJvZmlsZSJdLCJpc3MiOiJodHRwOi8vbG9jYWwuYXBpLnZhdXRoZW50aWNhdG9yLmNvbTo5MDkwIiwiZXhwIjoxNzIxODkzOTAyLCJpYXQiOjE3MjE4OTM1NDIsImp0aSI6ImU2ZDYyMWQzLTJjZmUtNDE1ZC04NGM4LTE0NjEwNGNiZTM2NiIsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiIsIlZBVVRIRU5USUNBVE9SX0FETUlOIl19.zwd43a7ZZvBizh4ebW6r36aQRmhSj8oHt21HRScGU2mHn0mOR1OEHMhw-0QPRwW75XfcwhpnLk05k9C2VDd-Nx4d_GZn13qgmnTFK-BPBxm620hbWR3arW8sXYSMzDZTZDGQRPDCUBqJigDS51hVZfyA5LvoFdzfbOQsyKXvd-ZDgjfBNFJSt20V9GlS11gqX_Vd9hSSecPONOdLzJbtVZb9iYwc8pb7VCmI47C9WVf4B40xto6uPfPkMGRI1P055HCQoVW6mFwru_N3BZenIl0Mypb-TdLmQatifPQMNFkdozdlhY6v5VQklxqf5l-MH7pDledow3JULAG1ed-cyQ
Authorization: Bearer eyJraWQiOiJkYTFiNzAwMS05NjlkLTQyNzQtYTM5Yy0wYTI2ZjMzODg2NmIiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMkBlbWFpbC5jb20iLCJhdWQiOiJ1c2VyLWludHJvc3BlY3Rpb24iLCJuYmYiOjE3MjIwMTI4NzEsInVzZXJfbmFtZSI6InVzZXIyQGVtYWlsLmNvbSIsInNjb3BlIjpbIm9wZW5pZCIsImVtYWlsIiwicHJvZmlsZSJdLCJpc3MiOiJodHRwOi8vbG9jYWwuYXBpLnZhdXRoZW50aWNhdG9yLmNvbTo5MDkwIiwiZXhwIjoxNzIyMDEzMjMxLCJpYXQiOjE3MjIwMTI4NzEsImp0aSI6ImY5ODQ0ZjYyLTllZDQtNDVmOS1iODJlLWJiZGU4ZGRmNDdmZSIsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiIsIlZBVVRIRU5USUNBVE9SX0FETUlOIl19.f8_LjNZ60y-2vT7kxc63fL0OHVTachIWZcL3aBLhJQZeylwKGWR67ENf474jBPfVX9QqdY-rllQwPp_l0tcVtSoQGXHd-181fPFiKry9AWUZ6jfQPB3EvvTiHmtthebYvZCvgh8EvuJHDr8F1Zf_qpcUMbZgUHE_IxSjX7isWjfWI0lJDK7S7wfKtU4Q_-5dCQq6l26IpOHhE_LXwhVFoBlnGxh_VhGg1fVesVgDX9he-QQxB0LKKJkL9UIKd0BPjgLUZGTSxHhLInhU7wumbPO2Z9TB5bDayOr77ilo5eAPma8c8zUem_BGhcGi3JuiPMfUuqmjPMyYGy_E1XmblQ

{
"mfaMethod": "EMAIL_MFA_METHOD",
"mfaChannel" : "[email protected]"
"ticket": "cd6c4b8c-e136-4fec-ad2d-c1bda930dc9e",
"code" : "505509"
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class VerifyEMailChallenge(
mfaMethodsEnrollmentAssociation.associate(ticket)
enableAccountFrom(it.userName)
}
.orElseThrow { throw InvalidTicketException("The ticket $ticket is not a valid ticket, it seems to be expired") }
.orElseThrow { throw InvalidTicketException("The ticket $ticket is not a valid ticket") }

}

private fun enableAccountFrom(email: String): Account =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,32 @@ import com.vauthenticator.server.ticket.Ticket.Companion.MFA_AUTO_ASSOCIATION_CO
import com.vauthenticator.server.ticket.Ticket.Companion.MFA_CHANNEL_CONTEXT_KEY
import com.vauthenticator.server.ticket.Ticket.Companion.MFA_METHOD_CONTEXT_KEY

typealias MfaAssociationVerifier = (ticket: Ticket) -> Unit

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

fun associate(ticket: String) {
associate(ticket) {
it.context.content[MFA_AUTO_ASSOCIATION_CONTEXT_KEY] === MFA_AUTO_ASSOCIATION_CONTEXT_VALUE
fun associate(ticketId: String) {
associate(
ticketId,
) {
if(it.context.content[MFA_AUTO_ASSOCIATION_CONTEXT_KEY] != MFA_AUTO_ASSOCIATION_CONTEXT_VALUE){
throw InvalidTicketException("Mfa association without code is allowed only if in the ticket context there is $MFA_AUTO_ASSOCIATION_CONTEXT_KEY feature enabled")
}
}

}

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

private fun associate(ticket: String, verifier: (ticket: Ticket) -> Unit) {
private fun associate(ticket: String, verifier: MfaAssociationVerifier) {
ticketRepository.loadFor(TicketId(ticket))
.map { ticket ->
verifier.invoke(ticket)
Expand Down Expand Up @@ -56,13 +64,15 @@ class MfaMethodsEnrollment(
): TicketId {
val email = account.email

val mfaAccountMethods = mfaAccountMethodsRepository.findAll(email)
if (!mfaAccountMethods.any { it.method == mfaMethod }) {
mfaAccountMethodsRepository.save(email, mfaMethod, mfaChannel)
}
mfaAccountMethodsRepository.findOne(email, mfaMethod, mfaChannel)
.ifPresentOrElse({},
{ mfaAccountMethodsRepository.save(email, mfaMethod, mfaChannel) }
)

if (sendChallengeCode) {
mfaSender.sendMfaChallenge(email, mfaChannel)
}

return ticketCreator.createTicketFor(
account,
clientAppId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class TaimosOtpMfa(
override fun generateSecretKeyFor(account: Account): MfaSecret {
//todo
val mfatMethod =
mfaAccountMethodsRepository.findOne(account.email, MfaMethod.EMAIL_MFA_METHOD, "todo").orElseGet { null }
mfaAccountMethodsRepository.findOne(account.email, MfaMethod.EMAIL_MFA_METHOD, account.email).orElseGet { null }
val encryptedSecret = keyRepository.keyFor(mfatMethod.key, KeyPurpose.MFA)
val decryptKeyAsByteArray = keyDecrypter.decryptKey(encryptedSecret.dataKey.encryptedPrivateKeyAsString())
val decryptedKey = Hex.encodeHexString(decoder.decode(decryptKeyAsByteArray))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import com.vauthenticator.server.oauth2.clientapp.ClientApplicationRepository
import com.vauthenticator.server.oauth2.clientapp.Scope
import com.vauthenticator.server.oauth2.clientapp.Scopes
import com.vauthenticator.server.support.AccountTestFixture.anAccount
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 io.mockk.every
import io.mockk.impl.annotations.MockK
Expand Down Expand Up @@ -66,7 +68,8 @@ internal class SendVerifyEMailChallengeTest {
MfaMethod.EMAIL_MFA_METHOD,
account.email,
ClientAppId.empty(),
false
false,
mapOf(Ticket.MFA_AUTO_ASSOCIATION_CONTEXT_KEY to MFA_AUTO_ASSOCIATION_CONTEXT_VALUE)
)
} returns ticketId
every { mailVerificationMailSender.sendFor(account, requestContext) } just runs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import org.junit.jupiter.api.extension.ExtendWith
import java.util.*

private const val RAW_TICKET = "A_TICKET"
private const val CODE = "CODE"

@ExtendWith(MockKExtension::class)
internal class VerifyEMailChallengeTest {
Expand Down Expand Up @@ -60,13 +59,12 @@ internal class VerifyEMailChallengeTest {
ClientAppId.empty().content
)
)
every { mfaMethodsEnrollmentAssociation.associate(RAW_TICKET, CODE) } just runs
every { mfaMethodsEnrollmentAssociation.associate(RAW_TICKET) } just runs
every { accountRepository.accountFor(account.email) } returns Optional.of(account)
every { accountRepository.save(enabledAccount) } just runs
every { ticketRepository.delete(ticketId) } just runs

underTest.verifyMail(RAW_TICKET)
verify(exactly = 1) { mfaMethodsEnrollmentAssociation.associate(RAW_TICKET, CODE) }
verify(exactly = 1) { mfaMethodsEnrollmentAssociation.associate(RAW_TICKET) }
}

@Test
Expand All @@ -82,7 +80,7 @@ internal class VerifyEMailChallengeTest {
)
)
every { accountRepository.accountFor(account.email) } returns Optional.empty()
every { mfaMethodsEnrollmentAssociation.associate(RAW_TICKET, CODE) } just runs
every { mfaMethodsEnrollmentAssociation.associate(RAW_TICKET) } just runs

assertThrows(InvalidTicketException::class.java) { underTest.verifyMail(RAW_TICKET) }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.vauthenticator.server.mfa.domain

import com.vauthenticator.server.clientapp.ClientAppFixture.aClientAppId
import com.vauthenticator.server.keys.Kid
import com.vauthenticator.server.mfa.domain.MfaMethod.EMAIL_MFA_METHOD
import com.vauthenticator.server.mfa.repository.MfaAccountMethodsRepository
import com.vauthenticator.server.support.AccountTestFixture.anAccount
import com.vauthenticator.server.support.TicketFixture.ticketContext
Expand All @@ -16,6 +18,9 @@ import junit.framework.TestCase.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import java.util.*

private const val emailMfaChannel = "[email protected]"

@ExtendWith(MockKExtension::class)
class MfaMethodsEnrollmentTest {
Expand All @@ -31,6 +36,16 @@ class MfaMethodsEnrollmentTest {

private lateinit var uut: MfaMethodsEnrollment

private val account = anAccount()
private val clientAppId = aClientAppId()
private val ticketId = TicketId("A_TICKET")
private val emailMfaAccountMethod = MfaAccountMethod(
account.email,
Kid("A_KID"),
EMAIL_MFA_METHOD,
emailMfaChannel
)

@BeforeEach
fun setUp() {
uut = MfaMethodsEnrollment(
Expand All @@ -42,38 +57,52 @@ class MfaMethodsEnrollmentTest {

@Test
fun `when the enrolment do not send the verification code together the verification ticket`() {
val account = anAccount()
val clientAppId = aClientAppId()

every {
mfaAccountMethodsRepository.findOne(
account.email,
EMAIL_MFA_METHOD,
emailMfaChannel
)
} returns Optional.of(emailMfaAccountMethod)
every { ticketCreator.createTicketFor(account, clientAppId, ticketContext(emailMfaChannel)) } returns ticketId

val ticketId = TicketId("A_TICKET")
val actual = uut.enroll(account, EMAIL_MFA_METHOD, emailMfaChannel, clientAppId, false)

every { ticketCreator.createTicketFor(account, clientAppId, ticketContext(account.email)) } returns ticketId
val actual = uut.enroll(account, MfaMethod.EMAIL_MFA_METHOD, account.email, clientAppId, false)
verify {
ticketCreator.createTicketFor(
account, clientAppId, ticketContext(account.email)
mfaAccountMethodsRepository.findOne(
account.email,
EMAIL_MFA_METHOD,
emailMfaChannel
)
}
verify { ticketCreator.createTicketFor(account, clientAppId, ticketContext(emailMfaChannel)) }

assertEquals(ticketId, actual)
}

@Test
fun `when the enrolment send the verification code together the verification ticket`() {
val account = anAccount()
val clientAppId = aClientAppId()


val ticketId = TicketId("A_TICKET")

every { ticketCreator.createTicketFor(account, clientAppId, ticketContext(account.email)) } returns ticketId
every { mfaSender.sendMfaChallenge(account.email, account.email) } just runs
every {
mfaAccountMethodsRepository.findOne(
account.email,
EMAIL_MFA_METHOD,
emailMfaChannel
)
} returns Optional.of(emailMfaAccountMethod)
every { ticketCreator.createTicketFor(account, clientAppId, ticketContext(emailMfaChannel)) } returns ticketId
every { mfaSender.sendMfaChallenge(account.email, emailMfaChannel) } just runs

val actual = uut.enroll(account, MfaMethod.EMAIL_MFA_METHOD, account.email, clientAppId, true)
val actual = uut.enroll(account, EMAIL_MFA_METHOD, emailMfaChannel, clientAppId, true)

verify { ticketCreator.createTicketFor(account, clientAppId, ticketContext(account.email)) }
verify { mfaSender.sendMfaChallenge(account.email, account.email) }
verify {
mfaAccountMethodsRepository.findOne(
account.email,
EMAIL_MFA_METHOD,
emailMfaChannel
)
}
verify { ticketCreator.createTicketFor(account, clientAppId, ticketContext(emailMfaChannel)) }
verify { mfaSender.sendMfaChallenge(account.email, emailMfaChannel) }

assertEquals(ticketId, actual)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class TaimosOtpMfaTest {
KeyPurpose.MFA,
0L
)
every { mfaAccountMethodsRepository.findOne(email, MfaMethod.EMAIL_MFA_METHOD,email) } returns
of(MfaAccountMethod(email, Kid("A_KID"), MfaMethod.EMAIL_MFA_METHOD,email))
every { mfaAccountMethodsRepository.findOne(email, MfaMethod.EMAIL_MFA_METHOD, email) } returns
of(MfaAccountMethod(email, Kid("A_KID"), MfaMethod.EMAIL_MFA_METHOD, email))

every { keyRepository.keyFor(Kid("A_KID"), KeyPurpose.MFA) } returns key
every { keyDecrypter.decryptKey("QV9FTkNSWVBURURfS0VZ") } returns "QV9ERUNSWVBURURfU1lNTUVUUklDX0tFWQ=="
Expand Down
Loading

0 comments on commit 9aaa715

Please sign in to comment.