Skip to content

Commit

Permalink
🔒 : encrypt Azure & Google credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
juwit committed Aug 16, 2020
1 parent a6821f4 commit 920fa83
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 32 deletions.
12 changes: 3 additions & 9 deletions src/main/java/io/gaia_app/credentials/Credentials.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.springframework.data.mongodb.core.mapping.Document
Type(value = GoogleCredentials::class, name = "google"),
Type(value = AzureRMCredentials::class, name = "azurerm")
)
abstract class Credentials {
sealed class Credentials(var provider: String) {

@Id
lateinit var id: String
Expand All @@ -33,12 +33,6 @@ abstract class Credentials {
@DBRef
lateinit var createdBy: User

var provider: String

constructor(provider: String) {
this.provider = provider
}

abstract fun toEnv(): List<String>
}

Expand All @@ -48,12 +42,12 @@ data class AWSCredentials(var accessKey:String, var secretKey:String):Credential
}

@Document
data class GoogleCredentials(val serviceAccountJSONContents:String):Credentials("google") {
data class GoogleCredentials(var serviceAccountJSONContents:String):Credentials("google") {
override fun toEnv() = listOf("GOOGLE_CREDENTIALS=$serviceAccountJSONContents")
}

@Document
data class AzureRMCredentials(val clientId:String, val clientSecret:String):Credentials("azurerm") {
data class AzureRMCredentials(var clientId:String, var clientSecret:String):Credentials("azurerm") {
override fun toEnv() = listOf("ARM_CLIENT_ID=$clientId", "ARM_CLIENT_SECRET=$clientSecret")
}

Expand Down
52 changes: 41 additions & 11 deletions src/main/java/io/gaia_app/credentials/CredentialsService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import org.springframework.stereotype.Service
import java.util.*

@Service
class CredentialsService(val credentialsRepository: CredentialsRepository){

@Autowired(required = false)
var encryptionService: EncryptionService? = null
class CredentialsService(val credentialsRepository: CredentialsRepository, val encryptionService: EncryptionService) {

fun findById(id: String): Optional<Credentials> = this.credentialsRepository.findById(id).map { decrypt(it) }

Expand All @@ -22,13 +19,18 @@ class CredentialsService(val credentialsRepository: CredentialsRepository){
return encrypt(credentials).apply { credentialsRepository.save(credentials) }
}

fun deleteById(id:String) = credentialsRepository.deleteById(id)
fun deleteById(id: String) = credentialsRepository.deleteById(id)

fun encrypt(it: Credentials): Credentials {
return when(it) {
is AWSCredentials -> encryptionService?.encrypt(it) ?: it
else -> it
}
fun encrypt(it: Credentials): Credentials = when (it) {
is AWSCredentials -> encryptionService.encryptAwsCredentials(it)
is GoogleCredentials -> encryptionService.encryptGoogleCredentials(it)
is AzureRMCredentials -> encryptionService.encryptAzurermCredentials(it)
}

fun decrypt(it: Credentials): Credentials = when (it) {
is AWSCredentials -> encryptionService.decryptAwsCredentials(it)
is GoogleCredentials -> encryptionService.decryptGoogleCredentials(it)
is AzureRMCredentials -> encryptionService.decryptAzurermCredentials(it)
}

fun decrypt(it: Credentials): Credentials {
Expand All @@ -45,8 +47,36 @@ fun EncryptionService.decrypt(awsCredentials: AWSCredentials): AWSCredentials {
return awsCredentials
}

fun EncryptionService.encrypt(awsCredentials: AWSCredentials): AWSCredentials {
fun EncryptionService.encryptAwsCredentials(awsCredentials: AWSCredentials): Credentials {
awsCredentials.accessKey = this.encrypt(awsCredentials.accessKey)
awsCredentials.secretKey = this.encrypt(awsCredentials.secretKey)
return awsCredentials
}

fun EncryptionService.decryptAwsCredentials(awsCredentials: AWSCredentials): Credentials {
awsCredentials.accessKey = this.decrypt(awsCredentials.accessKey)
awsCredentials.secretKey = this.decrypt(awsCredentials.secretKey)
return awsCredentials
}

fun EncryptionService.encryptGoogleCredentials(googleCredentials: GoogleCredentials): Credentials {
googleCredentials.serviceAccountJSONContents = this.encrypt(googleCredentials.serviceAccountJSONContents)
return googleCredentials
}

fun EncryptionService.decryptGoogleCredentials(googleCredentials: GoogleCredentials): Credentials {
googleCredentials.serviceAccountJSONContents = this.decrypt(googleCredentials.serviceAccountJSONContents)
return googleCredentials
}

fun EncryptionService.encryptAzurermCredentials(azureRMCredentials: AzureRMCredentials): Credentials {
azureRMCredentials.clientId = this.encrypt(azureRMCredentials.clientId)
azureRMCredentials.clientSecret = this.encrypt(azureRMCredentials.clientSecret)
return azureRMCredentials
}

fun EncryptionService.decryptAzurermCredentials(azureRMCredentials: AzureRMCredentials): Credentials {
azureRMCredentials.clientId = this.decrypt(azureRMCredentials.clientId)
azureRMCredentials.clientSecret = this.decrypt(azureRMCredentials.clientSecret)
return azureRMCredentials
}
84 changes: 72 additions & 12 deletions src/test/java/io/gaia_app/credentials/CredentialsServiceTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,39 @@ package io.gaia_app.credentials

import io.gaia_app.encryption.EncryptionService
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.ArgumentMatchers
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
import org.mockito.Mockito.*
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.junit.jupiter.MockitoSettings
import org.mockito.quality.Strictness
import org.mockito.stubbing.Answer
import java.util.*

@ExtendWith(MockitoExtension::class)
@MockitoSettings(strictness = Strictness.LENIENT)
class CredentialsServiceTest {

@Mock
lateinit var credentialsRepository: CredentialsRepository

@Mock
lateinit var encryptionService: EncryptionService

@InjectMocks
lateinit var credentialsService: CredentialsService

@BeforeEach
internal fun setUp() {
`when`(encryptionService.encrypt(ArgumentMatchers.anyString())).then(Answer { it.arguments[0] as String })
`when`(encryptionService.decrypt(ArgumentMatchers.anyString())).then(Answer { it.arguments[0] as String })
}

@Test
fun loadCredentials() {
val awsCredentials = AWSCredentials("access", "secret")
Expand Down Expand Up @@ -53,31 +67,77 @@ class CredentialsServiceTest {
lateinit var credentialsService: CredentialsService

@Test
fun loadCredentials_shouldReturnDecryptedCredentials() {
credentialsService.encryptionService = encryptionService

fun loadAWSCredentials_shouldReturnDecryptedCredentials() {
val encryptedAwsCredentials = AWSCredentials("encryptedAccess", "encryptedSecret")
val plainAWSCredentials = AWSCredentials("access", "secret")

`when`(encryptionService.decryptBatch(listOf("encryptedAccess", "encryptedSecret"))).thenReturn(listOf("access", "secret"))
`when`(encryptionService.decrypt("encryptedAccess")).thenReturn("access")
`when`(encryptionService.decrypt("encryptedSecret")).thenReturn("secret")
`when`(credentialsRepository.findById("aws")).thenReturn(Optional.of(encryptedAwsCredentials))

val credentials = credentialsService.findById("aws")
assertThat(credentials).isEqualTo(Optional.of(plainAWSCredentials))
val credentials = credentialsService.findById("aws").get()
assertThat(credentials).isEqualTo(plainAWSCredentials)
}

@Test
fun saveCredentials_shouldReturnEncryptCredentials() {
credentialsService.encryptionService = encryptionService

fun saveAWSCredentials_shouldReturnEncryptCredentials() {
val plainAWSCredentials = AWSCredentials("access", "secret")
val encryptedAwsCredentials = AWSCredentials("encryptedAccess", "encryptedSecret")

`when`(encryptionService.encryptBatch(listOf("access", "secret"))).thenReturn(listOf("encryptedAccess", "encryptedSecret"))
`when`(encryptionService.encrypt("access")).thenReturn("encryptedAccess")
`when`(encryptionService.encrypt("secret")).thenReturn("encryptedSecret")

val credentials = credentialsService.save(plainAWSCredentials)
assertThat(credentials).isEqualTo(encryptedAwsCredentials)
}

@Test
fun loadAzureRMCredentials_shouldReturnDecryptedCredentials() {
val encryptedAzureRMCredentials = AzureRMCredentials("encryptedClientId", "encryptedSecret")
val plainAzureRMCredentials = AzureRMCredentials("clientId", "secret")

`when`(encryptionService.decrypt("encryptedClientId")).thenReturn("clientId")
`when`(encryptionService.decrypt("encryptedSecret")).thenReturn("secret")
`when`(credentialsRepository.findById("AzureRM")).thenReturn(Optional.of(encryptedAzureRMCredentials))

val credentials = credentialsService.findById("AzureRM").get()
assertThat(credentials).isEqualTo(plainAzureRMCredentials)
}

@Test
fun saveAzureRMCredentials_shouldReturnEncryptCredentials() {
val plainAzureRMCredentials = AzureRMCredentials("clientId", "secret")
val encryptedAzureRMCredentials = AzureRMCredentials("encryptedClientId", "encryptedSecret")

`when`(encryptionService.encrypt("clientId")).thenReturn("encryptedClientId")
`when`(encryptionService.encrypt("secret")).thenReturn("encryptedSecret")

val credentials = credentialsService.save(plainAzureRMCredentials)
assertThat(credentials).isEqualTo(encryptedAzureRMCredentials)
}

@Test
fun loadGoogleCredentials_shouldReturnDecryptedCredentials() {
val encryptedGoogleCredentials = GoogleCredentials("encryptedJSON")
val plainGoogleCredentials = GoogleCredentials("plainJSON")

`when`(encryptionService.decrypt("encryptedJSON")).thenReturn("plainJSON")
`when`(credentialsRepository.findById("Google")).thenReturn(Optional.of(encryptedGoogleCredentials))

val credentials = credentialsService.findById("Google").get()
assertThat(credentials).isEqualTo(plainGoogleCredentials)
}

@Test
fun saveGoogleCredentials_shouldReturnEncryptCredentials() {
val plainGoogleCredentials = GoogleCredentials("plainJSON")
val encryptedGoogleCredentials = GoogleCredentials("encryptedJSON")

`when`(encryptionService.encrypt("plainJSON")).thenReturn("encryptedJSON")

val credentials = credentialsService.save(plainGoogleCredentials)
assertThat(credentials).isEqualTo(encryptedGoogleCredentials)
}
}

}
27 changes: 27 additions & 0 deletions src/test/java/io/gaia_app/credentials/CredentialsTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.gaia_app.credentials

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

import org.junit.jupiter.api.Assertions.*

internal class CredentialsTest {

@Test
fun `toEnv() for AWSCredentials should return AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY`() {
assertThat(AWSCredentials("access", "secret").toEnv())
.containsExactly("AWS_ACCESS_KEY_ID=access", "AWS_SECRET_ACCESS_KEY=secret")
}

@Test
fun `toEnv() for AzureRMCredentials should return ARM_CLIENT_ID and ARM_CLIENT_SECRET`() {
assertThat(AzureRMCredentials("clientId", "secret").toEnv())
.containsExactly("ARM_CLIENT_ID=clientId", "ARM_CLIENT_SECRET=secret")
}

@Test
fun `toEnv() for GoogleCredentials should return GOOGLE_CREDENTIALS`() {
assertThat(GoogleCredentials("jsonContent").toEnv())
.containsExactly("GOOGLE_CREDENTIALS=jsonContent")
}
}

0 comments on commit 920fa83

Please sign in to comment.