diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c00ff9e66..ffa48f664 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '17' + java-version: '21' - name: Setup protoc uses: arduino/setup-protoc@v1.1.2 with: diff --git a/Dockerfile b/Dockerfile index 33ffdd358..b4e710114 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # syntax = docker/dockerfile:experimental -ARG BUILDER_IMAGE=amd64/eclipse-temurin:17-jdk-focal -ARG BASE_IMAGE=gcr.io/distroless/java17-debian11 +ARG BUILDER_IMAGE=amd64/eclipse-temurin:21-jdk +ARG BASE_IMAGE=gcr.io/distroless/java21-debian12 FROM $BUILDER_IMAGE AS builder LABEL AUTHOR="Michael Lux (michael.lux@aisec.fraunhofer.de)" diff --git a/build.gradle.kts b/build.gradle.kts index 0f1a19b39..62af81023 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,7 +27,7 @@ allprojects { group = "de.fhg.aisec.ids" version = "7.2.0" - val versionRegex = ".*(rc-?[0-9]*|beta|-b.+)$".toRegex(RegexOption.IGNORE_CASE) + val versionRegex = ".*((rc|beta)-?[0-9]*|-b[0-9.]+)$".toRegex(RegexOption.IGNORE_CASE) tasks.withType { rejectVersionIf { @@ -81,6 +81,9 @@ subprojects { ), "org.eclipse.jetty" to mapOf( "*" to versions.jetty.get() + ), + "org.bouncycastle" to mapOf( + "*" to versions.bouncyCastle.get() ) ) // We need to explicitly specify the kotlin version for all kotlin dependencies, @@ -146,7 +149,9 @@ configure(subprojects.filter { it.name != "examples" }) { spotless { kotlin { target("src/*/kotlin/**/*.kt") - ktlint(libs.versions.ktlint.get()) + ktlint(libs.versions.ktlint.get()).editorConfigOverride(mapOf( + "ktlint_code_style" to "ktlint_official" + )) licenseHeader( """/*- * ========================LICENSE_START================================= diff --git a/buildx/docker-buildx.sh b/buildx/docker-buildx.sh index 2071a05b3..57211e97f 100755 --- a/buildx/docker-buildx.sh +++ b/buildx/docker-buildx.sh @@ -33,7 +33,7 @@ fi eval set -- "$PARSED" DOCKER_BUILD_TAGS="develop" -BASE_IMAGE_ARG="gcr.io/distroless/java17-debian11" +BASE_IMAGE_ARG="gcr.io/distroless/java21-debian12" TARGETS="core" OUTPUT_TYPE="docker" BAKE_ARGS="" diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ArtifactRequestCreationProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ArtifactRequestCreationProcessor.kt index bdfd92269..05d3629d9 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ArtifactRequestCreationProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ArtifactRequestCreationProcessor.kt @@ -31,7 +31,6 @@ import java.net.URI @Component("artifactRequestCreationProcessor") class ArtifactRequestCreationProcessor : Processor { - override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ArtifactRequestProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ArtifactRequestProcessor.kt index 4040f4636..281fb513a 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ArtifactRequestProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ArtifactRequestProcessor.kt @@ -33,22 +33,23 @@ import org.springframework.stereotype.Component @Component("artifactRequestProcessor") class ArtifactRequestProcessor : Processor { - override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") } - val artifactRequestMessage = exchange.message.getHeader( - IDS_HEADER, - ArtifactRequestMessage::class.java - ) + val artifactRequestMessage = + exchange.message.getHeader( + IDS_HEADER, + ArtifactRequestMessage::class.java + ) val requestedArtifact = artifactRequestMessage.requestedArtifact // TODO: If transferContract doesn't match expected contract from database, send rejection! - val usedContract = ProviderDB.artifactUrisMapped2ContractAgreements[ - Pair(requestedArtifact, UsageControlMaps.getExchangePeerIdentity(exchange)) - ] + val usedContract = + ProviderDB.artifactUrisMapped2ContractAgreements[ + Pair(requestedArtifact, UsageControlMaps.getExchangePeerIdentity(exchange)) + ] if (LOG.isDebugEnabled) { LOG.debug("Contract for requested Artifact found {}", usedContract) } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractAgreementReceiverProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractAgreementReceiverProcessor.kt index f4c8a587d..7d2614d32 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractAgreementReceiverProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractAgreementReceiverProcessor.kt @@ -31,21 +31,22 @@ import org.springframework.stereotype.Component @Component("contractAgreementReceiverProcessor") class ContractAgreementReceiverProcessor : Processor { - override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") } - val contractAgreementMessage = exchange.message.getHeader( - IDS_HEADER, - ContractAgreementMessage::class.java - ) + val contractAgreementMessage = + exchange.message.getHeader( + IDS_HEADER, + ContractAgreementMessage::class.java + ) - val contractAgreement = SERIALIZER.deserialize( - exchange.message.getBody(String::class.java), - ContractAgreement::class.java - ) + val contractAgreement = + SERIALIZER.deserialize( + exchange.message.getBody(String::class.java), + ContractAgreement::class.java + ) UsageControlMaps.addContractAgreement(contractAgreement) if (LOG.isDebugEnabled) { diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractHelper.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractHelper.kt index b0f738738..f6603e700 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractHelper.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractHelper.kt @@ -30,23 +30,27 @@ import org.slf4j.Logger import java.net.URI object ContractHelper { - - fun collectContractProperties(requestedArtifact: URI, exchange: Exchange): Map { - val contractProperties = mutableMapOf( - ContractConstants.ARTIFACT_URI_PROPERTY to requestedArtifact - ) + fun collectContractProperties( + requestedArtifact: URI, + exchange: Exchange + ): Map { + val contractProperties = + mutableMapOf( + ContractConstants.ARTIFACT_URI_PROPERTY to requestedArtifact + ) // Docker image whitelisting - contractProperties[ContractConstants.UC_DOCKER_IMAGE_URIS] = ( - exchange.getProperty(ContractConstants.UC_DOCKER_IMAGE_URIS) - // Legacy property name without "uc-" prefix - ?: exchange.getProperty("containerUri") - ?: "" + contractProperties[ContractConstants.UC_DOCKER_IMAGE_URIS] = + ( + exchange.getProperty(ContractConstants.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() + .split(Regex("\\s+")) + .map(String::trim) + .filter(String::isNotEmpty) + .map(URI::create) + .toList() // Add not after (BEFORE) usage constraint exchange.getProperty(ContractConstants.UC_NOT_AFTER_DATETIME)?.let { contractProperties[ContractConstants.UC_NOT_AFTER_DATETIME] = it @@ -58,11 +62,16 @@ object ContractHelper { return contractProperties } - fun handleContractOffer(exchange: Exchange, correlationId: URI, logger: Logger) { - val contractOfferReceived = ContractUtils.SERIALIZER.deserialize( - exchange.message.getBody(String::class.java), - ContractOffer::class.java - ) + fun handleContractOffer( + exchange: Exchange, + correlationId: URI, + logger: Logger + ) { + val contractOfferReceived = + ContractUtils.SERIALIZER.deserialize( + exchange.message.getBody(String::class.java), + ContractOffer::class.java + ) // if contract is denied send ContractRejectionMsg else send ContractAgreementMsg val contractOfferIsAccepted = true @@ -79,18 +88,19 @@ object ContractHelper { } } - val contractAgreement = ContractAgreementBuilder() - ._consumer_(contractOfferReceived.consumer) - ._provider_(contractOfferReceived.provider) - ._contractAnnex_(contractOfferReceived.contractAnnex) - ._contractDate_(contractOfferReceived.contractDate) - ._contractDocument_(contractOfferReceived.contractDocument) - ._contractEnd_(contractOfferReceived.contractEnd) - ._contractStart_(contractOfferReceived.contractStart) - ._obligation_(contractOfferReceived.obligation) - ._prohibition_(contractOfferReceived.prohibition) - ._permission_(contractOfferReceived.permission) - .build() + val contractAgreement = + ContractAgreementBuilder() + ._consumer_(contractOfferReceived.consumer) + ._provider_(contractOfferReceived.provider) + ._contractAnnex_(contractOfferReceived.contractAnnex) + ._contractDate_(contractOfferReceived.contractDate) + ._contractDocument_(contractOfferReceived.contractDocument) + ._contractEnd_(contractOfferReceived.contractEnd) + ._contractStart_(contractOfferReceived.contractStart) + ._obligation_(contractOfferReceived.obligation) + ._prohibition_(contractOfferReceived.prohibition) + ._permission_(contractOfferReceived.permission) + .build() UsageControlMaps.addContractAgreement(contractAgreement) if (logger.isDebugEnabled) { @@ -107,7 +117,11 @@ object ContractHelper { } } - private fun createContractRejectionMessage(exchange: Exchange, correlationId: URI, logger: Logger) { + private fun createContractRejectionMessage( + exchange: Exchange, + correlationId: URI, + logger: Logger + ) { if (logger.isDebugEnabled) { logger.debug("Constructing ContractRejectionMessage") } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferCreationProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferCreationProcessor.kt index 3194fee1f..6d7d5bd9c 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferCreationProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferCreationProcessor.kt @@ -35,8 +35,9 @@ import java.net.URI * This Processor handles a ContractRequestMessage and creates a ContractResponseMessage. */ @Component("contractOfferCreationProcessor") -class ContractOfferCreationProcessor(@Autowired private val contractManager: ContractManager) : Processor { - +class ContractOfferCreationProcessor( + @Autowired private val contractManager: ContractManager +) : Processor { override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") @@ -49,13 +50,14 @@ class ContractOfferCreationProcessor(@Autowired private val contractManager: Con exchange.message.setHeader(IDS_HEADER, it) } - val artifactUri = exchange.getProperty(ContractConstants.ARTIFACT_URI_PROPERTY)?.let { - if (it is URI) { - it - } else { - URI.create(it.toString()) - } - } ?: throw RuntimeException("No property \"artifactUri\" found in Exchange, cannot build contract!") + val artifactUri = + exchange.getProperty(ContractConstants.ARTIFACT_URI_PROPERTY)?.let { + if (it is URI) { + it + } else { + URI.create(it.toString()) + } + } ?: throw RuntimeException("No property \"artifactUri\" found in Exchange, cannot build contract!") val contractProperties = ContractHelper.collectContractProperties(artifactUri, exchange) val contractOffer = contractManager.makeContract(contractProperties) diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferLoaderProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferLoaderProcessor.kt index da4501397..ea2eafdda 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferLoaderProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferLoaderProcessor.kt @@ -34,8 +34,9 @@ import org.springframework.stereotype.Component * This Processor handles a ContractRequestMessage and creates a ContractResponseMessage. */ @Component("contractOfferLoaderProcessor") -class ContractOfferLoaderProcessor(@Autowired private val contractManager: ContractManager) : Processor { - +class ContractOfferLoaderProcessor( + @Autowired private val contractManager: ContractManager +) : Processor { override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") @@ -49,9 +50,10 @@ class ContractOfferLoaderProcessor(@Autowired private val contractManager: Contr } val storeKey = exchange.getProperty(CONTRACT_STORE_KEY)?.toString() - val contractOffer = storeKey?.let { - contractManager.loadContract(it) - } ?: throw RuntimeException("Error loading ContractOffer with store key \"$storeKey\"") + val contractOffer = + storeKey?.let { + contractManager.loadContract(it) + } ?: throw RuntimeException("Error loading ContractOffer with store key \"$storeKey\"") SERIALIZER.serialize(contractOffer).let { if (LOG.isDebugEnabled) { diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferProcessor.kt index 8fff5a257..a68d89941 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferProcessor.kt @@ -31,16 +31,16 @@ import org.springframework.stereotype.Component */ @Component("contractOfferProcessor") class ContractOfferProcessor : Processor { - override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") } - val contractOfferMessage = exchange.message.getHeader( - IDS_HEADER, - ContractOfferMessage::class.java - ) + val contractOfferMessage = + exchange.message.getHeader( + IDS_HEADER, + ContractOfferMessage::class.java + ) ContractHelper.handleContractOffer(exchange, contractOfferMessage.id, LOG) } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferStoreProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferStoreProcessor.kt index 93fb3e4ae..4e5bb0a6a 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferStoreProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractOfferStoreProcessor.kt @@ -33,20 +33,22 @@ import java.net.URI * This Processor handles a ContractRequestMessage and creates a ContractResponseMessage. */ @Component("contractOfferStoreProcessor") -class ContractOfferStoreProcessor(@Autowired private val contractManager: ContractManager) : Processor { - +class ContractOfferStoreProcessor( + @Autowired private val contractManager: ContractManager +) : Processor { override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") } - val artifactUri = exchange.getProperty(ContractConstants.ARTIFACT_URI_PROPERTY)?.let { - if (it is URI) { - it - } else { - URI.create(it.toString()) - } - } ?: throw RuntimeException("No property \"artifactUri\" found in Exchange, cannot build contract!") + val artifactUri = + exchange.getProperty(ContractConstants.ARTIFACT_URI_PROPERTY)?.let { + if (it is URI) { + it + } else { + URI.create(it.toString()) + } + } ?: throw RuntimeException("No property \"artifactUri\" found in Exchange, cannot build contract!") exchange.getProperty(CONTRACT_STORE_KEY)?.toString()?.let { val contractProperties = ContractHelper.collectContractProperties(artifactUri, exchange) diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractRequestCreationProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractRequestCreationProcessor.kt index 32747a307..904ebfc97 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractRequestCreationProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractRequestCreationProcessor.kt @@ -35,7 +35,6 @@ import java.net.URI @Component("contractRequestCreationProcessor") class ContractRequestCreationProcessor : Processor { - override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") @@ -48,30 +47,32 @@ class ContractRequestCreationProcessor : Processor { exchange.message.setHeader(IDS_HEADER, it) } - val artifactUri = exchange.getProperty(ARTIFACT_URI_PROPERTY)?.let { - if (it is URI) { - it - } else { - URI.create(it.toString()) + val artifactUri = + exchange.getProperty(ARTIFACT_URI_PROPERTY)?.let { + if (it is URI) { + it + } else { + URI.create(it.toString()) + } } - } // setting creation/start date of contract to now val contractDate = ContractUtils.newGregorianCalendar() - val contractRequest = ContractRequestBuilder() - ._contractDate_(contractDate) - ._contractStart_(contractDate) - // Contract end one year in the future - ._contractEnd_(contractDate.apply { year += 1 }) - // Request permission for (unrestricted?) usage of an artifact, identified by URI - ._permission_( - listOf( - PermissionBuilder() - ._target_(artifactUri) - ._action_(listOf(Action.USE)) - .build() + val contractRequest = + ContractRequestBuilder() + ._contractDate_(contractDate) + ._contractStart_(contractDate) + // Contract end one year in the future + ._contractEnd_(contractDate.apply { year += 1 }) + // Request permission for (unrestricted?) usage of an artifact, identified by URI + ._permission_( + listOf( + PermissionBuilder() + ._target_(artifactUri) + ._action_(listOf(Action.USE)) + .build() + ) ) - ) - .build() + .build() SERIALIZER.serialize(contractRequest).let { if (LOG.isDebugEnabled) LOG.debug("Serialization body: {}", it) exchange.message.body = it diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractRequestProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractRequestProcessor.kt index 81ee1c6cc..f4d3f2c17 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractRequestProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractRequestProcessor.kt @@ -36,23 +36,26 @@ import org.springframework.stereotype.Component * This Processor handles a ContractRequestMessage and creates a ContractResponseMessage. */ @Component("contractRequestProcessor") -class ContractRequestProcessor(@Autowired private val contractManager: ContractManager) : Processor { - +class ContractRequestProcessor( + @Autowired private val contractManager: ContractManager +) : Processor { override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") } - val contractRequest = SERIALIZER.deserialize( - exchange.message.getBody(String::class.java), - ContractRequest::class.java - ) + val contractRequest = + SERIALIZER.deserialize( + exchange.message.getBody(String::class.java), + ContractRequest::class.java + ) val requestedArtifact = contractRequest.permission[0].target - val contractRequestMessage = exchange.message.getHeader( - IDS_HEADER, - ContractRequestMessage::class.java - ) + val contractRequestMessage = + exchange.message.getHeader( + IDS_HEADER, + ContractRequestMessage::class.java + ) ContractResponseMessageBuilder() ._correlationMessage_(contractRequestMessage.id) @@ -64,20 +67,21 @@ class ContractRequestProcessor(@Autowired private val contractManager: ContractM } val storeKey = exchange.getProperty(CONTRACT_STORE_KEY)?.toString() - val contractOffer = storeKey?.let { - contractManager.loadContract(it)?.let { offer -> - if (offer.permission.none { p -> p.target == requestedArtifact }) { - throw RuntimeException( - "Offer with store key \"$it\"" + - " does not contain any permissions for artifact \"$requestedArtifact\"" - ) - } - offer - } ?: throw RuntimeException("Error loading ContractOffer using store key \"$storeKey\"") - } ?: run { - val contractProperties = ContractHelper.collectContractProperties(requestedArtifact, exchange) - contractManager.makeContract(contractProperties) - } + val contractOffer = + storeKey?.let { + contractManager.loadContract(it)?.let { offer -> + if (offer.permission.none { p -> p.target == requestedArtifact }) { + throw RuntimeException( + "Offer with store key \"$it\"" + + " does not contain any permissions for artifact \"$requestedArtifact\"" + ) + } + offer + } ?: throw RuntimeException("Error loading ContractOffer using store key \"$storeKey\"") + } ?: run { + val contractProperties = ContractHelper.collectContractProperties(requestedArtifact, exchange) + contractManager.makeContract(contractProperties) + } SERIALIZER.serialize(contractOffer).let { if (LOG.isDebugEnabled) { diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractResponseProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractResponseProcessor.kt index 4d0032203..afb4d1c71 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractResponseProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ContractResponseProcessor.kt @@ -31,16 +31,16 @@ import org.springframework.stereotype.Component */ @Component("contractResponseProcessor") class ContractResponseProcessor : Processor { - override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") } - val contractResponseMessage = exchange.message.getHeader( - IDS_HEADER, - ContractResponseMessage::class.java - ) + val contractResponseMessage = + exchange.message.getHeader( + IDS_HEADER, + ContractResponseMessage::class.java + ) ContractHelper.handleContractOffer(exchange, contractResponseMessage.id, LOG) } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/DescriptionRequestCreationProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/DescriptionRequestCreationProcessor.kt index 8dfa5b21f..9515f607a 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/DescriptionRequestCreationProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/DescriptionRequestCreationProcessor.kt @@ -28,7 +28,6 @@ import org.springframework.stereotype.Component @Component("descriptionRequestCreationProcessor") class DescriptionRequestCreationProcessor : Processor { - override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/DescriptionRequestProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/DescriptionRequestProcessor.kt index 538822a84..44f26bc54 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/DescriptionRequestProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/DescriptionRequestProcessor.kt @@ -31,7 +31,6 @@ import org.springframework.stereotype.Component @Component("descriptionRequestProcessor") class DescriptionRequestProcessor : Processor { - @Autowired private lateinit var infoModel: InfoModel diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/IdsMessageTypeExtractionProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/IdsMessageTypeExtractionProcessor.kt index 4469166c7..a2e2dfc29 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/IdsMessageTypeExtractionProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/IdsMessageTypeExtractionProcessor.kt @@ -56,24 +56,25 @@ class IdsMessageTypeExtractionProcessor : Processor { LOG.debug("[IN] ${IdsMessageTypeExtractionProcessor::class.java.simpleName}") } exchange.message.getHeader(IDS_HEADER, Message::class.java)?.let { header -> - val messageType = when (header) { - is ArtifactRequestMessage -> ArtifactRequestMessage::class.simpleName - is ArtifactResponseMessage -> ArtifactResponseMessage::class.simpleName - is ContractRequestMessage -> ContractRequestMessage::class.simpleName - is ContractResponseMessage -> ContractResponseMessage::class.simpleName - is ContractOfferMessage -> ContractOfferMessage::class.simpleName - is ContractAgreementMessage -> ContractAgreementMessage::class.simpleName - is ContractRejectionMessage -> ContractRejectionMessage::class.simpleName - is ResourceUpdateMessage -> ResourceUpdateMessage::class.simpleName - is MessageProcessedNotificationMessage -> MessageProcessedNotificationMessage::class.simpleName - is DescriptionRequestMessage -> DescriptionRequestMessage::class.simpleName - is DescriptionResponseMessage -> DescriptionResponseMessage::class.simpleName - is RejectionMessage -> RejectionMessage::class.simpleName - is LogMessage -> LogMessage::class.simpleName - is QueryMessage -> QueryMessage::class.simpleName - is RequestMessage -> RequestMessage::class.simpleName - else -> header::class.simpleName - } + val messageType = + when (header) { + is ArtifactRequestMessage -> ArtifactRequestMessage::class.simpleName + is ArtifactResponseMessage -> ArtifactResponseMessage::class.simpleName + is ContractRequestMessage -> ContractRequestMessage::class.simpleName + is ContractResponseMessage -> ContractResponseMessage::class.simpleName + is ContractOfferMessage -> ContractOfferMessage::class.simpleName + is ContractAgreementMessage -> ContractAgreementMessage::class.simpleName + is ContractRejectionMessage -> ContractRejectionMessage::class.simpleName + is ResourceUpdateMessage -> ResourceUpdateMessage::class.simpleName + is MessageProcessedNotificationMessage -> MessageProcessedNotificationMessage::class.simpleName + is DescriptionRequestMessage -> DescriptionRequestMessage::class.simpleName + is DescriptionResponseMessage -> DescriptionResponseMessage::class.simpleName + is RejectionMessage -> RejectionMessage::class.simpleName + is LogMessage -> LogMessage::class.simpleName + is QueryMessage -> QueryMessage::class.simpleName + is RequestMessage -> RequestMessage::class.simpleName + else -> header::class.simpleName + } if (LOG.isDebugEnabled) { LOG.debug("Detected ids-type: {}", messageType) } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ResourceUpdateCreationProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ResourceUpdateCreationProcessor.kt index 2935c9f8e..a340c31ec 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ResourceUpdateCreationProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/ResourceUpdateCreationProcessor.kt @@ -31,24 +31,25 @@ import java.net.URI @Component("resourceUpdateCreationProcessor") class ResourceUpdateCreationProcessor : Processor { - override fun process(exchange: Exchange) { if (LOG.isDebugEnabled) { LOG.debug("[IN] ${this::class.java.simpleName}") } - val artifactUri = exchange.getProperty(ContractConstants.ARTIFACT_URI_PROPERTY)?.let { - if (it is URI) { - it - } else { - URI.create(it.toString()) + val artifactUri = + exchange.getProperty(ContractConstants.ARTIFACT_URI_PROPERTY)?.let { + if (it is URI) { + it + } else { + URI.create(it.toString()) + } } - } - val usedContract = ProviderDB.artifactUrisMapped2ContractAgreements[ - Pair(artifactUri, UsageControlMaps.getExchangePeerIdentity(exchange)) - ] - ?: throw RuntimeException("No UC contract found for resource/artifact $artifactUri") + val usedContract = + ProviderDB.artifactUrisMapped2ContractAgreements[ + Pair(artifactUri, UsageControlMaps.getExchangePeerIdentity(exchange)) + ] + ?: throw RuntimeException("No UC contract found for resource/artifact $artifactUri") if (LOG.isDebugEnabled) { LOG.debug("Contract for requested Artifact found {}", usedContract) } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/UsageControlMaps.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/UsageControlMaps.kt index 0c28de96e..b82496eaa 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/UsageControlMaps.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/UsageControlMaps.kt @@ -35,8 +35,7 @@ object UsageControlMaps { private val peerContracts: MutableMap = MapMaker().weakKeys().makeMap() - fun getExchangePeerIdentity(exchange: Exchange): String? = - exchangePeerIdentityMap[exchange] + fun getExchangePeerIdentity(exchange: Exchange): String? = exchangePeerIdentityMap[exchange] fun getExchangeContract(exchange: Exchange): ContractAgreement? { return exchangePeerIdentityMap[exchange]?.let { identity -> @@ -50,21 +49,27 @@ object UsageControlMaps { contractMap[contractAgreement.id] = contractAgreement } - fun setPeerContract(peerIdentity: String, contractUri: URI?) { + fun setPeerContract( + peerIdentity: String, + contractUri: URI? + ) { if (contractUri != null) { peerContracts[peerIdentity] = contractUri if (LOG.isDebugEnabled) { - LOG.debug("UC: Assigned contract $contractUri to connection $peerIdentity") + LOG.debug("UC: Assigned contract $contractUri to peer identity $peerIdentity") } } else { peerContracts -= peerIdentity if (LOG.isDebugEnabled) { - LOG.debug("UC: Assigned no contract to connection $peerIdentity") + LOG.debug("UC: Assigned no contract to peer identity $peerIdentity") } } } - fun setExchangePeerIdentity(exchange: Exchange, peerIdentity: String) { + fun setExchangePeerIdentity( + exchange: Exchange, + peerIdentity: String + ) { exchangePeerIdentityMap[exchange] = peerIdentity if (LOG.isDebugEnabled) { LOG.debug("UC: Assigned exchange $exchange to peer identity $peerIdentity") diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/CertExposingEndpointStrategy.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/CertExposingEndpointStrategy.kt index 1f0915337..4b0618523 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/CertExposingEndpointStrategy.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/CertExposingEndpointStrategy.kt @@ -32,7 +32,10 @@ class CertExposingEndpointStrategy : EndpointStrategy { @Autowired private lateinit var certExposingHttpClientConfigurer: CertExposingHttpClientConfigurer - override fun registerEndpoint(uri: String, endpoint: Endpoint): Endpoint { + 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 diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/IdsMultiPartInputProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/IdsMultiPartInputProcessor.kt index 5b8f531a6..7103c49ec 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/IdsMultiPartInputProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/IdsMultiPartInputProcessor.kt @@ -39,7 +39,6 @@ import javax.net.ssl.SSLSession @Component("idsMultiPartInputProcessor") class IdsMultiPartInputProcessor : Processor { - @Autowired lateinit var beanFactory: BeanFactory @@ -52,34 +51,36 @@ class IdsMultiPartInputProcessor : Processor { // Parse Multipart message val parser = MultiPartStringParser(message.getBody(InputStream::class.java)) // Parse IDS header (should be an InfoModel Message object) - val idsHeader = parser.header?.let { header -> - SERIALIZER.deserialize(header, Message::class.java).also { - message.setHeader(MultiPartConstants.IDS_HEADER_KEY, it) - } - } ?: throw RuntimeException("No IDS header found!") + val idsHeader = + parser.header?.let { header -> + SERIALIZER.deserialize(header, Message::class.java).also { + message.setHeader(MultiPartConstants.IDS_HEADER_KEY, it) + } + } ?: throw RuntimeException("No IDS header found!") val dat = idsHeader.securityToken?.tokenValue ?: throw RuntimeException("No DAT provided!") dapsBeanName?.let { dapsBeanName -> - val peerCertificateHash: String = if (message.headers.containsKey("CamelHttpServletRequest")) { - // Assume server-side REST endpoint. - // Try to extract certificates from CamelHttpServletRequest reference. - val request = message.headers["CamelHttpServletRequest"] as Request - val sslSession = request.getAttribute("org.eclipse.jetty.servlet.request.ssl_session") as SSLSession - try { - sslSession.peerCertificates[0].sha256Fingerprint - } catch (e: SSLPeerUnverifiedException) { - LOG.error("Client didn't provide a certificate!") - throw e + val peerCertificateHash: String = + if (message.headers.containsKey("CamelHttpServletRequest")) { + // Assume server-side REST endpoint. + // Try to extract certificates from CamelHttpServletRequest reference. + val request = message.headers["CamelHttpServletRequest"] as Request + val sslSession = request.getAttribute("org.eclipse.jetty.servlet.request.ssl_session") as SSLSession + try { + sslSession.peerCertificates[0].sha256Fingerprint + } catch (e: SSLPeerUnverifiedException) { + LOG.error("Client didn't provide a certificate!") + throw e + } + } else { + // Assume client-side HTTPS request. + // Try to obtain Certificate hash extracted by CertExposingHttpClientConfigurer. + message.headers[CertExposingHttpClientConfigurer.SERVER_CERTIFICATE_HASH_HEADER]?.toString() + ?: throw RuntimeException( + "Could not obtain server TLS certificate! Has CertExposingHttpClientConfigurer been invoked?" + ) } - } else { - // Assume client-side HTTPS request. - // Try to obtain Certificate hash extracted by CertExposingHttpClientConfigurer. - message.headers[CertExposingHttpClientConfigurer.SERVER_CERTIFICATE_HASH_HEADER]?.toString() - ?: throw RuntimeException( - "Could not obtain server TLS certificate! Has CertExposingHttpClientConfigurer been invoked?" - ) - } if (LOG.isTraceEnabled) { LOG.trace("Peer Certificate hash: {}", peerCertificateHash) } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/IdsMultiPartOutputProcessor.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/IdsMultiPartOutputProcessor.kt index d8bdd978f..77f455283 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/IdsMultiPartOutputProcessor.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/IdsMultiPartOutputProcessor.kt @@ -87,7 +87,6 @@ import javax.xml.datatype.XMLGregorianCalendar */ @Component("idsMultiPartOutputProcessor") class IdsMultiPartOutputProcessor : Processor { - @Autowired lateinit var beanFactory: BeanFactory @@ -101,14 +100,16 @@ class IdsMultiPartOutputProcessor : Processor { multipartEntityBuilder.setMode(HttpMultipartMode.STRICT) multipartEntityBuilder.setBoundary(boundary) - val idsHeader = exchange.message.getHeader(IDS_HEADER_KEY) - ?: throw RuntimeException("Required header \"ids-header\" not found, aborting.") + val idsHeader = + exchange.message.getHeader(IDS_HEADER_KEY) + ?: throw RuntimeException("Required header \"ids-header\" not found, aborting.") - val daps = dapsBeanName?.let { beanFactory.getBean(it, DapsDriver::class.java) } - ?: run { - LOG.warn("No DAPS instance has been specified, dummy DAT will be used!") - null - } + val daps = + dapsBeanName?.let { beanFactory.getBean(it, DapsDriver::class.java) } + ?: run { + LOG.warn("No DAPS instance has been specified, dummy DAT will be used!") + null + } // Our detection heuristic for an incomplete InfoModel idsHeader if (idsHeader::class.simpleName?.endsWith("Builder") == true) { diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/MultiPartStringParser.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/MultiPartStringParser.kt index 0a17c8443..1447aae2b 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/MultiPartStringParser.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/camel/processors/multipart/MultiPartStringParser.kt @@ -31,59 +31,59 @@ import java.nio.charset.StandardCharsets class MultiPartStringParser internal constructor(private val multipartInput: InputStream) : UploadContext { - private var boundary: String? = null - var header: String? = null - var payload: InputStream? = null - var payloadContentType: String? = null + private var boundary: String? = null + var header: String? = null + var payload: InputStream? = null + var payloadContentType: String? = null - override fun getCharacterEncoding(): String = StandardCharsets.UTF_8.name() + override fun getCharacterEncoding(): String = StandardCharsets.UTF_8.name() - @Deprecated( - "Deprecated in favor of contentLength(), see parent class org.apache.commons.fileupload.UploadContext", - ReplaceWith("contentLength()") - ) - override fun getContentLength() = -1 + @Deprecated( + "Deprecated in favor of contentLength(), see parent class org.apache.commons.fileupload.UploadContext", + ReplaceWith("contentLength()") + ) + override fun getContentLength() = -1 - override fun getContentType() = "multipart/form-data, boundary=$boundary" + override fun getContentType() = "multipart/form-data, boundary=$boundary" - override fun getInputStream() = multipartInput + override fun getInputStream() = multipartInput - override fun contentLength() = -1L + override fun contentLength() = -1L - companion object { - private val LOG = LoggerFactory.getLogger(MultiPartStringParser::class.java) - } + companion object { + private val LOG = LoggerFactory.getLogger(MultiPartStringParser::class.java) + } - init { - multipartInput.mark(10240) - BufferedReader(InputStreamReader(multipartInput, StandardCharsets.UTF_8)).use { reader -> - val boundaryLine = - reader.readLine() - ?: throw IOException( - "Message body appears to be empty, expected multipart boundary." - ) - boundary = boundaryLine.substring(2).trim { it <= ' ' } - multipartInput.reset() - for (i in FileUpload(DiskFileItemFactory()).parseRequest(this)) { - val fieldName = i.fieldName - if (LOG.isTraceEnabled) { - LOG.trace("Found multipart field with name \"{}\"", fieldName) - } - if (MultiPartConstants.MULTIPART_HEADER == fieldName) { - header = i.string - if (LOG.isDebugEnabled) { - LOG.debug("Found header:\n{}", header) + init { + multipartInput.mark(10240) + BufferedReader(InputStreamReader(multipartInput, StandardCharsets.UTF_8)).use { reader -> + val boundaryLine = + reader.readLine() + ?: throw IOException( + "Message body appears to be empty, expected multipart boundary." + ) + boundary = boundaryLine.substring(2).trim { it <= ' ' } + multipartInput.reset() + for (i in FileUpload(DiskFileItemFactory()).parseRequest(this)) { + val fieldName = i.fieldName + if (LOG.isTraceEnabled) { + LOG.trace("Found multipart field with name \"{}\"", fieldName) } - } else if (MultiPartConstants.MULTIPART_PAYLOAD == fieldName) { - payload = i.inputStream - payloadContentType = i.contentType - if (LOG.isDebugEnabled) { - LOG.debug("Found body with Content-Type \"{}\"", payloadContentType) + if (MultiPartConstants.MULTIPART_HEADER == fieldName) { + header = i.string + if (LOG.isDebugEnabled) { + LOG.debug("Found header:\n{}", header) + } + } else if (MultiPartConstants.MULTIPART_PAYLOAD == fieldName) { + payload = i.inputStream + payloadContentType = i.contentType + if (LOG.isDebugEnabled) { + LOG.debug("Found body with Content-Type \"{}\"", payloadContentType) + } + } else { + throw IOException("Unknown multipart field name detected: $fieldName") } - } else { - throw IOException("Unknown multipart field name detected: $fieldName") } } } } -} diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/AisecDapsDriverFactoryBean.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/AisecDapsDriverFactoryBean.kt index 62bb4a01a..5bcd9f236 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/AisecDapsDriverFactoryBean.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/AisecDapsDriverFactoryBean.kt @@ -31,7 +31,6 @@ import javax.net.ssl.TrustManager @Suppress("unused") class AisecDapsDriverFactoryBean : FactoryBean { - private val builder = AisecDapsDriverConfig.Builder() var dapsUrl: String by BeanSetter(builder::setDapsUrl) @@ -45,12 +44,13 @@ class AisecDapsDriverFactoryBean : FactoryBean { var dapsSslParameters: SSLContextParameters by BeanSetter(builder::applySslContextParameters) var transportCertificatesParameters: SSLContextParameters by BeanSetter { - val ks = loadKeyStore( - it.keyManagers.keyStore.resource.let(Paths::get) - ?: throw RuntimeException("Error loading transport certificates: No KeyStore file provided!"), - it.keyManagers.keyStore.password?.toCharArray() - ?: throw RuntimeException("Error loading transport certificates: No KeyStore password provided!") - ) + val ks = + loadKeyStore( + it.keyManagers.keyStore.resource.let(Paths::get) + ?: throw RuntimeException("Error loading transport certificates: No KeyStore file provided!"), + it.keyManagers.keyStore.password?.toCharArray() + ?: throw RuntimeException("Error loading transport certificates: No KeyStore password provided!") + ) builder.loadTransportCertsFromKeystore(ks) } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/AttestationConfigFactoryBean.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/AttestationConfigFactoryBean.kt index 54652d0c4..d301528a0 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/AttestationConfigFactoryBean.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/AttestationConfigFactoryBean.kt @@ -24,7 +24,6 @@ import org.springframework.beans.factory.FactoryBean @Suppress("unused") class AttestationConfigFactoryBean : FactoryBean { - private val builder = AttestationConfig.Builder() var expectedRaSuite: String by BeanSetter { builder.setExpectedRaSuite(it.split('|').toTypedArray()) } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/BeanSetter.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/BeanSetter.kt index 37fab9501..724b9fa4c 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/BeanSetter.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/BeanSetter.kt @@ -24,10 +24,18 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty class BeanSetter(val setConsumer: (T) -> Unit) : ReadWriteProperty, T> { - override operator fun getValue(thisRef: FactoryBean, property: KProperty<*>): T { + override operator fun getValue( + thisRef: FactoryBean, + property: KProperty<*> + ): T { throw UnsupportedOperationException("FactoryBean set-only Builder method") } - override operator fun setValue(thisRef: FactoryBean, property: KProperty<*>, value: T) { + + override operator fun setValue( + thisRef: FactoryBean, + property: KProperty<*>, + value: T + ) { setConsumer(value) } } diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/Idscp2ConfigurationFactoryBean.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/Idscp2ConfigurationFactoryBean.kt index e78c60257..79a9a7836 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/Idscp2ConfigurationFactoryBean.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/Idscp2ConfigurationFactoryBean.kt @@ -26,7 +26,6 @@ import org.springframework.beans.factory.FactoryBean @Suppress("unused") class Idscp2ConfigurationFactoryBean : FactoryBean { - private val builder = Idscp2Configuration.Builder() var attestationConfig: AttestationConfig by BeanSetter(builder::setAttestationConfig) diff --git a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/NativeTlsConfigurationBuilderFactoryBean.kt b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/NativeTlsConfigurationBuilderFactoryBean.kt index 316e597f1..40579d01f 100644 --- a/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/NativeTlsConfigurationBuilderFactoryBean.kt +++ b/camel-processors/src/main/kotlin/de/fhg/aisec/ids/idscp2/beans/NativeTlsConfigurationBuilderFactoryBean.kt @@ -26,7 +26,6 @@ import org.springframework.beans.factory.FactoryBean @Suppress("unused") class NativeTlsConfigurationBuilderFactoryBean : FactoryBean { - private val builder = NativeTlsConfiguration.Builder() var sslParameters: SSLContextParameters by BeanSetter(builder::applySslContextParameters) diff --git a/docker-build/Dockerfile b/docker-build/Dockerfile index 9a1f94492..f33a98321 100644 --- a/docker-build/Dockerfile +++ b/docker-build/Dockerfile @@ -1,4 +1,4 @@ -ARG BASE_IMAGE=eclipse-temurin:17-jdk-focal +ARG BASE_IMAGE=eclipse-temurin:21-jdk FROM $BASE_IMAGE LABEL AUTHOR="Michael Lux (michael.lux@aisec.fraunhofer.de)" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 98fb87dbd..1badfd12b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,12 @@ [versions] -idscp2 = "0.18.1" -ktlint = "0.50.0" +idscp2 = "0.19.2" +ktlint = "1.0.1" # Kotlin library/compiler version -kotlin = "1.9.20" +kotlin = "1.9.21" kotlinx-coroutines = "1.7.3" # HTTP client -ktor = "2.3.5" +ktor = "2.3.6" # The used version of the infomodel from IESE infomodel = "4.1.3" @@ -22,11 +22,11 @@ influxDB = "2.23" guava = "32.1.3-jre" junit4 = "4.13.2" -junit5 = "5.10.0" +junit5 = "5.10.1" mockito = "5.7.0" mapdb = "3.0.10" jnrunix = "0.38.21" -protobuf = "3.25.0" +protobuf = "3.25.1" httpclient = "4.5.14" # Needed for policy reasoning with 2p (formerly tuProlog) @@ -43,8 +43,8 @@ javaxJson = "1.1.4" dockerJavaApi = "0.0.13" # We will pull in a newer version of jackson because of security fixes -jackson = "2.15.3" -jacksonDatabind = "2.15.3" +jackson = "2.16.0" +jacksonDatabind = "2.16.0" orgJson = "20220320" @@ -61,9 +61,9 @@ swagger = "1.6.12" jose4j = "0.9.3" jetty = "9.4.53.v20231009" -springBoot = "3.1.5" -springSecurity = "6.1.5" -bouncyCastle = "1.70" +springBoot = "3.2.0" +springSecurity = "6.2.0" +bouncyCastle = "1.77" [libraries] # common libraries @@ -132,8 +132,6 @@ mapdb = { group = "org.mapdb", name = "mapdb", version.ref = "mapdb" } kotlinx-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-reactive = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-reactive", version.ref = "kotlinx-coroutines" } kotlinx-reactor = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-reactor", version.ref = "kotlinx-coroutines" } -bouncycastle = { group = "org.bouncycastle", name = "bcprov-jdk15on", version.ref = "bouncyCastle" } -bouncycastlePkix = { group = "org.bouncycastle", name = "bcpkix-jdk15to18", version.ref = "bouncyCastle" } jose4j = { group = "org.bitbucket.b_c", name = "jose4j", version.ref = "jose4j" } auth0Jwt = { group = "com.auth0", name = "java-jwt", version.ref = "auth0Jwt" } swagger-jaxrs = { group = "io.swagger", name = "swagger-jaxrs", version.ref = "swagger" } @@ -152,13 +150,13 @@ jaxbImpl = ["jaxb-core", "jaxb-impl"] [plugins] springboot = { id = "org.springframework.boot", version.ref = "springBoot" } -spring-dependencyManagement = { id = "io.spring.dependency-management", version = "1.1.3" } +spring-dependencyManagement = { id = "io.spring.dependency-management", version = "1.1.4" } swagger = { id = "com.benjaminsproule.swagger", version = "1.0.14" } protobuf = { id = "com.google.protobuf", version = "0.9.4" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-plugin-spring = { id = "org.jetbrains.kotlin.plugin.spring", version.ref = "kotlin" } spotless = { id = "com.diffplug.spotless", version = "6.22.0" } licenseReport = { id = "com.github.jk1.dependency-license-report", version = "2.5" } -versions = { id = "com.github.ben-manes.versions", version = "0.49.0" } -buildconfig = { id = "com.github.gmazzo.buildconfig", version = "4.1.2" } -node = { id = "com.github.node-gradle.node", version = "3.5.1" } \ No newline at end of file +versions = { id = "com.github.ben-manes.versions", version = "0.50.0" } +buildconfig = { id = "com.github.gmazzo.buildconfig", version = "4.2.0" } +node = { id = "com.github.node-gradle.node", version = "7.0.1" } \ No newline at end of file diff --git a/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/AcmeChallengeServer.kt b/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/AcmeChallengeServer.kt index 80385b6cc..269ad95e7 100644 --- a/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/AcmeChallengeServer.kt +++ b/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/AcmeChallengeServer.kt @@ -34,7 +34,10 @@ object AcmeChallengeServer { private val LOG = LoggerFactory.getLogger(AcmeChallengeServer::class.java)!! @Throws(IOException::class) - fun startServer(acmeClient: AcmeClient, challengePort: Int) { + fun startServer( + acmeClient: AcmeClient, + challengePort: Int + ) { server = object : NanoHTTPD(challengePort) { override fun serve(session: IHTTPSession): Response { diff --git a/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/AcmeClientService.kt b/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/AcmeClientService.kt index ec76c8a62..dead9cfb5 100644 --- a/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/AcmeClientService.kt +++ b/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/AcmeClientService.kt @@ -61,7 +61,6 @@ import java.util.Date // property = [Scheduler.PROPERTY_SCHEDULER_EXPRESSION + "=0 0 3 * * ?"] ) class AcmeClientService : AcmeClient, Runnable, SslContextFactoryReloadableRegistry { - @Autowired private lateinit var settings: Settings @@ -349,14 +348,15 @@ class AcmeClientService : AcmeClient, Runnable, SslContextFactoryReloadableRegis // parallel. // This is especially important if the ACME protocol implementations are missing // upon boot. - val t = Thread { - renewCertificate( - targetDirectory, - URI.create(acmeServerUrl), - domains, - challengePort - ) - } + val t = + Thread { + renewCertificate( + targetDirectory, + URI.create(acmeServerUrl), + domains, + challengePort + ) + } t.name = "ACME Renewal Thread" t.isDaemon = true t.start() @@ -404,7 +404,6 @@ class AcmeClientService : AcmeClient, Runnable, SslContextFactoryReloadableRegis } companion object { - const val RENEWAL_THRESHOLD = 100.0 / 3.0 const val KEYSTORE_LATEST = "keystore_latest.p12" private val LOG = LoggerFactory.getLogger(AcmeClientService::class.java) diff --git a/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/provider/BoulderAcmeProvider.kt b/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/provider/BoulderAcmeProvider.kt index 5d5073fe7..11b83cc66 100644 --- a/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/provider/BoulderAcmeProvider.kt +++ b/ids-acme/src/main/kotlin/de/fhg/aisec/ids/acme/provider/BoulderAcmeProvider.kt @@ -32,7 +32,6 @@ import java.util.regex.Pattern * @see [Boulder](https://github.com/letsencrypt/boulder) */ class BoulderAcmeProvider : AbstractAcmeProvider() { - override fun accepts(serverUri: URI): Boolean { return "acme" == serverUri.scheme && "boulder" == serverUri.host } @@ -75,7 +74,6 @@ class BoulderAcmeProvider : AbstractAcmeProvider() { } companion object { - private val HOST_PATTERN = Pattern.compile("^/([^:/]+)(?::(\\d+))?/?$") const val DEFAULT_PORT = 4001 } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/acme/AcmeTermsOfService.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/acme/AcmeTermsOfService.kt index e32ddf99d..81d27ba33 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/acme/AcmeTermsOfService.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/acme/AcmeTermsOfService.kt @@ -21,4 +21,8 @@ package de.fhg.aisec.ids.api.acme import com.fasterxml.jackson.annotation.JsonProperty -class AcmeTermsOfService(val tos: String?, @get:JsonProperty(value = "isUri") val isUri: Boolean?, val error: String?) +class AcmeTermsOfService( + val tos: String?, + @get:JsonProperty(value = "isUri") val isUri: Boolean?, + val error: String? +) diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ApplicationContainer.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ApplicationContainer.kt index f68a6db90..af34dd53e 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ApplicationContainer.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ApplicationContainer.kt @@ -96,6 +96,6 @@ class ApplicationContainer { ", description=" + description + "]" - ) + ) } } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ContainerManager.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ContainerManager.kt index a6509e3b5..f359f2329 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ContainerManager.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ContainerManager.kt @@ -72,7 +72,10 @@ interface ContainerManager { * @throws NoContainerExistsException If the given container was not found. */ @Throws(NoContainerExistsException::class) - fun startContainer(containerID: String, key: String?) + fun startContainer( + containerID: String, + key: String? + ) /** * Stops a container. diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ContainerStatus.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ContainerStatus.kt index 64dc0822e..30c36efd2 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ContainerStatus.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/ContainerStatus.kt @@ -20,5 +20,11 @@ package de.fhg.aisec.ids.api.cm enum class ContainerStatus { - CREATED, RESTARTING, RUNNING, REMOVING, PAUSED, EXITED, DEAD + CREATED, + RESTARTING, + RUNNING, + REMOVING, + PAUSED, + EXITED, + DEAD } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Decision.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Decision.kt index 2b8b7a69e..72c4c1ca4 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Decision.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Decision.kt @@ -20,5 +20,7 @@ package de.fhg.aisec.ids.api.cm enum class Decision { - ALLOW, DENY, DROP + ALLOW, + DENY, + DROP } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Direction.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Direction.kt index 2b6de9ec9..05cc66793 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Direction.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Direction.kt @@ -20,5 +20,6 @@ package de.fhg.aisec.ids.api.cm enum class Direction { - OUTBOUND, INBOUND + OUTBOUND, + INBOUND } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Protocol.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Protocol.kt index 086c74d80..cbaf99d48 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Protocol.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/cm/Protocol.kt @@ -20,5 +20,6 @@ package de.fhg.aisec.ids.api.cm enum class Protocol { - TCP, UDP + TCP, + UDP } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/ConnectionManager.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/ConnectionManager.kt index e04f020ba..2ba390561 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/ConnectionManager.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/ConnectionManager.kt @@ -26,6 +26,8 @@ package de.fhg.aisec.ids.api.conm */ interface ConnectionManager { fun listIncomingConnections(): List + fun listOutgoingConnections(): List + fun listAvailableEndpoints(): List } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPClientEndpoint.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPClientEndpoint.kt index 15df764df..43e94e1fa 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPClientEndpoint.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPClientEndpoint.kt @@ -29,6 +29,7 @@ class IDSCPClientEndpoint { var endpointIdentifier: String? = null var attestationResult: RatResult? = null var endpointKey: String? = null + override fun toString(): String { return "IDSCPEndpoint [endpoint_identifier=$endpointIdentifier]" } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPIncomingConnection.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPIncomingConnection.kt index 3e3788f49..c4e1e4b1e 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPIncomingConnection.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPIncomingConnection.kt @@ -31,6 +31,7 @@ class IDSCPIncomingConnection { var remoteHostName: String? = null var metaData: String? = null private var dynamicAttributeToken: String? = null + override fun toString(): String { return ( "IDSCPConnection [endpoint_identifier=" + @@ -38,7 +39,7 @@ class IDSCPIncomingConnection { ", attestationResult=" + attestationResult + "]" - ) + ) } fun setDynamicAttributeToken(dynamicAttributeToken: String?) { diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPOutgoingConnection.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPOutgoingConnection.kt index 6a58b10ed..720f4affd 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPOutgoingConnection.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/IDSCPOutgoingConnection.kt @@ -31,6 +31,7 @@ class IDSCPOutgoingConnection { var endpointKey: String? = null var attestationResult: RatResult? = null var metaData: String? = null + override fun toString(): String { return "IDSCPOutgoingConnection [endpoint_identifier=$endpointIdentifier]" } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/RatResult.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/RatResult.kt index 77bc641a4..d4b969cab 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/RatResult.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/conm/RatResult.kt @@ -26,7 +26,8 @@ package de.fhg.aisec.ids.api.conm */ class RatResult(val status: Status, reason: String?) { enum class Status { - FAILED, SUCCESS + FAILED, + SUCCESS } var reason: String? = null diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/contracts/ContractManager.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/contracts/ContractManager.kt index 7329b2dd7..b5d1e6b9d 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/contracts/ContractManager.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/contracts/ContractManager.kt @@ -24,7 +24,10 @@ import de.fraunhofer.iais.eis.ContractOffer interface ContractManager { fun makeContract(contractProperties: Map): ContractOffer - fun storeContract(key: String, contract: ContractOffer) + fun storeContract( + key: String, + contract: ContractOffer + ) fun loadContract(key: String): ContractOffer? } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/contracts/ContractUtils.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/contracts/ContractUtils.kt index 2213c7b15..2d7d0bca5 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/contracts/ContractUtils.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/contracts/ContractUtils.kt @@ -29,6 +29,7 @@ object ContractUtils { 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 } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/endpointconfig/EndpointConfigManager.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/endpointconfig/EndpointConfigManager.kt index 113249c96..71ae839ce 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/endpointconfig/EndpointConfigManager.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/endpointconfig/EndpointConfigManager.kt @@ -29,7 +29,12 @@ package de.fhg.aisec.ids.api.endpointconfig * @author Leon Beckmann (leon.beckmann@aisec.fraunhofer.de) */ interface EndpointConfigManager { - fun addEndpointConfigListener(identifier: String, listener: EndpointConfigListener) + fun addEndpointConfigListener( + identifier: String, + listener: EndpointConfigListener + ) + fun removeEndpointConfigListener(identifier: String) + fun notify(endpointConfig: String) } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/idscp2/Idscp2UsageControlInterface.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/idscp2/Idscp2UsageControlInterface.kt index e163f9511..8ae324a93 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/idscp2/Idscp2UsageControlInterface.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/idscp2/Idscp2UsageControlInterface.kt @@ -37,7 +37,10 @@ interface Idscp2UsageControlInterface { fun isProtected(exchange: Exchange): Boolean - fun protectBody(exchange: Exchange, contractUri: URI) + fun protectBody( + exchange: Exchange, + contractUri: URI + ) fun unprotectBody(exchange: Exchange) } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/PAP.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/PAP.kt index 549a6667c..23b6f6bf6 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/PAP.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/PAP.kt @@ -44,6 +44,8 @@ interface PAP { * @return Active policy as prolog */ val policy: String + fun listRules(): List + fun verifyRoute(routeId: String): RouteVerificationProof? } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/PolicyDecision.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/PolicyDecision.kt index b9a27d248..006557534 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/PolicyDecision.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/PolicyDecision.kt @@ -26,7 +26,8 @@ package de.fhg.aisec.ids.api.policy */ class PolicyDecision { enum class Decision { - ALLOW, DENY + ALLOW, + DENY } var reason = "Default deny" diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/TransformationDecision.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/TransformationDecision.kt index 5398d1985..7415c7ec1 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/TransformationDecision.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/policy/TransformationDecision.kt @@ -35,7 +35,6 @@ class TransformationDecision( * @return Labels to add to the data in this processing step */ val labelsToAdd: MutableSet = mutableSetOf(), - /** * Returns a (possibly empty, but never null) set of labels that must be removed from a message. * diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/CounterExample.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/CounterExample.kt index dd852028a..4464233a2 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/CounterExample.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/CounterExample.kt @@ -27,8 +27,8 @@ abstract class CounterExample { override fun toString(): String { return """ - Explanation: $explanation - ${java.lang.String.join("\n|-- ", steps)} - """.trimIndent() + Explanation: $explanation + ${java.lang.String.join("\n|-- ", steps)} + """.trimIndent() } } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteComponent.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteComponent.kt index e80f2d2a4..a03b8e462 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteComponent.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteComponent.kt @@ -32,7 +32,7 @@ class RouteComponent { private set constructor() { - /* Bean std c'tor */ + // Bean std c'tor } constructor(bundleName: String?, description: String?) { diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteManager.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteManager.kt index 074d74e79..b92e49c16 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteManager.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteManager.kt @@ -76,6 +76,7 @@ interface RouteManager { * @return Map of Camel context names to contained endpoint URIs */ val endpoints: Map> + fun listEndpoints(): Map /** diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteObject.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteObject.kt index f7e682c9c..dd8d5322c 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteObject.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/RouteObject.kt @@ -34,7 +34,7 @@ class RouteObject { var id: String? = null constructor() { - /* Bean std c'tor */ + // Bean std c'tor } constructor( diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/graph/Node.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/graph/Node.kt index 5852462bf..3c669a61e 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/graph/Node.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/router/graph/Node.kt @@ -21,6 +21,8 @@ package de.fhg.aisec.ids.api.router.graph data class Node(val name: String, val action: String, val type: NodeType) { enum class NodeType { - EntryNode, Node, ChoiceNode + EntryNode, + Node, + ChoiceNode } } diff --git a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/settings/Settings.kt b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/settings/Settings.kt index 99b7331fd..c4c031bf6 100644 --- a/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/settings/Settings.kt +++ b/ids-api/src/main/kotlin/de/fhg/aisec/ids/api/settings/Settings.kt @@ -25,14 +25,33 @@ interface Settings { var connectorConfig: ConnectorConfig var connectorProfile: ConnectorProfile var connectorJsonLd: String? + fun getConnectionSettings(connection: String): ConnectionSettings - fun setConnectionSettings(connection: String, cSettings: ConnectionSettings) + + fun setConnectionSettings( + connection: String, + cSettings: ConnectionSettings + ) + val allConnectionSettings: Map + fun isUserStoreEmpty(): Boolean + fun getUserHash(username: String): String? - fun saveUser(username: String, hash: String) + + fun saveUser( + username: String, + hash: String + ) + fun removeUser(username: String) + fun getUsers(): Map + fun loadContract(key: String): String? - fun storeContract(key: String, contract: String) + + fun storeContract( + key: String, + contract: String + ) } diff --git a/ids-connector/Dockerfile b/ids-connector/Dockerfile index 3992255ec..3241b4e17 100644 --- a/ids-connector/Dockerfile +++ b/ids-connector/Dockerfile @@ -1,4 +1,4 @@ -ARG BASE_IMAGE=gcr.io/distroless/java17-debian11 +ARG BASE_IMAGE=gcr.io/distroless/java21-debian12 FROM $BASE_IMAGE LABEL AUTHOR="Michael Lux (michael.lux@aisec.fraunhofer.de)" diff --git a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ConnectorConfiguration.kt b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ConnectorConfiguration.kt index 28e5d5b52..00cd0dad3 100644 --- a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ConnectorConfiguration.kt +++ b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ConnectorConfiguration.kt @@ -37,7 +37,6 @@ import java.net.URI @Configuration class ConnectorConfiguration { - @Autowired(required = false) private var cml: ContainerManager? = null @@ -62,29 +61,32 @@ class ConnectorConfiguration { @Bean fun configureIdscp2(): CommandLineRunner { return CommandLineRunner { - Utils.issuerProducer = LazyProducer { - if (connectorUrl.isNotBlank()) { - URI.create(connectorUrl) - } else { - // Kept for backwards compatibility - settings.connectorProfile.connectorUrl - ?: URI.create("https://connector.ids") + Utils.issuerProducer = + LazyProducer { + if (connectorUrl.isNotBlank()) { + URI.create(connectorUrl) + } else { + // Kept for backwards compatibility + settings.connectorProfile.connectorUrl + ?: URI.create("https://connector.ids") + } } - } - Utils.senderAgentProducer = LazyProducer { - if (senderAgent.isNotBlank()) { - URI.create(senderAgent) - } else { - // Kept for backwards compatibility - settings.connectorProfile.maintainerUrl - ?: URI.create("https://sender-agent.ids") + Utils.senderAgentProducer = + LazyProducer { + if (senderAgent.isNotBlank()) { + URI.create(senderAgent) + } else { + // Kept for backwards compatibility + settings.connectorProfile.maintainerUrl + ?: URI.create("https://sender-agent.ids") + } } - } - Utils.dapsUrlProducer = LazyProducer { - dapsUrl.ifBlank { - settings.connectorConfig.dapsUrl + Utils.dapsUrlProducer = + LazyProducer { + dapsUrl.ifBlank { + settings.connectorConfig.dapsUrl + } } - } TrustedConnector.LOG.info("Information model {} loaded", BuildConfig.INFOMODEL_VERSION) Utils.infomodelVersion = BuildConfig.INFOMODEL_VERSION diff --git a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/Idscp2UsageControlComponent.kt b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/Idscp2UsageControlComponent.kt index cb9108119..dace703c0 100644 --- a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/Idscp2UsageControlComponent.kt +++ b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/Idscp2UsageControlComponent.kt @@ -28,10 +28,12 @@ import java.net.URI @Component class Idscp2UsageControlComponent : Idscp2UsageControlInterface { - override fun getExchangeContract(exchange: Exchange) = - UsageControlMaps.getExchangeContract(exchange) + override fun getExchangeContract(exchange: Exchange) = UsageControlMaps.getExchangeContract(exchange) - override fun protectBody(exchange: Exchange, contractUri: URI) { + override fun protectBody( + exchange: Exchange, + contractUri: URI + ) { protectedBodies[exchange] = exchange.message.body exchange.message.body = "### Usage control protected body, contract $contractUri ###" } diff --git a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ServerConfiguration.kt b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ServerConfiguration.kt deleted file mode 100644 index cfc0e412b..000000000 --- a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ServerConfiguration.kt +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * ========================LICENSE_START================================= - * ids-connector - * %% - * Copyright (C) 2021 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 - -// import de.fhg.aisec.ids.dynamictls.AcmeSslContextFactory -// import org.eclipse.jetty.server.Connector -// import org.eclipse.jetty.server.Server -// import org.eclipse.jetty.server.ServerConnector -// import org.eclipse.jetty.util.ssl.SslContextFactory -// import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer -// import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory -// import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory -// import org.springframework.context.annotation.Bean -// import org.springframework.context.annotation.Configuration -// -// @Configuration -// class ServerConfiguration { -// -// @Bean -// fun sslContextFactory(): SslContextFactory.Server { -// return AcmeSslContextFactory() -// } -// -// @Bean -// fun webServerFactory(sslContextFactory: SslContextFactory.Server): ConfigurableServletWebServerFactory { -// return JettyServletWebServerFactory().apply { -// port = 8443 -// serverCustomizers = listOf( -// JettyServerCustomizer { server: Server -> -// server.connectors = arrayOf( -// ServerConnector(server, sslContextFactory) -// ) -// } -// ) -// } -// } -// } diff --git a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ServerConfiguration.kt.backup b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ServerConfiguration.kt.backup new file mode 100644 index 000000000..ad9b2b5db --- /dev/null +++ b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/ServerConfiguration.kt.backup @@ -0,0 +1,54 @@ +/*- + * ========================LICENSE_START================================= + * ids-connector + * %% + * Copyright (C) 2021 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 + +import de.fhg.aisec.ids.dynamictls.AcmeSslContextFactory +import org.eclipse.jetty.server.Connector +import org.eclipse.jetty.server.Server +import org.eclipse.jetty.server.ServerConnector +import org.eclipse.jetty.util.ssl.SslContextFactory +import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer +import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class ServerConfiguration { + + @Bean + fun sslContextFactory(): SslContextFactory.Server { + return AcmeSslContextFactory() + } + + @Bean + fun webServerFactory(sslContextFactory: SslContextFactory.Server): ConfigurableServletWebServerFactory { + return JettyServletWebServerFactory().apply { + port = 8443 + serverCustomizers = listOf( + JettyServerCustomizer { server: Server -> + server.connectors = arrayOf( + ServerConnector(server, sslContextFactory) + ) + } + ) + } + } +} diff --git a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/TrustedConnector.kt b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/TrustedConnector.kt index 33b80d15d..645b8fc9a 100644 --- a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/TrustedConnector.kt +++ b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/TrustedConnector.kt @@ -27,9 +27,7 @@ import org.springframework.boot.runApplication /** Main startup class for the Trusted Connector using Spring Boot. */ @SpringBootApplication class TrustedConnector { - companion object { - val LOG: Logger = LoggerFactory.getLogger(TrustedConnector::class.java) @JvmStatic diff --git a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/dynamictls/AcmeSslContextFactory.kt b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/dynamictls/AcmeSslContextFactory.kt deleted file mode 100644 index 245d6a7b0..000000000 --- a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/dynamictls/AcmeSslContextFactory.kt +++ /dev/null @@ -1,77 +0,0 @@ -/*- - * ========================LICENSE_START================================= - * ids-connector - * %% - * Copyright (C) 2019 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.dynamictls - -// import de.fhg.aisec.ids.api.acme.SslContextFactoryReloadable -// import de.fhg.aisec.ids.api.acme.SslContextFactoryReloadableRegistry -// import org.eclipse.jetty.util.ssl.SslContextFactory -// import org.slf4j.LoggerFactory -// import org.springframework.beans.factory.annotation.Autowired -// -// /** -// * This SslContextFactory registers started instances to a service that allows reloading of -// * all active SslContextFactory instances. -// * -// * @author Michael Lux -// */ -// class AcmeSslContextFactory : SslContextFactory.Server(), SslContextFactoryReloadable { -// -// @Autowired -// private lateinit var reloadableRegistry: SslContextFactoryReloadableRegistry -// -// @Throws(Exception::class) -// override fun doStart() { -// if (LOG.isDebugEnabled) { -// LOG.debug("Starting {}", this) -// } -// reloadableRegistry.registerSslContextFactoryReloadable(this) -// super.doStart() -// } -// -// @Throws(java.lang.Exception::class) -// override fun doStop() { -// if (LOG.isDebugEnabled) { -// LOG.debug("Stopping {}", this) -// } -// reloadableRegistry.removeSslContextFactoryReloadable(this) -// super.doStop() -// } -// -// override fun reload(newKeyStorePath: String) { -// try { -// if (LOG.isInfoEnabled) { -// LOG.info("Reloading {}", this) -// } -// reload { f: SslContextFactory -> f.keyStorePath = newKeyStorePath } -// } catch (e: Exception) { -// LOG.error("Error whilst reloading SslContextFactory: $this", e) -// } -// } -// -// override fun toString(): String { -// return String.format( -// "%s@%x (%s)", this.javaClass.simpleName, this.hashCode(), this.keyStorePath -// ) -// } -// -// companion object { -// private val LOG = LoggerFactory.getLogger(AcmeSslContextFactory::class.java) -// } -// } diff --git a/ids-connector/src/main/kotlin/de/fhg/aisec/ids/dynamictls/AcmeSslContextFactory.kt.backup b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/dynamictls/AcmeSslContextFactory.kt.backup new file mode 100644 index 000000000..7844ea1f9 --- /dev/null +++ b/ids-connector/src/main/kotlin/de/fhg/aisec/ids/dynamictls/AcmeSslContextFactory.kt.backup @@ -0,0 +1,79 @@ +/*- + * ========================LICENSE_START================================= + * ids-connector + * %% + * Copyright (C) 2019 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.dynamictls + +import de.fhg.aisec.ids.api.acme.SslContextFactoryReloadable +import de.fhg.aisec.ids.api.acme.SslContextFactoryReloadableRegistry +import org.eclipse.jetty.util.ssl.SslContextFactory +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component + +/** + * This SslContextFactory registers started instances to a service that allows reloading of + * all active SslContextFactory instances. + * + * @author Michael Lux + */ +@Component +class AcmeSslContextFactory : SslContextFactory.Server(), SslContextFactoryReloadable { + + @Autowired + private lateinit var reloadableRegistry: SslContextFactoryReloadableRegistry + + @Throws(Exception::class) + override fun doStart() { + if (LOG.isDebugEnabled) { + LOG.debug("Starting {}", this) + } + reloadableRegistry.registerSslContextFactoryReloadable(this) + super.doStart() + } + + @Throws(java.lang.Exception::class) + override fun doStop() { + if (LOG.isDebugEnabled) { + LOG.debug("Stopping {}", this) + } + reloadableRegistry.removeSslContextFactoryReloadable(this) + super.doStop() + } + + override fun reload(newKeyStorePath: String?) { + try { + if (LOG.isInfoEnabled) { + LOG.info("Reloading {}", this) + } + reload { f: SslContextFactory -> f.keyStorePath = newKeyStorePath } + } catch (e: Exception) { + LOG.error("Error whilst reloading SslContextFactory: $this", e) + } + } + + override fun toString(): String { + return String.format( + "%s@%x (%s)", this.javaClass.simpleName, this.hashCode(), this.keyStorePath + ) + } + + companion object { + private val LOG = LoggerFactory.getLogger(AcmeSslContextFactory::class.java) + } +} diff --git a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/ContainerManagerService.kt b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/ContainerManagerService.kt index 0bd94bf8a..169fe8414 100644 --- a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/ContainerManagerService.kt +++ b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/ContainerManagerService.kt @@ -72,7 +72,10 @@ class ContainerManagerService : ContainerManager { } } - override fun startContainer(containerID: String, key: String?) { + override fun startContainer( + containerID: String, + key: String? + ) { try { containerManager.startContainer(containerID, key) } catch (e: NoContainerExistsException) { diff --git a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/docker/DockerCM.kt b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/docker/DockerCM.kt index a645b106c..8b1d83723 100644 --- a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/docker/DockerCM.kt +++ b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/docker/DockerCM.kt @@ -59,7 +59,7 @@ import kotlin.math.abs class DockerCM : ContainerManager { companion object { private val LOG = LoggerFactory.getLogger(DockerCM::class.java) - private lateinit var DOCKER_CLIENT: Docker + private lateinit var dockerClient: Docker private val PERIOD_UNITS = listOf(ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS) private val DURATION_UNITS = @@ -73,7 +73,7 @@ class DockerCM : ContainerManager { val isSupported: Boolean get() { return try { - DOCKER_CLIENT.ping() + dockerClient.ping() } catch (e: Throwable) { when (e) { is UninitializedPropertyAccessException -> @@ -90,7 +90,7 @@ class DockerCM : ContainerManager { // We have to modify the thread class loader for docker-java-api to find its config val threadContextClassLoader = Thread.currentThread().contextClassLoader Thread.currentThread().contextClassLoader = UnixDocker::class.java.classLoader - DOCKER_CLIENT = UnixDocker(File("/var/run/docker.sock")) + dockerClient = UnixDocker(File("/var/run/docker.sock")) Thread.currentThread().contextClassLoader = threadContextClassLoader } catch (x: Exception) { LOG.error("Error initializing docker client", x) @@ -128,7 +128,10 @@ class DockerCM : ContainerManager { } } - private fun formatDuration(a: ZonedDateTime, b: ZonedDateTime): String { + private fun formatDuration( + a: ZonedDateTime, + b: ZonedDateTime + ): String { val period = Period.between(a.toLocalDate(), b.toLocalDate()) var duration = ChronoUnit.SECONDS.between(a.toLocalTime(), b.toLocalTime()) val units: MutableList = LinkedList() @@ -156,7 +159,7 @@ class DockerCM : ContainerManager { withSize: Boolean = false ): Sequence { val filteredContainers = - DOCKER_CLIENT.containers().filter(filters ?: emptyMap()).withSize(withSize) + dockerClient.containers().filter(filters ?: emptyMap()).withSize(withSize) return if (all) { filteredContainers.all().asSequence() } else { @@ -165,7 +168,7 @@ class DockerCM : ContainerManager { } private fun getImages(filters: Map>?): Images { - return DOCKER_CLIENT.images().filter(filters ?: emptyMap()) + return dockerClient.images().filter(filters ?: emptyMap()) } override fun list(onlyRunning: Boolean): List { @@ -278,8 +281,7 @@ class DockerCM : ContainerManager { ) } - private fun getImage(container: Container) = - getImages(mapOf("reference" to listOf(container.getString("Image")))).firstOrNull() + private fun getImage(container: Container) = getImages(mapOf("reference" to listOf(container.getString("Image")))).firstOrNull() override fun wipe(containerID: String) { val container = getContainer(containerID) @@ -301,7 +303,10 @@ class DockerCM : ContainerManager { } } - override fun startContainer(containerID: String, key: String?) { + override fun startContainer( + containerID: String, + key: String? + ) { val container = getContainer(containerID) try { container.start() @@ -334,7 +339,7 @@ class DockerCM : ContainerManager { val tag = if (imageInfo.size == 2) imageInfo[1] else "latest" LOG.info("Pulling container image {} with tag {}", imageInfo[0], tag) // Pull image from std docker registry - DOCKER_CLIENT.images().pull(imageInfo[0], tag) + dockerClient.images().pull(imageInfo[0], tag) // Instantly create a container from that image, but do not start it yet. LOG.info("Creating container instance from image {}", app.image) @@ -352,7 +357,7 @@ class DockerCM : ContainerManager { "(?:((?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}" + "(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])):)?" + "([0-9]+):([0-9]+)(?:/(tcp|udp))?" - ) + ) .toRegex() for (port in app.ports) { val match = portRegex.matchEntire(port) @@ -398,7 +403,7 @@ class DockerCM : ContainerManager { hostConfig.add("Privileged", JsonValue.TRUE) } container.add("HostConfig", hostConfig) - val c = DOCKER_CLIENT.containers().create(containerName, container.build()) + val c = dockerClient.containers().create(containerName, container.build()) return c.containerId() } catch (e: InterruptedException) { @@ -460,7 +465,7 @@ class DockerCM : ContainerManager { /** Returns the version of docker on the system */ override val version: String get() { - val version = DOCKER_CLIENT.version() + val version = dockerClient.version() return "${version.platformName()} (${version.version()})" } } diff --git a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/dummy/DummyCM.kt b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/dummy/DummyCM.kt index 681f059bf..bb7563033 100644 --- a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/dummy/DummyCM.kt +++ b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/dummy/DummyCM.kt @@ -36,9 +36,16 @@ class DummyCM : ContainerManager { } override fun wipe(containerID: String) {} - override fun startContainer(containerID: String, key: String?) {} + + override fun startContainer( + containerID: String, + key: String? + ) {} + override fun stopContainer(containerID: String) {} + override fun restartContainer(containerID: String) {} + override fun pullImage(app: ApplicationContainer): String? { return null } diff --git a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXCM.kt b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXCM.kt index 20f22654e..51ab254c9 100644 --- a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXCM.kt +++ b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXCM.kt @@ -52,237 +52,244 @@ import kotlin.math.abs * * @author Julian Schütte (julian.schuette@aisec.fraunhofer.de) */ -class TrustXCM @JvmOverloads constructor(socket: String = SOCKET) : ContainerManager { - private var socketThread: TrustmeUnixSocketThread = TrustmeUnixSocketThread(socket) - private var responseHandler: TrustmeUnixSocketResponseHandler = TrustmeUnixSocketResponseHandler() - private val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT) - .withLocale(Locale.GERMANY) - .withZone(ZoneId.systemDefault()) +class TrustXCM + @JvmOverloads + constructor(socket: String = SOCKET) : ContainerManager { + private var socketThread: TrustmeUnixSocketThread = TrustmeUnixSocketThread(socket) + private var responseHandler: TrustmeUnixSocketResponseHandler = TrustmeUnixSocketResponseHandler() + private val formatter = + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT) + .withLocale(Locale.GERMANY) + .withZone(ZoneId.systemDefault()) - private fun stateToStatusString(state: ContainerState): ContainerStatus { - return when (state) { - ContainerState.RUNNING, ContainerState.SETUP -> ContainerStatus.RUNNING - else -> ContainerStatus.EXITED + private fun stateToStatusString(state: ContainerState): ContainerStatus { + return when (state) { + ContainerState.RUNNING, ContainerState.SETUP -> ContainerStatus.RUNNING + else -> ContainerStatus.EXITED + } } - } - override fun list(onlyRunning: Boolean): List { - LOG.debug("Starting list containers") - val result: MutableList = ArrayList() - val response = sendCommandAndWaitForResponse(ControllerToDaemon.Command.GET_CONTAINER_STATUS) - try { - val dtc = DaemonToController.parseFrom(response) - val containerStats = dtc.containerStatusList - for (cs in containerStats) { - var container: ApplicationContainer - if (!onlyRunning || ContainerState.RUNNING == cs.state) { - container = ApplicationContainer() - container.id = cs.uuid - container.image = "" - container.created = formatter.format(Instant.ofEpochSecond(cs.created)) - // container.setStatus(cs.getState().name()); - container.status = stateToStatusString(cs.state) - container.ports = emptyList() - container.names = cs.name - container.name = cs.name - container.size = "" - container.uptime = formatDuration(Duration.ofSeconds(cs.uptime)) - container.signature = "" - container.owner = "" - container.description = "trustx container" - container.labels = emptyMap() - LOG.debug("List add Container: $container") - result.add(container) + override fun list(onlyRunning: Boolean): List { + LOG.debug("Starting list containers") + val result: MutableList = ArrayList() + val response = sendCommandAndWaitForResponse(ControllerToDaemon.Command.GET_CONTAINER_STATUS) + try { + val dtc = DaemonToController.parseFrom(response) + val containerStats = dtc.containerStatusList + for (cs in containerStats) { + var container: ApplicationContainer + if (!onlyRunning || ContainerState.RUNNING == cs.state) { + container = ApplicationContainer() + container.id = cs.uuid + container.image = "" + container.created = formatter.format(Instant.ofEpochSecond(cs.created)) + // container.setStatus(cs.getState().name()); + container.status = stateToStatusString(cs.state) + container.ports = emptyList() + container.names = cs.name + container.name = cs.name + container.size = "" + container.uptime = formatDuration(Duration.ofSeconds(cs.uptime)) + container.signature = "" + container.owner = "" + container.description = "trustx container" + container.labels = emptyMap() + LOG.debug("List add Container: $container") + result.add(container) + } } + } catch (e: InvalidProtocolBufferException) { + LOG.error("Response Length: " + response.size, e) + LOG.error( + """ + Response was: + ${bytesToHex(response)} + """.trimIndent() + ) } - } catch (e: InvalidProtocolBufferException) { - LOG.error("Response Length: " + response.size, e) - LOG.error( - """ - Response was: - ${bytesToHex(response)} - """.trimIndent() - ) + return result } - return result - } - - override fun wipe(containerID: String) { - sendCommand(ControllerToDaemon.Command.CONTAINER_WIPE) - } - override fun startContainer(containerID: String, key: String?) { - LOG.debug("Starting start container with ID {}", containerID) - val ctdmsg = ControllerToDaemon.newBuilder() - ctdmsg.command = ControllerToDaemon.Command.CONTAINER_START - ctdmsg.addContainerUuids(containerID) - val cspbld = ContainerStartParams.newBuilder() - if (key != null) { - cspbld.key = key + override fun wipe(containerID: String) { + sendCommand(ControllerToDaemon.Command.CONTAINER_WIPE) } - cspbld.noSwitch = true - ctdmsg.containerStartParams = cspbld.build() - try { - val dtc = parseResponse(sendProtobufAndWaitForResponse(ctdmsg.build())) - if (DaemonToController.Response.CONTAINER_START_OK != dtc.response) { - LOG.error("Container start failed, response was {}", dtc.response) + + override fun startContainer( + containerID: String, + key: String? + ) { + LOG.debug("Starting start container with ID {}", containerID) + val ctdmsg = ControllerToDaemon.newBuilder() + ctdmsg.command = ControllerToDaemon.Command.CONTAINER_START + ctdmsg.addContainerUuids(containerID) + val cspbld = ContainerStartParams.newBuilder() + if (key != null) { + cspbld.key = key + } + cspbld.noSwitch = true + ctdmsg.containerStartParams = cspbld.build() + try { + val dtc = parseResponse(sendProtobufAndWaitForResponse(ctdmsg.build())) + if (DaemonToController.Response.CONTAINER_START_OK != dtc.response) { + LOG.error("Container start failed, response was {}", dtc.response) + } + LOG.error("Container start ok, response was {}", dtc.response) + } catch (e: InvalidProtocolBufferException) { + LOG.error("Protobuf error", e) } - LOG.error("Container start ok, response was {}", dtc.response) - } catch (e: InvalidProtocolBufferException) { - LOG.error("Protobuf error", e) } - } - override fun stopContainer(containerID: String) { - LOG.debug("Starting stop container with ID {}", containerID) - val ctdmsg = ControllerToDaemon.newBuilder() - ctdmsg.command = ControllerToDaemon.Command.CONTAINER_STOP - ctdmsg.addContainerUuids(containerID) - sendProtobuf(ctdmsg.build()) - } + override fun stopContainer(containerID: String) { + LOG.debug("Starting stop container with ID {}", containerID) + val ctdmsg = ControllerToDaemon.newBuilder() + ctdmsg.command = ControllerToDaemon.Command.CONTAINER_STOP + ctdmsg.addContainerUuids(containerID) + sendProtobuf(ctdmsg.build()) + } - override fun restartContainer(containerID: String) { - sendCommand(ControllerToDaemon.Command.CONTAINER_STOP) - sendCommand(ControllerToDaemon.Command.CONTAINER_START) - } + override fun restartContainer(containerID: String) { + sendCommand(ControllerToDaemon.Command.CONTAINER_STOP) + sendCommand(ControllerToDaemon.Command.CONTAINER_START) + } - override fun pullImage(app: ApplicationContainer): String? { - return null - } + override fun pullImage(app: ApplicationContainer): String? { + return null + } - override fun inspectContainer(containerID: String): String? { - // TODO Auto-generated method stub - return null - } + override fun inspectContainer(containerID: String): String? { + // TODO Auto-generated method stub + return null + } - override fun getMetadata(containerID: String): String? { - // TODO Auto-generated method stub - return null - } + override fun getMetadata(containerID: String): String? { + // TODO Auto-generated method stub + return null + } + + override fun setIpRule( + containerID: String, + direction: Direction, + srcPort: Int, + dstPort: Int, + srcDstRange: String, + protocol: Protocol, + decision: Decision + ) { + // TODO Auto-generated method stub + } - override fun setIpRule( - containerID: String, - direction: Direction, - srcPort: Int, - dstPort: Int, - srcDstRange: String, - protocol: Protocol, - decision: Decision - ) { // TODO Auto-generated method stub - } + override val version: String + get() = "1.0" - // TODO Auto-generated method stub - override val version: String - get() = "1.0" + /** + * Used for sending control commands to a device. + * + * @param command The command to be sent. + */ + private fun sendCommand(command: ControllerToDaemon.Command) { + val ctdmsg = ControllerToDaemon.newBuilder() + ctdmsg.command = command + sendProtobuf(ctdmsg.build()) + } - /** - * Used for sending control commands to a device. - * - * @param command The command to be sent. - */ - private fun sendCommand(command: ControllerToDaemon.Command) { - val ctdmsg = ControllerToDaemon.newBuilder() - ctdmsg.command = command - sendProtobuf(ctdmsg.build()) - } + /** + * More flexible than the sendCommand method. Required when other parameters need to be set than + * the Command + * + * @param ctd the control command + */ + private fun sendProtobuf(ctd: ControllerToDaemon) { + LOG.debug("sending message {}", ctd.command) + LOG.debug(ctd.toString()) + val encodedMessage = ctd.toByteArray() + try { + socketThread.sendWithHeader(encodedMessage, responseHandler) + } catch (e: IOException) { + LOG.error(e.message, e) + } catch (e: InterruptedException) { + LOG.error(e.message, e) + } + } - /** - * More flexible than the sendCommand method. Required when other parameters need to be set than - * the Command - * - * @param ctd the control command - */ - private fun sendProtobuf(ctd: ControllerToDaemon) { - LOG.debug("sending message {}", ctd.command) - LOG.debug(ctd.toString()) - val encodedMessage = ctd.toByteArray() - try { - socketThread.sendWithHeader(encodedMessage, responseHandler) - } catch (e: IOException) { - LOG.error(e.message, e) - } catch (e: InterruptedException) { - LOG.error(e.message, e) + /** + * Used for sending control commands to a device. + * + * @param command The command to be sent. + * @return Success state. + */ + private fun sendCommandAndWaitForResponse(command: ControllerToDaemon.Command): ByteArray { + sendCommand(command) + return responseHandler.waitForResponse() } - } - /** - * Used for sending control commands to a device. - * - * @param command The command to be sent. - * @return Success state. - */ - private fun sendCommandAndWaitForResponse(command: ControllerToDaemon.Command): ByteArray { - sendCommand(command) - return responseHandler.waitForResponse() - } + /** + * Used for sending control commands to a device. + * + * @param ctd The command to be sent. + * @return Success state. + */ + private fun sendProtobufAndWaitForResponse(ctd: ControllerToDaemon): ByteArray { + sendProtobuf(ctd) + return responseHandler.waitForResponse() + } - /** - * Used for sending control commands to a device. - * - * @param ctd The command to be sent. - * @return Success state. - */ - private fun sendProtobufAndWaitForResponse(ctd: ControllerToDaemon): ByteArray { - sendProtobuf(ctd) - return responseHandler.waitForResponse() - } + @Throws(InvalidProtocolBufferException::class) + private fun parseResponse(response: ByteArray?): DaemonToController { + return DaemonToController.parseFrom(response) + } - @Throws(InvalidProtocolBufferException::class) - private fun parseResponse(response: ByteArray?): DaemonToController { - return DaemonToController.parseFrom(response) - } + companion object { + private val LOG = LoggerFactory.getLogger(TrustXCM::class.java) + private const val SOCKET = "/run/socket/cml-control" + val isSupported: Boolean + get() { + val path = Paths.get(SOCKET) + var exists = false + if (Files.exists(path)) { + exists = true + } + return exists + } + private val hexArray = "0123456789ABCDEF".toCharArray() - companion object { - private val LOG = LoggerFactory.getLogger(TrustXCM::class.java) - private const val SOCKET = "/run/socket/cml-control" - val isSupported: Boolean - get() { - val path = Paths.get(SOCKET) - var exists = false - if (Files.exists(path)) { - exists = true + fun bytesToHex(bytes: ByteArray): String { + val hexChars = CharArray(bytes.size * 2) + for (j in bytes.indices) { + val v = bytes[j].toInt() and 0xFF + hexChars[j * 2] = hexArray[v ushr 4] + hexChars[j * 2 + 1] = hexArray[v and 0x0F] } - return exists - } - private val hexArray = "0123456789ABCDEF".toCharArray() - fun bytesToHex(bytes: ByteArray): String { - val hexChars = CharArray(bytes.size * 2) - for (j in bytes.indices) { - val v = bytes[j].toInt() and 0xFF - hexChars[j * 2] = hexArray[v ushr 4] - hexChars[j * 2 + 1] = hexArray[v and 0x0F] + return String(hexChars) } - return String(hexChars) - } - private fun formatDuration(duration: Duration): String { - val seconds = duration.seconds - val absSeconds = abs(seconds) - val days = dayString(absSeconds) - val hoursAndMinutes = String.format("%d:%02d", absSeconds / 3600 / 24, absSeconds % 3600 / 60) - return days + hoursAndMinutes - } + private fun formatDuration(duration: Duration): String { + val seconds = duration.seconds + val absSeconds = abs(seconds) + val days = dayString(absSeconds) + val hoursAndMinutes = String.format("%d:%02d", absSeconds / 3600 / 24, absSeconds % 3600 / 60) + return days + hoursAndMinutes + } - private fun dayString(seconds: Long): String { - if (seconds != 0L) { - val hours = seconds / 3600 - return when { - hours < 24 -> "" - hours < 48 -> "1 day " - else -> { - String.format("%d days ", hours / 24) + private fun dayString(seconds: Long): String { + if (seconds != 0L) { + val hours = seconds / 3600 + return when { + hours < 24 -> "" + hours < 48 -> "1 day " + else -> { + String.format("%d days ", hours / 24) + } } } + return "" } - return "" } - } - init { - Thread(socketThread).apply { - isDaemon = true - start() + init { + Thread(socketThread).apply { + isDaemon = true + start() + } } } -} diff --git a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/comm/unixsocket/TrustmeUnixSocketResponseHandler.kt b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/comm/unixsocket/TrustmeUnixSocketResponseHandler.kt index 653791cd8..4c9c1141e 100644 --- a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/comm/unixsocket/TrustmeUnixSocketResponseHandler.kt +++ b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/comm/unixsocket/TrustmeUnixSocketResponseHandler.kt @@ -26,8 +26,6 @@ import kotlin.concurrent.withLock class TrustmeUnixSocketResponseHandler { private val lock = ReentrantLock() private val condition = lock.newCondition() - - private val LOG = LoggerFactory.getLogger(TrustmeUnixSocketResponseHandler::class.java) private var rsp: ByteArray? = null fun handleResponse(rsp: ByteArray): Boolean { @@ -53,4 +51,8 @@ class TrustmeUnixSocketResponseHandler { return result } } + + companion object { + private val LOG = LoggerFactory.getLogger(TrustmeUnixSocketResponseHandler::class.java) + } } diff --git a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/comm/unixsocket/TrustmeUnixSocketThread.kt b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/comm/unixsocket/TrustmeUnixSocketThread.kt index 68e93fcf3..3355df66b 100644 --- a/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/comm/unixsocket/TrustmeUnixSocketThread.kt +++ b/ids-container-manager/src/main/kotlin/de/fhg/aisec/ids/comm/unixsocket/TrustmeUnixSocketThread.kt @@ -50,13 +50,20 @@ class TrustmeUnixSocketThread(private val socket: String) : Runnable { // send a protobuf message to the unix socket @Throws(IOException::class, InterruptedException::class) - fun sendWithHeader(data: ByteArray, handler: TrustmeUnixSocketResponseHandler?) { + fun sendWithHeader( + data: ByteArray, + handler: TrustmeUnixSocketResponseHandler? + ) { send(data, handler, true) } // send some data to the unix socket @Throws(IOException::class, InterruptedException::class) - fun send(data: ByteArray, handler: TrustmeUnixSocketResponseHandler?, withLengthHeader: Boolean) { + fun send( + data: ByteArray, + handler: TrustmeUnixSocketResponseHandler?, + withLengthHeader: Boolean + ) { LOG.debug("writing protobuf to socket") var result = data // if message has to be sent with length header @@ -175,32 +182,39 @@ class TrustmeUnixSocketThread(private val socket: String) : Runnable { } @Throws(IOException::class) - private fun readMessageLength(key: SelectionKey, channel: UnixSocketChannel): Int { + private fun readMessageLength( + key: SelectionKey, + channel: UnixSocketChannel + ): Int { // Clear out our read buffer so it's ready for new data lengthBuffer.clear() // Attempt to read off the channel - val length: Int = try { - val numRead = channel.read(lengthBuffer) - if (numRead == 4) { - BigInteger(lengthBuffer.array()).toInt() - } else { - -1 + val length: Int = + try { + val numRead = channel.read(lengthBuffer) + if (numRead == 4) { + BigInteger(lengthBuffer.array()).toInt() + } else { + -1 + } + } catch (e: IOException) { + // The remote forcibly closed the connection, cancel the selection key and close + // the channel. + LOG.debug("error while reading message length from socket", e) + key.cancel() + channel.close() + return -1 } - } catch (e: IOException) { - // The remote forcibly closed the connection, cancel the selection key and close - // the channel. - LOG.debug("error while reading message length from socket", e) - key.cancel() - channel.close() - return -1 - } LOG.debug("read message from UNIX socket with length $length") return length } @Throws(IOException::class) - private fun handleResponse(socketChannel: UnixSocketChannel, data: ByteArray) { + private fun handleResponse( + socketChannel: UnixSocketChannel, + data: ByteArray + ) { // Make a correctly sized copy of the data before handing it // to the client val rspData = ByteArray(data.size) diff --git a/ids-container-manager/src/test/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXMock.kt b/ids-container-manager/src/test/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXMock.kt index a800b3a1e..c01a83623 100644 --- a/ids-container-manager/src/test/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXMock.kt +++ b/ids-container-manager/src/test/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXMock.kt @@ -48,7 +48,10 @@ class TrustXMock(private var socket: String, private var handler: TrustXMockHand private val pendingData: MutableMap> = HashMap() // send a protobuf message to the unix socket - fun send(socket: UnixSocketChannel?, data: ByteArray?) { + fun send( + socket: UnixSocketChannel?, + data: ByteArray? + ) { synchronized(pendingChanges) { pendingChanges.add( ChangeRequest(socket!!, ChangeRequest.CHANGEOPS, SelectionKey.OP_WRITE) @@ -128,14 +131,15 @@ class TrustXMock(private var socket: String, private var handler: TrustXMockHand readBuffer.clear() // Attempt to read off the channel - val numRead: Int = try { - channel.read(readBuffer) - } catch (e: IOException) { - // The remote forcibly closed the connection, cancel the selection key and close the channel. - key.cancel() - channel.close() - return - } + val numRead: Int = + try { + channel.read(readBuffer) + } catch (e: IOException) { + // The remote forcibly closed the connection, cancel the selection key and close the channel. + key.cancel() + channel.close() + return + } LOG.debug("bytes read: $numRead") if (numRead == -1) { // Remote entity shut the socket down cleanly. Do the same from our end and cancel the @@ -179,11 +183,12 @@ class TrustXMock(private var socket: String, private var handler: TrustXMockHand socketFile.delete() socketFile.deleteOnExit() val address = UnixSocketAddress(socketFile.absoluteFile) - channel = UnixServerSocketChannel.open().apply { - configureBlocking(false) - socket().bind(address) - register(socketSelector, SelectionKey.OP_ACCEPT) - } + channel = + UnixServerSocketChannel.open().apply { + configureBlocking(false) + socket().bind(address) + register(socketSelector, SelectionKey.OP_ACCEPT) + } return socketSelector } diff --git a/ids-container-manager/src/test/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXMockHandler.kt b/ids-container-manager/src/test/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXMockHandler.kt index 1a669f70d..8f824b11a 100644 --- a/ids-container-manager/src/test/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXMockHandler.kt +++ b/ids-container-manager/src/test/kotlin/de/fhg/aisec/ids/cm/impl/trustx/TrustXMockHandler.kt @@ -49,7 +49,12 @@ class TrustXMockHandler : Runnable { } } - fun handleResponse(server: TrustXMock, socket: UnixSocketChannel, data: ByteArray, count: Int) { + fun handleResponse( + server: TrustXMock, + socket: UnixSocketChannel, + data: ByteArray, + count: Int + ) { val dataCopy = ByteArray(count) System.arraycopy(data, 0, dataCopy, 0, count) lock.withLock { diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/CamelInterceptor.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/CamelInterceptor.kt index 3ef796640..920c7380d 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/CamelInterceptor.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/CamelInterceptor.kt @@ -31,7 +31,6 @@ import org.springframework.stereotype.Component @Component("idsCamelInterceptor") class CamelInterceptor : InterceptStrategy { - @Autowired(required = false) private var pdp: PDP? = null diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/ContractManagerImpl.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/ContractManagerImpl.kt index 0c87c46f9..21a096a0f 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/ContractManagerImpl.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/ContractManagerImpl.kt @@ -40,13 +40,13 @@ import java.net.URI @Component("contractManager") class ContractManagerImpl : ContractManager { - @Autowired private lateinit var settings: Settings override fun makeContract(contractProperties: Map): ContractOffer { - val requestedArtifact = contractProperties[ContractConstants.ARTIFACT_URI_PROPERTY] as URI? - ?: throw RuntimeException("No artifact URI provided in contractProperties") + val requestedArtifact = + contractProperties[ContractConstants.ARTIFACT_URI_PROPERTY] as URI? + ?: throw RuntimeException("No artifact URI provided in contractProperties") val notAfterDateTime = contractProperties[ContractConstants.UC_NOT_AFTER_DATETIME] as String? val notBeforeDateTime = contractProperties[ContractConstants.UC_NOT_BEFORE_DATETIME] as String? @@ -59,29 +59,31 @@ class ContractManagerImpl : ContractManager { // Add not after (BEFORE) usage constraint notAfterDateTime.let { dateTime -> - timeConstraints += ConstraintBuilder() - ._leftOperand_(LeftOperand.POLICY_EVALUATION_TIME) - ._operator_(BinaryOperator.BEFORE) - ._rightOperand_( - TypedLiteral( - ContractUtils.DATATYPE_FACTORY.newXMLGregorianCalendar(dateTime.toString()).toString(), - ContractUtils.TYPE_DATETIMESTAMP + timeConstraints += + ConstraintBuilder() + ._leftOperand_(LeftOperand.POLICY_EVALUATION_TIME) + ._operator_(BinaryOperator.BEFORE) + ._rightOperand_( + TypedLiteral( + ContractUtils.DATATYPE_FACTORY.newXMLGregorianCalendar(dateTime.toString()).toString(), + ContractUtils.TYPE_DATETIMESTAMP + ) ) - ) - .build() + .build() } // Add not before (AFTER) usage constraint notBeforeDateTime?.let { dateTime -> - timeConstraints += ConstraintBuilder() - ._leftOperand_(LeftOperand.POLICY_EVALUATION_TIME) - ._operator_(BinaryOperator.AFTER) - ._rightOperand_( - TypedLiteral( - ContractUtils.DATATYPE_FACTORY.newXMLGregorianCalendar(dateTime).toString(), - ContractUtils.TYPE_DATETIMESTAMP + timeConstraints += + ConstraintBuilder() + ._leftOperand_(LeftOperand.POLICY_EVALUATION_TIME) + ._operator_(BinaryOperator.AFTER) + ._rightOperand_( + TypedLiteral( + ContractUtils.DATATYPE_FACTORY.newXMLGregorianCalendar(dateTime).toString(), + ContractUtils.TYPE_DATETIMESTAMP + ) ) - ) - .build() + .build() } return ContractOfferBuilder() ._contractDate_(contractDate) @@ -122,9 +124,10 @@ class ContractManagerImpl : ContractManager { .build() } - override fun storeContract(key: String, contract: ContractOffer) = - settings.storeContract(key, SERIALIZER.serialize(contract)) + override fun storeContract( + key: String, + contract: ContractOffer + ) = settings.storeContract(key, SERIALIZER.serialize(contract)) - override fun loadContract(key: String) = - settings.loadContract(key)?.let { SERIALIZER.deserialize(it, ContractOffer::class.java) } + override fun loadContract(key: String) = settings.loadContract(key)?.let { SERIALIZER.deserialize(it, ContractOffer::class.java) } } diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/PolicyDecisionPoint.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/PolicyDecisionPoint.kt index 2dcf32a6a..e630f52ea 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/PolicyDecisionPoint.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/PolicyDecisionPoint.kt @@ -57,7 +57,6 @@ import java.util.concurrent.TimeUnit */ @Component("idsDataflowControl") class PolicyDecisionPoint : PDP, PAP { - // Convenience val for this thread's LuconEngine instance private val engine: LuconEngine get() = threadEngine.get() @@ -77,7 +76,10 @@ class PolicyDecisionPoint : PDP, PAP { * @param target The target node of the transformation * @param labels The exchange properties */ - private fun createDecisionQuery(target: ServiceNode, labels: Set): String { + private fun createDecisionQuery( + target: ServiceNode, + labels: Set + ): String { val sb = StringBuilder() sb.append("rule(X), has_target(X, T), ") sb.append("has_endpoint(T, EP), ") @@ -195,7 +197,8 @@ class PolicyDecisionPoint : PDP, PAP { } else { throw RuntimeException("\"Removes\" is not a prolog list!") } - } catch (ignored: NoSolutionException) {} + } catch (ignored: NoSolutionException) { + } } } LOG.debug("Transformation: {}", result) diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/PolicyEnforcementPoint.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/PolicyEnforcementPoint.kt index 4b03f81f2..0f4d776a9 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/PolicyEnforcementPoint.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/PolicyEnforcementPoint.kt @@ -39,144 +39,147 @@ import org.slf4j.LoggerFactory import java.net.URI class PolicyEnforcementPoint -internal constructor(private val destinationNode: NamedNode, target: Processor) : + internal constructor(private val destinationNode: NamedNode, target: Processor) : DelegateAsyncProcessor(target) { - /** - * The method performs flow control and calls Exchange.setException() when necessary It iterates - * through nodes in CamelRoute (, , , , , ...) and launches node - * specific usage enforcement actions. - * - * At node : protect exchange msg's body if usage constraint is given At node : - * unprotect exchange msg's body if usage constraing it fulfilled - * - * @param exchange The exchange object to check - * @return Whether target.process() is to be called for this exchange object - */ - private fun processFlowControl(exchange: Exchange?): Boolean { - if (exchange == null) { - if (LOG.isWarnEnabled) { - LOG.warn("Cannot check data flow policy. Exchange object is null.") + /** + * The method performs flow control and calls Exchange.setException() when necessary It iterates + * through nodes in CamelRoute (, , , , , ...) and launches node + * specific usage enforcement actions. + * + * At node : protect exchange msg's body if usage constraint is given At node : + * unprotect exchange msg's body if usage constraing it fulfilled + * + * @param exchange The exchange object to check + * @return Whether target.process() is to be called for this exchange object + */ + private fun processFlowControl(exchange: Exchange?): Boolean { + if (exchange == null) { + if (LOG.isWarnEnabled) { + LOG.warn("Cannot check data flow policy. Exchange object is null.") + } + return false } - return false - } - // Strict policy: If PDP or Usage Control interface are not available, block every checked - // data flow - val pdp = CamelInterceptor.pdp ?: throw Exception("PDP is not available") - val ucInterface = - CamelInterceptor.usageControlInterface - ?: throw Exception("Usage Control Interface is not available") + // Strict policy: If PDP or Usage Control interface are not available, block every checked + // data flow + val pdp = CamelInterceptor.pdp ?: throw Exception("PDP is not available") + val ucInterface = + CamelInterceptor.usageControlInterface + ?: throw Exception("Usage Control Interface is not available") - // Save per exchange object the source node's content () + // Same entry in Hashmap per CamelRoute, change of exchange properties do not create new + // entry + val sourceNode: NamedNode = + lastDestinations[exchange] + ?: run { + // If there is no previously saved node for this exchange, use the parent + // to find the input + // (first statement) of the processed route. + var routeNode = destinationNode.parent + while (routeNode !is RouteDefinition) { + routeNode = routeNode.parent + } + routeNode.input } - routeNode.input - } - // Save current destination node of CamelRoute - lastDestinations[exchange] = destinationNode - val source = sourceNode.toString() - val destination = destinationNode.toString() - if (LOG.isTraceEnabled) { - LOG.trace("{} -> {}", source, destination) - } + // Save current destination node of CamelRoute + lastDestinations[exchange] = destinationNode + val source = sourceNode.toString() + val destination = destinationNode.toString() + if (LOG.isTraceEnabled) { + LOG.trace("{} -> {}", source, destination) + } - // Only take action if previous node was a node (input) - // or if current node or previous node is or has been a node (output and probably also input) - if (sourceNode is EndpointRequiredDefinition || destinationNode is ToDefinition) { - // If there is no known ContractAgreement for this Exchange, nothing to do here. - ucInterface.getExchangeContract(exchange)?.let { contract -> - val luconContract = LuconContract.getContract(contract) - // Check whether body protection has not yet been performed. - if (!ucInterface.isProtected(exchange)) { - ucInterface.protectBody(exchange, contract.id) - LOG.debug("UC: Protect Exchange body with UC contract {}", contract.id) - } - // Check whether we are about to send data via a node - if (destinationNode is ToDefinition) { - val endpointUri = URI.create(destinationNode.endpointUri) - val enforcementContext = EnforcementContext(endpointUri, LOG) - try { - luconContract.enforce(enforcementContext) - // Restore exchange body - ucInterface.unprotectBody(exchange) - LOG.debug("UC: Contract permits data flow, Exchange body has been restored.") - } catch (le: LuconException) { - LOG.warn(le.message) + // Only take action if previous node was a node (input) + // or if current node or previous node is or has been a node (output and probably also input) + if (sourceNode is EndpointRequiredDefinition || destinationNode is ToDefinition) { + // If there is no known ContractAgreement for this Exchange, nothing to do here. + ucInterface.getExchangeContract(exchange)?.let { contract -> + val luconContract = LuconContract.getContract(contract) + // Check whether body protection has not yet been performed. + if (!ucInterface.isProtected(exchange)) { + ucInterface.protectBody(exchange, contract.id) + LOG.debug("UC: Protect Exchange body with UC contract {}", contract.id) + } + // Check whether we are about to send data via a node + if (destinationNode is ToDefinition) { + val endpointUri = URI.create(destinationNode.endpointUri) + val enforcementContext = EnforcementContext(endpointUri, LOG) + try { + luconContract.enforce(enforcementContext) + // Restore exchange body + ucInterface.unprotectBody(exchange) + LOG.debug("UC: Contract permits data flow, Exchange body has been restored.") + } catch (le: LuconException) { + LOG.warn(le.message) + } } } } - } - val sourceServiceNode = ServiceNode(source) - val destinationServiceNode = ServiceNode(destination) + val sourceServiceNode = ServiceNode(source) + val destinationServiceNode = ServiceNode(destination) - // Call PDP to transform labels and decide whether to forward the Exchange - applyLabelTransformation(pdp.requestTranformations(sourceServiceNode), exchange) - val labels = exchangeLabels.computeIfAbsent(exchange) { HashSet() } - val decision = - pdp.requestDecision( - DecisionRequest(sourceServiceNode, destinationServiceNode, labels, null) - ) - return when (decision.decision) { - PolicyDecision.Decision.ALLOW -> true - PolicyDecision.Decision.DENY -> { - if (LOG.isWarnEnabled) { - LOG.warn( - "Exchange explicitly blocked (DENY) by data flow policy. " + - "Source: {}, Target: {}", - sourceServiceNode, - destinationServiceNode - ) + // Call PDP to transform labels and decide whether to forward the Exchange + applyLabelTransformation(pdp.requestTranformations(sourceServiceNode), exchange) + val labels = exchangeLabels.computeIfAbsent(exchange) { HashSet() } + val decision = + pdp.requestDecision( + DecisionRequest(sourceServiceNode, destinationServiceNode, labels, null) + ) + return when (decision.decision) { + PolicyDecision.Decision.ALLOW -> true + PolicyDecision.Decision.DENY -> { + if (LOG.isWarnEnabled) { + LOG.warn( + "Exchange explicitly blocked (DENY) by data flow policy. " + + "Source: {}, Target: {}", + sourceServiceNode, + destinationServiceNode + ) + } + exchange.setException(Exception("Exchange blocked by data flow policy")) + false } - exchange.setException(Exception("Exchange blocked by data flow policy")) - false } } - } - /** - * Removes and adds labels to an exchange object. - * - * @param requestTransformations The request transformations (label changes) to be performed - * @param exchange Exchange processed - */ - private fun applyLabelTransformation( - requestTransformations: TransformationDecision, - exchange: Exchange - ) { - val labels = exchangeLabels.computeIfAbsent(exchange) { HashSet() } + /** + * Removes and adds labels to an exchange object. + * + * @param requestTransformations The request transformations (label changes) to be performed + * @param exchange Exchange processed + */ + private fun applyLabelTransformation( + requestTransformations: TransformationDecision, + exchange: Exchange + ) { + val labels = exchangeLabels.computeIfAbsent(exchange) { HashSet() } - // Remove labels from exchange - labels.removeAll(requestTransformations.labelsToRemove) + // Remove labels from exchange + labels.removeAll(requestTransformations.labelsToRemove) - // Add labels to exchange - labels.addAll(requestTransformations.labelsToAdd) - } + // Add labels to exchange + labels.addAll(requestTransformations.labelsToAdd) + } - @Throws(Exception::class) - override fun process(exchange: Exchange, asyncCallback: AsyncCallback): Boolean { - if (processFlowControl(exchange)) { - return super.process(exchange, asyncCallback) - } else { - throw Exception("Exchange blocked by data flow policy") + @Throws(Exception::class) + override fun process( + exchange: Exchange, + asyncCallback: AsyncCallback + ): Boolean { + if (processFlowControl(exchange)) { + return super.process(exchange, asyncCallback) + } else { + throw Exception("Exchange blocked by data flow policy") + } } - } - companion object { - private val LOG = LoggerFactory.getLogger(PolicyEnforcementPoint::class.java) - private val lastDestinations: MutableMap = - MapMaker().weakKeys().makeMap() - private val exchangeLabels: MutableMap> = - MapMaker().weakKeys().makeMap() + companion object { + private val LOG = LoggerFactory.getLogger(PolicyEnforcementPoint::class.java) + private val lastDestinations: MutableMap = + MapMaker().weakKeys().makeMap() + private val exchangeLabels: MutableMap> = + MapMaker().weakKeys().makeMap() + } } -} diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/CounterExampleImpl.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/CounterExampleImpl.kt index 3abe5f600..8ed47292b 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/CounterExampleImpl.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/CounterExampleImpl.kt @@ -25,7 +25,6 @@ import de.fhg.aisec.ids.api.router.CounterExample import java.util.LinkedList class CounterExampleImpl(term: Term) : CounterExample() { - init { val traceIterator = (term as Struct).listIterator() val steps = LinkedList() @@ -73,7 +72,10 @@ class CounterExampleImpl(term: Term) : CounterExample() { } } - private fun appendCSList(sb: StringBuilder?, l: Term?) { + private fun appendCSList( + sb: StringBuilder?, + l: Term? + ) { if (sb == null || l == null) { return } diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/LuconEngine.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/LuconEngine.kt index 252771efc..e92215566 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/LuconEngine.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/LuconEngine.kt @@ -134,7 +134,10 @@ class LuconEngine } @Throws(MalformedGoalException::class) - fun query(query: String?, findAll: Boolean): List { + fun query( + query: String?, + findAll: Boolean + ): List { if (LOG.isTraceEnabled) { LOG.trace("Running Prolog query: " + query!!) } @@ -151,7 +154,11 @@ class LuconEngine return result } - private fun query(engine: Prolog, query: String?, findAll: Boolean): List { + private fun query( + engine: Prolog, + query: String?, + findAll: Boolean + ): List { val result = ArrayList() if (query == null) { return result @@ -178,7 +185,10 @@ class LuconEngine * @return A list of counterexamples which violate the rule or empty, if no route violates the * policy. */ - fun proofInvalidRoute(id: String, routePl: String): RouteVerificationProof { + fun proofInvalidRoute( + id: String, + routePl: String + ): RouteVerificationProof { // The proof object we will return val proof = RouteVerificationProof(id) diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/LuconLibrary.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/LuconLibrary.kt index 8be87f1f2..a2befc32b 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/LuconLibrary.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/LuconLibrary.kt @@ -50,135 +50,138 @@ class LuconLibrary : Library() { override fun getTheory(): String = """ -set_of(In, Out) :- % get a pairwise different, sorted set from a list - quicksort(In, '@<', Sorted), - no_duplicates(Sorted, Out). - -get_labels(Out) :- % collect and return asserted labels - once(setof(L, label(L), Out) ; Out = []). - -assert_labels(L, A) :- assert_labels(L, A, []). -assert_labels([], A, A). -assert_labels([L|Tail], Ar, A) :- label(L), assert_labels(Tail, Ar, A), !. -assert_labels([L|Tail], Ar, A) :- assert(label(L)), assert_labels(Tail, Ar, [L|A]). - -retract_labels(L, R) :- retract_labels(L, R, []). -retract_labels([], R, R). -retract_labels([L|Tail], Rr, R) :- retract(label(L)), retract_labels(Tail, Rr, [L|R]), !. -retract_labels([_|Tail], Rr, R) :- retract_labels(Tail, Rr, R). - -all_ground([]). -all_ground([Head|Tail]) :- ground(Head), all_ground(Tail). - -cache_put_all_unsafe(_, []). -cache_put_all_unsafe(KL, [V|T]) :- cache_put_unsafe(KL, V), cache_put_all_unsafe(KL, T). -cache_put_unsafe(KL, V) :- - %print(["CACHE PUT: "|[KL, V]]), nl, - assertz(cache_entry(KL, V)). - -cache_put_all(KL, VL) :- all_ground(KL), cache_put_all_unsafe(KL, VL). -cache_put(KL, V) :- cache_put_check(KL, V); true. -cache_put_check(KL, V) :- all_ground(KL), cache_put_unsafe(KL, V). - -cache_get(KL, V) :- - cache_entry(KL, V). - %-> print(["CACHE HIT: ", KL, V]), nl - %; print(["CACHE MISS: ", KL]), nl, fail. - -cache_clear(KL) :- retractall(cache_entry(KL, _)). - -action_service(Action, S) :- % Finds services S matching endpoints of N [ O(|Ep_S|) ] - has_endpoint(S, Regex), % a service S exists such that [ O(|Ep_S|) ] - regex_match(Regex, Action). % the action of A matches the endpoint of S [ assume O(1) ] - -collect_creates_labels([], []). -collect_creates_labels([S|SCTail], ACout) :- - collect_creates_labels(SCTail, ACnew), - findall(A, creates_label(S, A), AC), - once(bound(ACnew); ACnew = []), - append(AC, ACnew, ACout). - -collect_removes_labels([], []). -collect_removes_labels([S|SCTail], RCout) :- - collect_removes_labels(SCTail, RCnew), - findall(R, removes_label(S, R), RC), - once(bound(RCnew); RCnew = []), - append(RC, RCnew, RCout). - -update_labels(Act, Out, Aout, Rout) :- % Updates labels according to spec. of service S - once(setof(S, action_service(Act, S), SC); SC = []), % collect all relevant services - collect_creates_labels(SC, ACraw), set_of(ACraw, AC), assert_labels(AC, Aout), % assert new labels added by S - collect_removes_labels(SC, RCraw), set_of(RCraw, RC), retract_labels(RC, Rout), % retract labels removed by S - print([Act, "=>", SC, "added:", Aout, "removed:", Rout]),nl, - get_labels(Out). % collect and return asserted labels - -conflicting_rules(Act, Ri, Req, DC, PR) :- % Find conflicting rules [ O(|Ep_S| x |S -- R|) ] - action_service(Act, S2), % a service S2 [ O(|Ep_S|) ] - rule(R2), Ri \= R2, receives_label(R2), % with another VALID rule R2 - has_target(R2, S2), % that is targeting S2 [ O(|S -- R|) ] - has_decision(R2, D2), D2 \= Req, % which enforces a different decision, [ O(1) ] - rule_priority(R2, PR2), % and has priority PR2 [ O(1) ] - G =.. [DC, PR2, PR], call(G). % such that 'DC'(PR, PR2) is fulfilled [ O(1) ] - -dominant_rules(Act, Req, DC, S, R) :- % Find the dominant rule R for action Act (from cache) - get_labels(LC), % Collect currently asserted labels - cache_get([dr, Act, Req, DC, LC], V), % CACHE GET entry - list(V), V = [S, R]. % unpack result - -dominant_rules(Act, Req, DC, S, R) :- % Find the dominant rule R for action Act [ O(|Ep_S| x |S -- R|) ] - get_labels(LC), % Collect currently asserted labels - \+(cache_get([dr, Act, Req, DC, LC], _)), % CACHE GET entry - (setof(DomRule, ( - action_service(Act, Si), % Action Act is matched by a service Si [ O(|Ep_S|) ] - rule(Ri), receives_label(Ri), % There is a VALID rule Ri - has_target(Ri, Si), % targeting by service Si [ O(|S -- R|) ] - has_decision(Ri, Req), % with a decision that unifies with Require [ O(1) ] - rule_priority(Ri, PR), % that has priority PR, then [ O(1) ] - \+(conflicting_rules(Act, Ri, Req, DC, PR)), % there MUST NOT exist conflicting rules [ O(|Ep_S| x |S -- R|) ] - DomRule = [Si, Ri] % compose the result - ), RL) - -> cache_put_all([dr, Act, Req, DC, LC], RL) % IF successful, CACHE PUT ALL results - ; cache_put([dr, Act, Req, DC, LC], none) % ELSE CACHE PUT 'none' - ), !, % don't backtrack into the caching logic - dominant_rules(Act, Req, DC, S, R). % delegate to cache handler - -dominant_drop_rules(Act, S, R) :- dominant_rules(Act, drop, '>', S, R). -dominant_allow_rules(Act, S, R) :- dominant_rules(Act, allow, '>=', S, R). - -% Query for a path between two nodes and print the labels along the possible paths like so: -% -% path(stmt_1, stmt_5, Trace). -% -path(A,B,T) :- % Two nodes are connected if we can walk from A to B, - trace_walk(A, B, [[A, []]], T). % starting with empty label list - -trace_walk(A, B, Log, T) :- % We have walked from A to B and verify [ O(|Ep_S| x |S -- R|) ] - A = B, % A is the desired destination with [ O(1) ] - has_action(A, Act), % an action Act and there is [ O(1) ] - dominant_drop_rules(Act, S, R), % a dominant drop rule R and service S for Act [ O(|Ep_S| x |S -- R|) ] - receives_label(R), % R receives a set of labels with [ assume O(1) ] - get_labels(LC), % get asserted labels [ O(L_a), assume O(1) ] - T = [[S, LC, R]|Log]. % [unify the recursion result with Out] [ O(1) ] - %print("finished (END): "), print(A), nl. - -trace_walk(A, B, Log, T) :- % We can walk from A to B if [ O(|Ep_S| x |S -- R|) ] - succ(A, X), % A is connected to X and there is [ O(|succ(A, _)|), assume O(1) ] - has_action(A, Act), % an action Action and there is [ O(1) ] - dominant_allow_rules(Act, _, _), % a dominant allow rule and service S for Act [ O(|Ep_S| x |S -- R|) ] - update_labels(Act, LN, Aout, Rout), % [update the labels for the next step] [ O(|L|), assume O(1) ], - %print([Aout, Rout]), nl, - %print("transition: "), print([A, X, S, LN]), nl, - ( - trace_walk(X, B, [[X, LN]|Log], T) % we can get from X to B [ Recursion! ] - ; true % or otherwise, make sure that the cleanup stuff below gets called! - ), - retract_labels(Aout, _), % retract labels asserted before recursion - assert_labels(Rout, _), % assert labels retracted before recursion - %print("finished: "), print(A), nl, - ground(T). % If T is bound, recursion returned successfully, no result otherwise! + set_of(In, Out) :- % get a pairwise different, sorted set from a list + quicksort(In, '@<', Sorted), + no_duplicates(Sorted, Out). + + get_labels(Out) :- % collect and return asserted labels + once(setof(L, label(L), Out) ; Out = []). + + assert_labels(L, A) :- assert_labels(L, A, []). + assert_labels([], A, A). + assert_labels([L|Tail], Ar, A) :- label(L), assert_labels(Tail, Ar, A), !. + assert_labels([L|Tail], Ar, A) :- assert(label(L)), assert_labels(Tail, Ar, [L|A]). + + retract_labels(L, R) :- retract_labels(L, R, []). + retract_labels([], R, R). + retract_labels([L|Tail], Rr, R) :- retract(label(L)), retract_labels(Tail, Rr, [L|R]), !. + retract_labels([_|Tail], Rr, R) :- retract_labels(Tail, Rr, R). + + all_ground([]). + all_ground([Head|Tail]) :- ground(Head), all_ground(Tail). + + cache_put_all_unsafe(_, []). + cache_put_all_unsafe(KL, [V|T]) :- cache_put_unsafe(KL, V), cache_put_all_unsafe(KL, T). + cache_put_unsafe(KL, V) :- + %print(["CACHE PUT: "|[KL, V]]), nl, + assertz(cache_entry(KL, V)). + + cache_put_all(KL, VL) :- all_ground(KL), cache_put_all_unsafe(KL, VL). + cache_put(KL, V) :- cache_put_check(KL, V); true. + cache_put_check(KL, V) :- all_ground(KL), cache_put_unsafe(KL, V). + + cache_get(KL, V) :- + cache_entry(KL, V). + %-> print(["CACHE HIT: ", KL, V]), nl + %; print(["CACHE MISS: ", KL]), nl, fail. + + cache_clear(KL) :- retractall(cache_entry(KL, _)). + + action_service(Action, S) :- % Finds services S matching endpoints of N [ O(|Ep_S|) ] + has_endpoint(S, Regex), % a service S exists such that [ O(|Ep_S|) ] + regex_match(Regex, Action). % the action of A matches the endpoint of S [ assume O(1) ] + + collect_creates_labels([], []). + collect_creates_labels([S|SCTail], ACout) :- + collect_creates_labels(SCTail, ACnew), + findall(A, creates_label(S, A), AC), + once(bound(ACnew); ACnew = []), + append(AC, ACnew, ACout). + + collect_removes_labels([], []). + collect_removes_labels([S|SCTail], RCout) :- + collect_removes_labels(SCTail, RCnew), + findall(R, removes_label(S, R), RC), + once(bound(RCnew); RCnew = []), + append(RC, RCnew, RCout). + + update_labels(Act, Out, Aout, Rout) :- % Updates labels according to spec. of service S + once(setof(S, action_service(Act, S), SC); SC = []), % collect all relevant services + collect_creates_labels(SC, ACraw), set_of(ACraw, AC), assert_labels(AC, Aout), % assert new labels added by S + collect_removes_labels(SC, RCraw), set_of(RCraw, RC), retract_labels(RC, Rout), % retract labels removed by S + print([Act, "=>", SC, "added:", Aout, "removed:", Rout]),nl, + get_labels(Out). % collect and return asserted labels + + conflicting_rules(Act, Ri, Req, DC, PR) :- % Find conflicting rules [ O(|Ep_S| x |S -- R|) ] + action_service(Act, S2), % a service S2 [ O(|Ep_S|) ] + rule(R2), Ri \= R2, receives_label(R2), % with another VALID rule R2 + has_target(R2, S2), % that is targeting S2 [ O(|S -- R|) ] + has_decision(R2, D2), D2 \= Req, % which enforces a different decision, [ O(1) ] + rule_priority(R2, PR2), % and has priority PR2 [ O(1) ] + G =.. [DC, PR2, PR], call(G). % such that 'DC'(PR, PR2) is fulfilled [ O(1) ] + + dominant_rules(Act, Req, DC, S, R) :- % Find the dominant rule R for action Act (from cache) + get_labels(LC), % Collect currently asserted labels + cache_get([dr, Act, Req, DC, LC], V), % CACHE GET entry + list(V), V = [S, R]. % unpack result + + dominant_rules(Act, Req, DC, S, R) :- % Find the dominant rule R for action Act [ O(|Ep_S| x |S -- R|) ] + get_labels(LC), % Collect currently asserted labels + \+(cache_get([dr, Act, Req, DC, LC], _)), % CACHE GET entry + (setof(DomRule, ( + action_service(Act, Si), % Action Act is matched by a service Si [ O(|Ep_S|) ] + rule(Ri), receives_label(Ri), % There is a VALID rule Ri + has_target(Ri, Si), % targeting by service Si [ O(|S -- R|) ] + has_decision(Ri, Req), % with a decision that unifies with Require [ O(1) ] + rule_priority(Ri, PR), % that has priority PR, then [ O(1) ] + \+(conflicting_rules(Act, Ri, Req, DC, PR)), % there MUST NOT exist conflicting rules [ O(|Ep_S| x |S -- R|) ] + DomRule = [Si, Ri] % compose the result + ), RL) + -> cache_put_all([dr, Act, Req, DC, LC], RL) % IF successful, CACHE PUT ALL results + ; cache_put([dr, Act, Req, DC, LC], none) % ELSE CACHE PUT 'none' + ), !, % don't backtrack into the caching logic + dominant_rules(Act, Req, DC, S, R). % delegate to cache handler + + dominant_drop_rules(Act, S, R) :- dominant_rules(Act, drop, '>', S, R). + dominant_allow_rules(Act, S, R) :- dominant_rules(Act, allow, '>=', S, R). + + % Query for a path between two nodes and print the labels along the possible paths like so: + % + % path(stmt_1, stmt_5, Trace). + % + path(A,B,T) :- % Two nodes are connected if we can walk from A to B, + trace_walk(A, B, [[A, []]], T). % starting with empty label list + + trace_walk(A, B, Log, T) :- % We have walked from A to B and verify [ O(|Ep_S| x |S -- R|) ] + A = B, % A is the desired destination with [ O(1) ] + has_action(A, Act), % an action Act and there is [ O(1) ] + dominant_drop_rules(Act, S, R), % a dominant drop rule R and service S for Act [ O(|Ep_S| x |S -- R|) ] + receives_label(R), % R receives a set of labels with [ assume O(1) ] + get_labels(LC), % get asserted labels [ O(L_a), assume O(1) ] + T = [[S, LC, R]|Log]. % [unify the recursion result with Out] [ O(1) ] + %print("finished (END): "), print(A), nl. + + trace_walk(A, B, Log, T) :- % We can walk from A to B if [ O(|Ep_S| x |S -- R|) ] + succ(A, X), % A is connected to X and there is [ O(|succ(A, _)|), assume O(1) ] + has_action(A, Act), % an action Action and there is [ O(1) ] + dominant_allow_rules(Act, _, _), % a dominant allow rule and service S for Act [ O(|Ep_S| x |S -- R|) ] + update_labels(Act, LN, Aout, Rout), % [update the labels for the next step] [ O(|L|), assume O(1) ], + %print([Aout, Rout]), nl, + %print("transition: "), print([A, X, S, LN]), nl, + ( + trace_walk(X, B, [[X, LN]|Log], T) % we can get from X to B [ Recursion! ] + ; true % or otherwise, make sure that the cleanup stuff below gets called! + ), + retract_labels(Aout, _), % retract labels asserted before recursion + assert_labels(Rout, _), % assert labels retracted before recursion + %print("finished: "), print(A), nl, + ground(T). % If T is bound, recursion returned successfully, no result otherwise! """.trimIndent() - fun regex_match_2(regex: Term, input: Term): Boolean { + fun regex_match_2( + regex: Term, + input: Term + ): Boolean { if (LOG.isTraceEnabled) { LOG.trace("regex_match/2 called with $regex $input") } @@ -205,6 +208,7 @@ trace_walk(A, B, Log, T) :- % We can walk from A to B if [ O(|Ep_S companion object { private val LOG = LoggerFactory.getLogger(LuconLibrary::class.java) + private fun isComplex(term: Term): Boolean { var t = term if (t is Var) { diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/TuPrologHelper.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/TuPrologHelper.kt index 58c8b81c8..bb5e2bca4 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/TuPrologHelper.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/lucon/TuPrologHelper.kt @@ -27,7 +27,6 @@ import java.util.stream.Stream import java.util.stream.StreamSupport object TuPrologHelper { - fun escape(s: String?): String { if (s == null) { return "" diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/DockerImageConstraint.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/DockerImageConstraint.kt index 266e5b153..bbfed8cb4 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/DockerImageConstraint.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/DockerImageConstraint.kt @@ -78,7 +78,10 @@ class DockerImageConstraint(dockerUri: URI) : LuconConstraint { } } - override fun checkEnforcible(context: EnforcementContext, permission: LuconPermission) { + override fun checkEnforcible( + context: EnforcementContext, + permission: LuconPermission + ) { // Check local Docker containers' image hashes and port against Camel route's endpoint CamelInterceptor.containerManager?.let { cm -> val endpointIPs = InetAddress.getAllByName(context.endpointUri.host).toHashSet() @@ -86,9 +89,10 @@ class DockerImageConstraint(dockerUri: URI) : LuconConstraint { // Gather meta of all currently running Docker containers and cache it for other DockerImageConstraint // instances using the same EnforcementContext @Suppress("UNCHECKED_CAST") - val runningContainers = context.enforcementCache.computeIfAbsent("runningDockerContainers") { - cm.list(true) - } as List + val runningContainers = + context.enforcementCache.computeIfAbsent("runningDockerContainers") { + cm.list(true) + } as List val targetContainers = runningContainers.filter { container -> // From running docker containers, get all with the given hash. @@ -97,7 +101,7 @@ class DockerImageConstraint(dockerUri: URI) : LuconConstraint { ( container.imageId?.split(":")?.last() == hash || container.repoDigest?.any { it.split(":").last() == hash } ?: false - ) && + ) && // Additionally, filter relevant containers by their IP address(es) container.ipAddresses.any(endpointIPs::contains) } diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconConstraint.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconConstraint.kt index 441f08eb4..677234769 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconConstraint.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconConstraint.kt @@ -20,6 +20,10 @@ package de.fhg.aisec.ids.dataflowcontrol.usagecontrol interface LuconConstraint { - fun checkEnforcible(context: EnforcementContext, permission: LuconPermission) + fun checkEnforcible( + context: EnforcementContext, + permission: LuconPermission + ) + fun enforce(context: EnforcementContext) } diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconContract.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconContract.kt index ce7514e15..c12be6766 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconContract.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconContract.kt @@ -40,41 +40,43 @@ class LuconContract private constructor(contract: ContractAgreement) { fun enforce(eCtx: EnforcementContext) { val enforcementErrors = linkedSetOf() - val enforcementSuccessful = permissions.withIndex().any { (i, p) -> - try { - if (eCtx.log.isDebugEnabled) { - eCtx.log.debug("Checking permission # ${i + 1} of contract $contractId...") - } - p.checkEnforcible(eCtx) - if (eCtx.ucPolicies.isNotEmpty()) { - LOG.warn( - "UC policies have been added to EnforcementContext in LuconPermission::checkEnforcible(), " + - "before actual enforcement in LuconPermission::enforce()." + - "This is STRICTLY DISCOURAGED, as it can result in incorrect UC policies!" - ) - } - p.enforce(eCtx) - true - } catch (t: Throwable) { - if (t !is LuconException) { - LOG.error("Unexpected UC exception", t) - } - enforcementErrors += t.message.toString() - eCtx.log.let { log -> - if (log.isDebugEnabled) { - log.debug(t.message) + val enforcementSuccessful = + permissions.withIndex().any { (i, p) -> + try { + if (eCtx.log.isDebugEnabled) { + eCtx.log.debug("Checking permission # ${i + 1} of contract $contractId...") + } + p.checkEnforcible(eCtx) + if (eCtx.ucPolicies.isNotEmpty()) { + LOG.warn( + "UC policies have been added to EnforcementContext in LuconPermission::checkEnforcible(), " + + "before actual enforcement in LuconPermission::enforce()." + + "This is STRICTLY DISCOURAGED, as it can result in incorrect UC policies!" + ) + } + p.enforce(eCtx) + true + } catch (t: Throwable) { + if (t !is LuconException) { + LOG.error("Unexpected UC exception", t) + } + enforcementErrors += t.message.toString() + eCtx.log.let { log -> + if (log.isDebugEnabled) { + log.debug(t.message) + } } + false } - false } - } if (enforcementSuccessful) { runBlocking(Dispatchers.IO) { val ucUrl = "http://${eCtx.endpointUri.host}/usage-control" - val response = HTTP_CLIENT.post(ucUrl) { - contentType(ContentType.Application.Json) - setBody(eCtx.ucPolicies) - } + val response = + HTTP_CLIENT.post(ucUrl) { + contentType(ContentType.Application.Json) + setBody(eCtx.ucPolicies) + } if (response.status.value !in 200..299) { throw LuconException( "Enforcement checks were successful, but POSTing UC policies to $ucUrl failed." @@ -91,12 +93,14 @@ class LuconContract private constructor(contract: ContractAgreement) { companion object { private val LOG = LoggerFactory.getLogger(LuconContract::class.java) - private val HTTP_CLIENT = HttpClient(Java) { - install(ContentNegotiation) { - jackson() + private val HTTP_CLIENT = + HttpClient(Java) { + install(ContentNegotiation) { + jackson() + } } - } private val contracts: MutableMap = Collections.synchronizedMap(hashMapOf()) + fun getContract(contract: ContractAgreement) = contracts.computeIfAbsent(contract.id) { LuconContract(contract) diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconPermission.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconPermission.kt index 7229fa9aa..2e90b735a 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconPermission.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/LuconPermission.kt @@ -35,28 +35,29 @@ class LuconPermission(permission: Permission) { if (permission.preDuty?.isNotEmpty() == true || permission.postDuty?.isNotEmpty() == true) { throw LuconException("PreDuties and PostDuties are not supported yet!") } - constraints = permission.constraint.map { constraint -> - if (constraint !is Constraint) { - throw LuconException("Encountered constraint of invalid type ${constraint.javaClass.name}") + constraints = + permission.constraint.map { constraint -> + if (constraint !is Constraint) { + throw LuconException("Encountered constraint of invalid type ${constraint.javaClass.name}") + } + when (constraint.leftOperand) { + LeftOperand.SYSTEM -> + when (constraint.operator) { + BinaryOperator.SAME_AS -> DockerImageConstraint(constraint.rightOperandReference) + else -> throw LuconException( + "Unexpected Operator ${constraint.operator} for LeftOperand ${constraint.leftOperand}" + ) + } + LeftOperand.POLICY_EVALUATION_TIME -> + when (constraint.operator) { + BinaryOperator.BEFORE, BinaryOperator.AFTER -> UsageTimeConstraint(constraint) + else -> throw LuconException( + "Unexpected Operator ${constraint.operator} for LeftOperand ${constraint.leftOperand}" + ) + } + else -> throw LuconException("Unexpected LeftOperand ${constraint.leftOperand}") + } } - when (constraint.leftOperand) { - LeftOperand.SYSTEM -> - when (constraint.operator) { - BinaryOperator.SAME_AS -> DockerImageConstraint(constraint.rightOperandReference) - else -> throw LuconException( - "Unexpected Operator ${constraint.operator} for LeftOperand ${constraint.leftOperand}" - ) - } - LeftOperand.POLICY_EVALUATION_TIME -> - when (constraint.operator) { - BinaryOperator.BEFORE, BinaryOperator.AFTER -> UsageTimeConstraint(constraint) - else -> throw LuconException( - "Unexpected Operator ${constraint.operator} for LeftOperand ${constraint.leftOperand}" - ) - } - else -> throw LuconException("Unexpected LeftOperand ${constraint.leftOperand}") - } - } } fun checkEnforcible(ectx: EnforcementContext) { diff --git a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/UsageTimeConstraint.kt b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/UsageTimeConstraint.kt index eafba0cdf..96272c4ce 100644 --- a/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/UsageTimeConstraint.kt +++ b/ids-dataflow-control/src/main/kotlin/de/fhg/aisec/ids/dataflowcontrol/usagecontrol/UsageTimeConstraint.kt @@ -40,14 +40,18 @@ class UsageTimeConstraint(private val constraint: Constraint) : LuconConstraint } } - override fun checkEnforcible(context: EnforcementContext, permission: LuconPermission) { + override fun checkEnforcible( + context: EnforcementContext, + permission: LuconPermission + ) { val rightOperand = constraint.rightOperand if (rightOperand.type != TYPE_DATETIMESTAMP) { throw LuconException("Unexpected RDF resource type ${rightOperand.type}, $TYPE_DATETIMESTAMP expected") } val currentTimestamp = System.currentTimeMillis() - val policyTimestamp = DATATYPE_FACTORY.newXMLGregorianCalendar(rightOperand.value).toGregorianCalendar() - .timeInMillis + val policyTimestamp = + DATATYPE_FACTORY.newXMLGregorianCalendar(rightOperand.value).toGregorianCalendar() + .timeInMillis if (constraint.operator == BinaryOperator.BEFORE) { if (currentTimestamp < policyTimestamp) { checkSystemConstraint(context, permission) { "No usage after ${rightOperand.value}" } diff --git a/ids-dataflow-control/src/test/kotlin/de/fhg/aisec/ids/dataflowcontrol/LuconEngineTest.kt b/ids-dataflow-control/src/test/kotlin/de/fhg/aisec/ids/dataflowcontrol/LuconEngineTest.kt index adf3b0716..9576350b3 100644 --- a/ids-dataflow-control/src/test/kotlin/de/fhg/aisec/ids/dataflowcontrol/LuconEngineTest.kt +++ b/ids-dataflow-control/src/test/kotlin/de/fhg/aisec/ids/dataflowcontrol/LuconEngineTest.kt @@ -524,7 +524,7 @@ class LuconEngineTest { "move(1,X,Y,_) :- " + "write('Move top disk from '), write(X), write(' to '), write(Y), nl. \n" + "move(N,X,Y,Z) :- N>1, M is N-1, move(M,X,Z,Y), move(1,X,Y,_), move(M,Z,Y,X). " - ) + ) // A random but syntactically correct policy. private const val EXAMPLE_POLICY = @@ -591,7 +591,7 @@ class LuconEngineTest { "\n" + "service(testQueueService).\n" + "has_endpoint(testQueueService, \"^amqp:.*?:test\")." - ) + ) // Policy with extended labels, i.e. "purpose(green)" private const val EXTENDED_LABELS_POLICY = @@ -623,7 +623,7 @@ class LuconEngineTest { "has_endpoint(sanitizedata, \"^bean://SanitizerBean.*\").\n" + "creates_label(sanitizedata, public).\n" + "removes_label(sanitizedata, private).\n" - ) + ) // Route from LUCON paper with path searching logic private const val VERIFIABLE_ROUTE = @@ -660,6 +660,6 @@ class LuconEngineTest { "succ(anonymizer, hadoopClusters).\n" + "succ(hadoopClusters, testQueue).\n" + "\n" - ) + ) } } diff --git a/ids-infomodel-manager/src/main/kotlin/de/fhg/aisec/ids/informationmodelmanager/InfoModelService.kt b/ids-infomodel-manager/src/main/kotlin/de/fhg/aisec/ids/informationmodelmanager/InfoModelService.kt index 31a6f33e4..3e761bbbc 100644 --- a/ids-infomodel-manager/src/main/kotlin/de/fhg/aisec/ids/informationmodelmanager/InfoModelService.kt +++ b/ids-infomodel-manager/src/main/kotlin/de/fhg/aisec/ids/informationmodelmanager/InfoModelService.kt @@ -37,14 +37,13 @@ import de.fraunhofer.iais.eis.util.ConstraintViolationException import de.fraunhofer.iais.eis.util.TypedLiteral import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component import java.net.URI import java.net.URISyntaxException /** IDS Info Model Manager. */ -// @Component(name = "ids-infomodel-manager", immediate = true) -@org.springframework.stereotype.Component +@Component("ids-infomodel-manager") class InfoModelService : InfoModel { - @Autowired private lateinit var settings: Settings diff --git a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/ConnectionManagerService.kt b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/ConnectionManagerService.kt index efc09f6a9..40ef1b633 100644 --- a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/ConnectionManagerService.kt +++ b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/ConnectionManagerService.kt @@ -57,13 +57,15 @@ class ConnectionManagerService : ConnectionManager { emptyList() } } + override fun listAvailableEndpoints(): List { return camelContexts.flatMapTo(mutableSetOf()) { cCtx -> cCtx.endpointRegistry.values.mapNotNull { ep -> if (ep is Idscp2ServerEndpoint) { val baseUri = ep.endpointBaseUri - val matchGroups = listOf(Regex("(.*?)://(.*?):([0-9]+).*"), Regex("(.*?)://(.*?).*")) - .asSequence().mapNotNull { it.matchEntire(baseUri)?.groupValues }.firstOrNull() + val matchGroups = + listOf(Regex("(.*?)://(.*?):([0-9]+).*"), Regex("(.*?)://(.*?).*")) + .asSequence().mapNotNull { it.matchEntire(baseUri)?.groupValues }.firstOrNull() ServerEndpoint( baseUri, matchGroups?.get(1) ?: "?", @@ -85,14 +87,18 @@ class ConnectionManagerService : ConnectionManager { // Return the attestation status of an endpoint based on it's supported and expected RA suites. // An attestation is considered successfull if it does not accpet any known insecure driver. - private fun getAttestationStatus(supportedRaSuites: String, expectedRaSuites: String): RatResult { + private fun getAttestationStatus( + supportedRaSuites: String, + expectedRaSuites: String + ): RatResult { // This array contains all insecure default verifiers. // If one of these is detected, the attestation will be considered insecure. - val insecureVerifier = setOf( - RaVerifierDummy2.RA_VERIFIER_DUMMY2_ID, - RaVerifierDummy.RA_VERIFIER_DUMMY_ID, - DemoRaVerifier.DEMO_RA_VERIFIER_ID - ) + val insecureVerifier = + setOf( + RaVerifierDummy2.RA_VERIFIER_DUMMY2_ID, + RaVerifierDummy.RA_VERIFIER_DUMMY_ID, + DemoRaVerifier.DEMO_RA_VERIFIER_ID + ) val supportedRaSuitesList = supportedRaSuites.split('|') val expectedRaSuitesList = expectedRaSuites.split('|') @@ -110,59 +116,63 @@ class ConnectionManagerService : ConnectionManager { private val outgoingConnections: MutableList = mutableListOf() private val incomingConnections: MutableList = mutableListOf() - private val connectionListener = object : ConnectionListener { - fun handleConnection( - connection: C, - appLayerConnection: AppLayerConnection, - connectionsList: MutableList - ) { - // first register a idscp2connectionListener to keep track of connection cleanup - appLayerConnection.addConnectionListener(object : Idscp2ConnectionListener { - private fun removeConnection() { - appLayerConnection.removeConnectionListener(this) - connectionsList -= connection - } - - override fun onError(t: Throwable) {} - - override fun onClose() { - removeConnection() - } - }) - - connectionsList += connection - } + private val connectionListener = + object : ConnectionListener { + fun handleConnection( + connection: C, + appLayerConnection: AppLayerConnection, + connectionsList: MutableList + ) { + // first register a idscp2connectionListener to keep track of connection cleanup + appLayerConnection.addConnectionListener( + object : Idscp2ConnectionListener { + override fun onError(t: Throwable) {} + + override fun onClose() { + connectionsList -= connection + } + } + ) + + connectionsList += connection + } - override fun onClientConnection(connection: AppLayerConnection, endpoint: Idscp2ClientEndpoint) { - // When we are a client endpoint, we create an outgoing connection - val outgoing = IDSCPOutgoingConnection() + override fun onClientConnection( + connection: AppLayerConnection, + endpoint: Idscp2ClientEndpoint + ) { + // When we are a client endpoint, we create an outgoing connection + val outgoing = IDSCPOutgoingConnection() - handleConnection(outgoing, connection, outgoingConnections) + handleConnection(outgoing, connection, outgoingConnections) - // TODO handle information from connection and endpoint + // TODO handle information from connection and endpoint - outgoing.apply { - endpointIdentifier = endpoint.endpointBaseUri - attestationResult = getAttestationStatus(endpoint.supportedRaSuites, endpoint.expectedRaSuites) - remoteIdentity = connection.remotePeer() + outgoing.apply { + endpointIdentifier = endpoint.endpointBaseUri + attestationResult = getAttestationStatus(endpoint.supportedRaSuites, endpoint.expectedRaSuites) + remoteIdentity = connection.remotePeer() + } } - } - override fun onServerConnection(connection: AppLayerConnection, endpoint: Idscp2ServerEndpoint) { - // Since we are a server and therefore listening, all connections should be incomming - val incoming = IDSCPIncomingConnection() + override fun onServerConnection( + connection: AppLayerConnection, + endpoint: Idscp2ServerEndpoint + ) { + // Since we are a server and therefore listening, all connections should be incomming + val incoming = IDSCPIncomingConnection() - handleConnection(incoming, connection, incomingConnections) + handleConnection(incoming, connection, incomingConnections) - // TODO handle information from connection and endpoint + // TODO handle information from connection and endpoint - incoming.apply { - endpointIdentifier = endpoint.endpointBaseUri - attestationResult = getAttestationStatus(endpoint.supportedRaSuites, endpoint.expectedRaSuites) - remoteHostName = connection.remotePeer() + incoming.apply { + endpointIdentifier = endpoint.endpointBaseUri + attestationResult = getAttestationStatus(endpoint.supportedRaSuites, endpoint.expectedRaSuites) + remoteHostName = connection.remotePeer() + } } } - } @PostConstruct private fun registerConnectionListener() { diff --git a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/RouteManagerService.kt b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/RouteManagerService.kt index 4a311ac2a..edb2af5d5 100644 --- a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/RouteManagerService.kt +++ b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/RouteManagerService.kt @@ -186,7 +186,10 @@ class RouteManagerService : RouteManager { * @param rd The RouteDefinition to be transformed * @return The resulting RouteObject */ - private fun routeDefinitionToObject(cCtx: CamelContext, rd: RouteDefinition): RouteObject { + private fun routeDefinitionToObject( + cCtx: CamelContext, + rd: RouteDefinition + ): RouteObject { return RouteObject( rd.id, rd.descriptionText, diff --git a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/XmlDeployWatcher.kt b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/XmlDeployWatcher.kt index 6c462278c..d61d0c695 100644 --- a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/XmlDeployWatcher.kt +++ b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/XmlDeployWatcher.kt @@ -45,7 +45,6 @@ import kotlin.io.path.readBytes @Component("xmlDeployWatcher") class XmlDeployWatcher : ApplicationContextAware { - private lateinit var applicationContext: ApplicationContext private lateinit var rootBeanRegistry: DefaultListableBeanFactory @@ -56,32 +55,33 @@ class XmlDeployWatcher : ApplicationContextAware { @Synchronized private fun startXmlBeans(xmlPathString: String) { - xmlContexts += xmlPathString to CompletableFuture.supplyAsync { - try { - FileSystemXmlApplicationContext(arrayOf(xmlPathString), applicationContext).also { ctx -> - // Move special beans prefixed with "root" to the root ApplicationContext - (ctx.autowireCapableBeanFactory as DefaultListableBeanFactory).let { registry -> - registry.beanDefinitionNames.forEach { LOG.debug("Loaded bean: $it") } - registry.beanDefinitionNames - .filter { it.startsWith("root") } - // Memorize Beans for root ApplicationContext - .also { rootBeans += xmlPathString to it } - // Move root Beans to root ApplicationContext - .forEach { beanName -> - val beanDefinition = registry.getBeanDefinition(beanName) - registry.removeBeanDefinition(beanName) - rootBeanRegistry.registerBeanDefinition(beanName, beanDefinition) - if (LOG.isDebugEnabled) { - LOG.debug("Bean $beanName has been moved to root ApplicationContext") + xmlContexts += xmlPathString to + CompletableFuture.supplyAsync { + try { + FileSystemXmlApplicationContext(arrayOf(xmlPathString), applicationContext).also { ctx -> + // Move special beans prefixed with "root" to the root ApplicationContext + (ctx.autowireCapableBeanFactory as DefaultListableBeanFactory).let { registry -> + registry.beanDefinitionNames.forEach { LOG.debug("Loaded bean: $it") } + registry.beanDefinitionNames + .filter { it.startsWith("root") } + // Memorize Beans for root ApplicationContext + .also { rootBeans += xmlPathString to it } + // Move root Beans to root ApplicationContext + .forEach { beanName -> + val beanDefinition = registry.getBeanDefinition(beanName) + registry.removeBeanDefinition(beanName) + rootBeanRegistry.registerBeanDefinition(beanName, beanDefinition) + if (LOG.isDebugEnabled) { + LOG.debug("Bean $beanName has been moved to root ApplicationContext") + } } - } + } } + } catch (t: Throwable) { + LOG.error("Error loading $xmlPathString", t) + throw t } - } catch (t: Throwable) { - LOG.error("Error loading $xmlPathString", t) - throw t } - } } @Synchronized @@ -125,9 +125,10 @@ class XmlDeployWatcher : ApplicationContextAware { } } - private fun getXmlPathStream() = Files.walk(DEPLOY_PATH).filter { - Files.isRegularFile(it) && it.toString().endsWith(".xml") - } + private fun getXmlPathStream() = + Files.walk(DEPLOY_PATH).filter { + Files.isRegularFile(it) && it.toString().endsWith(".xml") + } private fun getPathSha256(path: Path) = MessageDigest.getInstance("SHA-256").digest(path.readBytes()) @@ -185,7 +186,6 @@ class XmlDeployWatcher : ApplicationContextAware { // WatcherService that may react faster to changes in the deploy folder. // Known not to work in some containerized environments. - @Suppress("BlockingMethodInNonBlockingContext") IO_SCOPE.launch { val watcher = FS.newWatchService() DEPLOY_PATH.register( diff --git a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/CamelRouteToDot.kt b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/CamelRouteToDot.kt index 512bd6e6d..97547eee4 100644 --- a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/CamelRouteToDot.kt +++ b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/CamelRouteToDot.kt @@ -42,7 +42,10 @@ class CamelRouteToDot { private var clusterCounter = 0 @Throws(IOException::class) - private fun printRoutes(writer: Writer, map: Map>) { + private fun printRoutes( + writer: Writer, + map: Map> + ) { val entries = map.entries for ((group, value) in entries) { printRoutes(writer, group, value) @@ -50,7 +53,11 @@ class CamelRouteToDot { } @Throws(IOException::class) - private fun printRoutes(writer: Writer, group: String?, routes: List) { + private fun printRoutes( + writer: Writer, + group: String?, + routes: List + ) { if (group != null) { writer.write( """subgraph cluster_${clusterCounter++} { @@ -77,7 +84,10 @@ class CamelRouteToDot { * @throws IOException */ @Throws(IOException::class) - fun printSingleRoute(writer: Writer?, route: RouteDefinition?) { + fun printSingleRoute( + writer: Writer?, + route: RouteDefinition? + ) { if (writer == null || route == null) { return } @@ -91,7 +101,11 @@ class CamelRouteToDot { } @Throws(IOException::class) - private fun printRoute(writer: Writer, route: RouteDefinition, input: FromDefinition) { + private fun printRoute( + writer: Writer, + route: RouteDefinition, + input: FromDefinition + ) { val nodeData = getNodeData(input) printNode(writer, nodeData) var from: NodeData? = nodeData @@ -149,27 +163,30 @@ class CamelRouteToDot { } @Throws(IOException::class) - private fun printNode(writer: Writer, data: NodeData?) { + private fun printNode( + writer: Writer, + data: NodeData? + ) { if (!data!!.nodeWritten) { data.nodeWritten = true writer.write("\n") writer.write( """ - ${data.id} - + ${data.id} + """.trimIndent() ) writer.write(" [\n") writer.write( """ - label = "${data.label}" - + label = "${data.label}" + """.trimIndent() ) writer.write( """ - tooltip = "${data.tooltip}" - + tooltip = "${data.tooltip}" + """.trimIndent() ) val image = data.image @@ -189,7 +206,10 @@ class CamelRouteToDot { } @Throws(IOException::class) - fun generateFile(writer: PrintWriter?, map: Map>?) { + fun generateFile( + writer: PrintWriter?, + map: Map>? + ) { if (writer == null || map == null) { return } diff --git a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/GraphProcessor.kt b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/GraphProcessor.kt index beb4bd020..ce34ce480 100644 --- a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/GraphProcessor.kt +++ b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/GraphProcessor.kt @@ -94,7 +94,10 @@ object GraphProcessor { } /** Prints a single FromDefinition (= a route entry point) in Prolog representation. */ - private fun processInput(graphData: GraphData, route: RouteDefinition) { + private fun processInput( + graphData: GraphData, + route: RouteDefinition + ) { val counter = AtomicInteger(0) val i = route.input // Make sure every input node has a unique id diff --git a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/NodeData.kt b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/NodeData.kt index e8c3b98ac..ebbb988df 100644 --- a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/NodeData.kt +++ b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/NodeData.kt @@ -196,7 +196,7 @@ class NodeData(var id: String, node: Any?, imagePrefix: String) { "http://camel.apache.org/" + nodeType!!.lowercase(Locale.ENGLISH).replace(' ', '-') + ".html" - ) + ) } if (node is ProcessorDefinition<*> && outputs == null) { outputs = node.outputs diff --git a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/PrologPrinter.kt b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/PrologPrinter.kt index 6990edf4a..8f5f5aad2 100644 --- a/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/PrologPrinter.kt +++ b/ids-route-manager/src/main/kotlin/de/fhg/aisec/ids/rm/util/PrologPrinter.kt @@ -36,7 +36,10 @@ class PrologPrinter { * @throws IOException */ @Throws(IOException::class) - fun printSingleRoute(writer: Writer?, route: RouteDefinition?) { + fun printSingleRoute( + writer: Writer?, + route: RouteDefinition? + ) { if (writer == null || route == null) { return } @@ -63,21 +66,21 @@ class PrologPrinter { for (p in preds) { writer.write( """ - succ(${p.id}, ${current.id}). - + succ(${p.id}, ${current.id}). + """.trimIndent() ) } writer.write( """ - stmt(${current.id}). - + stmt(${current.id}). + """.trimIndent() ) writer.write( """ - has_action(${current.id}, "${current.label}"). - + has_action(${current.id}, "${current.label}"). + """.trimIndent() ) @@ -115,7 +118,10 @@ class PrologPrinter { * @throws IOException */ @Throws(IOException::class) - private fun printInput(writer: Writer, route: RouteDefinition) { + private fun printInput( + writer: Writer, + route: RouteDefinition + ) { val counter = AtomicInteger(0) val i = route.input // Make sure every input node has a unique id @@ -125,20 +131,20 @@ class PrologPrinter { } writer.write( """ - stmt(${i.id}). - + stmt(${i.id}). + """.trimIndent() ) writer.write( """ - entrynode(${i.id}). - + entrynode(${i.id}). + """.trimIndent() ) writer.write( """ - has_action(${i.id}, "${i.label}"). - + has_action(${i.id}, "${i.label}"). + """.trimIndent() ) var prev: OptionalIdentifiedDefinition<*>? = i diff --git a/ids-settings/src/main/kotlin/de/fhg/aisec/ids/settings/ElsaSerializer.kt b/ids-settings/src/main/kotlin/de/fhg/aisec/ids/settings/ElsaSerializer.kt index 00630086e..977c1a561 100644 --- a/ids-settings/src/main/kotlin/de/fhg/aisec/ids/settings/ElsaSerializer.kt +++ b/ids-settings/src/main/kotlin/de/fhg/aisec/ids/settings/ElsaSerializer.kt @@ -28,11 +28,17 @@ import org.mapdb.elsa.ElsaSerializerPojo class ElsaSerializer : Serializer { private val serializer: ElsaSerializerPojo = ElsaMaker().make() - override fun serialize(output: DataOutput2, obj: T) { + override fun serialize( + output: DataOutput2, + obj: T + ) { serializer.serialize(output, obj) } - override fun deserialize(input: DataInput2, available: Int): T { + override fun deserialize( + input: DataInput2, + available: Int + ): T { return serializer.deserialize(input) } } diff --git a/ids-settings/src/main/kotlin/de/fhg/aisec/ids/settings/SettingsComponent.kt b/ids-settings/src/main/kotlin/de/fhg/aisec/ids/settings/SettingsComponent.kt index a8a3120d8..774233cce 100644 --- a/ids-settings/src/main/kotlin/de/fhg/aisec/ids/settings/SettingsComponent.kt +++ b/ids-settings/src/main/kotlin/de/fhg/aisec/ids/settings/SettingsComponent.kt @@ -39,7 +39,6 @@ import kotlin.reflect.KProperty @Component class SettingsComponent : Settings { - @PostConstruct private fun activate() { LOG.debug("Open Settings Database {}...", DB_PATH.toFile().absolutePath) @@ -88,12 +87,13 @@ class SettingsComponent : Settings { 3 -> { if (connectorConfig.dapsUrl == "https://daps.aisec.fraunhofer.de") { connectorConfig.let { - connectorConfig = ConnectorConfig( - it.appstoreUrl, it.brokerUrl, it.ttpHost, it.ttpPort, it.acmeServerWebcon, - it.acmeDnsWebcon, it.acmePortWebcon, it.tosAcceptWebcon, - "https://daps.aisec.fraunhofer.de/v2", - it.keystoreName, it.keystorePassword, it.keystoreAliasName, it.truststoreName - ) + connectorConfig = + ConnectorConfig( + it.appstoreUrl, it.brokerUrl, it.ttpHost, it.ttpPort, it.acmeServerWebcon, + it.acmeDnsWebcon, it.acmePortWebcon, it.tosAcceptWebcon, + "https://daps.aisec.fraunhofer.de/v2", + it.keystoreName, it.keystorePassword, it.keystoreAliasName, it.truststoreName + ) } } dbVersion = 4 @@ -115,24 +115,38 @@ class SettingsComponent : Settings { private val key: String, private val defaultProducer: () -> T ) : ReadWriteProperty { - override operator fun getValue(thisRef: Settings, property: KProperty<*>): T { + override operator fun getValue( + thisRef: Settings, + property: KProperty<*> + ): T { @Suppress("UNCHECKED_CAST") return settingsStore.getOrElse(key, defaultProducer) as T } - override operator fun setValue(thisRef: Settings, property: KProperty<*>, value: T) { + override operator fun setValue( + thisRef: Settings, + property: KProperty<*>, + value: T + ) { settingsStore[key] = value mapDB.commit() } } internal class NullableSetting(private val key: String) : ReadWriteProperty { - override operator fun getValue(thisRef: Settings, property: KProperty<*>): T? { + override operator fun getValue( + thisRef: Settings, + property: KProperty<*> + ): T? { @Suppress("UNCHECKED_CAST") return settingsStore[key] as T? } - override operator fun setValue(thisRef: Settings, property: KProperty<*>, value: T?) { + override operator fun setValue( + thisRef: Settings, + property: KProperty<*>, + value: T? + ) { if (value == null) { settingsStore -= key } else { @@ -157,7 +171,10 @@ class SettingsComponent : Settings { } } - override fun setConnectionSettings(connection: String, cSettings: ConnectionSettings) { + override fun setConnectionSettings( + connection: String, + cSettings: ConnectionSettings + ) { connectionSettings[connection] = cSettings mapDB.commit() } @@ -169,7 +186,10 @@ class SettingsComponent : Settings { override fun getUserHash(username: String) = userStore[username] - override fun saveUser(username: String, hash: String) { + override fun saveUser( + username: String, + hash: String + ) { userStore += username to hash mapDB.commit() } @@ -183,7 +203,10 @@ class SettingsComponent : Settings { mapDB.commit() } - override fun storeContract(key: String, contract: String) { + override fun storeContract( + key: String, + contract: String + ) { contractStore[key] = contract mapDB.commit() } diff --git a/ids-webconsole/build.gradle.kts b/ids-webconsole/build.gradle.kts index 70639089f..4871e1fd3 100644 --- a/ids-webconsole/build.gradle.kts +++ b/ids-webconsole/build.gradle.kts @@ -76,7 +76,6 @@ dependencies { implementation(libs.kotlinx.coroutines) implementation(libs.kotlinx.reactive) implementation(libs.kotlinx.reactor) - // implementation(libs.bouncycastlePkix) compileOnly(libs.swagger.jaxrs) diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/AppApi.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/AppApi.kt index 02490d513..c9578e1af 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/AppApi.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/AppApi.kt @@ -69,7 +69,6 @@ import javax.ws.rs.core.MediaType @RequestMapping("/app") @Api(value = "Applications", authorizations = [Authorization(value = "oauth2")]) class AppApi { - @Autowired private lateinit var cml: ContainerManager @@ -105,16 +104,18 @@ class AppApi { @GetMapping("start/{containerId}", produces = [MediaType.APPLICATION_JSON]) @ApiOperation( value = "Start an application", - notes = "Starting an application may take some time. " + - "This method will start the app asynchronously and return immediately. " + - "This method starts the latest version of the app.", + notes = + "Starting an application may take some time. " + + "This method will start the app asynchronously and return immediately. " + + "This method starts the latest version of the app.", response = Boolean::class ) @ApiResponses( ApiResponse( code = 200, - message = "true if the app has been requested to be started. " + - "false if no container management layer is available" + message = + "true if the app has been requested to be started. " + + "false if no container management layer is available" ) ) fun start( @@ -128,14 +129,17 @@ class AppApi { @GetMapping("start/{containerId}/{key}", produces = [MediaType.APPLICATION_JSON]) @ApiOperation( value = "Start an application", - notes = "Starting an application may take some time. This method will start the app asynchronously and return immediately. This methods starts a specific version of the app.", + notes = + "Starting an application may take some time. This method will start the app asynchronously " + + "and return immediately. This methods starts a specific version of the app.", response = Boolean::class ) @ApiResponses( ApiResponse( code = 200, - message = "true if the app has been requested to be started. " + - "false if no container management layer is available" + message = + "true if the app has been requested to be started. " + + "false if no container management layer is available" ) ) fun start( @@ -158,14 +162,17 @@ class AppApi { @GetMapping("stop/{containerId}", produces = [MediaType.APPLICATION_JSON]) @ApiOperation( value = "Stop an app", - notes = "Stops an application. The application will remain installed and can be re-started later. All temporary data will be lost, however.", + notes = + "Stops an application. The application will remain installed and can be re-started later. " + + "All temporary data will be lost, however.", response = Boolean::class ) @ApiResponses( ApiResponse( code = 200, - message = "true if the app has been requested to be stopped. " + - "false if no container management layer is available" + message = + "true if the app has been requested to be stopped. " + + "false if no container management layer is available" ) ) fun stop( @@ -187,9 +194,10 @@ class AppApi { @ApiResponses( ApiResponse( code = 200, - message = "If the app has been requested to be installed. " + - "The actual installation takes place asynchronously in the background " + - "and will terminate after a timeout of 20 minutes", + message = + "If the app has been requested to be installed. " + + "The actual installation takes place asynchronously in the background " + + "and will terminate after a timeout of 20 minutes", response = Boolean::class ), ApiResponse( @@ -259,7 +267,9 @@ class AppApi { consumes = [MediaType.TEXT_PLAIN], produces = [MediaType.APPLICATION_JSON] ) - suspend fun search(@RequestBody term: String?): List { + suspend fun search( + @RequestBody term: String? + ): List { return httpClient.get(settings.connectorConfig.appstoreUrl).body>().let { res -> if (term?.isNotBlank() == true) { res.filter { app: ApplicationContainer -> @@ -278,10 +288,11 @@ class AppApi { companion object { private val LOG = LoggerFactory.getLogger(AppApi::class.java) - private val httpClient = HttpClient(Java) { - install(ContentNegotiation) { - jackson(ContentType.Any) + private val httpClient = + HttpClient(Java) { + install(ContentNegotiation) { + jackson(ContentType.Any) + } } - } } } diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/CertApi.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/CertApi.kt index 9dc720739..583747976 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/CertApi.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/CertApi.kt @@ -99,8 +99,9 @@ import javax.ws.rs.core.MediaType @ApiController @RequestMapping("/certs") @Api(value = "Identities and Certificates", authorizations = [Authorization(value = "oauth2")]) -class CertApi(@Autowired private val settings: Settings) { - +class CertApi( + @Autowired private val settings: Settings +) { @Autowired(required = false) private var acmeClient: AcmeClient? = null @@ -189,7 +190,9 @@ class CertApi(@Autowired private val settings: Settings) { /** Delete a private/public key pair. */ @PostMapping("delete_identity", consumes = [MediaType.TEXT_PLAIN], produces = [MediaType.APPLICATION_JSON]) @ApiOperation(value = "Deletes a public/private key pair") - fun deleteIdentity(@RequestBody alias: String): String { + fun deleteIdentity( + @RequestBody alias: String + ): String { val keyStoreFile = getKeystoreFile(settings.connectorConfig.keystoreName) return if (delete(alias, keyStoreFile)) { alias @@ -201,7 +204,9 @@ class CertApi(@Autowired private val settings: Settings) { /** Deletes a trusted certificate. */ @PostMapping("delete_cert", consumes = [MediaType.TEXT_PLAIN], produces = [MediaType.APPLICATION_JSON]) @ApiOperation(value = "Deletes a trusted certificate") - fun deleteCert(@RequestBody alias: String): String { + fun deleteCert( + @RequestBody alias: String + ): String { val keyStoreFile = getKeystoreFile(settings.connectorConfig.truststoreName) return if (delete(alias, keyStoreFile)) { alias @@ -250,10 +255,12 @@ class CertApi(@Autowired private val settings: Settings) { private fun X509Certificate.isValid() = notThrowing { this.checkValidity() } - private fun X509Certificate.verify(maybeIssuer: X509Certificate) = - notThrowing { this.verify(maybeIssuer.publicKey) } + private fun X509Certificate.verify(maybeIssuer: X509Certificate) = notThrowing { this.verify(maybeIssuer.publicKey) } - private suspend fun fetchEstCaCerts(estUrl: String, permittedHash: String): List { + private suspend fun fetchEstCaCerts( + estUrl: String, + permittedHash: String + ): List { val ucUrl = "$estUrl/.well-known/est/cacerts" val response = insecureHttpClient.get(ucUrl) if (response.status.value !in 200..299) { @@ -331,7 +338,9 @@ class CertApi(@Autowired private val settings: Settings) { ApiResponse(code = 200, message = "EST CA certificate"), ApiResponse(code = 500, message = "No certificate found") ) - fun storeEstCACerts(@RequestBody certificates: String) { + fun storeEstCACerts( + @RequestBody certificates: String + ) { certificates.split("-----END CERTIFICATE-----").map { it.replace(CLEAR_PEM_REGEX, "") }.filter { it.isNotEmpty() }.map { c -> @@ -356,7 +365,9 @@ class CertApi(@Autowired private val settings: Settings) { ApiResponse(code = 200, message = "EST CA certificate fetched"), ApiResponse(code = 500, message = "No certificate found") ) - suspend fun requestEstIdentity(@RequestBody r: EstIdRequest) { + suspend fun requestEstIdentity( + @RequestBody r: EstIdRequest + ) { LOG.debug("Started EST process.") LOG.debug("Fetching CA certificates...") @@ -397,9 +408,7 @@ class CertApi(@Autowired private val settings: Settings) { } @Throws(java.lang.Exception::class) - private fun generatePKCS10( - keys: KeyPair - ): ByteArray { + private fun generatePKCS10(keys: KeyPair): ByteArray { val sigAlg = "SHA256WithRSA" val pkcs = PKCS10(keys.public) // val signature: Signature = Signature.getInstance(sigAlg).apply { initSign(keys.private) } @@ -412,51 +421,57 @@ class CertApi(@Autowired private val settings: Settings) { } } - private suspend fun sendEstIdReq(r: EstIdRequest, csr: ByteArray): PKCS7 { + private suspend fun sendEstIdReq( + r: EstIdRequest, + csr: ByteArray + ): PKCS7 { val trustStoreFile = getKeystoreFile(settings.connectorConfig.truststoreName) - val trustManagers = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).also { tmf -> - KeyStore.getInstance("pkcs12").also { - FileInputStream(trustStoreFile).use { fis -> - it.load(fis, KEYSTORE_PWD.toCharArray()) - tmf.init(it) - } - } - }.trustManagers - val secureHttpClient = HttpClient(Java) { - engine { - config { - sslContext( - SSLContext.getInstance("TLS").apply { - init(null, trustManagers, null) - } - ) + val trustManagers = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).also { tmf -> + KeyStore.getInstance("pkcs12").also { + FileInputStream(trustStoreFile).use { fis -> + it.load(fis, KEYSTORE_PWD.toCharArray()) + tmf.init(it) + } } - } - install(ContentNegotiation) { - jackson() - } - install(Auth) { - basic { - sendWithoutRequest { true } - credentials { - BasicAuthCredentials( - // We need a username here, but effectively only password is checked - username = "username", - password = r.iet + }.trustManagers + val secureHttpClient = + HttpClient(Java) { + engine { + config { + sslContext( + SSLContext.getInstance("TLS").apply { + init(null, trustManagers, null) + } ) } } + install(ContentNegotiation) { + jackson() + } + install(Auth) { + basic { + sendWithoutRequest { true } + credentials { + BasicAuthCredentials( + // We need a username here, but effectively only password is checked + username = "username", + password = r.iet + ) + } + } + } } - } val ucUrl = "${r.estUrl}/.well-known/est/simpleenroll" val pkcs10String = String(csr, StandardCharsets.UTF_8).replace(CLEAR_PEM_REGEX, "") - val response: HttpResponse = secureHttpClient.post(ucUrl) { - setBody(pkcs10String) - headers { - append("Content-Type", "application/pkcs10") - append("Content-Transfer-Encoding", "base64") + val response: HttpResponse = + secureHttpClient.post(ucUrl) { + setBody(pkcs10String) + headers { + append("Content-Type", "application/pkcs10") + append("Content-Transfer-Encoding", "base64") + } } - } if (response.status.value !in 200..299) { throw RuntimeException("Failed to fetch certificate: ${response.status}\n${response.bodyAsText()}") @@ -478,9 +493,10 @@ class CertApi(@Autowired private val settings: Settings) { FileInputStream(storeFile).use { fis -> keystore.load(fis, password) } - val entryAlias = alias ?: certificateChain[0].subjectX500Principal.name.let { name -> - name.split(",").map { it.split("=") }.firstOrNull { it[0] == "CN" }?.get(1) ?: name - } + val entryAlias = + alias ?: certificateChain[0].subjectX500Principal.name.let { name -> + name.split(",").map { it.split("=") }.firstOrNull { it[0] == "CN" }?.get(1) ?: name + } if (key == null) { // Add a CA certificate keystore.setCertificateEntry(entryAlias, certificateChain[0]) @@ -600,35 +616,39 @@ class CertApi(@Autowired private val settings: Settings) { sigAlgName: String, keyStoreFile: File ) { - val keytoolCmd = arrayOf( - "/bin/sh", - "-c", - "keytool", - "-genkey", - "-alias", - alias, - "-keyalg", - keyAlgName, - "-keysize", - keySize.toString(), - "-sigalg", - sigAlgName, - "-keystore", - keyStoreFile.absolutePath, - "-dname", - "CN=" + spec.cn + ", OU=" + spec.ou + ", O=" + spec.o + ", L=" + spec.l + ", S=" + spec.s + - ", C=" + spec.c, - "-storepass", - KEYSTORE_PWD, - "-keypass", - KEYSTORE_PWD - ) + val keytoolCmd = + arrayOf( + "/bin/sh", + "-c", + "keytool", + "-genkey", + "-alias", + alias, + "-keyalg", + keyAlgName, + "-keysize", + keySize.toString(), + "-sigalg", + sigAlgName, + "-keystore", + keyStoreFile.absolutePath, + "-dname", + "CN=" + spec.cn + ", OU=" + spec.ou + ", O=" + spec.o + ", L=" + spec.l + ", S=" + spec.s + + ", C=" + spec.c, + "-storepass", + KEYSTORE_PWD, + "-keypass", + KEYSTORE_PWD + ) val bos = ByteArrayOutputStream() ProcessExecutor().execute(keytoolCmd, bos, bos) LOG.debug("Keytool:\n\n{}", bos.toString(StandardCharsets.UTF_8)) } - private fun delete(alias: String, file: File): Boolean { + private fun delete( + alias: String, + file: File + ): Boolean { try { FileInputStream(file).use { fis -> val keystore = KeyStore.getInstance("pkcs12") @@ -653,29 +673,38 @@ class CertApi(@Autowired private val settings: Settings) { private val WHITESPACE_REGEX = Regex("\\s+") private val CLEAR_PEM_REGEX = Regex("\\s+|-----(?:BEGIN|END) [A-Z ]+-----") - private val insecureHttpClient = HttpClient(Java) { - engine { - config { - sslContext( - SSLContext.getInstance("TLS").apply { - init( - null, - arrayOf(object : X509TrustManager { - override fun checkClientTrusted(p0: Array?, p1: String?) {} - - override fun checkServerTrusted(p0: Array?, p1: String?) {} - - override fun getAcceptedIssuers(): Array = emptyArray() - }), - null - ) - } - ) + private val insecureHttpClient = + HttpClient(Java) { + engine { + config { + sslContext( + SSLContext.getInstance("TLS").apply { + init( + null, + arrayOf( + object : X509TrustManager { + override fun checkClientTrusted( + p0: Array?, + p1: String? + ) {} + + override fun checkServerTrusted( + p0: Array?, + p1: String? + ) {} + + override fun getAcceptedIssuers(): Array = emptyArray() + } + ), + null + ) + } + ) + } + } + install(ContentNegotiation) { + jackson() } } - install(ContentNegotiation) { - jackson() - } - } } } diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/ConfigApi.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/ConfigApi.kt index 47c83bda7..de1a97ecc 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/ConfigApi.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/ConfigApi.kt @@ -58,7 +58,6 @@ import javax.ws.rs.core.MediaType @RequestMapping("/config") @Api(value = "Connector Configuration", authorizations = [Authorization(value = "oauth2")]) class ConfigApi { - @Autowired private lateinit var settings: Settings @@ -85,7 +84,9 @@ class ConfigApi { message = "_No valid preferences received_: If incorrect configuration parameter is provided" ) ) - fun setConnectorConfig(@RequestBody config: ConnectorConfig) { + fun setConnectorConfig( + @RequestBody config: ConnectorConfig + ) { settings.connectorConfig = config } @@ -103,7 +104,10 @@ class ConfigApi { message = "_No valid connection settings received!_: If incorrect connection settings parameter is provided" ) ) - fun setConnectionConfigurations(@PathVariable("con") connection: String, conSettings: ConnectionSettings) { + fun setConnectionConfigurations( + @PathVariable("con") connection: String, + conSettings: ConnectionSettings + ) { conSettings.let { // connection has format " - host:port" // store only "host:port" in database to make connection available in other parts of the application @@ -130,7 +134,9 @@ class ConfigApi { */ @GetMapping("/connectionConfigs/{con}", produces = [MediaType.APPLICATION_JSON]) @ApiOperation(value = "Sends configuration of a connection", response = ConnectionSettings::class) - fun getConnectionConfigurations(@PathVariable("con") connection: String): ConnectionSettings { + fun getConnectionConfigurations( + @PathVariable("con") connection: String + ): ConnectionSettings { return settings.getConnectionSettings(connection) } @@ -154,29 +160,31 @@ class ConfigApi { val connectionManager = connectionManager ?: return emptyMap() // Set of all connection configurations, properly ordered - val allSettings: MutableMap = TreeMap( - Comparator { o1: String, o2: String -> - when (Constants.GENERAL_CONFIG) { - o1 -> { - return@Comparator -1 - } - o2 -> { - return@Comparator 1 - } - else -> { - return@Comparator o1.compareTo(o2) + val allSettings: MutableMap = + TreeMap( + Comparator { o1: String, o2: String -> + when (Constants.GENERAL_CONFIG) { + o1 -> { + return@Comparator -1 + } + o2 -> { + return@Comparator 1 + } + else -> { + return@Comparator o1.compareTo(o2) + } } } - } - ) + ) // Load all existing entries allSettings.putAll(settings.allConnectionSettings) // Assert global configuration entry allSettings.putIfAbsent(Constants.GENERAL_CONFIG, ConnectionSettings()) - val routeInputs = routeManager - .routes - .mapNotNull { it.id } - .associateWith { routeManager.getRouteInputUris(it) } + val routeInputs = + routeManager + .routes + .mapNotNull { it.id } + .associateWith { routeManager.getRouteInputUris(it) } // add all available endpoints for (endpoint in connectionManager.listAvailableEndpoints()) { @@ -196,13 +204,14 @@ class ConfigApi { if (key == Constants.GENERAL_CONFIG) { retAllSettings[key] = value } else { - val endpointIdentifiers = routeInputs - .entries - .filter { (_, value1) -> - value1.any { u: String -> u.startsWith("idsserver://$key") } - } - .map { "$it - $key" } - .ifEmpty { listOf(" - $key") } + val endpointIdentifiers = + routeInputs + .entries + .filter { (_, value1) -> + value1.any { u: String -> u.startsWith("idsserver://$key") } + } + .map { "$it - $key" } + .ifEmpty { listOf(" - $key") } // add endpoint configurations endpointIdentifiers.forEach { endpointIdentifier: String -> diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/ConnectionApi.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/ConnectionApi.kt index 6fd4d3be4..bdcf12893 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/ConnectionApi.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/ConnectionApi.kt @@ -44,7 +44,6 @@ import javax.ws.rs.core.MediaType @RequestMapping("/connections") @Api(value = "IDSCP Connections", authorizations = [Authorization(value = "oauth2")]) class ConnectionApi { - @Autowired private lateinit var connectionManager: ConnectionManager diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/JwtRestApiFilter.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/JwtRestApiFilter.kt index 945ef8419..b5db92e9c 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/JwtRestApiFilter.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/JwtRestApiFilter.kt @@ -35,15 +35,20 @@ import org.springframework.web.filter.OncePerRequestFilter */ @Component class JwtRestApiFilter : OncePerRequestFilter() { - override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) { + override fun doFilterInternal( + request: HttpServletRequest, + response: HttpServletResponse, + chain: FilterChain + ) { try { // Get JWT Bearer token from HTTP Authorization header - val authorizationHeader = request.getHeader("Authorization") ?: run { - response.reset() - response.status = HttpServletResponse.SC_UNAUTHORIZED - response.writer.write("Authorization token missing.") - return - } + val authorizationHeader = + request.getHeader("Authorization") ?: run { + response.reset() + response.status = HttpServletResponse.SC_UNAUTHORIZED + response.writer.write("Authorization token missing.") + return + } // Verify token VERIFIER.verify(authorizationHeader.substring(7).trim()) } catch (e: Exception) { diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/PolicyApi.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/PolicyApi.kt index 2eb331385..8006caa54 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/PolicyApi.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/PolicyApi.kt @@ -47,7 +47,6 @@ import javax.ws.rs.core.MediaType @RequestMapping("/policies") @Api(value = "Usage Control Policies", authorizations = [Authorization(value = "oauth2")]) class PolicyApi { - @Autowired(required = false) private var policyAdministrationPoint: PAP? = null diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/RouteApi.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/RouteApi.kt index 2259e1ea2..7ceafc07b 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/RouteApi.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/RouteApi.kt @@ -54,7 +54,6 @@ import javax.ws.rs.core.MediaType @RequestMapping("/routes") @Api(value = "Message Routing", authorizations = [Authorization(value = "oauth2")]) class RouteApi { - @Autowired private lateinit var rm: RouteManager @@ -96,7 +95,9 @@ class RouteApi { /** Stop a route based on an id. */ @GetMapping("/startroute/{id}", produces = [MediaType.APPLICATION_JSON]) @ApiOperation(value = "Starts a Camel route. The route will start to process messages.") - fun startRoute(@PathVariable("id") id: String): Result { + fun startRoute( + @PathVariable("id") id: String + ): Result { return try { rm.startRoute(id) Result() @@ -109,7 +110,9 @@ class RouteApi { /** Stop a route based on its id. */ @GetMapping("/stoproute/{id}", produces = [MediaType.APPLICATION_JSON]) @ApiOperation(value = "Stops a Camel route. The route will remain installed but it will not process any messages.") - fun stopRoute(@PathVariable("id") id: String): Result { + fun stopRoute( + @PathVariable("id") id: String + ): Result { return try { rm.stopRoute(id) Result() @@ -134,9 +137,12 @@ class RouteApi { } @GetMapping("/validate/{routeId}", produces = [MediaType.APPLICATION_JSON]) - fun validate(@PathVariable("routeId") routeId: String): ValidationInfo { - val pap: PAP = policyAdministrationPoint - ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR) + fun validate( + @PathVariable("routeId") routeId: String + ): ValidationInfo { + val pap: PAP = + policyAdministrationPoint + ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR) val rvp = pap.verifyRoute(routeId) ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR) val vi = ValidationInfo() vi.valid = rvp.isValid @@ -147,7 +153,9 @@ class RouteApi { } @GetMapping("/prolog/{routeId}", produces = [MediaType.TEXT_PLAIN]) - fun getRouteProlog(@PathVariable("routeId") routeId: String): String { + fun getRouteProlog( + @PathVariable("routeId") routeId: String + ): String { return rm.getRouteAsProlog(routeId) } diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/SettingsApi.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/SettingsApi.kt index 1d8a2e54b..ae0de82f4 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/SettingsApi.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/SettingsApi.kt @@ -47,13 +47,14 @@ import javax.ws.rs.core.MediaType @RequestMapping("/settings") @Api(value = "Self-Description and Connector Profiles", authorizations = [Authorization(value = "oauth2")]) class SettingsApi { - @Autowired private lateinit var im: InfoModel @PostMapping("/connectorProfile", consumes = [MediaType.APPLICATION_JSON]) @ApiOperation(value = "Configure the connector's self-description (\"Connector Profile\").") - fun postConnectorProfile(@RequestBody profile: ConnectorProfile) { + fun postConnectorProfile( + @RequestBody profile: ConnectorProfile + ) { if (!im.setConnector(profile)) { throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Error while storing ConnectorProfile") } @@ -86,16 +87,16 @@ class SettingsApi { @get:GetMapping("/selfInformation", produces = ["application/ld+json"]) @set:PostMapping("/selfInformation", consumes = ["application/ld+json"]) var selfInformation: String - // TODO Document ApiOperation - get() = try { - im.connectorAsJsonLd - } catch (e: Throwable) { - LOG.error("Connector description build failed", e) - throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Connector description build failed", e) - } - - // TODO Document ApiOperation - set(@RequestBody selfInformation) { + get() = + try { + im.connectorAsJsonLd + } catch (e: Throwable) { + LOG.error("Connector description build failed", e) + throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Connector description build failed", e) + } + set( + @RequestBody selfInformation + ) { try { im.setConnectorByJsonLd(selfInformation) } catch (e: NullPointerException) { @@ -104,7 +105,6 @@ class SettingsApi { } /** Remove static connector profile based on JSON-LD data */ - // TODO Document ApiOperation @DeleteMapping("/selfInformation") fun removeSelfInformation() { try { diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/UserApi.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/UserApi.kt index e881b4393..91b115f31 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/UserApi.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/UserApi.kt @@ -49,7 +49,9 @@ import javax.ws.rs.core.MediaType @ApiController @RequestMapping("/user") @Api(value = "User Authentication") -class UserApi(@Autowired private val settings: Settings) { +class UserApi( + @Autowired private val settings: Settings +) { /** * Given a correct username/password, this method returns a JWT token that is valid for one day. * @@ -57,7 +59,9 @@ class UserApi(@Autowired private val settings: Settings) { * @return A JWT token as plain text, if successful, 401 UNAUTHORIZED if not. */ @PostMapping("/login", produces = [MediaType.TEXT_PLAIN], consumes = [MediaType.APPLICATION_JSON]) - fun authenticateUser(@RequestBody user: User): String { + fun authenticateUser( + @RequestBody user: User + ): String { if (user.username.isBlank() || user.password.isBlank()) { throw ResponseStatusException( HttpStatus.UNAUTHORIZED, @@ -87,7 +91,10 @@ class UserApi(@Autowired private val settings: Settings) { } @Throws(LoginException::class) - private fun authenticate(username: String, password: String): Boolean { + private fun authenticate( + username: String, + password: String + ): Boolean { return if (settings.isUserStoreEmpty()) { LOG.warn("WARNING: User store is empty! This is insecure! Please create an admin user via the REST API!") username == "ids" && password == "ids" @@ -103,7 +110,9 @@ class UserApi(@Autowired private val settings: Settings) { } @PostMapping("/saveUser", consumes = [MediaType.APPLICATION_JSON]) - fun addUser(@RequestBody user: User) { + fun addUser( + @RequestBody user: User + ) { if (user.username.isBlank() || user.password.isBlank()) { LOG.error("Username or password blank, please provide valid credentials!") } else { @@ -112,7 +121,9 @@ class UserApi(@Autowired private val settings: Settings) { } @PostMapping("/setPassword", consumes = [MediaType.APPLICATION_JSON]) - fun setPassword(@RequestBody change: PasswordChangeRequest) { + fun setPassword( + @RequestBody change: PasswordChangeRequest + ) { if (change.username.isBlank() || change.oldPassword.isBlank() || change.newPassword.isBlank()) { LOG.error("Username or password blank, please provide valid credentials!") } else if ( @@ -132,7 +143,9 @@ class UserApi(@Autowired private val settings: Settings) { consumes = [MediaType.APPLICATION_JSON], produces = [MediaType.APPLICATION_JSON] ) - fun removeUser(@PathVariable("user") username: String) = settings.removeUser(username) + fun removeUser( + @PathVariable("user") username: String + ) = settings.removeUser(username) @GetMapping("list_user_names", produces = [MediaType.APPLICATION_JSON]) @ApiOperation(value = "Lists user names", responseContainer = "List") diff --git a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/helper/ProcessExecutor.kt b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/helper/ProcessExecutor.kt index 4a104ce88..235c3bdef 100644 --- a/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/helper/ProcessExecutor.kt +++ b/ids-webconsole/src/main/kotlin/de/fhg/aisec/ids/webconsole/api/helper/ProcessExecutor.kt @@ -25,7 +25,11 @@ import java.io.OutputStream class ProcessExecutor { @Throws(InterruptedException::class, IOException::class) - fun execute(cmd: Array?, stdout: OutputStream?, stderr: OutputStream?): Int { + fun execute( + cmd: Array?, + stdout: OutputStream?, + stderr: OutputStream? + ): Int { val rt = Runtime.getRuntime() val proc = rt.exec(cmd) val errorGobbler = StreamGobbler(proc.errorStream, stderr) diff --git a/ids-webconsole/src/test/kotlin/de/fhg/aisec/ids/webconsole/api/PortainerCompatibilityIT.kt b/ids-webconsole/src/test/kotlin/de/fhg/aisec/ids/webconsole/api/PortainerCompatibilityIT.kt index 88fbf1abc..d29ead465 100644 --- a/ids-webconsole/src/test/kotlin/de/fhg/aisec/ids/webconsole/api/PortainerCompatibilityIT.kt +++ b/ids-webconsole/src/test/kotlin/de/fhg/aisec/ids/webconsole/api/PortainerCompatibilityIT.kt @@ -58,8 +58,8 @@ class PortainerCompatibilityIT { while (br.readLine().also { line = it } != null) { sb.append( """ - $line - + $line + """.trimIndent() ) } diff --git a/ids-webconsole/src/test/kotlin/de/fhg/aisec/ids/webconsole/api/RestApiTests.kt b/ids-webconsole/src/test/kotlin/de/fhg/aisec/ids/webconsole/api/RestApiTests.kt index d6f13e501..10321810a 100644 --- a/ids-webconsole/src/test/kotlin/de/fhg/aisec/ids/webconsole/api/RestApiTests.kt +++ b/ids-webconsole/src/test/kotlin/de/fhg/aisec/ids/webconsole/api/RestApiTests.kt @@ -170,11 +170,11 @@ class RestApiTests : Assertions() { // assertFalse(metrics.isEmpty()) // } - /** - * Retrieves a fresh JWT from server. - * - * @return The generated authentication token - */ + // /** + // * Retrieves a fresh JWT from server. + // * + // * @return The generated authentication token + // */ // private fun login(): String? { // val c = newClient(null) // c.path("/user/login") @@ -192,9 +192,10 @@ class RestApiTests : Assertions() { private const val ENDPOINT_ADDRESS = "local://testserver" // private lateinit var server: Server - private val settings = Mockito.mock( - Settings::class.java - ) + private val settings = + Mockito.mock( + Settings::class.java + ) // @BeforeAll // @JvmStatic @@ -205,7 +206,7 @@ class RestApiTests : Assertions() { // startServer() // } - /** Starts a test server. Note that REST endpoints must be registered manually here. */ + // /** Starts a test server. Note that REST endpoints must be registered manually here. */ // private fun startServer() { // val sf = JAXRSServerFactoryBean() // sf.setResourceClasses(CertApi::class.java)