Skip to content

Commit

Permalink
Merge pull request #129 from Fraunhofer-AISEC/feature/example-ids-mul…
Browse files Browse the repository at this point in the history
…tipart-uc

Feature/example ids multipart uc
  • Loading branch information
milux authored Jan 23, 2023
2 parents cd35531 + a4e8011 commit 889c65b
Show file tree
Hide file tree
Showing 16 changed files with 401 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
package de.fhg.aisec.ids.camel.processors

import com.google.common.collect.MapMaker
import de.fhg.aisec.ids.idscp2.applayer.AppLayerConnection
import de.fraunhofer.iais.eis.ContractAgreement
import org.apache.camel.Exchange
import org.slf4j.LoggerFactory
Expand All @@ -40,8 +39,8 @@ object UsageControlMaps {
exchangePeerIdentityMap[exchange]

fun getExchangeContract(exchange: Exchange): ContractAgreement? {
return exchangePeerIdentityMap[exchange]?.let { connection ->
peerContracts[connection]?.let { uri ->
return exchangePeerIdentityMap[exchange]?.let { identity ->
peerContracts[identity]?.let { uri ->
contractMap[uri] ?: throw RuntimeException("Contract $uri is not available!")
}
}
Expand All @@ -51,24 +50,24 @@ object UsageControlMaps {
contractMap[contractAgreement.id] = contractAgreement
}

fun setConnectionContract(connection: AppLayerConnection, contractUri: URI?) {
fun setPeerContract(peerIdentity: String, contractUri: URI?) {
if (contractUri != null) {
peerContracts[connection.peerDat.identity] = contractUri
peerContracts[peerIdentity] = contractUri
if (LOG.isDebugEnabled) {
LOG.debug("UC: Assigned contract $contractUri to connection $connection")
LOG.debug("UC: Assigned contract $contractUri to connection $peerIdentity")
}
} else {
peerContracts -= connection.peerDat.identity
peerContracts -= peerIdentity
if (LOG.isDebugEnabled) {
LOG.debug("UC: Assigned no contract to connection $connection")
LOG.debug("UC: Assigned no contract to connection $peerIdentity")
}
}
}

fun setExchangeConnection(exchange: Exchange, connection: AppLayerConnection) {
exchangePeerIdentityMap[exchange] = connection.peerDat.identity
fun setExchangePeerIdentity(exchange: Exchange, peerIdentity: String) {
exchangePeerIdentityMap[exchange] = peerIdentity
if (LOG.isDebugEnabled) {
LOG.debug("UC: Assigned exchange $exchange to connection $connection")
LOG.debug("UC: Assigned exchange $exchange to peer identity $peerIdentity")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*-
* ========================LICENSE_START=================================
* camel-processors
* %%
* Copyright (C) 2023 Fraunhofer AISEC
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =========================LICENSE_END==================================
*/
package de.fhg.aisec.ids.camel.processors.multipart

import org.apache.camel.Endpoint
import org.apache.camel.component.http.HttpEndpoint
import org.apache.camel.spi.EndpointStrategy
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

@Component("certExposingEndpointStrategy")
class CertExposingEndpointStrategy : EndpointStrategy {
@Autowired
private lateinit var certExposingHttpClientConfigurer: CertExposingHttpClientConfigurer

override fun registerEndpoint(uri: String, endpoint: Endpoint): Endpoint {
if (endpoint is HttpEndpoint && uri.startsWith("https")) {
LOG.info("Configured endpoint with uri $uri")
endpoint.httpClientConfigurer = certExposingHttpClientConfigurer
}
return endpoint
}

companion object {
val LOG: Logger = LoggerFactory.getLogger(CertExposingEndpointStrategy::class.java)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class CertExposingHttpClientConfigurer : HttpClientConfigurer {
val certs = sslSession.peerCertificates
val certHash = MessageDigest.getInstance("SHA-256").digest(certs[0].encoded).toHexString().lowercase()
certificateMap += certHash to certs
response.addHeader(SERVER_CERTIFICATE_HASH_HEADER, certHash)
response.setHeader(SERVER_CERTIFICATE_HASH_HEADER, certHash)
if (LOG.isDebugEnabled) {
LOG.debug("Captured server certificate with SHA256 fingerprint $certHash.")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package de.fhg.aisec.ids.camel.processors.multipart

import de.fhg.aisec.ids.api.contracts.ContractUtils.SERIALIZER
import de.fhg.aisec.ids.camel.processors.UsageControlMaps
import de.fhg.aisec.ids.idscp2.api.drivers.DapsDriver
import de.fraunhofer.iais.eis.Message
import org.apache.camel.Exchange
Expand Down Expand Up @@ -86,7 +87,11 @@ class IdsMultiPartInputProcessor : Processor {
}
val daps = beanFactory.getBean(dapsBeanName, DapsDriver::class.java)
try {
daps.verifyToken(dat.toByteArray(), peerCertificates[0] as X509Certificate)
val verifiedDat = daps.verifyToken(dat.toByteArray(), peerCertificates[0] as X509Certificate)
// Save exchange peer identity for contract association
UsageControlMaps.setExchangePeerIdentity(exchange, verifiedDat.identity)
// Save effective transfer contract for peer
UsageControlMaps.setPeerContract(verifiedDat.identity, idsHeader.transferContract)
} catch (e: Exception) {
throw SecurityException("Access Token did not match presented certificate!", e)
}
Expand Down
6 changes: 3 additions & 3 deletions examples/src/main/resources/etc/application.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
logging:
level:
root: info
# de.fhg.aisec: DEBUG
# de.fhg.aisec: debug
# Use for IDSCP2 debugging
# de.fhg.aisec.ids.idscp2: TRACE
# de.fhg.aisec.ids.camel.idscp2: TRACE
# de.fhg.aisec.ids.idscp2: trace
# de.fhg.aisec.ids.camel.idscp2: trace

spring:
web:
Expand Down
2 changes: 2 additions & 0 deletions examples/src/main/resources/example-ids-multipart-uc/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This defines the tag used for docker-compose example YAML files in the current directory
EXAMPLE_TAG=develop
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# IDSCP2 communication examples

This example demonstrates usage control between trusted connectors via the IDS Multipart protocol.

### Usage

First, start the server with the command `docker compose --profile server up`.

Second, start the client using the command `docker compose --profile client up`.
63 changes: 63 additions & 0 deletions examples/src/main/resources/example-ids-multipart-uc/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
version: '3'
services:

consumer-core:
image: fraunhoferaisec/trusted-connector-core:${EXAMPLE_TAG:-develop}
tty: true
stdin_open: true
command: [ "--class-path", "./jars/*", "de.fhg.aisec.ids.TrustedConnector",
"--spring.config.location=/root/etc/application.yml" ]
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ../etc/application.yml:/root/etc/application.yml
- ../deploy/allow-all-flows.pl:/root/deploy/allow-all-flows.pl
- ../etc/settings.mapdb:/root/etc/settings.mapdb
- ../etc/consumer-keystore.p12:/root/etc/keystore.p12
- ../etc/truststore.p12:/root/etc/truststore.p12
- ./example-multipart-uc-server.xml:/root/deploy/example-multipart-uc-server.xml
- ./make-contract.xml:/root/deploy/make-contract.xml
ports:
- "8080:8080"
networks:
- ids-wide
profiles:
- server

provider-core:
image: fraunhoferaisec/trusted-connector-core:${EXAMPLE_TAG:-develop}
tty: true
stdin_open: true
command: [ "--class-path", "./jars/*", "de.fhg.aisec.ids.TrustedConnector",
"--spring.config.location=/root/etc/application.yml" ]
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ../etc/application.yml:/root/etc/application.yml
- ../deploy/allow-all-flows.pl:/root/deploy/allow-all-flows.pl
- ../etc/settings2.mapdb:/root/etc/settings.mapdb
- ../etc/provider-keystore.p12:/root/etc/keystore.p12
- ../etc/truststore.p12:/root/etc/truststore.p12
- ./example-multipart-uc-client.xml:/root/deploy/example-multipart-uc-client.xml
ports:
- "8081:8080"
networks:
- ids-wide
- provider-internal
profiles:
- client

echo-server:
image: jmalloc/echo-server@sha256:c461e7e54d947a8777413aaf9c624b4ad1f1bac5d8272475da859ae82c1abd7d
environment:
PORT: "80"
LOG_HTTP_HEADERS: 1
LOG_HTTP_BODY: 1
networks:
- provider-internal
profiles:
- client

networks:
ids-wide:
driver: bridge
provider-internal:
driver: bridge
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

<camel:sslContextParameters id="rootClientSslContext" certAlias="1">
<camel:keyManagers keyPassword="password">
<camel:keyStore resource="etc/keystore.p12" password="password" />
</camel:keyManagers>
<camel:trustManagers>
<camel:keyStore resource="etc/truststore.p12" password="password" />
</camel:trustManagers>
</camel:sslContextParameters>

<bean id="rootDaps" class="de.fhg.aisec.ids.idscp2.beans.AisecDapsDriverFactoryBean">
<property name="dapsUrl" value="https://daps-dev.aisec.fraunhofer.de/v4" />
<property name="dapsSslParameters" ref="rootClientSslContext" />
<property name="transportCertificatesParameters" ref="rootClientSslContext" />
</bean>

<camelContext xmlns="http://camel.apache.org/schema/spring">
<errorHandler id="infErrorHandler" type="DeadLetterChannel" deadLetterUri="log:dead?level=ERROR">
<redeliveryPolicy maximumRedeliveries="-1" redeliveryDelay="1000" />
</errorHandler>

<route errorHandlerRef="infErrorHandler">
<from uri="timer://contractRequest?repeatCount=1" />
<setProperty name="artifactUri">
<constant>https://example.com/some_artifact</constant>
</setProperty>
<process ref="contractRequestCreationProcessor" />
<process ref="idsMultiPartOutputProcessor" />
<to uri="https://consumer-core:28282/usageControl?sslContextParameters=#rootClientSslContext" />
<process ref="idsMultiPartInputProcessor" />
<process ref="idsMessageTypeExtractionProcessor" />
<choice>
<when>
<simple>${exchangeProperty.ids-type} == 'ContractResponseMessage'</simple>
<log message="### Handle ContractResponseMessage ###" />
<process ref="contractResponseProcessor" />
<process ref="idsMultiPartOutputProcessor" />
<to uri="https://consumer-core:28282/usageControl?sslContextParameters=#rootClientSslContext" />
<process ref="idsMultiPartInputProcessor" />
<process ref="idsMessageTypeExtractionProcessor" />
<choice>
<when>
<simple>${exchangeProperty.ids-type} == 'MessageProcessedNotificationMessage'</simple>
<log message="### Received MessageProcessedNotificationMessage, starting artifactRequestRoute... ###" />
<to uri="controlbus:route?routeId=artifactRequestRoute&amp;action=start" />
</when>
<otherwise>
<log loggingLevel="ERROR" message="Expected MessageProcessedNotificationMessage, but received:\n${body}\n### Header: ###\n${headers[ids-header]}" />
<removeHeader name="ids-header" />
<setBody>
<simple>${null}</simple>
</setBody>
</otherwise>
</choice>
</when>
<otherwise>
<log loggingLevel="ERROR" message="Expected ContractResponseMessage, but received:\n${body}\n### Header: ###\n${headers[ids-header]}" />
<removeHeader name="ids-header" />
<setBody>
<simple>${null}</simple>
</setBody>
</otherwise>
</choice>
</route>

<route id="artifactRequestRoute" autoStartup="false">
<from uri="timer://tenSecondsTimer?fixedRate=true&amp;period=10000" />
<setProperty name="artifactUri">
<constant>https://example.com/some_artifact</constant>
</setProperty>
<process ref="artifactRequestCreationProcessor" />
<process ref="idsMultiPartOutputProcessor" />
<to uri="https://consumer-core:28282/usageControl?sslContextParameters=#rootClientSslContext" />
<process ref="idsMultiPartInputProcessor" />
<process ref="idsMessageTypeExtractionProcessor" />
<choice>
<when>
<simple>${exchangeProperty.ids-type} == 'ArtifactResponseMessage'</simple>
<log message="### Handle ArtifactResponseMessage ###" />
<to uri="http://echo-server:80" />
</when>
<otherwise>
<log loggingLevel="ERROR" message="Expected ArtifactResponseMessage, but received:\n${body}\n### Header: ###\n${headers[ids-header]}" />
</otherwise>
</choice>
</route>

</camelContext>

</beans>
Loading

0 comments on commit 889c65b

Please sign in to comment.