Skip to content

Commit

Permalink
Merge pull request #99 from Fraunhofer-AISEC/uc-time-constraints
Browse files Browse the repository at this point in the history
UC time constraints & more
  • Loading branch information
milux authored Mar 2, 2022
2 parents 372d34f + 10ef897 commit c8736ca
Show file tree
Hide file tree
Showing 34 changed files with 738 additions and 561 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ licenseReport {

allprojects {
group = "de.fhg.aisec.ids"
version = "6.1.0"
version = "6.2.0"
}

subprojects {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ package de.fhg.aisec.ids.camel.processors
object Constants {
const val IDSCP2_HEADER = "idscp2-header"
const val IDS_TYPE = "ids-type"
const val CONTAINER_URI_PROPERTY = "containerUri"
const val UC_DOCKER_IMAGE_URIS = "uc-docker-image-uris"
const val UC_NOT_BEFORE_DATETIME = "uc-not-before-datetime"
const val UC_NOT_AFTER_DATETIME = "uc-not-after-datetime"
const val ARTIFACT_URI_PROPERTY = "artifactUri"
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class ContractAgreementReceiverProcessor : Processor {

ProviderDB.contractAgreements[contractAgreement.id] = contractAgreement
for (permission in contractAgreement.permission) {
// Entry for the case when provider is setting up multiple agreements with different requesting connectors
ProviderDB.artifactUrisMapped2ContractAgreements[
Pair(
permission.target,
Expand All @@ -60,6 +61,8 @@ class ContractAgreementReceiverProcessor : Processor {
)
)
] = contractAgreement.id
// Additional entry for the case when an artifact is pushed directly to the consumer
ProviderDB.artifactUrisMapped2ContractAgreements[Pair(permission.target, null)] = contractAgreement.id
}

if (LOG.isDebugEnabled) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*-
* ========================LICENSE_START=================================
* camel-processors
* %%
* Copyright (C) 2022 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

import de.fraunhofer.iais.eis.AbstractConstraint
import de.fraunhofer.iais.eis.Action
import de.fraunhofer.iais.eis.BinaryOperator
import de.fraunhofer.iais.eis.ConstraintBuilder
import de.fraunhofer.iais.eis.ContractOffer
import de.fraunhofer.iais.eis.ContractOfferBuilder
import de.fraunhofer.iais.eis.LeftOperand
import de.fraunhofer.iais.eis.PermissionBuilder
import de.fraunhofer.iais.eis.util.TypedLiteral
import org.apache.camel.Exchange
import java.net.URI

object ContractFactory {

fun buildContractOffer(requestedArtifact: URI, exchange: Exchange): ContractOffer {
// Docker image whitelisting
val dockerImageUris = (
exchange.getProperty(Constants.UC_DOCKER_IMAGE_URIS)
// Legacy property name without "uc-" prefix
?: exchange.getProperty("containerUri")
?: ""
).toString()
.split(Regex("\\s+"))
.map(String::trim)
.filter(String::isNotEmpty)
.map(URI::create)
.toList()
val contractDate = Utils.newGregorianCalendar()
val timeConstraints = mutableListOf<AbstractConstraint>()
// Add not after (BEFORE) usage constraint
exchange.getProperty(Constants.UC_NOT_AFTER_DATETIME)?.let { dateTime ->
timeConstraints += ConstraintBuilder()
._leftOperand_(LeftOperand.POLICY_EVALUATION_TIME)
._operator_(BinaryOperator.BEFORE)
._rightOperand_(
TypedLiteral(
Utils.DATATYPE_FACTORY.newXMLGregorianCalendar(dateTime.toString()).toString(),
Utils.TYPE_DATETIMESTAMP
)
)
.build()
}
// Add not before (AFTER) usage constraint
exchange.getProperty(Constants.UC_NOT_BEFORE_DATETIME)?.let { dateTime ->
timeConstraints += ConstraintBuilder()
._leftOperand_(LeftOperand.POLICY_EVALUATION_TIME)
._operator_(BinaryOperator.AFTER)
._rightOperand_(
TypedLiteral(
Utils.DATATYPE_FACTORY.newXMLGregorianCalendar(dateTime.toString()).toString(),
Utils.TYPE_DATETIMESTAMP
)
)
.build()
}
return ContractOfferBuilder()
._contractDate_(contractDate)
._contractStart_(contractDate)
// Contract end one year in the future
._contractEnd_(contractDate.copy().apply { year += 1 })
._permission_(
if (dockerImageUris.isEmpty()) {
// If no Docker images have been specified, just use time constraints
listOf(
PermissionBuilder()
._target_(requestedArtifact)
._action_(listOf(Action.USE))
._constraint_(
timeConstraints
)
.build()
)
} else {
// If Docker images have been specified, combine each with the specified time constraints
dockerImageUris.map {
PermissionBuilder()
._target_(requestedArtifact)
._action_(listOf(Action.USE))
._constraint_(
listOf(
ConstraintBuilder()
._leftOperand_(LeftOperand.SYSTEM)
._operator_(BinaryOperator.SAME_AS)
._rightOperandReference_(it)
.build()
) + timeConstraints
)
.build()
}
}
)
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,9 @@
*/
package de.fhg.aisec.ids.camel.processors

import de.fhg.aisec.ids.camel.idscp2.Utils
import de.fhg.aisec.ids.camel.processors.Constants.CONTAINER_URI_PROPERTY
import de.fhg.aisec.ids.camel.processors.Constants.IDSCP2_HEADER
import de.fhg.aisec.ids.camel.processors.Utils.SERIALIZER
import de.fraunhofer.iais.eis.BinaryOperator
import de.fraunhofer.iais.eis.ConstraintBuilder
import de.fraunhofer.iais.eis.ContractOfferBuilder
import de.fraunhofer.iais.eis.ContractOfferMessageBuilder
import de.fraunhofer.iais.eis.LeftOperand
import de.fraunhofer.iais.eis.PermissionBuilder
import org.apache.camel.Exchange
import org.apache.camel.Processor
import org.slf4j.LoggerFactory
Expand All @@ -37,6 +30,7 @@ import java.net.URI
/**
* This Processor handles a ContractRequestMessage and creates a ContractResponseMessage.
*/
@Suppress("unused")
class ContractOfferCreationProcessor : Processor {

override fun process(exchange: Exchange) {
Expand All @@ -58,38 +52,9 @@ class ContractOfferCreationProcessor : Processor {
} else {
URI.create(it.toString())
}
}
val containerUri = exchange.getProperty(CONTAINER_URI_PROPERTY).let {
if (it is URI) {
it
} else {
URI.create(it.toString())
}
}
val contractDate = Utils.createGregorianCalendarTimestamp(System.currentTimeMillis())
val contractOffer = ContractOfferBuilder()
._contractDate_(contractDate)
._contractStart_(contractDate)
// Contract end one year in the future
._contractEnd_(contractDate.apply { year += 1 })
// Permission for data processing inside a specific system (docker container)
._permission_(
listOf(
PermissionBuilder()
._target_(artifactUri)
._constraint_(
listOf(
ConstraintBuilder()
._leftOperand_(LeftOperand.SYSTEM)
._operator_(BinaryOperator.SAME_AS)
._rightOperandReference_(containerUri)
.build()
)
)
.build()
)
)
.build()
} ?: throw RuntimeException("No property \"artifactUri\" found in Exchange, cannot build contract!")

val contractOffer = ContractFactory.buildContractOffer(artifactUri, exchange)

SERIALIZER.serialize(contractOffer).let {
if (LOG.isDebugEnabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,14 @@
*/
package de.fhg.aisec.ids.camel.processors

import de.fhg.aisec.ids.camel.idscp2.Utils
import de.fhg.aisec.ids.camel.processors.Constants.CONTAINER_URI_PROPERTY
import de.fhg.aisec.ids.camel.processors.Constants.IDSCP2_HEADER
import de.fhg.aisec.ids.camel.processors.Utils.SERIALIZER
import de.fraunhofer.iais.eis.Action
import de.fraunhofer.iais.eis.BinaryOperator
import de.fraunhofer.iais.eis.ConstraintBuilder
import de.fraunhofer.iais.eis.ContractOfferBuilder
import de.fraunhofer.iais.eis.ContractRequest
import de.fraunhofer.iais.eis.ContractRequestMessage
import de.fraunhofer.iais.eis.ContractResponseMessageBuilder
import de.fraunhofer.iais.eis.LeftOperand
import de.fraunhofer.iais.eis.PermissionBuilder
import org.apache.camel.Exchange
import org.apache.camel.Processor
import org.slf4j.LoggerFactory
import java.net.URI

/**
* This Processor handles a ContractRequestMessage and creates a ContractResponseMessage.
Expand Down Expand Up @@ -66,36 +57,7 @@ class ContractRequestProcessor : Processor {
exchange.message.setHeader(IDSCP2_HEADER, it)
}

// create ContractOffer, allowing use of received data in the given container only
val containerUris = exchange.getProperty(CONTAINER_URI_PROPERTY).toString()
.split(Regex("\\s+"))
.map { URI.create(it.trim()) }
.toList()
val contractDate = Utils.createGregorianCalendarTimestamp(System.currentTimeMillis())
val contractOffer = ContractOfferBuilder()
._contractDate_(contractDate)
._contractStart_(contractDate)
// Contract end one year in the future
._contractEnd_(contractDate.apply { year += 1 })
// Permissions for data processing inside specific "systems" (docker containers)
._permission_(
containerUris.map {
PermissionBuilder()
._target_(requestedArtifact)
._action_(listOf(Action.USE))
._constraint_(
listOf(
ConstraintBuilder()
._leftOperand_(LeftOperand.SYSTEM)
._operator_(BinaryOperator.SAME_AS)
._rightOperandReference_(it)
.build()
)
)
.build()
}
)
.build()
val contractOffer = ContractFactory.buildContractOffer(requestedArtifact, exchange)

SERIALIZER.serialize(contractOffer).let {
if (LOG.isDebugEnabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import java.util.concurrent.ConcurrentHashMap
object ProviderDB {
val availableArtifactURIs: ConcurrentHashMap<URI, String> = ConcurrentHashMap()
val artifactUrisMapped2ContractAgreements:
ConcurrentHashMap<Pair<URI, AppLayerConnection>, URI> = ConcurrentHashMap()
ConcurrentHashMap<Pair<URI, AppLayerConnection?>, URI> = ConcurrentHashMap()
val contractAgreements: ConcurrentHashMap<URI, ContractAgreement> = ConcurrentHashMap()

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,19 @@
package de.fhg.aisec.ids.camel.processors

import de.fraunhofer.iais.eis.ids.jsonld.Serializer
import java.net.URI
import java.util.GregorianCalendar
import javax.xml.datatype.DatatypeFactory
import javax.xml.datatype.XMLGregorianCalendar

object Utils {
val SERIALIZER: Serializer by lazy { Serializer() }
val TYPE_DATETIMESTAMP: URI = URI.create("http://www.w3.org/2001/XMLSchema#dateTimeStamp")
val DATATYPE_FACTORY: DatatypeFactory = DatatypeFactory.newInstance()
fun newGregorianCalendar(millis: Long = System.currentTimeMillis()): XMLGregorianCalendar =
DATATYPE_FACTORY.newXMLGregorianCalendar(
GregorianCalendar().apply { timeInMillis = millis }
)
}

fun XMLGregorianCalendar.copy() = this.clone() as XMLGregorianCalendar
4 changes: 4 additions & 0 deletions examples/example-idscp2-uc/docker-compose-client.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ services:
image: jmalloc/echo-server@sha256:c461e7e54d947a8777413aaf9c624b4ad1f1bac5d8272475da859ae82c1abd7d
networks:
- provider-internal
environment:
PORT: "80"
LOG_HTTP_HEADERS: 1
LOG_HTTP_BODY: 1

networks:
ids-wide:
Expand Down
3 changes: 1 addition & 2 deletions examples/example-idscp2-uc/example-idscp2-client.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@
<when>
<simple>${exchangeProperty.ids-type} == 'ArtifactResponseMessage'</simple>
<log message="### Handle ArtifactResponseMessage ###"/>
<to uri="http://echo-server:8080"/>
<log message="Response body\n\n${body}"/>
<to uri="http://echo-server:80"/>
</when>
<otherwise>
<log loggingLevel="ERROR" message="Expected ArtifactResponseMessage, but received:\n${body}\n### Header: ###\n${headers[idscp2-header]}"/>
Expand Down
11 changes: 9 additions & 2 deletions examples/example-idscp2-uc/example-idscp2-server.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@
<when>
<simple>${exchangeProperty.ids-type} == 'ContractRequestMessage'</simple>
<log message="### Handle ContractRequestMessage ###"/>
<setProperty name="containerUri">
<setProperty name="uc-docker-image-uris">
<constant>
https://hub.docker.com/layers/jmalloc/echo-server/latest/images/sha256-c461e7e54d947a8777413aaf9c624b4ad1f1bac5d8272475da859ae82c1abd7d#8080
https://hub.docker.com/layers/jmalloc/echo-server/latest/images/sha256-c461e7e54d947a8777413aaf9c624b4ad1f1bac5d8272475da859ae82c1abd7d#80
https://hub.docker.com/layers/jmalloc/echo-server/latest/images/sha256-d461e7e54d947a8777413aaf9c624b4ad1f1bac5d8272475da859ae82c1abd7d#8080
https://hub.docker.com/layers/jmalloc/echo-server/latest/images/sha256-e461e7e54d947a8777413aaf9c624b4ad1f1bac5d8272475da859ae82c1abd7d#8081
</constant>
</setProperty>
<!-- These values are examples that are always fulfilled (until 2100), replace them with your own values as necessary. -->
<setProperty name="uc-not-before-datetime">
<constant>2022-01-01T00:00:00.0Z</constant>
</setProperty>
<setProperty name="uc-not-after-datetime">
<constant>2100-01-01T00:00:00.0Z</constant>
</setProperty>
<process ref="ContractRequestProcessor"/>
</when>
<when>
Expand Down
Binary file added examples/trusted-connector-examples_6.2.0.zip
Binary file not shown.
Binary file modified examples/trusted-connector-examples_latest.zip
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ class ApplicationContainer {
var owner: String? = null
var image: String? = null
var imageId: String? = null
var imageDigests: List<String> = emptyList()
var repoDigest: List<String>? = null
var cmd: List<String>? = null
var entrypoint: List<String>? = null
var imageCmd: List<String>? = null
var imageEntrypoint: List<String>? = null
var ipAddresses: List<InetAddress> = emptyList()

// Portainer attributes:
Expand All @@ -55,18 +59,19 @@ class ApplicationContainer {
var title: String? = null
var description: String? = null
var note: String? = null
var categories: List<String> = ArrayList()
var categories: List<String> = emptyList()
var platform = "linux"
var logo: String? = null
var registry = ""
var command = ""
var network: String? = null
var env: List<Map<String, Any>> = ArrayList()
var env: List<Map<String, Any>> = emptyList()
var isPrivileged = false
var isInteractive = false
var restartPolicy = "always"
var labels: Map<String, Any> = HashMap()
var volumes: List<Any> = ArrayList()
var labels: Map<String, Any> = emptyMap()
var volumes: List<Any> = emptyList()

override fun toString(): String {
return (
"ApplicationContainer [id=" +
Expand Down
Loading

0 comments on commit c8736ca

Please sign in to comment.