From 014b78fabe46f16f225d2f7ab7c5d16499123394 Mon Sep 17 00:00:00 2001 From: David Sloan Date: Fri, 10 Mar 2023 08:39:15 +0000 Subject: [PATCH 1/2] Add formatting rules --- .scalafmt.conf | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index f4a5aed..1272939 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1 +1,31 @@ -version = "2.4.2" +version=2.6.1 +maxColumn = 120 +preset = IntelliJ +align.preset = most +align.openParenCallSite = true +align.tokens.add = [{code = "="},{code = ":"}] +align.multiline = false +align.arrowEnumeratorGenerator = false +assumeStandardLibraryStripMargin = true +newlines.source=keep +newlines.sometimesBeforeColonInMethodReturnType = false +newlines.alwaysBeforeMultilineDef = false +verticalMultiline.atDefnSite = true +verticalMultiline.excludeDanglingParens = [] +newlines.implicitParamListModifierForce = [before,after] +optIn.breakChainOnFirstMethodDot = false +optIn.configStyleArguments = true +runner.optimizer.forceConfigStyleOnOffset = 120 +runner.optimizer.forceConfigStyleMinArgCount = 1 +trailingCommas = always +spaces.inImportCurlyBraces = true + +rewrite.rules = [ + PreferCurlyFors, + RedundantBraces, + ExpandImportSelectors, + RedundantParens +] +rewrite.redundantBraces.generalExpressions = false + +project.git = true From f95f8d8a8fc3b725492c9b1dd991886b841f499b Mon Sep 17 00:00:00 2001 From: David Sloan Date: Fri, 10 Mar 2023 08:39:58 +0000 Subject: [PATCH 2/2] reformat --- build.sbt | 7 +- project/Dependencies.scala | 54 ++--- project/Settings.scala | 32 +-- project/Versioning.scala | 3 +- .../secrets/async/AsyncFunctionLoop.scala | 48 ++-- .../secrets/config/AWSProviderConfig.scala | 26 ++- .../secrets/config/AWSProviderSettings.scala | 20 +- .../config/AbstractConfigExtensions.scala | 5 +- .../secrets/config/Aes256ProviderConfig.scala | 18 +- .../secrets/config/AzureProviderConfig.scala | 21 +- .../config/AzureProviderSettings.scala | 20 +- .../secrets/config/ENVProviderConfig.scala | 14 +- .../secrets/config/VaultProviderConfig.scala | 118 +++++----- .../config/VaultProviderSettings.scala | 129 ++++++----- .../connect/secrets/io/FileWriter.scala | 18 +- .../io/lenses/connect/secrets/package.scala | 62 +++-- .../connect/secrets/providers/AWSHelper.scala | 76 +++--- .../secrets/providers/AWSSecretProvider.scala | 28 +-- .../providers/Aes256DecodingHelper.scala | 34 +-- .../providers/Aes256DecodingProvider.scala | 21 +- .../secrets/providers/AzureHelper.scala | 34 ++- .../providers/AzureSecretProvider.scala | 39 ++-- .../secrets/providers/ENVSecretProvider.scala | 64 +++--- .../secrets/providers/VaultHelper.scala | 31 +-- .../providers/VaultSecretProvider.scala | 57 +++-- .../connect/secrets/utils/EncodingAndId.scala | 7 +- .../connect/secrets/utils/WithRetry.scala | 11 +- .../secrets/async/AsyncFunctionLoopTest.scala | 9 +- .../secrets/io/FileWriterOnceTest.scala | 14 +- .../providers/AWSSecretProviderTest.scala | 114 ++++----- .../providers/Aes256DecodingHelperTest.scala | 11 +- .../Aes256DecodingProviderTest.scala | 47 ++-- .../providers/AesDecodingTestHelper.scala | 21 +- .../providers/AzureSecretProviderTest.scala | 173 +++++++------- .../secrets/providers/DecodeTest.scala | 37 ++- .../providers/ENVSecretProviderTest.scala | 19 +- .../providers/VaultSecretProviderTest.scala | 217 +++++++++--------- 37 files changed, 824 insertions(+), 835 deletions(-) diff --git a/build.sbt b/build.sbt index 0e5aeb1..4e57fe4 100644 --- a/build.sbt +++ b/build.sbt @@ -7,9 +7,8 @@ name := "secret-provider" javacOptions ++= Seq("--release", "11") javaOptions ++= Seq("-Xms512M", "-Xmx2048M") - lazy val subProjects: Seq[Project] = Seq( - `secret-provider` + `secret-provider`, ) lazy val subProjectsRefs: Seq[ProjectReference] = subProjects.map(projectToLocalProject) @@ -38,9 +37,9 @@ lazy val `secret-provider` = (project in file("secret-provider")) addCommandAlias( "validateAll", - ";scalafmtCheck;scalafmtSbtCheck;test:scalafmtCheck;" + ";scalafmtCheck;scalafmtSbtCheck;test:scalafmtCheck;", ) addCommandAlias( "formatAll", - ";scalafmt;scalafmtSbt;test:scalafmt;" + ";scalafmt;scalafmtSbt;test:scalafmt;", ) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 1d63148..60af3a8 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -8,25 +8,25 @@ trait Dependencies { object Versions { - val scalaLoggingVersion = "3.9.5" - val kafkaVersion = "3.4.0" - val vaultVersion = "5.1.0" + val scalaLoggingVersion = "3.9.5" + val kafkaVersion = "3.4.0" + val vaultVersion = "5.1.0" val azureKeyVaultVersion = "4.5.2" val azureIdentityVersion = "1.8.0" - val awsSecretsVersion = "1.12.411" + val awsSecretsVersion = "1.12.411" //test - val scalaTestVersion = "3.2.15" - val mockitoVersion = "3.2.15.0" - val byteBuddyVersion = "1.14.0" - val slf4jVersion = "2.0.5" - val commonsIOVersion = "1.3.2" - val jettyVersion = "11.0.13" + val scalaTestVersion = "3.2.15" + val mockitoVersion = "3.2.15.0" + val byteBuddyVersion = "1.14.0" + val slf4jVersion = "2.0.5" + val commonsIOVersion = "1.3.2" + val jettyVersion = "11.0.13" val testContainersVersion = "1.12.3" - val flexmarkVersion = "0.64.0" + val flexmarkVersion = "0.64.0" val scalaCollectionCompatVersion = "2.8.1" - val jakartaServletVersion = "6.0.0" + val jakartaServletVersion = "6.0.0" } @@ -45,13 +45,13 @@ trait Dependencies { val `aws-secrets-manager` = "com.amazonaws" % "aws-java-sdk-secretsmanager" % awsSecretsVersion - val `mockito` = "org.scalatestplus" %% "mockito-4-6" % mockitoVersion - val `scalatest` = "org.scalatest" %% "scalatest" % scalaTestVersion - val `jetty` = "org.eclipse.jetty" % "jetty-server" % jettyVersion - val `commons-io` = "org.apache.commons" % "commons-io" % commonsIOVersion - val `flexmark` = "com.vladsch.flexmark" % "flexmark-all" % flexmarkVersion - val `slf4j-api` = "org.slf4j" % "slf4j-api" % slf4jVersion - val `slf4j-simple` = "org.slf4j" % "slf4j-simple" % slf4jVersion + val `mockito` = "org.scalatestplus" %% "mockito-4-6" % mockitoVersion + val `scalatest` = "org.scalatest" %% "scalatest" % scalaTestVersion + val `jetty` = "org.eclipse.jetty" % "jetty-server" % jettyVersion + val `commons-io` = "org.apache.commons" % "commons-io" % commonsIOVersion + val `flexmark` = "com.vladsch.flexmark" % "flexmark-all" % flexmarkVersion + val `slf4j-api` = "org.slf4j" % "slf4j-api" % slf4jVersion + val `slf4j-simple` = "org.slf4j" % "slf4j-simple" % slf4jVersion val `byteBuddy` = "net.bytebuddy" % "byte-buddy" % byteBuddyVersion val `scalaCollectionCompat` = @@ -71,14 +71,14 @@ trait Dependencies { `aws-secrets-manager`, `scalaCollectionCompat`, `jakartaServlet` % Test, - `mockito` % Test, - `byteBuddy` % Test, - `scalatest` % Test, - `jetty` % Test, - `commons-io` % Test, - `flexmark` % Test, - `slf4j-api` % Test, - `slf4j-simple` % Test + `mockito` % Test, + `byteBuddy` % Test, + `scalatest` % Test, + `jetty` % Test, + `commons-io` % Test, + `flexmark` % Test, + `slf4j-api` % Test, + `slf4j-simple` % Test, ) } diff --git a/project/Settings.scala b/project/Settings.scala index 680b276..d7a8ff5 100644 --- a/project/Settings.scala +++ b/project/Settings.scala @@ -3,7 +3,8 @@ */ import sbt.Keys._ -import sbt.{Def, _} +import sbt.Def +import sbt._ import sbtassembly.AssemblyKeys._ import sbtassembly.MergeStrategy @@ -11,19 +12,19 @@ object Settings extends Dependencies { val scala212 = "2.12.14" val scala213 = "2.13.10" - val scala3 = "3.2.2" + val scala3 = "3.2.2" val nextVersion = "2.1.7" val artifactVersion = { sys.env.get("LENSES_TAG_NAME") match { case Some(tag) => tag - case _ => s"$nextVersion-SNAPSHOT" + case _ => s"$nextVersion-SNAPSHOT" } } object ScalacFlags { - val FatalWarnings212 = "-Xfatal-warnings" - val FatalWarnings213 = "-Werror" + val FatalWarnings212 = "-Xfatal-warnings" + val FatalWarnings213 = "-Werror" val WarnUnusedImports212 = "-Ywarn-unused-import" val WarnUnusedImports213 = "-Ywarn-unused:imports" } @@ -34,9 +35,9 @@ object Settings extends Dependencies { scalaOrganization := "org.scala-lang", resolvers ++= Seq( Resolver.mavenLocal, - Resolver.mavenCentral + Resolver.mavenCentral, ), - crossScalaVersions := List(/*scala3, */ scala213 /*scala212*/), + crossScalaVersions := List( /*scala3, */ scala213 /*scala212*/ ), Compile / scalacOptions ++= Seq( "-release:11", "-encoding", @@ -44,21 +45,20 @@ object Settings extends Dependencies { "-deprecation", "-unchecked", "-feature", - "11" + "11", ), Compile / scalacOptions ++= { Seq( - ScalacFlags.WarnUnusedImports213 + ScalacFlags.WarnUnusedImports213, ) }, Compile / console / scalacOptions --= Seq( ScalacFlags.FatalWarnings212, ScalacFlags.FatalWarnings213, ScalacFlags.WarnUnusedImports212, - ScalacFlags.WarnUnusedImports213 + ScalacFlags.WarnUnusedImports213, ), - - Test / fork := true + Test / fork := true, ) implicit final class AssemblyConfigurator(project: Project) { @@ -71,7 +71,7 @@ object Settings extends Dependencies { "org.apache.avro", "org.apache.kafka", "io.confluent", - "org.apache.zookeeper" + "org.apache.zookeeper", ) cp filter { f => excludes.exists(f.data.getName.contains(_)) } }, @@ -82,9 +82,9 @@ object Settings extends Dependencies { case x => val oldStrategy = (assembly / assemblyMergeStrategy).value oldStrategy(x) - } + }, ) - } + } -} \ No newline at end of file +} diff --git a/project/Versioning.scala b/project/Versioning.scala index bcfc176..ca00fed 100644 --- a/project/Versioning.scala +++ b/project/Versioning.scala @@ -1,4 +1,5 @@ -import java.util.regex.{Matcher, Pattern} +import java.util.regex.Matcher +import java.util.regex.Pattern case class SemanticVersioning(version: String) { diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/async/AsyncFunctionLoop.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/async/AsyncFunctionLoop.scala index e7575f5..5952fb3 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/async/AsyncFunctionLoop.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/async/AsyncFunctionLoop.scala @@ -8,17 +8,19 @@ package io.lenses.connect.secrets.async import com.typesafe.scalalogging.StrictLogging -import java.util.concurrent.atomic.{AtomicBoolean, AtomicLong} -import java.util.concurrent.{Executors, TimeUnit} +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicLong +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit import scala.concurrent.duration.Duration class AsyncFunctionLoop(interval: Duration, description: String)(thunk: => Unit) extends AutoCloseable with StrictLogging { - private val running = new AtomicBoolean(false) - private val success = new AtomicLong(0L) - private val failure = new AtomicLong(0L) + private val running = new AtomicBoolean(false) + private val success = new AtomicLong(0L) + private val failure = new AtomicLong(0L) private val executorService = Executors.newFixedThreadPool(1) def start(): Unit = { @@ -26,32 +28,32 @@ class AsyncFunctionLoop(interval: Duration, description: String)(thunk: => Unit) throw new IllegalStateException(s"$description already running.") } logger.info( - s"Starting $description loop with an interval of ${interval.toMillis}ms." + s"Starting $description loop with an interval of ${interval.toMillis}ms.", ) - executorService.submit(new Runnable { - override def run(): Unit = { - while (running.get()) { - try { - Thread.sleep(interval.toMillis) - thunk - success.incrementAndGet() - } catch { - case _: InterruptedException => - case t: Throwable => - logger.warn("Failed to renew the Kerberos ticket", t) - failure.incrementAndGet() + executorService.submit( + new Runnable { + override def run(): Unit = + while (running.get()) { + try { + Thread.sleep(interval.toMillis) + thunk + success.incrementAndGet() + } catch { + case _: InterruptedException => + case t: Throwable => + logger.warn("Failed to renew the Kerberos ticket", t) + failure.incrementAndGet() + } } - } - } - }) + }, + ) } - override def close(): Unit = { + override def close(): Unit = if (running.compareAndSet(true, false)) { executorService.shutdownNow() executorService.awaitTermination(10000, TimeUnit.MILLISECONDS) } - } def successRate: Long = success.get() def failureRate: Long = failure.get() diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AWSProviderConfig.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AWSProviderConfig.scala index 544368e..c67a62c 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AWSProviderConfig.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AWSProviderConfig.scala @@ -6,39 +6,42 @@ package io.lenses.connect.secrets.config -import io.lenses.connect.secrets.connect.{AuthMode, _} -import org.apache.kafka.common.config.ConfigDef.{Importance, Type} -import org.apache.kafka.common.config.{AbstractConfig, ConfigDef} +import io.lenses.connect.secrets.connect.AuthMode +import io.lenses.connect.secrets.connect._ +import org.apache.kafka.common.config.ConfigDef.Importance +import org.apache.kafka.common.config.ConfigDef.Type +import org.apache.kafka.common.config.AbstractConfig +import org.apache.kafka.common.config.ConfigDef import java.util object AWSProviderConfig { - val AWS_REGION: String = "aws.region" + val AWS_REGION: String = "aws.region" val AWS_ACCESS_KEY: String = "aws.access.key" val AWS_SECRET_KEY: String = "aws.secret.key" - val AUTH_METHOD: String = "aws.auth.method" + val AUTH_METHOD: String = "aws.auth.method" val config: ConfigDef = new ConfigDef() .define( AWS_REGION, Type.STRING, Importance.HIGH, - "AWS region the Secrets manager is in" + "AWS region the Secrets manager is in", ) .define( AWS_ACCESS_KEY, Type.STRING, null, Importance.HIGH, - "AWS access key" + "AWS access key", ) .define( AWS_SECRET_KEY, Type.PASSWORD, null, Importance.HIGH, - "AWS password key" + "AWS password key", ) .define( AUTH_METHOD, @@ -49,16 +52,15 @@ object AWSProviderConfig { | AWS authenticate method, 'credentials' to use the provided credentials | or 'default' for the standard AWS provider chain. | Default is 'credentials' - |""".stripMargin + |""".stripMargin, ) .define( FILE_DIR, Type.STRING, "", Importance.MEDIUM, - FILE_DIR_DESC + FILE_DIR_DESC, ) } -case class AWSProviderConfig(props: util.Map[String, _]) - extends AbstractConfig(AWSProviderConfig.config, props) +case class AWSProviderConfig(props: util.Map[String, _]) extends AbstractConfig(AWSProviderConfig.config, props) diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AWSProviderSettings.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AWSProviderSettings.scala index d11b096..58bbfad 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AWSProviderSettings.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AWSProviderSettings.scala @@ -12,11 +12,11 @@ import org.apache.kafka.common.config.types.Password import org.apache.kafka.connect.errors.ConnectException case class AWSProviderSettings( - region: String, - accessKey: String, - secretKey: Password, - authMode: AuthMode, - fileDir: String + region: String, + accessKey: String, + secretKey: Password, + authMode: AuthMode, + fileDir: String, ) import io.lenses.connect.secrets.config.AbstractConfigExtensions._ @@ -34,21 +34,21 @@ object AWSProviderSettings { if (authMode == AuthMode.CREDENTIALS) { if (accessKey.isEmpty) throw new ConnectException( - s"${AWSProviderConfig.AWS_ACCESS_KEY} not set" + s"${AWSProviderConfig.AWS_ACCESS_KEY} not set", ) if (secretKey.value().isEmpty) throw new ConnectException( - s"${AWSProviderConfig.AWS_SECRET_KEY} not set" + s"${AWSProviderConfig.AWS_SECRET_KEY} not set", ) } val fileDir = configs.getString(FILE_DIR) new AWSProviderSettings( - region = region, + region = region, accessKey = accessKey, secretKey = secretKey, - authMode = authMode, - fileDir = fileDir + authMode = authMode, + fileDir = fileDir, ) } } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AbstractConfigExtensions.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AbstractConfigExtensions.scala index 5cebe46..1ff7fe3 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AbstractConfigExtensions.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AbstractConfigExtensions.scala @@ -11,8 +11,7 @@ import org.apache.kafka.common.config.types.Password import org.apache.kafka.connect.errors.ConnectException object AbstractConfigExtensions { - implicit class AbstractConfigExtension(val config: AbstractConfig) - extends AnyVal { + implicit class AbstractConfigExtension(val config: AbstractConfig) extends AnyVal { def getStringOrThrowOnNull(field: String): String = Option(config.getString(field)).getOrElse(raiseException(field)) @@ -23,7 +22,7 @@ object AbstractConfigExtensions { } private def raiseException(fieldName: String) = throw new ConnectException( - s"$fieldName not set" + s"$fieldName not set", ) } } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/Aes256ProviderConfig.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/Aes256ProviderConfig.scala index 8c164e1..c9ff71f 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/Aes256ProviderConfig.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/Aes256ProviderConfig.scala @@ -1,8 +1,11 @@ package io.lenses.connect.secrets.config -import io.lenses.connect.secrets.connect.{FILE_DIR, FILE_DIR_DESC} -import org.apache.kafka.common.config.ConfigDef.{Importance, Type} -import org.apache.kafka.common.config.{AbstractConfig, ConfigDef} +import io.lenses.connect.secrets.connect.FILE_DIR +import io.lenses.connect.secrets.connect.FILE_DIR_DESC +import org.apache.kafka.common.config.ConfigDef.Importance +import org.apache.kafka.common.config.ConfigDef.Type +import org.apache.kafka.common.config.AbstractConfig +import org.apache.kafka.common.config.ConfigDef import java.util @@ -15,19 +18,18 @@ object Aes256ProviderConfig { Type.STRING, "", Importance.MEDIUM, - "Key used to decode AES256 encoded values" + "Key used to decode AES256 encoded values", ) .define( FILE_DIR, Type.STRING, "", Importance.MEDIUM, - FILE_DIR_DESC + FILE_DIR_DESC, ) } -case class Aes256ProviderConfig(props: util.Map[String, _]) - extends AbstractConfig(Aes256ProviderConfig.config, props) { - def aes256Key: String = getString(Aes256ProviderConfig.SECRET_KEY) +case class Aes256ProviderConfig(props: util.Map[String, _]) extends AbstractConfig(Aes256ProviderConfig.config, props) { + def aes256Key: String = getString(Aes256ProviderConfig.SECRET_KEY) def writeDirectory: String = getString(FILE_DIR) } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AzureProviderConfig.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AzureProviderConfig.scala index a8b5c5e..fda0048 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AzureProviderConfig.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AzureProviderConfig.scala @@ -7,8 +7,10 @@ package io.lenses.connect.secrets.config import io.lenses.connect.secrets.connect._ -import org.apache.kafka.common.config.ConfigDef.{Importance, Type} -import org.apache.kafka.common.config.{AbstractConfig, ConfigDef} +import org.apache.kafka.common.config.ConfigDef.Importance +import org.apache.kafka.common.config.ConfigDef.Type +import org.apache.kafka.common.config.AbstractConfig +import org.apache.kafka.common.config.ConfigDef import java.util @@ -17,7 +19,7 @@ object AzureProviderConfig { val AZURE_CLIENT_ID = "azure.client.id" val AZURE_TENANT_ID = "azure.tenant.id" val AZURE_SECRET_ID = "azure.secret.id" - val AUTH_METHOD = "azure.auth.method" + val AUTH_METHOD = "azure.auth.method" val config: ConfigDef = new ConfigDef() .define( @@ -25,21 +27,21 @@ object AzureProviderConfig { Type.STRING, null, Importance.HIGH, - "Azure client id for the service principal" + "Azure client id for the service principal", ) .define( AZURE_TENANT_ID, Type.STRING, null, Importance.HIGH, - "Azure tenant id for the service principal" + "Azure tenant id for the service principal", ) .define( AZURE_SECRET_ID, Type.PASSWORD, null, Importance.HIGH, - "Azure secret id for the service principal" + "Azure secret id for the service principal", ) .define( AUTH_METHOD, @@ -50,16 +52,15 @@ object AzureProviderConfig { |Azure authenticate method, 'credentials' to use the provided credentials or |'default' for the standard Azure provider chain |Default is 'credentials' - |""".stripMargin + |""".stripMargin, ) .define( FILE_DIR, Type.STRING, "", Importance.MEDIUM, - FILE_DIR_DESC + FILE_DIR_DESC, ) } -case class AzureProviderConfig(props: util.Map[String, _]) - extends AbstractConfig(AzureProviderConfig.config, props) +case class AzureProviderConfig(props: util.Map[String, _]) extends AbstractConfig(AzureProviderConfig.config, props) diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AzureProviderSettings.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AzureProviderSettings.scala index 31d58ce..72ffa15 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AzureProviderSettings.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/AzureProviderSettings.scala @@ -13,11 +13,11 @@ import org.apache.kafka.common.config.types.Password import org.apache.kafka.connect.errors.ConnectException case class AzureProviderSettings( - clientId: String, - tenantId: String, - secretId: Password, - authMode: AuthMode, - fileDir: String + clientId: String, + tenantId: String, + secretId: Password, + authMode: AuthMode, + fileDir: String, ) import io.lenses.connect.secrets.config.AbstractConfigExtensions._ @@ -25,7 +25,7 @@ object AzureProviderSettings extends StrictLogging { def apply(config: AzureProviderConfig): AzureProviderSettings = { val authMode = getAuthenticationMethod( - config.getString(AzureProviderConfig.AUTH_METHOD) + config.getString(AzureProviderConfig.AUTH_METHOD), ) if (authMode == AuthMode.CREDENTIALS) { @@ -38,15 +38,15 @@ object AzureProviderSettings extends StrictLogging { if (clientId.isEmpty) throw new ConnectException( - s"${AzureProviderConfig.AZURE_CLIENT_ID} not set" + s"${AzureProviderConfig.AZURE_CLIENT_ID} not set", ) if (tenantId.isEmpty) throw new ConnectException( - s"${AzureProviderConfig.AZURE_TENANT_ID} not set" + s"${AzureProviderConfig.AZURE_TENANT_ID} not set", ) if (secretId.value().isEmpty) throw new ConnectException( - s"${AzureProviderConfig.AZURE_SECRET_ID} not set" + s"${AzureProviderConfig.AZURE_SECRET_ID} not set", ) } @@ -57,7 +57,7 @@ object AzureProviderSettings extends StrictLogging { tenantId = config.getString(AzureProviderConfig.AZURE_TENANT_ID), secretId = config.getPassword(AzureProviderConfig.AZURE_SECRET_ID), authMode = authMode, - fileDir = fileDir + fileDir = fileDir, ) } } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/ENVProviderConfig.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/ENVProviderConfig.scala index e21f531..4806ac5 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/ENVProviderConfig.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/ENVProviderConfig.scala @@ -6,9 +6,12 @@ package io.lenses.connect.secrets.config -import io.lenses.connect.secrets.connect.{FILE_DIR, FILE_DIR_DESC} -import org.apache.kafka.common.config.ConfigDef.{Importance, Type} -import org.apache.kafka.common.config.{AbstractConfig, ConfigDef} +import io.lenses.connect.secrets.connect.FILE_DIR +import io.lenses.connect.secrets.connect.FILE_DIR_DESC +import org.apache.kafka.common.config.ConfigDef.Importance +import org.apache.kafka.common.config.ConfigDef.Type +import org.apache.kafka.common.config.AbstractConfig +import org.apache.kafka.common.config.ConfigDef import java.util @@ -18,9 +21,8 @@ object ENVProviderConfig { Type.STRING, "", Importance.MEDIUM, - FILE_DIR_DESC + FILE_DIR_DESC, ) } -case class ENVProviderConfig(props: util.Map[String, _]) - extends AbstractConfig(ENVProviderConfig.config, props) +case class ENVProviderConfig(props: util.Map[String, _]) extends AbstractConfig(ENVProviderConfig.config, props) diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/VaultProviderConfig.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/VaultProviderConfig.scala index 05eb808..33ed9e6 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/VaultProviderConfig.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/VaultProviderConfig.scala @@ -6,26 +6,29 @@ package io.lenses.connect.secrets.config -import io.lenses.connect.secrets.connect.{FILE_DIR, FILE_DIR_DESC} -import org.apache.kafka.common.config.ConfigDef.{Importance, Type} -import org.apache.kafka.common.config.{AbstractConfig, ConfigDef, SslConfigs} +import io.lenses.connect.secrets.connect.FILE_DIR +import io.lenses.connect.secrets.connect.FILE_DIR_DESC +import org.apache.kafka.common.config.ConfigDef.Importance +import org.apache.kafka.common.config.ConfigDef.Type +import org.apache.kafka.common.config.AbstractConfig +import org.apache.kafka.common.config.ConfigDef +import org.apache.kafka.common.config.SslConfigs import java.util object VaultAuthMethod extends Enumeration { type VaultAuthMethod = Value - val KUBERNETES, AWSIAM, GCP, USERPASS, LDAP, JWT, CERT, APPROLE, TOKEN, - GITHUB = Value + val KUBERNETES, AWSIAM, GCP, USERPASS, LDAP, JWT, CERT, APPROLE, TOKEN, GITHUB = Value def withNameOpt(s: String): Option[Value] = values.find(_.toString == s) } object VaultProviderConfig { - val VAULT_ADDR: String = "vault.addr" - val VAULT_TOKEN: String = "vault.token" - val VAULT_NAMESPACE: String = "vault.namespace" + val VAULT_ADDR: String = "vault.addr" + val VAULT_TOKEN: String = "vault.token" + val VAULT_NAMESPACE: String = "vault.namespace" val VAULT_CLIENT_PEM: String = "vault.client.pem" - val VAULT_PEM: String = "vault.pem" + val VAULT_PEM: String = "vault.pem" val VAULT_ENGINE_VERSION = "vault.engine.version" val AUTH_METHOD: String = "vault.auth.method" @@ -36,42 +39,42 @@ object VaultProviderConfig { val VAULT_KEYSTORE_PASS: String = s"vault.${SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG}" - val KUBERNETES_ROLE: String = "kubernetes.role" + val KUBERNETES_ROLE: String = "kubernetes.role" val KUBERNETES_TOKEN_PATH: String = "kubernetes.token.path" val KUBERNETES_DEFAULT_TOKEN_PATH: String = "/var/run/secrets/kubernetes.io/serviceaccount/token" - val APP_ROLE: String = "app.role.id" + val APP_ROLE: String = "app.role.id" val APP_ROLE_SECRET_ID: String = "app.role.secret.id" - val AWS_ROLE: String = "aws.role" - val AWS_REQUEST_URL: String = "aws.request.url" + val AWS_ROLE: String = "aws.role" + val AWS_REQUEST_URL: String = "aws.request.url" val AWS_REQUEST_HEADERS: String = "aws.request.headers" - val AWS_REQUEST_BODY: String = "aws.request.body" - val AWS_MOUNT: String = "aws.mount" + val AWS_REQUEST_BODY: String = "aws.request.body" + val AWS_MOUNT: String = "aws.mount" val GCP_ROLE: String = "gcp.role" - val GCP_JWT: String = "gcp.jwt" + val GCP_JWT: String = "gcp.jwt" val LDAP_USERNAME: String = "ldap.username" val LDAP_PASSWORD: String = "ldap.password" - val LDAP_MOUNT: String = "ldap.mount" + val LDAP_MOUNT: String = "ldap.mount" val USERNAME: String = "username" val PASSWORD: String = "password" val UP_MOUNT: String = "mount" - val JWT_ROLE: String = "jwt.role" + val JWT_ROLE: String = "jwt.role" val JWT_PROVIDER: String = "jwt.provider" - val JWT: String = "jwt" + val JWT: String = "jwt" val CERT_MOUNT: String = "cert.mount" val GITHUB_TOKEN: String = "github.token" val GITHUB_MOUNT: String = "github.mount" - val TOKEN_RENEWAL: String = "token.renewal.ms" - val TOKEN_RENEWAL_DEFAULT: Int = 600000 + val TOKEN_RENEWAL: String = "token.renewal.ms" + val TOKEN_RENEWAL_DEFAULT: Int = 600000 val config: ConfigDef = new ConfigDef() .define( @@ -79,63 +82,63 @@ object VaultProviderConfig { ConfigDef.Type.STRING, "http://localhost:8200", Importance.HIGH, - "Address of the Vault server" + "Address of the Vault server", ) .define( VAULT_TOKEN, ConfigDef.Type.PASSWORD, null, Importance.HIGH, - s"Vault app role token. $AUTH_METHOD must be 'token'" + s"Vault app role token. $AUTH_METHOD must be 'token'", ) .define( VAULT_NAMESPACE, Type.STRING, "", Importance.MEDIUM, - "Sets a global namespace to the Vault server instance. Required Vault Enterprize Pro" + "Sets a global namespace to the Vault server instance. Required Vault Enterprize Pro", ) .define( VAULT_KEYSTORE_LOC, ConfigDef.Type.STRING, "", ConfigDef.Importance.HIGH, - SslConfigs.SSL_KEYSTORE_LOCATION_DOC + SslConfigs.SSL_KEYSTORE_LOCATION_DOC, ) .define( VAULT_KEYSTORE_PASS, ConfigDef.Type.PASSWORD, "", ConfigDef.Importance.HIGH, - SslConfigs.SSL_KEYSTORE_PASSWORD_DOC + SslConfigs.SSL_KEYSTORE_PASSWORD_DOC, ) .define( VAULT_TRUSTSTORE_LOC, ConfigDef.Type.STRING, "", ConfigDef.Importance.HIGH, - SslConfigs.SSL_TRUSTSTORE_LOCATION_DOC + SslConfigs.SSL_TRUSTSTORE_LOCATION_DOC, ) .define( VAULT_PEM, Type.STRING, "", Importance.HIGH, - "File containing the Vault server certificate string contents" + "File containing the Vault server certificate string contents", ) .define( VAULT_CLIENT_PEM, Type.STRING, "", Importance.HIGH, - "File containing the Client certificate string contents" + "File containing the Client certificate string contents", ) .define( VAULT_ENGINE_VERSION, Type.INT, 2, Importance.HIGH, - "KV Secrets Engine version of the Vault server instance. Defaults to 2" + "KV Secrets Engine version of the Vault server instance. Defaults to 2", ) // auth mode .define( @@ -147,7 +150,7 @@ object VaultProviderConfig { |The authentication mode for Vault. |Available values are approle, userpass, kubernetes, cert, token, ldap, gcp, awsiam, jwt, github | - |""".stripMargin + |""".stripMargin, ) // app role auth mode .define( @@ -155,14 +158,14 @@ object VaultProviderConfig { Type.STRING, null, Importance.HIGH, - s"Vault App role id. $AUTH_METHOD must be 'approle'" + s"Vault App role id. $AUTH_METHOD must be 'approle'", ) .define( APP_ROLE_SECRET_ID, Type.PASSWORD, null, Importance.HIGH, - s"Vault App role name secret id. $AUTH_METHOD must be 'approle'" + s"Vault App role name secret id. $AUTH_METHOD must be 'approle'", ) // userpass .define( @@ -170,21 +173,21 @@ object VaultProviderConfig { Type.STRING, null, Importance.HIGH, - s"Username to connect to Vault with. $AUTH_METHOD must be 'userpass'" + s"Username to connect to Vault with. $AUTH_METHOD must be 'userpass'", ) .define( PASSWORD, Type.PASSWORD, null, Importance.HIGH, - s"Password for the username. $AUTH_METHOD must be 'uerspass'" + s"Password for the username. $AUTH_METHOD must be 'uerspass'", ) .define( UP_MOUNT, Type.STRING, "userpass", Importance.HIGH, - s"The mount name of the userpass authentication back end. Defaults to 'userpass'. $AUTH_METHOD must be 'userpass'" + s"The mount name of the userpass authentication back end. Defaults to 'userpass'. $AUTH_METHOD must be 'userpass'", ) // kubernetes .define( @@ -192,7 +195,7 @@ object VaultProviderConfig { Type.STRING, null, Importance.HIGH, - s"The kubernetes role used for authentication. $AUTH_METHOD must be 'kubernetes'" + s"The kubernetes role used for authentication. $AUTH_METHOD must be 'kubernetes'", ) .define( KUBERNETES_TOKEN_PATH, @@ -205,7 +208,7 @@ object VaultProviderConfig { | $AUTH_METHOD must be ' - |""".stripMargin + |""".stripMargin, ) // awsiam .define( @@ -222,7 +225,7 @@ object VaultProviderConfig { henticated. |If a matching role is not found, login fails. $AUTH_METHOD must be 'awsiam' - |""".stripMargin + |""".stripMargin, ) .define( AWS_REQUEST_URL, @@ -233,14 +236,14 @@ object VaultProviderConfig { |PKCS7 signature of the identity document with all \n characters removed.Base64-encoded Hsed in the signed request. |Most likely just aHR0cHM6Ly9zdHMuYW1hem9uYXdzLmNvbS8= (base64-encoding of https://sts.amom/) as most requests will |probably use POST with an empty URI. $AUTH_METHOD must be 'awsiam' - |""".stripMargin + |""".stripMargin, ) .define( AWS_REQUEST_HEADERS, Type.PASSWORD, null, Importance.HIGH, - s"Request headers. $AUTH_METHOD must be 'awsiam'" + s"Request headers. $AUTH_METHOD must be 'awsiam'", ) .define( AWS_REQUEST_BODY, @@ -254,14 +257,14 @@ object VaultProviderConfig { nNpb249MjAxMS0wNi0xNQ== which is |the base64 encoding of Action=GetCallerIdentity&Versi 5. $AUTH_METHOD must be 'awsiam' - |""".stripMargin + |""".stripMargin, ) .define( AWS_MOUNT, Type.STRING, "aws", Importance.HIGH, - s"AWS auth mount. $AUTH_METHOD must be 'awsiam'. Default 'aws'" + s"AWS auth mount. $AUTH_METHOD must be 'awsiam'. Default 'aws'", ) //ldap .define( @@ -269,21 +272,21 @@ object VaultProviderConfig { Type.STRING, null, Importance.HIGH, - s"LDAP username to connect to Vault with. $AUTH_METHOD must be 'ldap'" + s"LDAP username to connect to Vault with. $AUTH_METHOD must be 'ldap'", ) .define( LDAP_PASSWORD, Type.PASSWORD, null, Importance.HIGH, - s"LDAP Password for the username. $AUTH_METHOD must be 'ldap'" + s"LDAP Password for the username. $AUTH_METHOD must be 'ldap'", ) .define( LDAP_MOUNT, Type.STRING, "ldap", Importance.HIGH, - s"The mount name of the ldap authentication back end. Defaults to 'ldap'. $AUTH_METHOD must be 'ldap'" + s"The mount name of the ldap authentication back end. Defaults to 'ldap'. $AUTH_METHOD must be 'ldap'", ) //jwt .define( @@ -291,21 +294,21 @@ object VaultProviderConfig { Type.STRING, null, Importance.HIGH, - s"Role the JWT token belongs to. $AUTH_METHOD must be 'jwt'" + s"Role the JWT token belongs to. $AUTH_METHOD must be 'jwt'", ) .define( JWT_PROVIDER, Type.STRING, null, Importance.HIGH, - s"Provider of JWT token. $AUTH_METHOD must be 'jwt'" + s"Provider of JWT token. $AUTH_METHOD must be 'jwt'", ) .define( JWT, Type.PASSWORD, null, Importance.HIGH, - s"JWT token. $AUTH_METHOD must be 'jwt'" + s"JWT token. $AUTH_METHOD must be 'jwt'", ) //gcp .define( @@ -313,14 +316,14 @@ object VaultProviderConfig { Type.STRING, null, Importance.HIGH, - s"The gcp role used for authentication. $AUTH_METHOD must be 'gcp'" + s"The gcp role used for authentication. $AUTH_METHOD must be 'gcp'", ) .define( GCP_JWT, Type.PASSWORD, null, Importance.HIGH, - s"JWT token. $AUTH_METHOD must be 'gcp'" + s"JWT token. $AUTH_METHOD must be 'gcp'", ) // cert mount .define( @@ -328,36 +331,35 @@ object VaultProviderConfig { Type.STRING, "cert", Importance.HIGH, - s"The mount name of the cert authentication back end. Defaults to 'cert'. $AUTH_METHOD must be 'cert'" + s"The mount name of the cert authentication back end. Defaults to 'cert'. $AUTH_METHOD must be 'cert'", ) .define( GITHUB_TOKEN, Type.PASSWORD, null, Importance.HIGH, - s"The github app-id used for authentication. $AUTH_METHOD must be 'github'" + s"The github app-id used for authentication. $AUTH_METHOD must be 'github'", ) .define( GITHUB_MOUNT, Type.STRING, "github", Importance.HIGH, - s"The mount name of the github authentication back end. Defaults to 'cert'. $AUTH_METHOD must be 'github'" + s"The mount name of the github authentication back end. Defaults to 'cert'. $AUTH_METHOD must be 'github'", ) .define( FILE_DIR, Type.STRING, "", Importance.MEDIUM, - FILE_DIR_DESC + FILE_DIR_DESC, ) .define( TOKEN_RENEWAL, Type.INT, TOKEN_RENEWAL_DEFAULT, Importance.MEDIUM, - "The time in milliseconds to renew the Vault token" + "The time in milliseconds to renew the Vault token", ) } -case class VaultProviderConfig(props: util.Map[String, _]) - extends AbstractConfig(VaultProviderConfig.config, props) +case class VaultProviderConfig(props: util.Map[String, _]) extends AbstractConfig(VaultProviderConfig.config, props) diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/VaultProviderSettings.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/VaultProviderSettings.scala index e7b61e9..ae934cb 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/config/VaultProviderSettings.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/config/VaultProviderSettings.scala @@ -14,16 +14,19 @@ import io.lenses.connect.secrets.connect._ import org.apache.kafka.common.config.types.Password import org.apache.kafka.connect.errors.ConnectException -import scala.concurrent.duration.{FiniteDuration, _} +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ import scala.io.Source -import scala.util.{Failure, Success, Using} +import scala.util.Failure +import scala.util.Success +import scala.util.Using case class AwsIam( - role: String, - url: String, - headers: Password, - body: Password, - mount: String + role: String, + url: String, + headers: Password, + body: Password, + mount: String, ) case class Gcp(role: String, jwt: Password) case class Jwt(role: String, provider: String, jwt: Password) @@ -35,50 +38,50 @@ case class Cert(mount: String) case class Github(token: Password, mount: String) case class VaultSettings( - addr: String, - namespace: String, - token: Password, - authMode: VaultAuthMethod, - keystoreLoc: String, - keystorePass: Password, - truststoreLoc: String, - pem: String, - clientPem: String, - engineVersion: Int = 2, - appRole: Option[AppRole], - awsIam: Option[AwsIam], - gcp: Option[Gcp], - jwt: Option[Jwt], - userPass: Option[UserPass], - ldap: Option[Ldap], - k8s: Option[K8s], - cert: Option[Cert], - github: Option[Github], - fileDir: String, - tokenRenewal: FiniteDuration + addr: String, + namespace: String, + token: Password, + authMode: VaultAuthMethod, + keystoreLoc: String, + keystorePass: Password, + truststoreLoc: String, + pem: String, + clientPem: String, + engineVersion: Int = 2, + appRole: Option[AppRole], + awsIam: Option[AwsIam], + gcp: Option[Gcp], + jwt: Option[Jwt], + userPass: Option[UserPass], + ldap: Option[Ldap], + k8s: Option[K8s], + cert: Option[Cert], + github: Option[Github], + fileDir: String, + tokenRenewal: FiniteDuration, ) object VaultSettings extends StrictLogging { def apply(config: VaultProviderConfig): VaultSettings = { - val addr = config.getString(VaultProviderConfig.VAULT_ADDR) - val token = config.getPassword(VaultProviderConfig.VAULT_TOKEN) - val namespace = config.getString(VaultProviderConfig.VAULT_NAMESPACE) + val addr = config.getString(VaultProviderConfig.VAULT_ADDR) + val token = config.getPassword(VaultProviderConfig.VAULT_TOKEN) + val namespace = config.getString(VaultProviderConfig.VAULT_NAMESPACE) val keystoreLoc = config.getString(VaultProviderConfig.VAULT_KEYSTORE_LOC) val keystorePass = config.getPassword(VaultProviderConfig.VAULT_KEYSTORE_PASS) val truststoreLoc = config.getString(VaultProviderConfig.VAULT_TRUSTSTORE_LOC) - val pem = config.getString(VaultProviderConfig.VAULT_PEM) - val clientPem = config.getString(VaultProviderConfig.VAULT_CLIENT_PEM) + val pem = config.getString(VaultProviderConfig.VAULT_PEM) + val clientPem = config.getString(VaultProviderConfig.VAULT_CLIENT_PEM) val engineVersion = config.getInt(VaultProviderConfig.VAULT_ENGINE_VERSION) val authMode = VaultAuthMethod.withNameOpt( - config.getString(VaultProviderConfig.AUTH_METHOD).toUpperCase + config.getString(VaultProviderConfig.AUTH_METHOD).toUpperCase, ) match { case Some(auth) => auth case None => throw new ConnectException( - s"Unsupported ${VaultProviderConfig.AUTH_METHOD}" + s"Unsupported ${VaultProviderConfig.AUTH_METHOD}", ) } @@ -110,27 +113,27 @@ object VaultSettings extends StrictLogging { val tokenRenewal = config.getInt(TOKEN_RENEWAL).toInt.milliseconds VaultSettings( - addr = addr, - namespace = namespace, - token = token, - authMode = authMode, - keystoreLoc = keystoreLoc, - keystorePass = keystorePass, + addr = addr, + namespace = namespace, + token = token, + authMode = authMode, + keystoreLoc = keystoreLoc, + keystorePass = keystorePass, truststoreLoc = truststoreLoc, - pem = pem, - clientPem = clientPem, + pem = pem, + clientPem = clientPem, engineVersion = engineVersion, - appRole = appRole, - awsIam = awsIam, - gcp = gcp, - jwt = jwt, - userPass = userpass, - ldap = ldap, - k8s = k8s, - cert = cert, - github = github, - fileDir = fileDir, - tokenRenewal = tokenRenewal + appRole = appRole, + awsIam = awsIam, + gcp = gcp, + jwt = jwt, + userPass = userpass, + ldap = ldap, + k8s = k8s, + cert = cert, + github = github, + fileDir = fileDir, + tokenRenewal = tokenRenewal, ) } @@ -146,18 +149,18 @@ object VaultSettings extends StrictLogging { def getAWS(config: VaultProviderConfig): AwsIam = { val role = config.getStringOrThrowOnNull(VaultProviderConfig.AWS_ROLE) - val url = config.getStringOrThrowOnNull(VaultProviderConfig.AWS_REQUEST_URL) + val url = config.getStringOrThrowOnNull(VaultProviderConfig.AWS_REQUEST_URL) val headers = config.getPasswordOrThrowOnNull(VaultProviderConfig.AWS_REQUEST_HEADERS) val body = config.getPasswordOrThrowOnNull(VaultProviderConfig.AWS_REQUEST_BODY) val mount = config.getStringOrThrowOnNull(VaultProviderConfig.AWS_MOUNT) AwsIam( - role = role, - url = url, + role = role, + url = url, headers = headers, - body = body, - mount = mount + body = body, + mount = mount, ) } @@ -177,7 +180,7 @@ object VaultSettings extends StrictLogging { case Failure(exception) => throw new ConnectException( s"Failed to load kubernetes token file [$path]", - exception + exception, ) case Success(fileContents) => K8s(role = role, jwt = new Password(fileContents)) @@ -185,8 +188,8 @@ object VaultSettings extends StrictLogging { } def getUserPass(config: VaultProviderConfig): UserPass = { - val user = config.getStringOrThrowOnNull(VaultProviderConfig.USERNAME) - val pass = config.getPasswordOrThrowOnNull(VaultProviderConfig.PASSWORD) + val user = config.getStringOrThrowOnNull(VaultProviderConfig.USERNAME) + val pass = config.getPasswordOrThrowOnNull(VaultProviderConfig.PASSWORD) val mount = config.getStringOrThrowOnNull(VaultProviderConfig.UP_MOUNT) UserPass(username = user, password = pass, mount = mount) } @@ -201,7 +204,7 @@ object VaultSettings extends StrictLogging { def getGCP(config: VaultProviderConfig): Gcp = { val role = config.getStringOrThrowOnNull(VaultProviderConfig.GCP_ROLE) - val jwt = config.getPasswordOrThrowOnNull(VaultProviderConfig.GCP_JWT) + val jwt = config.getPasswordOrThrowOnNull(VaultProviderConfig.GCP_JWT) Gcp(role = role, jwt = jwt) } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/io/FileWriter.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/io/FileWriter.scala index c4a3326..5d55287 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/io/FileWriter.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/io/FileWriter.scala @@ -8,9 +8,12 @@ package io.lenses.connect.secrets.io import com.typesafe.scalalogging.StrictLogging import io.lenses.connect.secrets.utils.WithRetry -import java.io.{BufferedOutputStream, FileOutputStream} +import java.io.BufferedOutputStream +import java.io.FileOutputStream import java.nio.file.attribute.PosixFilePermissions -import java.nio.file.{Files, Path, Paths} +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths import scala.concurrent.duration._ import scala.util.Try @@ -18,13 +21,10 @@ trait FileWriter { def write(fileName: String, content: Array[Byte], key: String): Path } -class FileWriterOnce(rootPath: Path) - extends FileWriter - with WithRetry - with StrictLogging { +class FileWriterOnce(rootPath: Path) extends FileWriter with WithRetry with StrictLogging { private val folderPermissions = PosixFilePermissions.fromString("rwx------") - private val filePermissions = PosixFilePermissions.fromString("rw-------") + private val filePermissions = PosixFilePermissions.fromString("rw-------") private val folderAttributes = PosixFilePermissions.asFileAttribute(folderPermissions) private val fileAttributes = @@ -35,7 +35,7 @@ class FileWriterOnce(rootPath: Path) def write(fileName: String, content: Array[Byte], key: String): Path = { val fullPath = Paths.get(rootPath.toString, fileName) - val file = fullPath.toFile + val file = fullPath.toFile if (file.exists()) fullPath else { val tempPath = Paths.get(rootPath.toString, fileName + ".bak") @@ -49,7 +49,7 @@ class FileWriterOnce(rootPath: Path) fos.write(content) fos.flush() logger.info( - s"Payload written to [${file.getAbsolutePath}] for key [$key]" + s"Payload written to [${file.getAbsolutePath}] for key [$key]", ) } finally { Try(fos.close()) diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/package.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/package.scala index 2334ecb..206477b 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/package.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/package.scala @@ -10,17 +10,20 @@ import com.typesafe.scalalogging.StrictLogging import org.apache.kafka.common.config.ConfigData import org.apache.kafka.connect.errors.ConnectException -import java.io.{File, FileOutputStream} +import java.io.File +import java.io.FileOutputStream import java.time.OffsetDateTime import java.util.Base64 import scala.collection.mutable import scala.jdk.CollectionConverters._ -import scala.util.{Failure, Success, Try} +import scala.util.Failure +import scala.util.Success +import scala.util.Try package object connect extends StrictLogging { val FILE_ENCODING: String = "file-encoding" - val FILE_DIR: String = "file.dir" + val FILE_DIR: String = "file.dir" val FILE_DIR_DESC: String = """ | Location to write any files for any secrets that need to @@ -42,46 +45,43 @@ package object connect extends StrictLogging { } // get the authmethod - def getAuthenticationMethod(method: String): AuthMode.Value = { + def getAuthenticationMethod(method: String): AuthMode.Value = AuthMode.withNameOpt(method.toUpperCase) match { case Some(auth) => auth case None => throw new ConnectException( - s"Unsupported authentication method" + s"Unsupported authentication method", ) } - } // base64 decode secret - def decode(key: String, value: String): String = { + def decode(key: String, value: String): String = Try(Base64.getDecoder.decode(value)) match { case Success(decoded) => decoded.map(_.toChar).mkString case Failure(exception) => throw new ConnectException( s"Failed to decode value for key [$key]", - exception + exception, ) } - } - def decodeToBytes(key: String, value: String): Array[Byte] = { + def decodeToBytes(key: String, value: String): Array[Byte] = Try(Base64.getDecoder.decode(value)) match { case Success(decoded) => decoded case Failure(exception) => throw new ConnectException( s"Failed to decode value for key [$key]", - exception + exception, ) } - } // decode a key bases on the prefix encoding def decodeKey( - encoding: Option[Encoding.Value], - key: String, - value: String, - writeFileFn: Array[Byte] => String - ): String = { + encoding: Option[Encoding.Value], + key: String, + value: String, + writeFileFn: Array[Byte] => String, + ): String = encoding.fold(value) { case Encoding.BASE64 => decode(key, value) case Encoding.BASE64_FILE => @@ -90,40 +90,38 @@ package object connect extends StrictLogging { case Encoding.UTF8 => value case Encoding.UTF8_FILE => writeFileFn(value.getBytes()) } - } // write secrets to file - private def writer(file: File, payload: Array[Byte], key: String): Unit = { + private def writer(file: File, payload: Array[Byte], key: String): Unit = Try(file.createNewFile()) match { case Success(_) => Try(new FileOutputStream(file)) match { case Success(fos) => fos.write(payload) logger.info( - s"Payload written to [${file.getAbsolutePath}] for key [$key]" + s"Payload written to [${file.getAbsolutePath}] for key [$key]", ) case Failure(exception) => throw new ConnectException( s"Failed to write payload to file [${file.getAbsolutePath}] for key [$key]", - exception + exception, ) } case Failure(exception) => throw new ConnectException( s"Failed to create file [${file.getAbsolutePath}] for key [$key]", - exception + exception, ) } - } // write secrets to a file def fileWriter( - fileName: String, - payload: Array[Byte], - key: String, - overwrite: Boolean = false + fileName: String, + payload: Array[Byte], + key: String, + overwrite: Boolean = false, ): Unit = { val file = new File(fileName) file.getParentFile.mkdirs() @@ -140,7 +138,7 @@ package object connect extends StrictLogging { //calculate the min expiry for secrets and return the configData and expiry def getSecretsAndExpiry( - secrets: Map[String, (String, Option[OffsetDateTime])] + secrets: Map[String, (String, Option[OffsetDateTime])], ): (Option[OffsetDateTime], ConfigData) = { val expiryList = mutable.ListBuffer.empty[OffsetDateTime] @@ -163,10 +161,10 @@ package object connect extends StrictLogging { } def getFileName( - rootDir: String, - path: String, - key: String, - separator: String + rootDir: String, + path: String, + key: String, + separator: String, ): String = s"${rootDir.stripSuffix(separator)}$separator$path$separator${key.toLowerCase}" } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AWSHelper.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AWSHelper.scala index cb75a56..77c170c 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AWSHelper.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AWSHelper.scala @@ -6,24 +6,20 @@ package io.lenses.connect.secrets.providers -import com.amazonaws.auth.{ - AWSStaticCredentialsProvider, - BasicAWSCredentials, - DefaultAWSCredentialsProviderChain -} -import com.amazonaws.services.secretsmanager.model.{ - DescribeSecretRequest, - GetSecretValueRequest -} -import com.amazonaws.services.secretsmanager.{ - AWSSecretsManager, - AWSSecretsManagerClientBuilder -} +import com.amazonaws.auth.AWSStaticCredentialsProvider +import com.amazonaws.auth.BasicAWSCredentials +import com.amazonaws.auth.DefaultAWSCredentialsProviderChain +import com.amazonaws.services.secretsmanager.model.DescribeSecretRequest +import com.amazonaws.services.secretsmanager.model.GetSecretValueRequest +import com.amazonaws.services.secretsmanager.AWSSecretsManager +import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder import com.fasterxml.jackson.databind.ObjectMapper import com.typesafe.scalalogging.StrictLogging import io.lenses.connect.secrets.config.AWSProviderSettings -import io.lenses.connect.secrets.connect.{AuthMode, decodeKey} -import io.lenses.connect.secrets.io.{FileWriter, FileWriterOnce} +import io.lenses.connect.secrets.connect.AuthMode +import io.lenses.connect.secrets.connect.decodeKey +import io.lenses.connect.secrets.io.FileWriter +import io.lenses.connect.secrets.io.FileWriterOnce import io.lenses.connect.secrets.utils.EncodingAndId import org.apache.kafka.connect.errors.ConnectException @@ -31,7 +27,9 @@ import java.nio.file.Paths import java.time.OffsetDateTime import java.util.Calendar import scala.jdk.CollectionConverters._ -import scala.util.{Failure, Success, Try} +import scala.util.Failure +import scala.util.Success +import scala.util.Try trait AWSHelper extends StrictLogging { @@ -39,7 +37,7 @@ trait AWSHelper extends StrictLogging { def createClient(settings: AWSProviderSettings): AWSSecretsManager = { logger.info( - s"Initializing client with mode [${settings.authMode}]" + s"Initializing client with mode [${settings.authMode}]", ) val credentialProvider = settings.authMode match { @@ -47,8 +45,8 @@ trait AWSHelper extends StrictLogging { new AWSStaticCredentialsProvider( new BasicAWSCredentials( settings.accessKey, - settings.secretKey.value() - ) + settings.secretKey.value(), + ), ) case _ => new DefaultAWSCredentialsProviderChain() @@ -64,8 +62,8 @@ trait AWSHelper extends StrictLogging { // determine the ttl for the secret private def getTTL( - client: AWSSecretsManager, - secretId: String + client: AWSSecretsManager, + secretId: String, ): Option[OffsetDateTime] = { // describe to get the ttl @@ -84,7 +82,7 @@ trait AWSHelper extends StrictLogging { //increment cal.add(Calendar.DAY_OF_MONTH, nextRotationInDays.toInt) Some( - OffsetDateTime.ofInstant(cal.toInstant, cal.getTimeZone.toZoneId) + OffsetDateTime.ofInstant(cal.toInstant, cal.getTimeZone.toZoneId), ) } else None @@ -92,60 +90,58 @@ trait AWSHelper extends StrictLogging { case Failure(exception) => throw new ConnectException( s"Failed to describe secret [$secretId]", - exception + exception, ) } } // get the key value and ttl in the specified secret def getSecretValue( - client: AWSSecretsManager, - rootDir: String, - secretId: String, - key: String - ): (String, Option[OffsetDateTime]) = { - + client: AWSSecretsManager, + rootDir: String, + secretId: String, + key: String, + ): (String, Option[OffsetDateTime]) = // get the secret Try( - client.getSecretValue(new GetSecretValueRequest().withSecretId(secretId)) + client.getSecretValue(new GetSecretValueRequest().withSecretId(secretId)), ) match { case Success(secret) => val value = new ObjectMapper() .readValue( secret.getSecretString, - classOf[java.util.HashMap[String, String]] + classOf[java.util.HashMap[String, String]], ) .asScala .getOrElse( key, throw new ConnectException( - s"Failed to look up key [$key] in secret [${secret.getName}]. key not found" - ) + s"Failed to look up key [$key] in secret [${secret.getName}]. key not found", + ), ) val fileWriter: FileWriter = new FileWriterOnce( - Paths.get(rootDir, secretId) + Paths.get(rootDir, secretId), ) // decode the value val encodingAndId = EncodingAndId.from(key) ( decodeKey( - key = key, - value = value, + key = key, + value = value, encoding = encodingAndId.encoding, writeFileFn = content => { fileWriter.write(key.toLowerCase, content, key).toString - } + }, ), - getTTL(client, secretId) + getTTL(client, secretId), ) case Failure(exception) => throw new ConnectException( s"Failed to look up key [$key] in secret [$secretId] due to [${exception.getMessage}]", - exception + exception, ) } - } } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AWSSecretProvider.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AWSSecretProvider.scala index 0cc4a1a..161b1d7 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AWSSecretProvider.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AWSSecretProvider.scala @@ -7,7 +7,8 @@ package io.lenses.connect.secrets.providers import com.amazonaws.services.secretsmanager.AWSSecretsManager -import io.lenses.connect.secrets.config.{AWSProviderConfig, AWSProviderSettings} +import io.lenses.connect.secrets.config.AWSProviderConfig +import io.lenses.connect.secrets.config.AWSProviderSettings import io.lenses.connect.secrets.connect.getSecretsAndExpiry import org.apache.kafka.common.config.ConfigData import org.apache.kafka.common.config.provider.ConfigProvider @@ -19,48 +20,43 @@ import scala.jdk.CollectionConverters._ class AWSSecretProvider() extends ConfigProvider with AWSHelper { - var client: Option[AWSSecretsManager] = None - var rootDir: String = "" + var client: Option[AWSSecretsManager] = None + var rootDir: String = "" override def get(path: String): ConfigData = new ConfigData(Map.empty[String, String].asJava) // path is expected to be the name of the AWS secret // keys are expect to be the keys in the payload - override def get(path: String, keys: util.Set[String]): ConfigData = { - + override def get(path: String, keys: util.Set[String]): ConfigData = client match { case Some(awsClient) => //aws client caches so we don't need to check here val (expiry, data) = getSecretsAndExpiry( - getSecrets(awsClient, path, keys.asScala.toSet) - ) - expiry.foreach(exp => - logger.info(s"Min expiry for TTL set to [${exp.toString}]") + getSecrets(awsClient, path, keys.asScala.toSet), ) + expiry.foreach(exp => logger.info(s"Min expiry for TTL set to [${exp.toString}]")) data case None => throw new ConnectException("AWS client is not set.") } - } override def close(): Unit = client.foreach(_.shutdown()) override def configure(configs: util.Map[String, _]): Unit = { val settings = AWSProviderSettings(AWSProviderConfig(props = configs)) rootDir = settings.fileDir - client = Some(createClient(settings)) + client = Some(createClient(settings)) } def getSecrets( - awsClient: AWSSecretsManager, - path: String, - keys: Set[String] - ): Map[String, (String, Option[OffsetDateTime])] = { + awsClient: AWSSecretsManager, + path: String, + keys: Set[String], + ): Map[String, (String, Option[OffsetDateTime])] = keys.map { key => logger.info(s"Looking up value at [$path] for key [$key]") val (value, expiry) = getSecretValue(awsClient, rootDir, path, key) (key, (value, expiry)) }.toMap - } } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/Aes256DecodingHelper.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/Aes256DecodingHelper.scala index dfd64be..e3b0f3f 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/Aes256DecodingHelper.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/Aes256DecodingHelper.scala @@ -3,8 +3,10 @@ package io.lenses.connect.secrets.providers import java.security.SecureRandom import java.util.Base64 import javax.crypto.Cipher -import javax.crypto.spec.{IvParameterSpec, SecretKeySpec} -import scala.util.{Failure, Try} +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.SecretKeySpec +import scala.util.Failure +import scala.util.Try private[providers] object Aes256DecodingHelper { @@ -12,7 +14,7 @@ private[providers] object Aes256DecodingHelper { val INITIALISATION_VECTOR_SEPARATOR = " " private val BYTES_AMOUNT = 32 - private val CHARSET = "UTF-8" + private val CHARSET = "UTF-8" /** * Initializes AES256 decoder for valid key or fails for invalid key @@ -30,8 +32,8 @@ private[providers] object Aes256DecodingHelper { } private[providers] class Aes256DecodingHelper private ( - key: String, - ivSeparator: String + key: String, + ivSeparator: String, ) { import Aes256DecodingHelper.CHARSET @@ -43,18 +45,18 @@ private[providers] class Aes256DecodingHelper private ( for { (iv, encoded) <- InitializationVector.extractInitialisationVector( s, - ivSeparator + ivSeparator, ) - decoded <- base64Decode(encoded) + decoded <- base64Decode(encoded) decrypted <- decryptBytes(iv, decoded) } yield new String(decrypted, CHARSET) private def decryptBytes( - iv: InitializationVector, - bytes: Array[Byte] + iv: InitializationVector, + bytes: Array[Byte], ): Try[Array[Byte]] = for { - cipher <- getCipher(Cipher.DECRYPT_MODE, iv) + cipher <- getCipher(Cipher.DECRYPT_MODE, iv) encrypted <- Try(cipher.doFinal(bytes)) } yield encrypted @@ -84,20 +86,18 @@ private object InitializationVector { } def extractInitialisationVector( - s: String, - ivSeparator: String + s: String, + ivSeparator: String, ): Try[(InitializationVector, String)] = s.indexOf(ivSeparator) match { case -1 => Failure( new IllegalStateException( - "Invalid format: missing initialization vector" - ) + "Invalid format: missing initialization vector", + ), ) case i => - base64Decode(s.substring(0, i)).map(b => - (new InitializationVector(b), s.substring(i + 1)) - ) + base64Decode(s.substring(0, i)).map(b => (new InitializationVector(b), s.substring(i + 1))) } } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/Aes256DecodingProvider.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/Aes256DecodingProvider.scala index 43edbac..c09df39 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/Aes256DecodingProvider.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/Aes256DecodingProvider.scala @@ -2,10 +2,12 @@ package io.lenses.connect.secrets.providers import io.lenses.connect.secrets.config.Aes256ProviderConfig import io.lenses.connect.secrets.connect.decodeKey -import io.lenses.connect.secrets.io.{FileWriter, FileWriterOnce} +import io.lenses.connect.secrets.io.FileWriter +import io.lenses.connect.secrets.io.FileWriterOnce import io.lenses.connect.secrets.utils.EncodingAndId import org.apache.kafka.common.config.provider.ConfigProvider -import org.apache.kafka.common.config.{ConfigData, ConfigException} +import org.apache.kafka.common.config.ConfigData +import org.apache.kafka.common.config.ConfigException import org.apache.kafka.connect.errors.ConnectException import java.nio.file.Paths @@ -21,7 +23,7 @@ class Aes256DecodingProvider extends ConfigProvider { override def configure(configs: util.Map[String, _]): Unit = { val aes256Cfg = Aes256ProviderConfig(configs) val aes256Key = aes256Cfg.aes256Key - val writeDir = aes256Cfg.writeDirectory + val writeDir = aes256Cfg.writeDirectory decoder = Option(aes256Key) .map(Aes256DecodingHelper.init) @@ -40,13 +42,12 @@ class Aes256DecodingProvider extends ConfigProvider { val decrypted = d .decrypt(key) .fold( - e => - throw new ConnectException("Failed to decrypt the secret.", e), - identity + e => throw new ConnectException("Failed to decrypt the secret.", e), + identity, ) decodeKey( - key = key, - value = decrypted, + key = key, + value = decrypted, encoding = encodingAndId.encoding, writeFileFn = { content => encodingAndId.id match { @@ -54,10 +55,10 @@ class Aes256DecodingProvider extends ConfigProvider { fileWriter.write(value, content, key).toString case None => throw new ConnectException( - s"Invalid argument received for key:$key. Expecting a file identifier." + s"Invalid argument received for key:$key. Expecting a file identifier.", ) } - } + }, ) } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AzureHelper.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AzureHelper.scala index 0acd6bd..0f42f7d 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AzureHelper.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AzureHelper.scala @@ -7,10 +7,8 @@ package io.lenses.connect.secrets.providers import com.azure.core.credential.TokenCredential -import com.azure.identity.{ - ClientSecretCredentialBuilder, - DefaultAzureCredentialBuilder -} +import com.azure.identity.ClientSecretCredentialBuilder +import com.azure.identity.DefaultAzureCredentialBuilder import com.azure.security.keyvault.secrets.SecretClient import com.typesafe.scalalogging.StrictLogging import io.lenses.connect.secrets.config.AzureProviderSettings @@ -19,7 +17,9 @@ import org.apache.kafka.connect.errors.ConnectException import java.nio.file.FileSystems import java.time.OffsetDateTime -import scala.util.{Failure, Success, Try} +import scala.util.Failure +import scala.util.Success +import scala.util.Try trait AzureHelper extends StrictLogging { @@ -27,12 +27,11 @@ trait AzureHelper extends StrictLogging { // look up secret in Azure def getSecretValue( - rootDir: String, - path: String, - client: SecretClient, - key: String - ): (String, Option[OffsetDateTime]) = { - + rootDir: String, + path: String, + client: SecretClient, + key: String, + ): (String, Option[OffsetDateTime]) = Try(client.getSecret(key)) match { case Success(secret) => val value = secret.getValue @@ -42,9 +41,9 @@ trait AzureHelper extends StrictLogging { val encoding = Encoding.withName( Option(props.getTags) - .map { _.getOrDefault(FILE_ENCODING, Encoding.UTF8.toString) } + .map(_.getOrDefault(FILE_ENCODING, Encoding.UTF8.toString)) .getOrElse(Encoding.UTF8.toString) - .toUpperCase + .toUpperCase, ) val content = encoding match { @@ -57,7 +56,7 @@ trait AzureHelper extends StrictLogging { fileWriter( fileName, value.getBytes, - key.toLowerCase + key.toLowerCase, ) fileName @@ -72,7 +71,7 @@ trait AzureHelper extends StrictLogging { fileWriter( fileName, decoded, - key.toLowerCase + key.toLowerCase, ) fileName } @@ -83,16 +82,15 @@ trait AzureHelper extends StrictLogging { case Failure(e) => throw new ConnectException( s"Failed to look up secret [$key] at [${client.getVaultUrl}]", - e + e, ) } - } // setup azure credentials def createCredentials(settings: AzureProviderSettings): TokenCredential = { logger.info( - s"Initializing client with mode [${settings.authMode.toString}]" + s"Initializing client with mode [${settings.authMode.toString}]", ) settings.authMode match { diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AzureSecretProvider.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AzureSecretProvider.scala index 41efa0a..c9a071a 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AzureSecretProvider.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/AzureSecretProvider.scala @@ -7,11 +7,10 @@ package io.lenses.connect.secrets.providers import com.azure.core.credential.TokenCredential -import com.azure.security.keyvault.secrets.{SecretClient, SecretClientBuilder} -import io.lenses.connect.secrets.config.{ - AzureProviderConfig, - AzureProviderSettings -} +import com.azure.security.keyvault.secrets.SecretClient +import com.azure.security.keyvault.secrets.SecretClientBuilder +import io.lenses.connect.secrets.config.AzureProviderConfig +import io.lenses.connect.secrets.config.AzureProviderSettings import io.lenses.connect.secrets.connect.getSecretsAndExpiry import org.apache.kafka.common.config.ConfigData import org.apache.kafka.common.config.provider.ConfigProvider @@ -23,15 +22,15 @@ import scala.jdk.CollectionConverters._ class AzureSecretProvider() extends ConfigProvider with AzureHelper { - private var rootDir: String = _ - private var credentials: Option[TokenCredential] = None - val clientMap: mutable.Map[String, SecretClient] = mutable.Map.empty + private var rootDir: String = _ + private var credentials: Option[TokenCredential] = None + val clientMap: mutable.Map[String, SecretClient] = mutable.Map.empty val cache = mutable.Map.empty[String, (Option[OffsetDateTime], ConfigData)] // configure the vault client override def configure(configs: util.Map[String, _]): Unit = { val settings = AzureProviderSettings(AzureProviderConfig(configs)) - rootDir = settings.fileDir + rootDir = settings.fileDir credentials = Some(createCredentials(settings)) } @@ -58,7 +57,7 @@ class AzureSecretProvider() extends ConfigProvider with AzureHelper { new SecretClientBuilder() .vaultUrl(keyVaultUrl) .credential(credentials.get) - .buildClient + .buildClient, ) clientMap += (keyVaultUrl -> client) @@ -68,9 +67,11 @@ class AzureSecretProvider() extends ConfigProvider with AzureHelper { // we have all the keys and are before the expiry val now = OffsetDateTime.now() - if (keys.asScala.subsetOf(data.data().asScala.keySet) && (expiresAt - .getOrElse(now.plusSeconds(1)) - .isAfter(now))) { + if ( + keys.asScala.subsetOf(data.data().asScala.keySet) && (expiresAt + .getOrElse(now.plusSeconds(1)) + .isAfter(now)) + ) { logger.info("Fetching secrets from cache") ( expiresAt, @@ -84,8 +85,8 @@ class AzureSecretProvider() extends ConfigProvider with AzureHelper { } .toMap .asJava, - data.ttl() - ) + data.ttl(), + ), ) } else { // missing some or expired so reload @@ -96,9 +97,7 @@ class AzureSecretProvider() extends ConfigProvider with AzureHelper { getSecretsAndExpiry(getSecrets(client, keys.asScala.toSet)) } - expiry.foreach(exp => - logger.info(s"Min expiry for TTL set to [${exp.toString}]") - ) + expiry.foreach(exp => logger.info(s"Min expiry for TTL set to [${exp.toString}]")) cache += (keyVaultUrl -> (expiry, data)) data } @@ -106,8 +105,8 @@ class AzureSecretProvider() extends ConfigProvider with AzureHelper { override def close(): Unit = {} private def getSecrets( - client: SecretClient, - keys: Set[String] + client: SecretClient, + keys: Set[String], ): Map[String, (String, Option[OffsetDateTime])] = { val path = client.getVaultUrl.stripPrefix("https://") keys.map { key => diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/ENVSecretProvider.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/ENVSecretProvider.scala index 4fa8353..648f21f 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/ENVSecretProvider.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/ENVSecretProvider.scala @@ -7,12 +7,10 @@ package io.lenses.connect.secrets.providers import io.lenses.connect.secrets.config.ENVProviderConfig -import io.lenses.connect.secrets.connect.{ - FILE_DIR, - decode, - decodeToBytes, - fileWriter -} +import io.lenses.connect.secrets.connect.FILE_DIR +import io.lenses.connect.secrets.connect.decode +import io.lenses.connect.secrets.connect.decodeToBytes +import io.lenses.connect.secrets.connect.fileWriter import org.apache.kafka.common.config.ConfigData import org.apache.kafka.common.config.provider.ConfigProvider import org.apache.kafka.connect.errors.ConnectException @@ -24,11 +22,11 @@ import scala.jdk.CollectionConverters._ class ENVSecretProvider extends ConfigProvider { var vars = Map.empty[String, String] - var fileDir: String = "" + var fileDir: String = "" private val separator: String = FileSystems.getDefault.getSeparator private val BASE64_FILE = "(ENV-mounted-base64:)(.*$)".r - private val UTF8_FILE = "(ENV-mounted:)(.*$)".r - private val BASE64 = "(ENV-base64:)(.*$)".r + private val UTF8_FILE = "(ENV-mounted:)(.*$)".r + private val BASE64 = "(ENV-base64:)(.*$)".r override def get(path: String): ConfigData = new ConfigData(Map.empty[String, String].asJava) @@ -37,35 +35,33 @@ class ENVSecretProvider extends ConfigProvider { val data = keys.asScala .map { key => - { - val envVarVal = - vars.getOrElse( - key, - throw new ConnectException( - s"Failed to lookup environment variable [$key]" - ) - ) + val envVarVal = + vars.getOrElse( + key, + throw new ConnectException( + s"Failed to lookup environment variable [$key]", + ), + ) - // match the value to see if its coming from contains - // the value metadata pattern - envVarVal match { - case BASE64_FILE(_, v) => - //decode and write to file - val fileName = s"$fileDir$separator${key.toLowerCase}" - fileWriter(fileName, decodeToBytes(key, v), key) - (key, fileName) + // match the value to see if its coming from contains + // the value metadata pattern + envVarVal match { + case BASE64_FILE(_, v) => + //decode and write to file + val fileName = s"$fileDir$separator${key.toLowerCase}" + fileWriter(fileName, decodeToBytes(key, v), key) + (key, fileName) - case UTF8_FILE(_, v) => - val fileName = s"$fileDir$separator${key.toLowerCase}" - fileWriter(fileName, v.getBytes(), key) - (key, fileName) + case UTF8_FILE(_, v) => + val fileName = s"$fileDir$separator${key.toLowerCase}" + fileWriter(fileName, v.getBytes(), key) + (key, fileName) - case BASE64(_, v) => - (key, decode(key, v)) + case BASE64(_, v) => + (key, decode(key, v)) - case _ => - (key, envVarVal) - } + case _ => + (key, envVarVal) } } .toMap diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/VaultHelper.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/VaultHelper.scala index b9fef96..9b06358 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/VaultHelper.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/VaultHelper.scala @@ -6,9 +6,12 @@ package io.lenses.connect.secrets.providers -import com.bettercloud.vault.{SslConfig, Vault, VaultConfig} +import com.bettercloud.vault.SslConfig +import com.bettercloud.vault.Vault +import com.bettercloud.vault.VaultConfig import com.typesafe.scalalogging.StrictLogging -import io.lenses.connect.secrets.config.{VaultAuthMethod, VaultSettings} +import io.lenses.connect.secrets.config.VaultAuthMethod +import io.lenses.connect.secrets.config.VaultSettings import org.apache.kafka.connect.errors.ConnectException import java.io.File @@ -34,7 +37,7 @@ trait VaultHelper extends StrictLogging { val vault = new Vault(config.build()) logger.info( - s"Initializing client with mode [${settings.authMode.toString}]" + s"Initializing client with mode [${settings.authMode.toString}]", ) val token = settings.authMode match { @@ -44,7 +47,7 @@ trait VaultHelper extends StrictLogging { vault .auth() .loginByUserPass(up.username, up.password.value(), up.mount) - .getAuthClientToken + .getAuthClientToken, ) case VaultAuthMethod.APPROLE => @@ -53,7 +56,7 @@ trait VaultHelper extends StrictLogging { vault .auth() .loginByAppRole(ar.role, ar.secretId.value()) - .getAuthClientToken + .getAuthClientToken, ) case VaultAuthMethod.CERT => @@ -70,9 +73,9 @@ trait VaultHelper extends StrictLogging { aws.url, aws.body.value(), aws.headers.value(), - aws.mount + aws.mount, ) - .getAuthClientToken + .getAuthClientToken, ) case VaultAuthMethod.KUBERNETES => @@ -81,7 +84,7 @@ trait VaultHelper extends StrictLogging { vault .auth() .loginByKubernetes(k8s.role, k8s.jwt.value()) - .getAuthClientToken + .getAuthClientToken, ) case VaultAuthMethod.GCP => settings.gcp @@ -89,7 +92,7 @@ trait VaultHelper extends StrictLogging { vault .auth() .loginByGCP(gcp.role, gcp.jwt.value()) - .getAuthClientToken + .getAuthClientToken, ) case VaultAuthMethod.LDAP => @@ -98,7 +101,7 @@ trait VaultHelper extends StrictLogging { vault .auth() .loginByLDAP(l.username, l.password.value(), l.mount) - .getAuthClientToken + .getAuthClientToken, ) case VaultAuthMethod.JWT => @@ -107,7 +110,7 @@ trait VaultHelper extends StrictLogging { vault .auth() .loginByJwt(j.provider, j.role, j.jwt.value()) - .getAuthClientToken + .getAuthClientToken, ) case VaultAuthMethod.TOKEN => @@ -119,12 +122,12 @@ trait VaultHelper extends StrictLogging { vault .auth() .loginByGithub(gh.token.value(), gh.mount) - .getAuthClientToken + .getAuthClientToken, ) case _ => throw new ConnectException( - s"Unsupported auth method [${settings.authMode.toString}]" + s"Unsupported auth method [${settings.authMode.toString}]", ) } @@ -141,7 +144,7 @@ trait VaultHelper extends StrictLogging { logger.info(s"Configuring keystore at [${settings.keystoreLoc}]") ssl.keyStoreFile( new File(settings.keystoreLoc), - settings.keystorePass.value() + settings.keystorePass.value(), ) } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/VaultSecretProvider.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/VaultSecretProvider.scala index 44f2827..2ab1fbb 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/VaultSecretProvider.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/providers/VaultSecretProvider.scala @@ -6,7 +6,8 @@ package io.lenses.connect.secrets.providers -import io.lenses.connect.secrets.config.{VaultProviderConfig, VaultSettings} +import io.lenses.connect.secrets.config.VaultProviderConfig +import io.lenses.connect.secrets.config.VaultSettings import io.lenses.connect.secrets.connect._ import com.bettercloud.vault.Vault import io.lenses.connect.secrets.async.AsyncFunctionLoop @@ -21,12 +22,14 @@ import java.time.OffsetDateTime import java.util import scala.collection.mutable import scala.jdk.CollectionConverters._ -import scala.util.{Failure, Success, Try} +import scala.util.Failure +import scala.util.Success +import scala.util.Try class VaultSecretProvider() extends ConfigProvider with VaultHelper { - private var settings: VaultSettings = _ - private var vaultClient: Option[Vault] = None + private var settings: VaultSettings = _ + private var vaultClient: Option[Vault] = None private var tokenRenewal: Option[AsyncFunctionLoop] = None private val cache = mutable.Map.empty[String, (Option[OffsetDateTime], ConfigData)] @@ -34,11 +37,11 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { // configure the vault client override def configure(configs: util.Map[String, _]): Unit = { - settings = VaultSettings(VaultProviderConfig(configs)) + settings = VaultSettings(VaultProviderConfig(configs)) vaultClient = Some(createClient(settings)) val renewalLoop = new AsyncFunctionLoop(settings.tokenRenewal, "Vault Token Renewal")( - renewToken() + renewToken(), ) tokenRenewal = Some(renewalLoop) renewalLoop.start() @@ -47,9 +50,8 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { def tokenRenewalSuccess: Long = tokenRenewal.map(_.successRate).getOrElse(-1) def tokenRenewalFailure: Long = tokenRenewal.map(_.failureRate).getOrElse(-1) - private def renewToken(): Unit = { - vaultClient.foreach { client => client.auth().renewSelf() } - } + private def renewToken(): Unit = + vaultClient.foreach(client => client.auth().renewSelf()) // lookup secrets at a path override def get(path: String): ConfigData = { @@ -70,9 +72,7 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { getSecretsAndExpiry(getSecrets(path)) } - expiry.foreach(exp => - logger.info(s"Min expiry for TTL set to [${exp.toString}]") - ) + expiry.foreach(exp => logger.info(s"Min expiry for TTL set to [${exp.toString}]")) cache += (path -> (expiry, data)) data } @@ -85,9 +85,11 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { // we have all the keys and are before the expiry val now = OffsetDateTime.now() - if (keys.asScala.subsetOf(data.data().asScala.keySet) && expiresAt - .getOrElse(now.plusSeconds(1)) - .isAfter(now)) { + if ( + keys.asScala.subsetOf(data.data().asScala.keySet) && expiresAt + .getOrElse(now.plusSeconds(1)) + .isAfter(now) + ) { logger.info("Fetching secrets from cache") ( expiresAt, @@ -101,8 +103,8 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { } .toMap .asJava, - data.ttl() - ) + data.ttl(), + ), ) } else { // missing some or expired so reload @@ -117,20 +119,17 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { }.toMap) } - expiry.foreach(exp => - logger.info(s"Min expiry for TTL set to [${exp.toString}]") - ) + expiry.foreach(exp => logger.info(s"Min expiry for TTL set to [${exp.toString}]")) cache += (path -> (expiry, data)) data } - override def close(): Unit = { + override def close(): Unit = tokenRenewal.foreach(_.close()) - } // get the secrets and ttl under a path def getSecrets( - path: String + path: String, ): Map[String, (String, Option[OffsetDateTime])] = { val now = OffsetDateTime.now() @@ -140,7 +139,7 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { case Success(response) => if (response.getRestResponse.getStatus != 200) { throw new ConnectException( - s"No secrets found at path [$path]. Vault response: ${new String(response.getRestResponse.getBody)}" + s"No secrets found at path [$path]. Vault response: ${new String(response.getRestResponse.getBody)}", ) } @@ -151,7 +150,7 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { if (response.getData.isEmpty) { throw new ConnectException( - s"No secrets found at path [$path]" + s"No secrets found at path [$path]", ) } @@ -161,11 +160,11 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { val decoded = decodeKey( encoding = encodingAndId.encoding, - key = k, - value = v, + key = k, + value = v, writeFileFn = { content => fileWriter.write(k.toLowerCase, content, k).toString - } + }, ) (k, (decoded, ttl)) @@ -174,7 +173,7 @@ class VaultSecretProvider() extends ConfigProvider with VaultHelper { case Failure(exception) => throw new ConnectException( s"Failed to fetch secrets from path [$path]", - exception + exception, ) } } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/utils/EncodingAndId.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/utils/EncodingAndId.scala index 3b97e4d..01697d7 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/utils/EncodingAndId.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/utils/EncodingAndId.scala @@ -15,13 +15,13 @@ object EncodingAndId { Encoding.UTF8_FILE, Encoding.BASE64_FILE, Encoding.BASE64, - Encoding.UTF8 + Encoding.UTF8, ) - def from(key: String): EncodingAndId = { + def from(key: String): EncodingAndId = Option(key).map(_.trim).filter(_.nonEmpty).fold(EncodingAndId(None, None)) { value => val encoding = encodingPrioritised - .map { v => v.toString.toLowerCase() -> v } + .map(v => v.toString.toLowerCase() -> v) .collectFirst { case (v, e) if value.toLowerCase.startsWith(v) => e } .map(identity) @@ -32,5 +32,4 @@ object EncodingAndId { } EncodingAndId(encoding, id) } - } } diff --git a/secret-provider/src/main/scala/io/lenses/connect/secrets/utils/WithRetry.scala b/secret-provider/src/main/scala/io/lenses/connect/secrets/utils/WithRetry.scala index 1ac541b..a961269 100644 --- a/secret-provider/src/main/scala/io/lenses/connect/secrets/utils/WithRetry.scala +++ b/secret-provider/src/main/scala/io/lenses/connect/secrets/utils/WithRetry.scala @@ -7,15 +7,18 @@ package io.lenses.connect.secrets.utils import scala.annotation.tailrec import scala.concurrent.duration.FiniteDuration -import scala.util.{Failure, Success, Try} +import scala.util.Failure +import scala.util.Success +import scala.util.Try trait WithRetry { @tailrec protected final def withRetry[T]( - retry: Int = 5, - interval: Option[FiniteDuration] - )(thunk: => T): T = + retry: Int = 5, + interval: Option[FiniteDuration], + )(thunk: => T, + ): T = Try { thunk } match { diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/async/AsyncFunctionLoopTest.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/async/AsyncFunctionLoopTest.scala index d0b0c22..5e0f452 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/async/AsyncFunctionLoopTest.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/async/AsyncFunctionLoopTest.scala @@ -9,15 +9,16 @@ package io.lenses.connect.secrets.async import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import java.util.concurrent.{CountDownLatch, TimeUnit} +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit import scala.concurrent.duration.DurationInt class AsyncFunctionLoopTest extends AnyFunSuite with Matchers { test("it loops 5 times in 10 seconds with 2s delay") { val countDownLatch = new CountDownLatch(5) - val looper = new AsyncFunctionLoop(2.seconds, "test")({ - countDownLatch.countDown() - }) + val looper = new AsyncFunctionLoop(2.seconds, "test")( + countDownLatch.countDown(), + ) looper.start() countDownLatch.await(11000, TimeUnit.MILLISECONDS) shouldBe true looper.close() diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/io/FileWriterOnceTest.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/io/FileWriterOnceTest.scala index e86c306..9ac7726 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/io/FileWriterOnceTest.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/io/FileWriterOnceTest.scala @@ -8,22 +8,20 @@ import java.io.File import java.nio.file.Paths import java.util.UUID import scala.io.Source -import scala.util.{Success, Try, Using} +import scala.util.Success +import scala.util.Try +import scala.util.Using -class FileWriterOnceTest - extends AnyFunSuite - with Matchers - with BeforeAndAfterAll { +class FileWriterOnceTest extends AnyFunSuite with Matchers with BeforeAndAfterAll { private val folder = new File(UUID.randomUUID().toString) folder.deleteOnExit() private val writer = new FileWriterOnce(folder.toPath) - override protected def beforeAll(): Unit = { + override protected def beforeAll(): Unit = folder.mkdir() - } override protected def afterAll(): Unit = { - folder.listFiles().foreach { f => Try(f.delete()) } + folder.listFiles().foreach(f => Try(f.delete())) folder.delete() } diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AWSSecretProviderTest.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AWSSecretProviderTest.scala index a568daf..0bf5e0e 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AWSSecretProviderTest.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AWSSecretProviderTest.scala @@ -10,8 +10,11 @@ import com.amazonaws.services.secretsmanager.AWSSecretsManager import com.amazonaws.services.secretsmanager.model._ import com.bettercloud.vault.json.JsonObject import io.lenses.connect.secrets.TmpDirUtil.getTempDir -import io.lenses.connect.secrets.config.{AWSProviderConfig, AWSProviderSettings} -import io.lenses.connect.secrets.connect.{AuthMode, Encoding, _} +import io.lenses.connect.secrets.config.AWSProviderConfig +import io.lenses.connect.secrets.config.AWSProviderSettings +import io.lenses.connect.secrets.connect.AuthMode +import io.lenses.connect.secrets.connect.Encoding +import io.lenses.connect.secrets.connect._ import io.lenses.connect.secrets.utils.EncodingAndId import org.apache.kafka.common.config.ConfigTransformer import org.apache.kafka.common.config.provider.ConfigProvider @@ -23,25 +26,24 @@ import org.scalatest.wordspec.AnyWordSpec import org.scalatestplus.mockito.MockitoSugar import java.nio.file.FileSystems -import java.util.{Base64, Date} +import java.util.Base64 +import java.util.Date import scala.io.Source import scala.jdk.CollectionConverters._ -import scala.util.{Success, Using} +import scala.util.Success +import scala.util.Using -class AWSSecretProviderTest - extends AnyWordSpec - with Matchers - with MockitoSugar { +class AWSSecretProviderTest extends AnyWordSpec with Matchers with MockitoSugar { val separator: String = FileSystems.getDefault.getSeparator - val tmp: String = s"$getTempDir${separator}provider-tests-aws" + val tmp: String = s"$getTempDir${separator}provider-tests-aws" "should authenticate with credentials" in { val props = Map( - AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AWSProviderConfig.AWS_ACCESS_KEY -> "somekey", AWSProviderConfig.AWS_SECRET_KEY -> "secretkey", - AWSProviderConfig.AWS_REGION -> "someregion" + AWSProviderConfig.AWS_REGION -> "someregion", ).asJava val provider = new AWSSecretProvider() @@ -51,14 +53,14 @@ class AWSSecretProviderTest "should authenticate with credentials and lookup a secret" in { val props = Map( - AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AWSProviderConfig.AWS_ACCESS_KEY -> "somekey", AWSProviderConfig.AWS_SECRET_KEY -> "secretkey", - AWSProviderConfig.AWS_REGION -> "someregion" + AWSProviderConfig.AWS_REGION -> "someregion", ).asJava - val secretKey = "my-secret-key" - val secretName = "my-secret-name" + val secretKey = "my-secret-key" + val secretName = "my-secret-name" val secretValue = "secret-value" val provider = new AWSSecretProvider() @@ -68,11 +70,11 @@ class AWSSecretProviderTest val secretValRequest = new GetSecretValueRequest().withSecretId(secretName) val secretValResponse = new GetSecretValueResult() - val secretJson = new JsonObject().add(secretKey, secretValue) + val secretJson = new JsonObject().add(secretKey, secretValue) secretValResponse.setName(secretName) secretValResponse.setSecretString(secretJson.toString()) - val now = new Date() + val now = new Date() val describeSecretResponse = new DescribeSecretResult() describeSecretResponse.setLastRotatedDate(now) describeSecretResponse.setRotationEnabled(true) @@ -95,14 +97,14 @@ class AWSSecretProviderTest "should authenticate with credentials and lookup a base64 secret" in { val props = Map( - AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AWSProviderConfig.AWS_ACCESS_KEY -> "somekey", AWSProviderConfig.AWS_SECRET_KEY -> "secretkey", - AWSProviderConfig.AWS_REGION -> "someregion" + AWSProviderConfig.AWS_REGION -> "someregion", ).asJava - val secretKey = Encoding.BASE64.toString - val secretName = "my-secret-name" + val secretKey = Encoding.BASE64.toString + val secretName = "my-secret-name" val secretValue = "base64-secret-value" val provider = new AWSSecretProvider() @@ -115,11 +117,11 @@ class AWSSecretProviderTest secretValResponse.setName(secretName) val secretJson = new JsonObject().add( secretKey, - Base64.getEncoder.encodeToString(secretValue.getBytes) + Base64.getEncoder.encodeToString(secretValue.getBytes), ) secretValResponse.setSecretString(secretJson.toString) - val now = new Date() + val now = new Date() val describeSecretResponse = new DescribeSecretResult() describeSecretResponse.setLastRotatedDate(now) describeSecretResponse.setRotationEnabled(true) @@ -144,15 +146,15 @@ class AWSSecretProviderTest "should authenticate with credentials and lookup a base64 secret and write to file" in { val props = Map( - AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AWSProviderConfig.AWS_ACCESS_KEY -> "somekey", AWSProviderConfig.AWS_SECRET_KEY -> "secretkey", - AWSProviderConfig.AWS_REGION -> "someregion", - FILE_DIR -> tmp + AWSProviderConfig.AWS_REGION -> "someregion", + FILE_DIR -> tmp, ).asJava - val secretKey = Encoding.BASE64_FILE.toString - val secretName = "my-secret-name" + val secretKey = Encoding.BASE64_FILE.toString + val secretName = "my-secret-name" val secretValue = "base64-secret-value" val provider = new AWSSecretProvider() @@ -165,11 +167,11 @@ class AWSSecretProviderTest secretValResponse.setName(secretName) val secretJson = new JsonObject().add( secretKey, - Base64.getEncoder.encodeToString("base64-secret-value".getBytes) + Base64.getEncoder.encodeToString("base64-secret-value".getBytes), ) secretValResponse.setSecretString(secretJson.toString) - val now = new Date() + val now = new Date() val describeSecretResponse = new DescribeSecretResult() describeSecretResponse.setLastRotatedDate(now) describeSecretResponse.setRotationEnabled(true) @@ -185,12 +187,12 @@ class AWSSecretProviderTest .thenReturn(secretValResponse) provider.client = Some(mockClient) - val data = provider.get(secretName, Set(secretKey).asJava) + val data = provider.get(secretName, Set(secretKey).asJava) val outputFile = data.data().get(secretKey) outputFile shouldBe s"$tmp$separator$secretName$separator${secretKey.toLowerCase}" Using(Source.fromFile(outputFile))(_.getLines().mkString) shouldBe Success( - secretValue + secretValue, ) provider.get("").data().isEmpty shouldBe true @@ -199,16 +201,16 @@ class AWSSecretProviderTest "should authenticate with credentials and lookup a utf8 secret and write to file" in { val props = Map( - AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AWSProviderConfig.AWS_ACCESS_KEY -> "somekey", AWSProviderConfig.AWS_SECRET_KEY -> "secretkey", - AWSProviderConfig.AWS_REGION -> "someregion", - FILE_DIR -> tmp + AWSProviderConfig.AWS_REGION -> "someregion", + FILE_DIR -> tmp, ).asJava val secretKey = s"${Encoding.UTF8_FILE}${EncodingAndId.Separator}my-secret-key" - val secretName = "my-secret-name" + val secretName = "my-secret-name" val secretValue = "utf8-secret-value" val provider = new AWSSecretProvider() @@ -221,11 +223,11 @@ class AWSSecretProviderTest secretValResponse.setName(secretName) val secretJson = new JsonObject().add( secretKey, - secretValue + secretValue, ) secretValResponse.setSecretString(secretJson.toString) - val now = new Date() + val now = new Date() val describeSecretResponse = new DescribeSecretResult() describeSecretResponse.setLastRotatedDate(now) describeSecretResponse.setRotationEnabled(true) @@ -241,12 +243,12 @@ class AWSSecretProviderTest .thenReturn(secretValResponse) provider.client = Some(mockClient) - val data = provider.get(secretName, Set(secretKey).asJava) + val data = provider.get(secretName, Set(secretKey).asJava) val outputFile = data.data().get(secretKey) outputFile shouldBe s"$tmp$separator$secretName$separator${secretKey.toLowerCase}" Using(Source.fromFile(outputFile))(_.getLines().mkString) shouldBe Success( - secretValue + secretValue, ) provider.get("").data().isEmpty shouldBe true @@ -259,11 +261,11 @@ class AWSSecretProviderTest AWSProviderSettings( AWSProviderConfig( Map( - AWSProviderConfig.AWS_REGION -> "someregion", - AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, - AWSProviderConfig.AWS_SECRET_KEY -> "secretId" - ).asJava - ) + AWSProviderConfig.AWS_REGION -> "someregion", + AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AWSProviderConfig.AWS_SECRET_KEY -> "secretId", + ).asJava, + ), ) } } @@ -274,30 +276,30 @@ class AWSSecretProviderTest AWSProviderSettings( AWSProviderConfig( Map( - AWSProviderConfig.AWS_REGION -> "someregion", - AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, - AWSProviderConfig.AWS_ACCESS_KEY -> "someclientid" - ).asJava - ) + AWSProviderConfig.AWS_REGION -> "someregion", + AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AWSProviderConfig.AWS_ACCESS_KEY -> "someclientid", + ).asJava, + ), ) } } "should check transformer" in { - val secretKey = s"my-secret-key" - val secretName = "my-secret-name" + val secretKey = s"my-secret-key" + val secretName = "my-secret-name" val secretValue = "utf8-secret-value" val mockClient = mock[AWSSecretsManager] val secretValRequest = new GetSecretValueRequest().withSecretId(secretName) val secretValResponse = new GetSecretValueResult() - val secretJson = new JsonObject().add(secretKey, secretValue) + val secretJson = new JsonObject().add(secretKey, secretValue) secretValResponse.setName(secretName) secretValResponse.setSecretString(secretJson.toString()) - val now = new Date() + val now = new Date() val describeSecretResponse = new DescribeSecretResult() describeSecretResponse.setLastRotatedDate(now) describeSecretResponse.setRotationEnabled(true) @@ -313,10 +315,10 @@ class AWSSecretProviderTest .thenReturn(secretValResponse) val props = Map( - AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AWSProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AWSProviderConfig.AWS_ACCESS_KEY -> "somekey", AWSProviderConfig.AWS_SECRET_KEY -> "secretkey", - AWSProviderConfig.AWS_REGION -> "someregion" + AWSProviderConfig.AWS_REGION -> "someregion", ).asJava val provider = new AWSSecretProvider() diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/Aes256DecodingHelperTest.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/Aes256DecodingHelperTest.scala index 4e313de..ece0826 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/Aes256DecodingHelperTest.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/Aes256DecodingHelperTest.scala @@ -9,10 +9,7 @@ import java.util.UUID.randomUUID import scala.util.Random.nextString import scala.util.Success -class Aes256DecodingHelperTest - extends AnyWordSpec - with Matchers - with TableDrivenPropertyChecks { +class Aes256DecodingHelperTest extends AnyWordSpec with Matchers with TableDrivenPropertyChecks { import AesDecodingTestHelper.encrypt @@ -34,7 +31,7 @@ class Aes256DecodingHelperTest "decrypt encrypted text" in new TestContext { forAll(inputs) { text: String => - val aes256 = newEncryption(key) + val aes256 = newEncryption(key) val encrypted = encrypt(text, key) aes256.decrypt(encrypted) shouldBe Success(text) @@ -43,7 +40,7 @@ class Aes256DecodingHelperTest "decrypt same text prefixed with different initialization vector" in new TestContext { forAll(inputs) { text: String => - val aes256 = newEncryption(key) + val aes256 = newEncryption(key) val encrypted1 = encrypt(text, key) val encrypted2 = encrypt(text, key) removePrefix(encrypted1) should not be removePrefix(encrypted2) @@ -65,7 +62,7 @@ class Aes256DecodingHelperTest nextString(length = 10), nextString(length = 100), nextString(length = 1000), - nextString(length = 10000) + nextString(length = 10000), ) def removePrefix(s: String) = diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/Aes256DecodingProviderTest.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/Aes256DecodingProviderTest.scala index 7f8e187..43385e5 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/Aes256DecodingProviderTest.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/Aes256DecodingProviderTest.scala @@ -1,10 +1,12 @@ package io.lenses.connect.secrets.providers import io.lenses.connect.secrets.config.Aes256ProviderConfig -import io.lenses.connect.secrets.connect.{Encoding, FILE_DIR} +import io.lenses.connect.secrets.connect.Encoding +import io.lenses.connect.secrets.connect.FILE_DIR import io.lenses.connect.secrets.utils.EncodingAndId import org.apache.kafka.common.config.provider.ConfigProvider -import org.apache.kafka.common.config.{ConfigException, ConfigTransformer} +import org.apache.kafka.common.config.ConfigException +import org.apache.kafka.common.config.ConfigTransformer import org.apache.kafka.connect.errors.ConnectException import org.scalatest.matchers.should.Matchers import org.scalatest.prop.TableDrivenPropertyChecks @@ -17,17 +19,15 @@ import java.util.Base64 import java.util.UUID.randomUUID import scala.io.Source import scala.jdk.CollectionConverters._ -import scala.util.{Random, Success, Using} +import scala.util.Random +import scala.util.Success +import scala.util.Using -class Aes256DecodingProviderTest - extends AnyWordSpec - with TableDrivenPropertyChecks - with Matchers { +class Aes256DecodingProviderTest extends AnyWordSpec with TableDrivenPropertyChecks with Matchers { import AesDecodingTestHelper.encrypt "aes256 provider" should { - "decrypt aes 256 utf-8 encoded value" in new TestContext - with ConfiguredProvider { + "decrypt aes 256 utf-8 encoded value" in new TestContext with ConfiguredProvider { val encrypted = encrypt(value, key) forAll(Table("encoding", "", "utf-8")) { encoding => @@ -38,8 +38,7 @@ class Aes256DecodingProviderTest } } - "decrypt aes 256 base64 encoded value" in new TestContext - with ConfiguredProvider { + "decrypt aes 256 base64 encoded value" in new TestContext with ConfiguredProvider { val encrypted = encrypt(Base64.getEncoder.encodeToString(value.getBytes()), key) @@ -49,8 +48,7 @@ class Aes256DecodingProviderTest decrypted.get(encrypted) shouldBe Some(value) } - "decrypt aes 256 encoded value stored in file with utf-8 encoding" in new TestContext - with ConfiguredProvider { + "decrypt aes 256 encoded value stored in file with utf-8 encoding" in new TestContext with ConfiguredProvider { val encrypted = encrypt(value, key) val providerData = provider @@ -62,21 +60,20 @@ class Aes256DecodingProviderTest decryptedPath should startWith(s"$tmpDir/secrets/") decryptedPath.toLowerCase.contains(encrypted.toLowerCase) shouldBe false Using(Source.fromFile(decryptedPath))(_.getLines().mkString) shouldBe Success( - value + value, ) } - "decrypt aes 256 encoded value stored in file with base64 encoding" in new TestContext - with ConfiguredProvider { + "decrypt aes 256 encoded value stored in file with base64 encoding" in new TestContext with ConfiguredProvider { val bytesAmount = 100 - val bytesInput = Array.fill[Byte](bytesAmount)(0) + val bytesInput = Array.fill[Byte](bytesAmount)(0) Random.nextBytes(bytesInput) val encrypted = encrypt(Base64.getEncoder.encodeToString(bytesInput), key) val providerData = provider .get( s"${Encoding.BASE64_FILE}${EncodingAndId.Separator}fileId1", - Set(encrypted).asJava + Set(encrypted).asJava, ) .data() .asScala @@ -91,15 +88,15 @@ class Aes256DecodingProviderTest } "transform value referencing to the provider" in new TestContext { - val value = "hi!" + val value = "hi!" val encrypted = encrypt(value, key) provider.configure(config) val transformer = new ConfigTransformer( - Map[String, ConfigProvider]("aes256" -> provider).asJava + Map[String, ConfigProvider]("aes256" -> provider).asJava, ) val props = Map("mykey" -> ("$" + s"{aes256::$encrypted}")).asJava - val data = transformer.transform(props) + val data = transformer.transform(props) data.data().containsKey(encrypted) data.data().get("mykey") shouldBe value } @@ -135,8 +132,8 @@ class Aes256DecodingProviderTest provider.configure( Map( Aes256ProviderConfig.SECRET_KEY -> "too-short", - FILE_DIR -> "/tmp" - ).asJava + FILE_DIR -> "/tmp", + ).asJava, ) } } @@ -165,7 +162,7 @@ class Aes256DecodingProviderTest val provider = new Aes256DecodingProvider() val config: util.Map[String, String] = Map( Aes256ProviderConfig.SECRET_KEY -> key, - FILE_DIR -> tmpDir + FILE_DIR -> tmpDir, ).asJava } @@ -175,6 +172,6 @@ class Aes256DecodingProviderTest "utf8", "utf_file", "base64", - "base64_file" + "base64_file", ) } diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AesDecodingTestHelper.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AesDecodingTestHelper.scala index 6a957d0..6097d58 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AesDecodingTestHelper.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AesDecodingTestHelper.scala @@ -4,7 +4,8 @@ import io.lenses.connect.secrets.providers.Aes256DecodingHelper.INITIALISATION_V import java.util.Base64 import javax.crypto.Cipher -import javax.crypto.spec.{IvParameterSpec, SecretKeySpec} +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.SecretKeySpec import scala.util.Try object AesDecodingTestHelper { @@ -15,26 +16,26 @@ object AesDecodingTestHelper { encryptBytes(s.getBytes("UTF-8"), iv, key) .map(encrypted => base64Encode(iv.bytes) + INITIALISATION_VECTOR_SEPARATOR + base64Encode( - encrypted - ) + encrypted, + ), ) .get } private def encryptBytes( - bytes: Array[Byte], - iv: InitializationVector, - key: String + bytes: Array[Byte], + iv: InitializationVector, + key: String, ): Try[Array[Byte]] = for { - cipher <- getCipher(Cipher.ENCRYPT_MODE, iv, key) + cipher <- getCipher(Cipher.ENCRYPT_MODE, iv, key) encrypted <- Try(cipher.doFinal(bytes)) } yield encrypted private def getCipher( - mode: Int, - iv: InitializationVector, - key: String + mode: Int, + iv: InitializationVector, + key: String, ): Try[Cipher] = Try { val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AzureSecretProviderTest.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AzureSecretProviderTest.scala index 3ae7696..490ab20 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AzureSecretProviderTest.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/AzureSecretProviderTest.scala @@ -7,19 +7,16 @@ package io.lenses.connect.secrets.providers import com.azure.security.keyvault.secrets.SecretClient -import com.azure.security.keyvault.secrets.models.{ - KeyVaultSecret, - SecretProperties -} +import com.azure.security.keyvault.secrets.models.KeyVaultSecret +import com.azure.security.keyvault.secrets.models.SecretProperties import io.lenses.connect.secrets.TmpDirUtil.getTempDir -import io.lenses.connect.secrets.config.{ - AzureProviderConfig, - AzureProviderSettings -} +import io.lenses.connect.secrets.config.AzureProviderConfig +import io.lenses.connect.secrets.config.AzureProviderSettings import io.lenses.connect.secrets.connect import io.lenses.connect.secrets.connect.AuthMode import org.apache.kafka.common.config.provider.ConfigProvider -import org.apache.kafka.common.config.{ConfigData, ConfigTransformer} +import org.apache.kafka.common.config.ConfigData +import org.apache.kafka.common.config.ConfigTransformer import org.apache.kafka.connect.errors.ConnectException import org.mockito.Mockito.when import org.scalatestplus.mockito.MockitoSugar @@ -31,12 +28,10 @@ import java.time.OffsetDateTime import java.util.Base64 import scala.io.Source import scala.jdk.CollectionConverters._ -import scala.util.{Success, Using} +import scala.util.Success +import scala.util.Using -class AzureSecretProviderTest - extends AnyWordSpec - with Matchers - with MockitoSugar { +class AzureSecretProviderTest extends AnyWordSpec with Matchers with MockitoSugar { val separator: String = FileSystems.getDefault.getSeparator val tmp: String = @@ -44,24 +39,24 @@ class AzureSecretProviderTest "should get secrets at a path with service principal credentials" in { val props = Map( - AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid", - AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid" + AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid", ).asJava val provider = new AzureSecretProvider provider.configure(props) - val secretKey = "my-key" + val secretKey = "my-key" val secretValue = "secret-value" - val secretPath = "my-path.vault.azure.net" + val secretPath = "my-path.vault.azure.net" val client = mock[SecretClient] when(client.getVaultUrl).thenReturn(s"https://$secretPath") - val secret = mock[KeyVaultSecret] + val secret = mock[KeyVaultSecret] val secretProperties = mock[SecretProperties] - val offset = OffsetDateTime.now() + val offset = OffsetDateTime.now() // string secret when(secretProperties.getExpiresOn).thenReturn(offset) @@ -81,34 +76,34 @@ class AzureSecretProviderTest "should get base64 secrets at a path with service principal credentials" in { val props = Map( - AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid", - AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid" + AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid", ).asJava val provider = new AzureSecretProvider provider.configure(props) - val secretKey = "base64-key" + val secretKey = "base64-key" val secretValue = "base64-secret-value" - val secretPath = "my-path.vault.azure.net" + val secretPath = "my-path.vault.azure.net" val client = mock[SecretClient] when(client.getVaultUrl).thenReturn(s"https://$secretPath") //base64 secret - val secretb64 = mock[KeyVaultSecret] + val secretb64 = mock[KeyVaultSecret] val secretPropertiesb64 = mock[SecretProperties] - val ttl = OffsetDateTime.now() + val ttl = OffsetDateTime.now() when(secretPropertiesb64.getExpiresOn).thenReturn(ttl) when(secretPropertiesb64.getTags) .thenReturn( - Map(connect.FILE_ENCODING -> connect.Encoding.BASE64.toString).asJava + Map(connect.FILE_ENCODING -> connect.Encoding.BASE64.toString).asJava, ) when(secretb64.getValue).thenReturn( - Base64.getEncoder.encodeToString(secretValue.getBytes) + Base64.getEncoder.encodeToString(secretValue.getBytes), ) when(secretb64.getProperties).thenReturn(secretPropertiesb64) when(client.getSecret(secretKey)).thenReturn(secretb64) @@ -124,34 +119,34 @@ class AzureSecretProviderTest "should get base64 secrets and write to file" in { val props = Map( - AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid", AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid", - connect.FILE_DIR -> tmp + connect.FILE_DIR -> tmp, ).asJava val provider = new AzureSecretProvider provider.configure(props) - val secretKey = "base64-key" + val secretKey = "base64-key" val secretValue = "base64-secret-value" - val secretPath = "my-path.vault.azure.net" + val secretPath = "my-path.vault.azure.net" val client = mock[SecretClient] when(client.getVaultUrl).thenReturn(s"https://$secretPath") //base64 secret - val secretb64 = mock[KeyVaultSecret] + val secretb64 = mock[KeyVaultSecret] val secretPropertiesb64 = mock[SecretProperties] - val ttl = OffsetDateTime.now() + val ttl = OffsetDateTime.now() when(secretPropertiesb64.getExpiresOn).thenReturn(ttl) when(secretPropertiesb64.getTags) .thenReturn( - Map(connect.FILE_ENCODING -> connect.Encoding.BASE64_FILE.toString).asJava + Map(connect.FILE_ENCODING -> connect.Encoding.BASE64_FILE.toString).asJava, ) when(secretb64.getValue).thenReturn( - Base64.getEncoder.encodeToString(secretValue.getBytes) + Base64.getEncoder.encodeToString(secretValue.getBytes), ) when(secretb64.getProperties).thenReturn(secretPropertiesb64) when(client.getSecret(secretKey)).thenReturn(secretb64) @@ -159,13 +154,13 @@ class AzureSecretProviderTest // poke in the mocked client provider.clientMap += (s"https://$secretPath" -> client) - val data = provider.get(secretPath, Set(secretKey).asJava) + val data = provider.get(secretPath, Set(secretKey).asJava) val outputFile = data.data().get(secretKey) outputFile shouldBe s"$tmp$separator$secretPath$separator$secretKey" Using(Source.fromFile(outputFile))(_.getLines().mkString) shouldBe Success( - secretValue + secretValue, ) provider.get("").data().isEmpty shouldBe true @@ -174,31 +169,31 @@ class AzureSecretProviderTest "should get utf secrets and write to file" in { val props = Map( - AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid", AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid", - connect.FILE_DIR -> tmp + connect.FILE_DIR -> tmp, ).asJava val provider = new AzureSecretProvider provider.configure(props) - val secretKey = "utf8-key" + val secretKey = "utf8-key" val secretValue = "utf8-secret-value" - val secretPath = "my-path.vault.azure.net" + val secretPath = "my-path.vault.azure.net" val client = mock[SecretClient] when(client.getVaultUrl).thenReturn(s"https://$secretPath") - val secret = mock[KeyVaultSecret] + val secret = mock[KeyVaultSecret] val secretProperties = mock[SecretProperties] - val ttl = OffsetDateTime.now() + val ttl = OffsetDateTime.now() when(secretProperties.getExpiresOn).thenReturn(ttl) when(secretProperties.getTags) .thenReturn( - Map(connect.FILE_ENCODING -> connect.Encoding.UTF8_FILE.toString).asJava + Map(connect.FILE_ENCODING -> connect.Encoding.UTF8_FILE.toString).asJava, ) when(secret.getValue).thenReturn(secretValue) when(secret.getProperties).thenReturn(secretProperties) @@ -207,13 +202,13 @@ class AzureSecretProviderTest // poke in the mocked client provider.clientMap += (s"https://$secretPath" -> client) - val data = provider.get(secretPath, Set(secretKey).asJava) + val data = provider.get(secretPath, Set(secretKey).asJava) val outputFile = data.data().get(secretKey) outputFile shouldBe s"$tmp$separator$secretPath$separator$secretKey" Using(Source.fromFile(outputFile))(_.getLines().mkString) shouldBe Success( - secretValue + secretValue, ) provider.get("").data().isEmpty shouldBe true @@ -222,17 +217,17 @@ class AzureSecretProviderTest "should use cache" in { val props = Map( - AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid", AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid", - connect.FILE_DIR -> tmp + connect.FILE_DIR -> tmp, ).asJava val provider = new AzureSecretProvider provider.configure(props) - val secretKey = "utf8-key" + val secretKey = "utf8-key" val secretPath = "my-path.vault.azure.net" val client = mock[SecretClient] @@ -240,9 +235,9 @@ class AzureSecretProviderTest // poke in the mocked client provider.clientMap += (s"https://$secretPath" -> client) - val now = OffsetDateTime.now().plusMinutes(10) + val now = OffsetDateTime.now().plusMinutes(10) val cachedData = new ConfigData(Map(secretKey -> secretPath).asJava) - val cached = (Some(now), cachedData) + val cached = (Some(now), cachedData) // add to cache provider.cache += (s"https://$secretPath" -> cached) @@ -252,32 +247,32 @@ class AzureSecretProviderTest "should use not cache because of expiry" in { val props = Map( - AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid", AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid", - connect.FILE_DIR -> tmp + connect.FILE_DIR -> tmp, ).asJava val provider = new AzureSecretProvider provider.configure(props) - val secretKey = "utf8-key" + val secretKey = "utf8-key" val secretValue = "utf8-secret-value" - val secretPath = "my-path.vault.azure.net" - val vaultUrl = s"https://$secretPath" + val secretPath = "my-path.vault.azure.net" + val vaultUrl = s"https://$secretPath" val client = mock[SecretClient] when(client.getVaultUrl).thenReturn(s"https://$secretPath") - val secret = mock[KeyVaultSecret] + val secret = mock[KeyVaultSecret] val secretProperties = mock[SecretProperties] - val ttl = OffsetDateTime.now().plusHours(1) + val ttl = OffsetDateTime.now().plusHours(1) when(secretProperties.getExpiresOn).thenReturn(ttl) when(secretProperties.getTags) .thenReturn( - Map(connect.FILE_ENCODING -> connect.Encoding.UTF8_FILE.toString).asJava + Map(connect.FILE_ENCODING -> connect.Encoding.UTF8_FILE.toString).asJava, ) when(secret.getValue).thenReturn(secretValue) when(secret.getProperties).thenReturn(secretProperties) @@ -287,9 +282,9 @@ class AzureSecretProviderTest // poke in the mocked client provider.clientMap += (vaultUrl -> client) //put expiry of cache 1 second behind - val now = OffsetDateTime.now().minusSeconds(1) + val now = OffsetDateTime.now().minusSeconds(1) val cachedData = new ConfigData(Map(secretKey -> secretPath).asJava) - val cached = (Some(now), cachedData) + val cached = (Some(now), cachedData) // add to cache provider.cache += (vaultUrl -> cached) @@ -301,32 +296,32 @@ class AzureSecretProviderTest "should use not cache because of different keys" in { val props = Map( - AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid", AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid", - connect.FILE_DIR -> tmp + connect.FILE_DIR -> tmp, ).asJava val provider = new AzureSecretProvider provider.configure(props) - val secretKey = "utf8-key" + val secretKey = "utf8-key" val secretValue = "utf8-secret-value" - val secretPath = "my-path.vault.azure.net" - val vaultUrl = s"https://$secretPath" + val secretPath = "my-path.vault.azure.net" + val vaultUrl = s"https://$secretPath" val client = mock[SecretClient] when(client.getVaultUrl).thenReturn(s"https://$secretPath") - val secret = mock[KeyVaultSecret] + val secret = mock[KeyVaultSecret] val secretProperties = mock[SecretProperties] - val ttl = OffsetDateTime.now().plusHours(1) + val ttl = OffsetDateTime.now().plusHours(1) when(secretProperties.getExpiresOn).thenReturn(ttl) when(secretProperties.getTags) .thenReturn( - Map(connect.FILE_ENCODING -> connect.Encoding.UTF8_FILE.toString).asJava + Map(connect.FILE_ENCODING -> connect.Encoding.UTF8_FILE.toString).asJava, ) when(secret.getValue).thenReturn(secretValue) when(secret.getProperties).thenReturn(secretProperties) @@ -336,9 +331,9 @@ class AzureSecretProviderTest // poke in the mocked client provider.clientMap += (vaultUrl -> client) //put expiry of cache 1 second behind - val now = OffsetDateTime.now() + val now = OffsetDateTime.now() val cachedData = new ConfigData(Map("old-key" -> secretPath).asJava) - val cached = (Some(now), cachedData) + val cached = (Some(now), cachedData) // add to cache provider.cache += (vaultUrl -> cached) @@ -351,8 +346,8 @@ class AzureSecretProviderTest intercept[ConnectException] { AzureProviderSettings( AzureProviderConfig( - Map(AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString).asJava - ) + Map(AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString).asJava, + ), ) } } @@ -363,10 +358,10 @@ class AzureSecretProviderTest AzureProviderSettings( AzureProviderConfig( Map( - AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, - AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid" - ).asJava - ) + AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", + ).asJava, + ), ) } } @@ -377,11 +372,11 @@ class AzureSecretProviderTest AzureProviderSettings( AzureProviderConfig( Map( - AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, + AzureProviderConfig.AUTH_METHOD -> AuthMode.CREDENTIALS.toString, AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", - AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid" - ).asJava - ) + AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid", + ).asJava, + ), ) } } @@ -390,8 +385,8 @@ class AzureSecretProviderTest val settings = AzureProviderSettings( AzureProviderConfig( - Map(AzureProviderConfig.AUTH_METHOD -> AuthMode.DEFAULT.toString).asJava - ) + Map(AzureProviderConfig.AUTH_METHOD -> AuthMode.DEFAULT.toString).asJava, + ), ) settings.authMode shouldBe AuthMode.DEFAULT @@ -401,19 +396,19 @@ class AzureSecretProviderTest val props1 = Map( AzureProviderConfig.AZURE_CLIENT_ID -> "someclientid", AzureProviderConfig.AZURE_TENANT_ID -> "sometenantid", - AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid" + AzureProviderConfig.AZURE_SECRET_ID -> "somesecretid", ).asJava - val secretKey = "key-1" + val secretKey = "key-1" val secretValue = "utf8-secret-value" - val secretPath = "my-path.vault.azure.net" + val secretPath = "my-path.vault.azure.net" val client = mock[SecretClient] when(client.getVaultUrl).thenReturn(s"https://$secretPath") - val secret = mock[KeyVaultSecret] + val secret = mock[KeyVaultSecret] val secretProperties = mock[SecretProperties] - val offset = OffsetDateTime.now() + val offset = OffsetDateTime.now() // string secret when(secretProperties.getExpiresOn).thenReturn(offset) diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/DecodeTest.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/DecodeTest.scala index 95794b7..14b37d2 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/DecodeTest.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/DecodeTest.scala @@ -29,33 +29,28 @@ class DecodeTest extends AnyWordSpec with Matchers { } "should decode UTF" in { - connect.decodeKey(None, "my-key", "secret", { _ => - fail("No files here") - }) shouldBe "secret" - connect.decodeKey(Some(Encoding.UTF8), "my-key", "secret", { _ => - fail("No files here") - }) shouldBe "secret" + connect.decodeKey(None, "my-key", "secret", _ => fail("No files here")) shouldBe "secret" + connect.decodeKey(Some(Encoding.UTF8), "my-key", "secret", _ => fail("No files here")) shouldBe "secret" } "should decode BASE64" in { val value = Base64.getEncoder.encodeToString("secret".getBytes) - connect.decodeKey(Some(Encoding.BASE64), s"my-key", value, { _ => - fail("No files here") - }) shouldBe "secret" + connect.decodeKey(Some(Encoding.BASE64), s"my-key", value, _ => fail("No files here")) shouldBe "secret" } "should decode BASE64 and write to a file" in { val fileName = s"${tmp}my-file-base64" - val value = Base64.getEncoder.encodeToString("secret".getBytes) + val value = Base64.getEncoder.encodeToString("secret".getBytes) var written = false connect.decodeKey( Some(Encoding.BASE64_FILE), s"my-key", - value, { _ => + value, + { _ => written = true fileName - } + }, ) shouldBe fileName written shouldBe true } @@ -65,16 +60,17 @@ class DecodeTest extends AnyWordSpec with Matchers { val jksFile: String = getClass.getClassLoader.getResource("keystore.jks").getPath val fileContent = FileUtils.readFileToByteArray(new File(jksFile)) - val jksEncoded = Base64.getEncoder.encodeToString(fileContent) + val jksEncoded = Base64.getEncoder.encodeToString(fileContent) var written = false connect.decodeKey( Some(Encoding.BASE64_FILE), s"keystore.jks", - jksEncoded, { _ => + jksEncoded, + { _ => written = true fileName - } + }, ) shouldBe fileName written shouldBe true @@ -82,15 +78,16 @@ class DecodeTest extends AnyWordSpec with Matchers { "should decode UTF8 and write to a file" in { val fileName = s"${tmp}my-file-utf8" - var written = false + var written = false connect.decodeKey( Some(Encoding.UTF8_FILE), s"my-key", - "secret", { _ => + "secret", + { _ => written = true fileName - } + }, ) shouldBe fileName written shouldBe true } @@ -98,9 +95,9 @@ class DecodeTest extends AnyWordSpec with Matchers { "min list test" in { val now = OffsetDateTime.now() val secrets = Map( - "ke3" -> ("value", Some(OffsetDateTime.now().plusHours(3))), + "ke3" -> ("value", Some(OffsetDateTime.now().plusHours(3))), "key1" -> ("value", Some(now)), - "key2" -> ("value", Some(OffsetDateTime.now().plusHours(1))) + "key2" -> ("value", Some(OffsetDateTime.now().plusHours(1))), ) val (expiry, _) = connect.getSecretsAndExpiry(secrets) diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/ENVSecretProviderTest.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/ENVSecretProviderTest.scala index 9a7dbab..1c99baf 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/ENVSecretProviderTest.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/ENVSecretProviderTest.scala @@ -15,7 +15,8 @@ import java.nio.file.FileSystems import java.util.Base64 import scala.io.Source import scala.jdk.CollectionConverters._ -import scala.util.{Success, Using} +import scala.util.Success +import scala.util.Using class ENVSecretProviderTest extends AnyWordSpec with Matchers { @@ -28,11 +29,11 @@ class ENVSecretProviderTest extends AnyWordSpec with Matchers { "should filter and match" in { val provider = new ENVSecretProvider() provider.vars = Map( - "RANDOM" -> "somevalue", + "RANDOM" -> "somevalue", "CONNECT_CASSANDRA_PASSWORD" -> "secret", - "BASE64" -> s"ENV-base64:${Base64.getEncoder.encodeToString("my-base64-secret".getBytes)}", - "BASE64_FILE" -> s"ENV-mounted-base64:${Base64.getEncoder.encodeToString("my-base64-secret".getBytes)}", - "UTF8_FILE" -> s"ENV-mounted:my-secret" + "BASE64" -> s"ENV-base64:${Base64.getEncoder.encodeToString("my-base64-secret".getBytes)}", + "BASE64_FILE" -> s"ENV-mounted-base64:${Base64.getEncoder.encodeToString("my-base64-secret".getBytes)}", + "UTF8_FILE" -> s"ENV-mounted:my-secret", ) provider.fileDir = tmp @@ -48,20 +49,20 @@ class ENVSecretProviderTest extends AnyWordSpec with Matchers { val data3 = provider.get("", Set("BASE64").asJava) data3.data().get("BASE64") shouldBe "my-base64-secret" - val data4 = provider.get("", Set("BASE64_FILE").asJava) + val data4 = provider.get("", Set("BASE64_FILE").asJava) val outputFile = data4.data().get("BASE64_FILE") outputFile shouldBe s"$tmp${separator}base64_file" Using(Source.fromFile(outputFile))(_.getLines().mkString) shouldBe Success( - "my-base64-secret" + "my-base64-secret", ) - val data5 = provider.get("", Set("UTF8_FILE").asJava) + val data5 = provider.get("", Set("UTF8_FILE").asJava) val outputFile5 = data5.data().get("UTF8_FILE") outputFile5 shouldBe s"$tmp${separator}utf8_file" Using(Source.fromFile(outputFile5))(_.getLines().mkString) shouldBe Success( - "my-secret" + "my-secret", ) } diff --git a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/VaultSecretProviderTest.scala b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/VaultSecretProviderTest.scala index a1d82c7..1e440d3 100644 --- a/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/VaultSecretProviderTest.scala +++ b/secret-provider/src/test/scala/io/lenses/connect/secrets/providers/VaultSecretProviderTest.scala @@ -6,17 +6,19 @@ package io.lenses.connect.secrets.providers -import com.bettercloud.vault.json.{JsonArray, JsonObject} -import io.lenses.connect.secrets.TmpDirUtil.{getTempDir, separator} -import io.lenses.connect.secrets.config.{ - VaultAuthMethod, - VaultProviderConfig, - VaultSettings -} +import com.bettercloud.vault.json.JsonArray +import com.bettercloud.vault.json.JsonObject +import io.lenses.connect.secrets.TmpDirUtil.getTempDir +import io.lenses.connect.secrets.TmpDirUtil.separator +import io.lenses.connect.secrets.config.VaultAuthMethod +import io.lenses.connect.secrets.config.VaultProviderConfig +import io.lenses.connect.secrets.config.VaultSettings import io.lenses.connect.secrets.connect -import io.lenses.connect.secrets.vault.{MockVault, VaultTestUtils} +import io.lenses.connect.secrets.vault.MockVault +import io.lenses.connect.secrets.vault.VaultTestUtils import org.apache.kafka.common.config.provider.ConfigProvider -import org.apache.kafka.common.config.{ConfigData, ConfigTransformer} +import org.apache.kafka.common.config.ConfigData +import org.apache.kafka.common.config.ConfigTransformer import org.eclipse.jetty.server.Server import org.scalatest.BeforeAndAfterAll import org.scalatest.matchers.should.Matchers @@ -26,12 +28,10 @@ import java.io.File import java.util.Base64 import scala.io.Source import scala.jdk.CollectionConverters._ -import scala.util.{Success, Using} +import scala.util.Success +import scala.util.Using -class VaultSecretProviderTest - extends AnyWordSpec - with Matchers - with BeforeAndAfterAll { +class VaultSecretProviderTest extends AnyWordSpec with Matchers with BeforeAndAfterAll { val tmp: String = s"$getTempDir${separator}provider-tests-vault" @@ -43,12 +43,12 @@ class VaultSecretProviderTest .add("utf8_file_some_key", "secret-value") .add( "base64_some_key", - Base64.getEncoder.encodeToString("base64-secret-value".getBytes) + Base64.getEncoder.encodeToString("base64-secret-value".getBytes), ) .add( "base64_file_some_key", - Base64.getEncoder.encodeToString("base64-secret-value".getBytes) - ) + Base64.getEncoder.encodeToString("base64-secret-value".getBytes), + ), ) val auth: JsonObject = new JsonObject() @@ -63,7 +63,7 @@ class VaultSecretProviderTest val server: Server = VaultTestUtils.initHttpsMockVault(mockVault) val jksFile: String = getClass.getClassLoader.getResource("keystore.jks").getPath - val pemFile: String = getClass.getClassLoader.getResource("cert.pem").getPath + val pemFile: String = getClass.getClassLoader.getResource("cert.pem").getPath val k8sToken: String = getClass.getClassLoader.getResource("cert.pem").getPath def cleanUp(): AnyVal = { @@ -71,9 +71,8 @@ class VaultSecretProviderTest if (tmpFile.exists) tmpFile.delete() } - override def afterAll(): Unit = { + override def afterAll(): Unit = cleanUp() - } override def beforeAll(): Unit = { cleanUp() @@ -83,14 +82,14 @@ class VaultSecretProviderTest "should renew the token" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, VaultProviderConfig.VAULT_CLIENT_PEM -> pemFile, - VaultProviderConfig.TOKEN_RENEWAL -> "1000" + VaultProviderConfig.TOKEN_RENEWAL -> "1000", ).asJava - val config = VaultProviderConfig(props) + val config = VaultProviderConfig(props) val settings = VaultSettings(config) settings.pem shouldBe pemFile @@ -107,12 +106,12 @@ class VaultSecretProviderTest "should be configured for username and password auth" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.VAULT_PEM -> pemFile, VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.USERPASS.toString, - VaultProviderConfig.USERNAME -> "user", - VaultProviderConfig.PASSWORD -> "password" + VaultProviderConfig.USERNAME -> "user", + VaultProviderConfig.PASSWORD -> "password", ).asJava val settings = VaultSettings(VaultProviderConfig(props)) @@ -121,13 +120,13 @@ class VaultSecretProviderTest "should be configured for ldap auth" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, VaultProviderConfig.VAULT_CLIENT_PEM -> pemFile, - VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.LDAP.toString, - VaultProviderConfig.LDAP_USERNAME -> "username", - VaultProviderConfig.LDAP_PASSWORD -> "password" + VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.LDAP.toString, + VaultProviderConfig.LDAP_USERNAME -> "username", + VaultProviderConfig.LDAP_PASSWORD -> "password", ).asJava val settings = VaultSettings(VaultProviderConfig(props)) @@ -136,14 +135,14 @@ class VaultSecretProviderTest "should be configured for aws auth" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, - VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.AWSIAM.toString, - VaultProviderConfig.AWS_REQUEST_BODY -> "body", + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.AWSIAM.toString, + VaultProviderConfig.AWS_REQUEST_BODY -> "body", VaultProviderConfig.AWS_REQUEST_HEADERS -> "headers", - VaultProviderConfig.AWS_ROLE -> "role", - VaultProviderConfig.AWS_REQUEST_URL -> "url" + VaultProviderConfig.AWS_ROLE -> "role", + VaultProviderConfig.AWS_REQUEST_URL -> "url", ).asJava val settings = VaultSettings(VaultProviderConfig(props)) @@ -152,12 +151,12 @@ class VaultSecretProviderTest "should be configured for gcp auth" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.VAULT_PEM -> pemFile, VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.GCP.toString, - VaultProviderConfig.GCP_ROLE -> "role", - VaultProviderConfig.GCP_JWT -> "jwt" + VaultProviderConfig.GCP_ROLE -> "role", + VaultProviderConfig.GCP_JWT -> "jwt", ).asJava val settings = VaultSettings(VaultProviderConfig(props)) @@ -166,13 +165,13 @@ class VaultSecretProviderTest "should be configured for jwt auth" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, - VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.JWT.toString, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.JWT.toString, VaultProviderConfig.JWT_PROVIDER -> "provider", - VaultProviderConfig.JWT_ROLE -> "role", - VaultProviderConfig.JWT -> "jwt" + VaultProviderConfig.JWT_ROLE -> "role", + VaultProviderConfig.JWT -> "jwt", ).asJava val settings = VaultSettings(VaultProviderConfig(props)) @@ -181,11 +180,11 @@ class VaultSecretProviderTest "should be configured for github auth" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, - VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.GITHUB.toString, - VaultProviderConfig.GITHUB_TOKEN -> "token" + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.GITHUB.toString, + VaultProviderConfig.GITHUB_TOKEN -> "token", ).asJava val settings = VaultSettings(VaultProviderConfig(props)) @@ -194,12 +193,12 @@ class VaultSecretProviderTest "should be configured for kubernetes auth" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, - VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.KUBERNETES.toString, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.KUBERNETES.toString, VaultProviderConfig.KUBERNETES_TOKEN_PATH -> k8sToken, - VaultProviderConfig.KUBERNETES_ROLE -> "role" + VaultProviderConfig.KUBERNETES_ROLE -> "role", ).asJava val settings = VaultSettings(VaultProviderConfig(props)) @@ -208,12 +207,12 @@ class VaultSecretProviderTest "should be configured for approle auth" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, - VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.APPROLE.toString, - VaultProviderConfig.APP_ROLE -> "some-app-role", - VaultProviderConfig.APP_ROLE_SECRET_ID -> "secret" + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.AUTH_METHOD -> VaultAuthMethod.APPROLE.toString, + VaultProviderConfig.APP_ROLE -> "some-app-role", + VaultProviderConfig.APP_ROLE_SECRET_ID -> "secret", ).asJava val settings = VaultSettings(VaultProviderConfig(props)) @@ -222,13 +221,13 @@ class VaultSecretProviderTest "should be configured for ssl with pem" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, - VaultProviderConfig.VAULT_CLIENT_PEM -> pemFile + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.VAULT_CLIENT_PEM -> pemFile, ).asJava - val config = VaultProviderConfig(props) + val config = VaultProviderConfig(props) val settings = VaultSettings(config) settings.pem shouldBe pemFile @@ -241,14 +240,14 @@ class VaultSecretProviderTest "should be configured for ssl with jks" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_KEYSTORE_LOC -> jksFile, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_KEYSTORE_LOC -> jksFile, VaultProviderConfig.VAULT_TRUSTSTORE_LOC -> jksFile, - VaultProviderConfig.VAULT_KEYSTORE_PASS -> "password" + VaultProviderConfig.VAULT_KEYSTORE_PASS -> "password", ).asJava - val config = VaultProviderConfig(props) + val config = VaultProviderConfig(props) val settings = VaultSettings(config) settings.keystoreLoc shouldBe jksFile @@ -262,19 +261,19 @@ class VaultSecretProviderTest "should get values at a path" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, VaultProviderConfig.VAULT_CLIENT_PEM -> pemFile, - connect.FILE_DIR -> tmp + connect.FILE_DIR -> tmp, ).asJava val provider = new VaultSecretProvider() provider.configure(props) - val secretKey = "value" + val secretKey = "value" val secretValue = "mock" - val secretPath = "secret/hello" + val secretPath = "secret/hello" val data: ConfigData = provider.get(secretPath) data.data().get(secretKey) shouldBe secretValue @@ -290,19 +289,19 @@ class VaultSecretProviderTest "should get values at a path for base64" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, VaultProviderConfig.VAULT_CLIENT_PEM -> pemFile, - connect.FILE_DIR -> tmp + connect.FILE_DIR -> tmp, ).asJava val provider = new VaultSecretProvider() provider.configure(props) - val secretKey = "base64_some_key" + val secretKey = "base64_some_key" val secretValue = "base64-secret-value" - val secretPath = "secret/hello" + val secretPath = "secret/hello" val data = provider.get(secretPath, Set(secretKey).asJava) data.data().get(secretKey) shouldBe secretValue @@ -313,19 +312,19 @@ class VaultSecretProviderTest "should get values at a path for base64 file" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, VaultProviderConfig.VAULT_CLIENT_PEM -> pemFile, - connect.FILE_DIR -> tmp + connect.FILE_DIR -> tmp, ).asJava val provider = new VaultSecretProvider() provider.configure(props) - val secretKey = "base64_file_some_key" + val secretKey = "base64_file_some_key" val secretValue = "base64-secret-value" - val secretPath = "secret/hello" + val secretPath = "secret/hello" val data = provider.get(secretPath, Set(secretKey).asJava) val outputFile = data @@ -334,7 +333,7 @@ class VaultSecretProviderTest outputFile shouldBe s"$tmp$separator$secretPath$separator$secretKey" Using(Source.fromFile(outputFile))(_.getLines().mkString) shouldBe Success( - secretValue + secretValue, ) provider.close() @@ -343,19 +342,19 @@ class VaultSecretProviderTest "should get values at a path for utf file" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_PEM -> pemFile, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_PEM -> pemFile, VaultProviderConfig.VAULT_CLIENT_PEM -> pemFile, - connect.FILE_DIR -> tmp + connect.FILE_DIR -> tmp, ).asJava val provider = new VaultSecretProvider() provider.configure(props) - val secretKey = "utf8_file_some_key" + val secretKey = "utf8_file_some_key" val secretValue = "secret-value" - val secretPath = "secret/hello" + val secretPath = "secret/hello" val data = provider.get(secretPath, Set(secretKey).asJava) val outputFile = data @@ -364,7 +363,7 @@ class VaultSecretProviderTest outputFile shouldBe s"$tmp$separator$secretPath$separator$secretKey" Using(Source.fromFile(outputFile))(_.getLines().mkString) shouldBe Success( - secretValue + secretValue, ) provider.close() @@ -373,12 +372,12 @@ class VaultSecretProviderTest "check transformer" in { val props = Map( - VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", - VaultProviderConfig.VAULT_TOKEN -> "mock_token", - VaultProviderConfig.VAULT_KEYSTORE_LOC -> jksFile, + VaultProviderConfig.VAULT_ADDR -> "https://127.0.0.1:9998", + VaultProviderConfig.VAULT_TOKEN -> "mock_token", + VaultProviderConfig.VAULT_KEYSTORE_LOC -> jksFile, VaultProviderConfig.VAULT_TRUSTSTORE_LOC -> jksFile, - VaultProviderConfig.VAULT_KEYSTORE_PASS -> "password", - connect.FILE_DIR -> tmp + VaultProviderConfig.VAULT_KEYSTORE_PASS -> "password", + connect.FILE_DIR -> tmp, ).asJava val provider = new VaultSecretProvider()