-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'release/os/5.2' into yift/core-18720/introduce-session-…
…state # Conflicts: # gradle.properties
- Loading branch information
Showing
34 changed files
with
1,440 additions
and
46 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
103 changes: 103 additions & 0 deletions
103
.../crypto-client-impl/src/main/kotlin/net/corda/crypto/client/impl/SessionEncryptionImpl.kt
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 |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package net.corda.crypto.client.impl | ||
|
||
import net.corda.crypto.core.ApiNames.DECRYPT_PATH | ||
import net.corda.crypto.core.ApiNames.ENCRYPT_PATH | ||
import net.corda.crypto.core.CryptoConsts | ||
import net.corda.crypto.core.CryptoTenants | ||
import net.corda.data.crypto.wire.ops.encryption.request.DecryptRpcCommand | ||
import net.corda.data.crypto.wire.ops.encryption.request.EncryptRpcCommand | ||
import net.corda.data.crypto.wire.ops.encryption.response.CryptoDecryptionResult | ||
import net.corda.data.crypto.wire.ops.encryption.response.CryptoEncryptionResult | ||
import net.corda.data.crypto.wire.ops.encryption.response.DecryptionOpsResponse | ||
import net.corda.data.crypto.wire.ops.encryption.response.EncryptionOpsError | ||
import net.corda.data.crypto.wire.ops.encryption.response.EncryptionOpsResponse | ||
import net.corda.libs.configuration.SmartConfig | ||
import net.corda.libs.platform.PlatformInfoProvider | ||
import net.corda.messaging.api.publisher.HttpRpcClient | ||
import net.corda.messaging.api.publisher.send | ||
import net.corda.schema.configuration.BootConfig.CRYPTO_WORKER_REST_ENDPOINT | ||
import net.corda.v5.base.exceptions.CordaRuntimeException | ||
import net.corda.v5.crypto.exceptions.CryptoException | ||
import org.slf4j.Logger | ||
import org.slf4j.LoggerFactory | ||
import java.net.URI | ||
import java.nio.ByteBuffer | ||
|
||
@Suppress("ThrowsCount") | ||
class SessionEncryptionImpl( | ||
private val sender: HttpRpcClient, | ||
platformInfoProvider: PlatformInfoProvider, | ||
messagingConfig: SmartConfig, | ||
) { | ||
private companion object { | ||
val logger: Logger = LoggerFactory.getLogger(this::class.java.enclosingClass) | ||
} | ||
|
||
fun encryptSessionData(plainBytes: ByteArray, alias: String?): ByteArray { | ||
logger.info( | ||
"Sending '{}'(alias={})", | ||
EncryptRpcCommand::class.java.simpleName, | ||
alias, | ||
) | ||
val request = EncryptRpcCommand( | ||
CryptoConsts.Categories.ENCRYPTION_SECRET, | ||
alias, | ||
ByteBuffer.wrap(plainBytes), | ||
) | ||
|
||
val response = sender.send<EncryptionOpsResponse>( | ||
getRequestUrl(ENCRYPT_PATH), | ||
request, | ||
)?.response ?: throw CordaRuntimeException( | ||
"Received empty response for ${request::class.java.name} for tenant '${CryptoTenants.P2P}'.", | ||
) | ||
|
||
return when (response) { | ||
is CryptoEncryptionResult -> response.cipherBytes.array() | ||
is EncryptionOpsError -> throw CryptoException( | ||
"${response.errorMessage.errorType} - ${response.errorMessage.errorMessage}", | ||
) | ||
else -> throw CordaRuntimeException( | ||
"Unexpected response type ${response::class.java} for ${request::class.java.name}.", | ||
) | ||
} | ||
} | ||
|
||
fun decryptSessionData(cipherBytes: ByteArray, alias: String?): ByteArray { | ||
logger.info( | ||
"Sending '{}'(alias={})", | ||
DecryptRpcCommand::class.java.simpleName, | ||
alias, | ||
) | ||
val request = DecryptRpcCommand( | ||
CryptoConsts.Categories.ENCRYPTION_SECRET, | ||
alias, | ||
ByteBuffer.wrap(cipherBytes), | ||
) | ||
val response = sender.send<DecryptionOpsResponse>( | ||
getRequestUrl(DECRYPT_PATH), | ||
request, | ||
)?.response ?: throw CordaRuntimeException( | ||
"Received empty response for ${request::class.java.name} for tenant '${CryptoTenants.P2P}'.", | ||
) | ||
|
||
return when (response) { | ||
is CryptoDecryptionResult -> response.plainBytes.array() | ||
is EncryptionOpsError -> throw CryptoException( | ||
"${response.errorMessage.errorType} - ${response.errorMessage.errorMessage}", | ||
) | ||
else -> throw CordaRuntimeException( | ||
"Unexpected response type ${response::class.java} for ${request::class.java.name}.", | ||
) | ||
} | ||
} | ||
|
||
private val baseUrl by lazy { | ||
val platformVersion = platformInfoProvider.localWorkerSoftwareShortVersion | ||
"http://${messagingConfig.getString(CRYPTO_WORKER_REST_ENDPOINT)}/api/$platformVersion" | ||
} | ||
|
||
private fun getRequestUrl(path: String): URI { | ||
return URI.create("$baseUrl$path") | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
...lient-impl/src/main/kotlin/net/corda/crypto/client/impl/SessionEncryptionOpsClientImpl.kt
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 |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package net.corda.crypto.client.impl | ||
|
||
import net.corda.configuration.read.ConfigChangedEvent | ||
import net.corda.configuration.read.ConfigurationReadService | ||
import net.corda.crypto.client.SessionEncryptionOpsClient | ||
import net.corda.crypto.component.impl.AbstractConfigurableComponent | ||
import net.corda.crypto.component.impl.DependenciesTracker | ||
import net.corda.libs.configuration.helper.getConfig | ||
import net.corda.libs.platform.PlatformInfoProvider | ||
import net.corda.lifecycle.LifecycleCoordinatorFactory | ||
import net.corda.lifecycle.LifecycleCoordinatorName | ||
import net.corda.messaging.api.publisher.factory.PublisherFactory | ||
import net.corda.schema.configuration.ConfigKeys.MESSAGING_CONFIG | ||
import org.osgi.service.component.annotations.Activate | ||
import org.osgi.service.component.annotations.Component | ||
import org.osgi.service.component.annotations.Reference | ||
|
||
@Component(service = [SessionEncryptionOpsClient::class]) | ||
class SessionEncryptionOpsClientImpl @Activate constructor( | ||
@Reference(service = LifecycleCoordinatorFactory::class) | ||
coordinatorFactory: LifecycleCoordinatorFactory, | ||
@Reference(service = PublisherFactory::class) | ||
private val publisherFactory: PublisherFactory, | ||
@Reference(service = ConfigurationReadService::class) | ||
configurationReadService: ConfigurationReadService, | ||
@Reference(service = PlatformInfoProvider::class) | ||
val platformInfoProvider: PlatformInfoProvider, | ||
) : AbstractConfigurableComponent<SessionEncryptionOpsClientImpl.Impl>( | ||
coordinatorFactory = coordinatorFactory, | ||
myName = LifecycleCoordinatorName.forComponent<SessionEncryptionOpsClient>(), | ||
configurationReadService = configurationReadService, | ||
upstream = DependenciesTracker.Default( | ||
setOf( | ||
LifecycleCoordinatorName.forComponent<ConfigurationReadService>(), | ||
), | ||
), | ||
configKeys = setOf(MESSAGING_CONFIG), | ||
), | ||
SessionEncryptionOpsClient { | ||
override fun encryptSessionData(plainBytes: ByteArray, alias: String?): ByteArray = | ||
impl.ops.encryptSessionData(plainBytes, alias) | ||
|
||
override fun decryptSessionData(cipherBytes: ByteArray, alias: String?): ByteArray = | ||
impl.ops.decryptSessionData(cipherBytes, alias) | ||
|
||
override fun createActiveImpl(event: ConfigChangedEvent): Impl = | ||
Impl(publisherFactory, platformInfoProvider, event) | ||
|
||
class Impl( | ||
publisherFactory: PublisherFactory, | ||
platformInfoProvider: PlatformInfoProvider, | ||
event: ConfigChangedEvent, | ||
) : AbstractImpl { | ||
val ops = SessionEncryptionImpl( | ||
publisherFactory.createHttpRpcClient(), | ||
platformInfoProvider, | ||
event.config.getConfig(MESSAGING_CONFIG), | ||
) | ||
override val downstream = DependenciesTracker.AlwaysUp() | ||
} | ||
} |
116 changes: 116 additions & 0 deletions
116
...l/src/test/kotlin/net/corda/crypto/client/impl/SessionEncryptionOpsClientComponentTest.kt
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 |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package net.corda.crypto.client.impl | ||
|
||
import net.corda.configuration.read.ConfigChangedEvent | ||
import net.corda.configuration.read.ConfigurationReadService | ||
import net.corda.data.crypto.wire.ops.encryption.request.DecryptRpcCommand | ||
import net.corda.data.crypto.wire.ops.encryption.request.EncryptRpcCommand | ||
import net.corda.data.crypto.wire.ops.encryption.response.CryptoDecryptionResult | ||
import net.corda.data.crypto.wire.ops.encryption.response.CryptoEncryptionResult | ||
import net.corda.data.crypto.wire.ops.encryption.response.EncryptionOpsResponse | ||
import net.corda.data.crypto.wire.ops.encryption.response.DecryptionOpsResponse | ||
import net.corda.libs.configuration.SmartConfig | ||
import net.corda.libs.platform.PlatformInfoProvider | ||
import net.corda.lifecycle.LifecycleCoordinator | ||
import net.corda.lifecycle.LifecycleCoordinatorFactory | ||
import net.corda.lifecycle.LifecycleEventHandler | ||
import net.corda.lifecycle.LifecycleStatus | ||
import net.corda.lifecycle.RegistrationHandle | ||
import net.corda.lifecycle.RegistrationStatusChangeEvent | ||
import net.corda.lifecycle.Resource | ||
import net.corda.lifecycle.StartEvent | ||
import net.corda.messaging.api.publisher.HttpRpcClient | ||
import net.corda.messaging.api.publisher.factory.PublisherFactory | ||
import net.corda.schema.configuration.BootConfig | ||
import net.corda.schema.configuration.ConfigKeys | ||
import org.assertj.core.api.Assertions.assertThat | ||
import org.junit.jupiter.api.Test | ||
import org.mockito.kotlin.any | ||
import org.mockito.kotlin.argumentCaptor | ||
import org.mockito.kotlin.doAnswer | ||
import org.mockito.kotlin.doReturn | ||
import org.mockito.kotlin.eq | ||
import org.mockito.kotlin.mock | ||
import org.mockito.kotlin.whenever | ||
import java.nio.ByteBuffer | ||
|
||
class SessionEncryptionOpsClientComponentTest { | ||
private val handler = argumentCaptor<LifecycleEventHandler>() | ||
private val registrationHandle = mock<RegistrationHandle>() | ||
private val coordinator = mock<LifecycleCoordinator>() { | ||
on { status } doReturn LifecycleStatus.UP | ||
on { start() } doAnswer { | ||
handler.firstValue.processEvent(StartEvent(), mock) | ||
} | ||
on { followStatusChangesByName(any()) } doReturn registrationHandle | ||
} | ||
private val coordinatorFactory = mock<LifecycleCoordinatorFactory> { | ||
on { createCoordinator(any(), handler.capture()) } doReturn coordinator | ||
} | ||
private val encryptionResponse = mock<EncryptionOpsResponse>() | ||
private val decryptionResponse = mock<DecryptionOpsResponse>() | ||
private val httpRpcClient = mock<HttpRpcClient> { | ||
on { send(any(), any<EncryptRpcCommand>(), eq(EncryptionOpsResponse::class.java)) } doReturn encryptionResponse | ||
on { send(any(), any<DecryptRpcCommand>(), eq(DecryptionOpsResponse::class.java)) } doReturn decryptionResponse | ||
} | ||
private val publisherFactory = mock<PublisherFactory> { | ||
on { createHttpRpcClient() } doReturn httpRpcClient | ||
} | ||
private val messagingConfig = mock<SmartConfig> { | ||
on { getString(BootConfig.CRYPTO_WORKER_REST_ENDPOINT) } doReturn "localhost:1231" | ||
} | ||
private val configurationReadService = mock<ConfigurationReadService> { | ||
on { registerComponentForUpdates(any(), any()) } doAnswer { | ||
val resource = mock<Resource>() | ||
handler.firstValue.processEvent( | ||
ConfigChangedEvent( | ||
setOf(ConfigKeys.MESSAGING_CONFIG), | ||
mapOf(ConfigKeys.MESSAGING_CONFIG to messagingConfig) | ||
), | ||
coordinator, | ||
) | ||
resource | ||
} | ||
} | ||
private val platformInfoProvider = mock<PlatformInfoProvider>() | ||
private val component = SessionEncryptionOpsClientImpl( | ||
coordinatorFactory, | ||
publisherFactory, | ||
configurationReadService, | ||
platformInfoProvider, | ||
) | ||
|
||
private fun start() { | ||
component.start() | ||
handler.firstValue.processEvent( | ||
RegistrationStatusChangeEvent( | ||
registrationHandle, | ||
LifecycleStatus.UP, | ||
), | ||
coordinator, | ||
) | ||
} | ||
|
||
@Test | ||
fun `encryptSessionData send data to the client`() { | ||
start() | ||
val data = "data".toByteArray() | ||
val results = CryptoEncryptionResult(ByteBuffer.wrap(data)) | ||
whenever(encryptionResponse.response).doReturn(results) | ||
|
||
val encrypted = component.encryptSessionData("hello".toByteArray()) | ||
|
||
assertThat(encrypted).isEqualTo(data) | ||
} | ||
|
||
@Test | ||
fun `decryptSessionData send data to the client`() { | ||
start() | ||
val data = "data".toByteArray() | ||
val results = CryptoDecryptionResult(ByteBuffer.wrap(data)) | ||
whenever(decryptionResponse.response).doReturn(results) | ||
|
||
val encrypted = component.decryptSessionData("hello".toByteArray()) | ||
|
||
assertThat(encrypted).isEqualTo(data) | ||
} | ||
} |
Oops, something went wrong.