-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: save multiple identity provider ids for same email
- Loading branch information
Showing
10 changed files
with
121 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,9 +6,11 @@ import org.springframework.beans.factory.annotation.Autowired | |
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc | ||
import org.springframework.boot.test.context.SpringBootTest | ||
import org.springframework.http.MediaType.APPLICATION_JSON | ||
import org.springframework.security.oauth2.jwt.Jwt | ||
import org.springframework.test.web.servlet.MockMvc | ||
import org.springframework.test.web.servlet.ResultActions | ||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder | ||
import tw.waterballsa.gaas.domain.User | ||
|
||
@SpringBootTest | ||
@AutoConfigureMockMvc | ||
|
@@ -19,6 +21,8 @@ abstract class AbstractSpringBootTest { | |
@Autowired | ||
private lateinit var objectMapper: ObjectMapper | ||
|
||
protected val mockUser: User = mockDefaultUser() | ||
|
||
protected fun <T> ResultActions.getBody(type: Class<T>): T = | ||
andReturn().response.contentAsString.let { objectMapper.readValue(it, type) } | ||
|
||
|
@@ -29,4 +33,18 @@ abstract class AbstractSpringBootTest { | |
|
||
protected fun MockHttpServletRequestBuilder.withJson(request: Any): MockHttpServletRequestBuilder = | ||
contentType(APPLICATION_JSON).content(request.toJson()) | ||
|
||
protected fun mockDefaultUser(): User = | ||
User(User.Id("1"), | ||
"[email protected]", | ||
"user-437b200d-da9c-449e-b147-114b4822b5aa", | ||
listOf("google-oauth2|102527320242660434908") | ||
) | ||
|
||
protected fun mockJwt(subject: String, email: String): Jwt = | ||
Jwt.withTokenValue("mock-token") | ||
.header("alg", "none") | ||
.subject(subject) | ||
.claim("email", email) | ||
.build() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,10 +4,10 @@ import org.assertj.core.api.Assertions.assertThat | |
import org.junit.jupiter.api.BeforeEach | ||
import org.junit.jupiter.api.Test | ||
import org.springframework.beans.factory.annotation.Autowired | ||
import org.springframework.security.oauth2.jwt.Jwt | ||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt | ||
import org.springframework.test.web.servlet.ResultActions | ||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get | ||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath | ||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status | ||
import tw.waterballsa.gaas.application.repositories.UserRepository | ||
import tw.waterballsa.gaas.domain.User | ||
|
@@ -17,63 +17,92 @@ class OAuth2ControllerTest @Autowired constructor( | |
val userRepository: UserRepository, | ||
) : AbstractSpringBootTest() { | ||
|
||
val email = "[email protected]" | ||
val googleIdentityProviderId = "google-oauth2|102527320242660434908" | ||
val discordIdentityProviderId = "discord|102527320242660434908" | ||
|
||
@BeforeEach | ||
fun cleanUp() { | ||
userRepository.deleteAll() | ||
} | ||
|
||
@Test | ||
fun givenInvalidJwtSubject_whenUserLogin_thenShouldLoginFailed() { | ||
givenInvalidJwtSubject() | ||
?.whenUserLogin() | ||
?.thenShouldLoginFailed() | ||
givenInvalidJwt() | ||
.whenUserLogin() | ||
.thenShouldLoginFailed() | ||
} | ||
|
||
@Test | ||
fun givenNewUserWithJwtSubject_whenUserLogin_thenCreateUser() { | ||
givenNewUserWithJwtSubject() | ||
fun givenOldEmail_andOldIdentityProviderId_whenUserLogin_thenLoginSuccessfully() { | ||
givenGoogleOAuth2Jwt() | ||
.whenUserLogin() | ||
.thenCreateUser() | ||
.thenLoginSuccessfully() | ||
} | ||
|
||
@Test | ||
fun givenOldUser_whenUserLogin_thenShouldLoginSuccessfully() { | ||
givenOldUserWithJwtSubject() | ||
fun givenOldEmail_andNewIdentityProviderId_whenUserLogin_thenSaveNewIdentityProviderId() { | ||
givenDiscordOAuth2Jwt() | ||
.whenUserLogin() | ||
.thenLoginSuccessfully() | ||
.thenSaveNewIdentityProviderId() | ||
} | ||
|
||
@Test | ||
fun givenNewEmail_andNewIdentityProviderId_whenUserLogin_thenCreateNewUser() { | ||
givenJwt(googleIdentityProviderId, email) | ||
.whenUserLogin() | ||
.thenCreateNewUser() | ||
} | ||
|
||
private fun givenInvalidJwtSubject(): String? = null | ||
private fun givenInvalidJwt(): Jwt = | ||
Jwt("invalid_token", | ||
null, | ||
null, | ||
mapOf("alg" to "none"), | ||
mapOf("no_email" to "none")) | ||
|
||
private fun givenNewUserWithJwtSubject(): String { | ||
val subject = "google-oauth2|102527320242660434908" | ||
assertThat(userRepository.existsByIdentitiesIn(subject)).isFalse() | ||
return subject | ||
private fun givenGoogleOAuth2Jwt(): Jwt { | ||
userRepository.createUser(mockUser) | ||
return givenJwt(googleIdentityProviderId, mockUser.email) | ||
} | ||
|
||
private fun givenOldUserWithJwtSubject(): String { | ||
val subject = givenNewUserWithJwtSubject() | ||
userRepository.createUser(User(identities = listOf(subject))) | ||
assertThat(userRepository.existsByIdentitiesIn(subject)).isTrue() | ||
return subject | ||
private fun givenDiscordOAuth2Jwt(): Jwt { | ||
userRepository.createUser(mockUser) | ||
return givenJwt(discordIdentityProviderId, mockUser.email) | ||
} | ||
|
||
private fun String.whenUserLogin(): ResultActions = | ||
mockMvc.perform(get("/").with(jwt().jwt { it.subject(this) })) | ||
private fun givenJwt(identityProviderId: String, email: String): Jwt = | ||
mockJwt(identityProviderId, email) | ||
|
||
private fun Jwt.whenUserLogin(): ResultActions = | ||
mockMvc.perform(get("/").with(jwt().jwt(this))) | ||
|
||
private fun ResultActions.thenShouldLoginFailed() { | ||
this.andExpect(status().isBadRequest) | ||
.andExpect(jsonPath("$").value("JWT subject is null")) | ||
} | ||
|
||
private fun ResultActions.thenLoginSuccessfully() { | ||
this.andExpect(status().isOk) | ||
} | ||
|
||
private fun ResultActions.thenCreateUser() { | ||
private fun ResultActions.thenSaveNewIdentityProviderId() { | ||
thenLoginSuccessfully() | ||
val subject = "google-oauth2|102527320242660434908" | ||
assertThat(userRepository.existsByIdentitiesIn(subject)).isTrue() | ||
userRepository.findByEmail(email)!! | ||
.thenSaveIdentityProviderId(googleIdentityProviderId) | ||
.thenSaveIdentityProviderId(discordIdentityProviderId) | ||
} | ||
|
||
private fun ResultActions.thenCreateNewUser() { | ||
thenLoginSuccessfully() | ||
userRepository.findByEmail(email)!! | ||
.thenSaveIdentityProviderId(googleIdentityProviderId) | ||
} | ||
|
||
private fun User.thenSaveIdentityProviderId(identityProviderId: String): User { | ||
assertThat(this).isNotNull | ||
assertThat(identities).isNotEmpty | ||
assertThat(identities).contains(identityProviderId) | ||
return this | ||
} | ||
|
||
} |