/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the "Elastic License
 * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
 * Public License v 1"; you may not use this file except in compliance with, at
 * your election, the "Elastic License 2.0", the "GNU Affero General Public
 * License v3.0 only", or the "Server Side Public License, v 1".
 */


import org.elasticsearch.gradle.internal.ExportElasticsearchBuildResourcesTask
import org.elasticsearch.gradle.internal.test.rest.RestTestBasePlugin
import org.elasticsearch.gradle.testclusters.StandaloneRestIntegTestTask
import org.elasticsearch.gradle.testclusters.TestClustersAware

//apply plugin: org.elasticsearch.gradle.internal.info.GlobalBuildInfoPlugin

// Common config when running with a FIPS-140 runtime JVM
if (buildParams.inFipsJvm) {
  allprojects {
    String javaSecurityFilename = buildParams.runtimeJavaDetails.get().toLowerCase().contains('oracle') ? 'fips_java_oracle.security' : 'fips_java.security'
    File fipsResourcesDir = new File(project.buildDir, 'fips-resources')
    File fipsSecurity = new File(fipsResourcesDir, javaSecurityFilename)
    File fipsPolicy = new File(fipsResourcesDir, 'fips_java.policy')
    File fipsTrustStore = new File(fipsResourcesDir, 'cacerts.bcfks')
    def bcFips = dependencies.create('org.bouncycastle:bc-fips:1.0.2.5')
    def bcTlsFips = dependencies.create('org.bouncycastle:bctls-fips:1.0.19')
    def manualDebug = false; //change this to manually debug bouncy castle in an IDE
    if(manualDebug) {
      bcFips = dependencies.create('org.bouncycastle:bc-fips-debug:1.0.2.5')
      bcTlsFips = dependencies.create('org.bouncycastle:bctls-fips:1.0.19'){
        exclude group: 'org.bouncycastle', module: 'bc-fips'  // to avoid jar hell
      }
    }
    pluginManager.withPlugin('java-base') {
      TaskProvider<ExportElasticsearchBuildResourcesTask> fipsResourcesTask = project.tasks.register('fipsResources', ExportElasticsearchBuildResourcesTask)
      fipsResourcesTask.configure {
        outputDir = fipsResourcesDir
        copy javaSecurityFilename
        copy 'fips_java.policy'
        copy 'cacerts.bcfks'
      }

      def extraFipsJarsConfiguration = configurations.create("fipsImplementation") {
        withDependencies {
          add(bcFips)
          add(bcTlsFips)
        }
      }

      project.afterEvaluate {
        // ensure that bouncycastle is on classpath for the all of test types, must happen in evaluateAfter since the rest tests explicitly
        // set the class path to help maintain pure black box testing, and here we are adding to that classpath
        tasks.withType(Test).configureEach { Test test ->
          test.setClasspath(test.getClasspath().plus(extraFipsJarsConfiguration))
        }
      }

      pluginManager.withPlugin("elasticsearch.testclusters") {
        // This configuration can be removed once system modules are available
        testClusters.configureEach {
            extraJarFiles extraFipsJarsConfiguration
        }
        tasks.withType(TestClustersAware).configureEach {
          dependsOn 'fipsResources'
        }
        testClusters.configureEach {
          extraConfigFile "fips_java.security", fipsSecurity
          extraConfigFile "fips_java.policy", fipsPolicy
          extraConfigFile "cacerts.bcfks", fipsTrustStore
          systemProperty 'java.security.properties', '=${ES_PATH_CONF}/fips_java.security'
          systemProperty 'java.security.policy', '=${ES_PATH_CONF}/fips_java.policy'
          systemProperty 'javax.net.ssl.trustStore', '${ES_PATH_CONF}/cacerts.bcfks'
          systemProperty 'javax.net.ssl.trustStorePassword', 'password'
          systemProperty 'javax.net.ssl.keyStorePassword', 'password'
          systemProperty 'javax.net.ssl.keyStoreType', 'BCFKS'
          systemProperty 'org.bouncycastle.fips.approved_only', 'true'
          // Setting security explicitly off as a default behavior for the tests which normally run
          // with no x-pack. Tests having security explicitly enabled/disabled will override this setting
          setting 'xpack.security.enabled', 'false'
          setting 'xpack.security.fips_mode.enabled', 'true'
          setting 'xpack.license.self_generated.type', 'trial'
          setting 'xpack.security.authc.password_hashing.algorithm', 'pbkdf2_stretch'
          keystorePassword 'keystore-password'
        }
      }

      plugins.withType(RestTestBasePlugin) {
        tasks.withType(StandaloneRestIntegTestTask).configureEach {
          inputs.files(extraFipsJarsConfiguration).withNormalizer(ClasspathNormalizer)
          nonInputProperties.systemProperty "tests.cluster.fips.jars.path", "${-> extraFipsJarsConfiguration.asPath}"
        }
      }

      project.tasks.withType(Test).configureEach { Test task ->
        dependsOn 'fipsResources'
        task.systemProperty('javax.net.ssl.trustStorePassword', 'password')
        task.systemProperty('javax.net.ssl.keyStorePassword', 'password')
        task.systemProperty('javax.net.ssl.trustStoreType', 'BCFKS')
        // Using the key==value format to override default JVM security settings and policy
        // see also: https://docs.oracle.com/javase/8/docs/technotes/guides/security/PolicyFiles.html
        task.systemProperty('java.security.properties', String.format(Locale.ROOT, "=%s", fipsSecurity))
        task.systemProperty('java.security.policy', String.format(Locale.ROOT, "=%s", fipsPolicy))
        task.systemProperty('javax.net.ssl.trustStore', fipsTrustStore)
        task.systemProperty('org.bouncycastle.fips.approved_only', 'true')
      }
    }
  }
}
