diff --git a/src/integrationTest/groovy/wooga/gradle/secrets/SecretsPluginIntegrationSpec.groovy b/src/integrationTest/groovy/wooga/gradle/secrets/SecretsPluginIntegrationSpec.groovy index fcfc3e5..1f0aa6e 100644 --- a/src/integrationTest/groovy/wooga/gradle/secrets/SecretsPluginIntegrationSpec.groovy +++ b/src/integrationTest/groovy/wooga/gradle/secrets/SecretsPluginIntegrationSpec.groovy @@ -169,8 +169,6 @@ class SecretsPluginIntegrationSpec extends SecretsIntegrationSpec { })) } """.stripIndent() - - } } diff --git a/src/main/groovy/wooga/gradle/secrets/SecretResolverFactory.groovy b/src/main/groovy/wooga/gradle/secrets/SecretResolverFactory.groovy new file mode 100644 index 0000000..658677a --- /dev/null +++ b/src/main/groovy/wooga/gradle/secrets/SecretResolverFactory.groovy @@ -0,0 +1,59 @@ +/* + * Copyright 2021 Wooga GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package wooga.gradle.secrets + +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider +import software.amazon.awssdk.profiles.ProfileFile +import software.amazon.awssdk.regions.Region +import wooga.gradle.secrets.internal.AWSSecretsManagerResolver +import wooga.gradle.secrets.internal.EnvironmentResolver +import wooga.gradle.secrets.internal.SecretResolverChain + +trait SecretResolverFactory { + SecretResolver awsSecretResolver(AwsCredentialsProvider credentials, Region region) { + new AWSSecretsManagerResolver(credentials, region) + } + + SecretResolver awsSecretResolver(String profileName, Region region) { + new AWSSecretsManagerResolver(awsCredentialsProvider(profileName), region) + } + + SecretResolver awsSecretResolver(Region region) { + new AWSSecretsManagerResolver(region) + } + + SecretResolver environmentResolver() { + new EnvironmentResolver() + } + + SecretResolver chainResolver(SecretResolver... resolvers) { + chainResolver(resolvers.toList()) + } + + SecretResolver chainResolver(Iterable resolvers) { + new SecretResolverChain(resolvers) + } + + AwsCredentialsProvider awsCredentialsProvider(String profileName) { + awsCredentialsProvider(profileName, ProfileFile.defaultProfileFile()) + } + + AwsCredentialsProvider awsCredentialsProvider(String profileName, ProfileFile profileFile) { + DefaultCredentialsProvider.builder().profileFile(profileFile).profileName(profileName).build() + } +} diff --git a/src/main/groovy/wooga/gradle/secrets/SecretsPlugin.groovy b/src/main/groovy/wooga/gradle/secrets/SecretsPlugin.groovy index 7bead09..b10f6b3 100755 --- a/src/main/groovy/wooga/gradle/secrets/SecretsPlugin.groovy +++ b/src/main/groovy/wooga/gradle/secrets/SecretsPlugin.groovy @@ -20,7 +20,6 @@ import org.apache.commons.lang3.RandomStringUtils import org.gradle.api.Plugin import org.gradle.api.Project import wooga.gradle.secrets.internal.DefaultSecretsPluginExtension -import wooga.gradle.secrets.internal.EnvironmentResolver import wooga.gradle.secrets.tasks.SecretsTask import javax.crypto.SecretKeyFactory diff --git a/src/main/groovy/wooga/gradle/secrets/SecretsPluginExtension.groovy b/src/main/groovy/wooga/gradle/secrets/SecretsPluginExtension.groovy index 023352b..dd716d5 100755 --- a/src/main/groovy/wooga/gradle/secrets/SecretsPluginExtension.groovy +++ b/src/main/groovy/wooga/gradle/secrets/SecretsPluginExtension.groovy @@ -25,7 +25,7 @@ import wooga.gradle.secrets.internal.SecretResolverChain import java.util.logging.Logger -trait SecretsPluginExtension extends SecretSpec { +trait SecretsPluginExtension implements SecretSpec, SecretResolverFactory { static Logger LOGGER = Logger.getLogger(SecretsPluginExtension.class.getName()); @@ -91,4 +91,5 @@ trait SecretsPluginExtension extends SecretSpec { tempFile })) } + } diff --git a/src/test/groovy/wooga/gradle/secrets/SecretsPluginExtensionSpec.groovy b/src/test/groovy/wooga/gradle/secrets/SecretsPluginExtensionSpec.groovy index 18a2b94..c45e059 100644 --- a/src/test/groovy/wooga/gradle/secrets/SecretsPluginExtensionSpec.groovy +++ b/src/test/groovy/wooga/gradle/secrets/SecretsPluginExtensionSpec.groovy @@ -17,6 +17,11 @@ package wooga.gradle.secrets import nebula.test.ProjectSpec +import org.junit.Rule +import org.junit.contrib.java.lang.system.EnvironmentVariables +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider +import software.amazon.awssdk.profiles.ProfileFile +import software.amazon.awssdk.regions.Region import wooga.gradle.secrets.internal.DefaultSecret class SecretsPluginExtensionSpec extends ProjectSpec { @@ -25,6 +30,9 @@ class SecretsPluginExtensionSpec extends ProjectSpec { SecretsPluginExtension subjectUnderTest def resolver = Mock(SecretResolver) + @Rule + EnvironmentVariables environmentVariables + def setup() { project.plugins.apply(PLUGIN_NAME) subjectUnderTest = project.extensions.findByName('secrets') as SecretsPluginExtension @@ -156,4 +164,143 @@ class SecretsPluginExtensionSpec extends ProjectSpec { noExceptionThrown() !present } + + def "security resolver factory method awsSecretResolver with region creates resolver"() { + when: + def resolver = subjectUnderTest.awsSecretResolver(Region.US_EAST_1) + + then: + resolver != null + SecretResolver.class.isAssignableFrom(resolver.class) + } + + def "security resolver factory method awsSecretResolver with profileName and region creates resolver"() { + when: + def resolver = subjectUnderTest.awsSecretResolver("some_profile", Region.US_EAST_1) + + then: + resolver != null + SecretResolver.class.isAssignableFrom(resolver.class) + } + + def "security resolver factory method awsSecretResolver with credentials provider and region creates resolver"() { + when: + def resolver = subjectUnderTest.awsSecretResolver(DefaultCredentialsProvider.builder().build(), Region.US_EAST_1) + + then: + resolver != null + SecretResolver.class.isAssignableFrom(resolver.class) + } + + def "security resolver factory method environmentResolver creates resolver"() { + when: + def resolver = subjectUnderTest.environmentResolver() + + then: + resolver != null + SecretResolver.class.isAssignableFrom(resolver.class) + + } + + def "security resolver factory method chainResolver creates resolver"() { + when: + def resolver = subjectUnderTest.chainResolver() + + then: + resolver != null + SecretResolver.class.isAssignableFrom(resolver.class) + + } + + def "security resolver factory method chainResolver with provided resolvers creates resolver"() { + when: + def resolver = subjectUnderTest.chainResolver(subjectUnderTest.environmentResolver(), subjectUnderTest.awsSecretResolver(Region.CN_NORTH_1)) + + then: + resolver != null + SecretResolver.class.isAssignableFrom(resolver.class) + } + + def "method awsCredentialsProvider creates AwsCredentialsProvider with profileName and profileFile"() { + given: "a custom aws profile file" + def credentialsFile = File.createTempFile("some", "awsprofile") + credentialsFile << """ + [default] + aws_access_key_id = AKIAIOSFODNN7EXAMPLE + aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + + [${awsProfileName}] + aws_access_key_id = ${accessKeyId} + aws_secret_access_key = ${awsSecretAccessKey} + + """.stripIndent() + + def p = ProfileFile.builder().content(credentialsFile.toPath()).type(ProfileFile.Type.CREDENTIALS).build() + def profile = ProfileFile.aggregator().addFile(p).build() + + and: "a clean aws environment" + environmentVariables.clear( + "AWS_ACCESS_KEY_ID", + "AWS_SECRET_ACCESS_KEY", + "AWS_SESSION_TOKEN", + "AWS_CA_Bundle", + "AWS_CONFIG_FILE", + "AWS_SHARED_CREDENTIALS_FILE") + + when: + def credentials = subjectUnderTest.awsCredentialsProvider(awsProfileName, profile) + + then: + credentials != null + def c = credentials.resolveCredentials() + c.accessKeyId() == accessKeyId + c.secretAccessKey() == awsSecretAccessKey + + where: + accessKeyId = 'AKIAIOSFODNN8EXAMPLE' + awsSecretAccessKey = 'wJalrXUtnFEMI/K7MDENG/bPyRfiCYEXAMPLEKEY' + awsProfileName = 'someProfile' + } + + def "method awsCredentialsProvider creates AwsCredentialsProvider with profileName"() { + given: "a custom credentials file" + def credentialsFile = File.createTempFile("some", "awsprofile") + credentialsFile << """ + [default] + aws_access_key_id = AKIAIOSFODNN7EXAMPLE + aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + + [${awsProfileName}] + aws_access_key_id = ${accessKeyId} + aws_secret_access_key = ${awsSecretAccessKey} + + """.stripIndent() + + and: "a clean aws environment" + environmentVariables.clear( + "AWS_ACCESS_KEY_ID", + "AWS_SECRET_ACCESS_KEY", + "AWS_SESSION_TOKEN", + "AWS_CA_Bundle", + "AWS_CONFIG_FILE", + "AWS_SHARED_CREDENTIALS_FILE") + + and: "a new environment value to point to our custom credentials file" + environmentVariables.set("AWS_SHARED_CREDENTIALS_FILE", credentialsFile.absolutePath) + + when: + def credentials = subjectUnderTest.awsCredentialsProvider(awsProfileName) + + then: + credentials != null + def c = credentials.resolveCredentials() + c.accessKeyId() == accessKeyId + c.secretAccessKey() == awsSecretAccessKey + + where: + accessKeyId = 'AKIAIOSFODNN8EXAMPLE' + awsSecretAccessKey = 'wJalrXUtnFEMI/K7MDENG/bPyRfiCYEXAMPLEKEY' + awsProfileName = 'someProfile' + } + }