From 695ed6c38e5ccffd5d34ca059158f6bc8126e4b1 Mon Sep 17 00:00:00 2001 From: Jonas Konrad Date: Fri, 5 Jul 2024 09:48:03 +0200 Subject: [PATCH 1/4] Add shared, lazy SessionKeySupplier implementation (#940) During startup, prof shows that a significant time is spent inside RSA key generation in the default SessionKeySupplierImpl, both in the constructor and in refreshKeys. This PR adds a new implementation that avoids generating keys until first time of use, and shares the session key between authorization providers. Sharing between bootstrap and normal context is not yet implemented. I have no way to test this, so can't say how much it helps. --- .../core/LazySessionKeySupplier.java | 78 +++++++++++++++++++ .../core/OracleCloudCoreFactory.java | 23 ++++-- .../identity/OkeWorkloadIdentityFactory.java | 12 ++- 3 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 oraclecloud-common/src/main/java/io/micronaut/oraclecloud/core/LazySessionKeySupplier.java diff --git a/oraclecloud-common/src/main/java/io/micronaut/oraclecloud/core/LazySessionKeySupplier.java b/oraclecloud-common/src/main/java/io/micronaut/oraclecloud/core/LazySessionKeySupplier.java new file mode 100644 index 000000000..2d6dba414 --- /dev/null +++ b/oraclecloud-common/src/main/java/io/micronaut/oraclecloud/core/LazySessionKeySupplier.java @@ -0,0 +1,78 @@ +/* + * Copyright 2017-2024 original authors + * + * 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 + * + * https://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 io.micronaut.oraclecloud.core; + +import com.oracle.bmc.auth.SessionKeySupplier; +import io.micronaut.context.annotation.BootstrapContextCompatible; +import io.micronaut.context.annotation.Secondary; +import jakarta.inject.Singleton; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * {@link SessionKeySupplier} implementation that lazily generates RSA keys to avoid generating keys + * that go unused. This is a singleton that is used for all session keys in the application context. + *

+ * Ideally this should also be shared with the bootstrap context in the future. + * + * @since 4.2.0 + * @author Jonas Konrad + */ +@Singleton +@Secondary +@BootstrapContextCompatible +final class LazySessionKeySupplier implements SessionKeySupplier { + private static final KeyPairGenerator GENERATOR; + + private final Lock lock = new ReentrantLock(); + private volatile KeyPair keyPair = null; + + static { + try { + GENERATOR = KeyPairGenerator.getInstance("RSA"); + GENERATOR.initialize(2048); + } catch (NoSuchAlgorithmException e) { + throw new Error(e.getMessage(), e); + } + } + + @Override + public KeyPair getKeyPair() { + KeyPair kp = keyPair; + if (kp == null) { + lock.lock(); + try { + kp = keyPair; + if (kp == null) { + kp = GENERATOR.generateKeyPair(); + keyPair = kp; + } + } finally { + lock.unlock(); + } + } + return kp; + } + + @Override + public void refreshKeys() { + keyPair = null; + } +} diff --git a/oraclecloud-common/src/main/java/io/micronaut/oraclecloud/core/OracleCloudCoreFactory.java b/oraclecloud-common/src/main/java/io/micronaut/oraclecloud/core/OracleCloudCoreFactory.java index 0a9959879..8aca1c09f 100644 --- a/oraclecloud-common/src/main/java/io/micronaut/oraclecloud/core/OracleCloudCoreFactory.java +++ b/oraclecloud-common/src/main/java/io/micronaut/oraclecloud/core/OracleCloudCoreFactory.java @@ -21,24 +21,25 @@ import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; import com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider; import com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider; +import com.oracle.bmc.auth.SessionKeySupplier; import com.oracle.bmc.auth.SessionTokenAuthenticationDetailsProvider; import com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider; import com.oracle.bmc.auth.URLBasedX509CertificateSupplier; import com.oracle.bmc.auth.internal.AuthUtils; -import io.micronaut.context.annotation.Property; -import io.micronaut.core.annotation.Nullable; import io.micronaut.context.annotation.BootstrapContextCompatible; import io.micronaut.context.annotation.Context; import io.micronaut.context.annotation.Factory; import io.micronaut.context.annotation.Primary; +import io.micronaut.context.annotation.Property; import io.micronaut.context.annotation.Requires; import io.micronaut.context.exceptions.ConfigurationException; import io.micronaut.context.exceptions.DisabledBeanException; - +import io.micronaut.core.annotation.Nullable; import io.micronaut.core.util.StringUtils; import io.micronaut.discovery.cloud.oraclecloud.OracleCloudMetadataConfiguration; import jakarta.inject.Inject; import jakarta.inject.Singleton; + import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -77,6 +78,10 @@ public class OracleCloudCoreFactory { private OracleCloudConfigFileConfigurationProperties ociConfigFileConfiguration; + @Inject + @Nullable + SessionKeySupplier sessionKeySupplier; + /** * @param profile The configured profile * @param configPath The configuration file path @@ -156,7 +161,11 @@ protected SimpleAuthenticationDetailsProvider simpleAuthenticationDetailsProvide @Primary @BootstrapContextCompatible protected ResourcePrincipalAuthenticationDetailsProvider resourcePrincipalAuthenticationDetailsProvider() { - return ResourcePrincipalAuthenticationDetailsProvider.builder().build(); + ResourcePrincipalAuthenticationDetailsProvider.ResourcePrincipalAuthenticationDetailsProviderBuilder builder = ResourcePrincipalAuthenticationDetailsProvider.builder(); + if (sessionKeySupplier != null) { + builder.sessionKeySupplier(sessionKeySupplier); + } + return builder.build(); } /** @@ -172,7 +181,11 @@ protected ResourcePrincipalAuthenticationDetailsProvider resourcePrincipalAuthen @Primary @BootstrapContextCompatible protected InstancePrincipalsAuthenticationDetailsProvider instancePrincipalAuthenticationDetailsProvider(InstancePrincipalConfiguration instancePrincipalConfiguration) { - return instancePrincipalConfiguration.getBuilder().build(); + InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder builder = instancePrincipalConfiguration.getBuilder(); + if (sessionKeySupplier != null) { + builder.sessionKeySupplier(sessionKeySupplier); + } + return builder.build(); } /** diff --git a/oraclecloud-oke-workload-identity/src/main/java/io/micronaut/oraclecloud/oke/workload/identity/OkeWorkloadIdentityFactory.java b/oraclecloud-oke-workload-identity/src/main/java/io/micronaut/oraclecloud/oke/workload/identity/OkeWorkloadIdentityFactory.java index 2e01618e2..f67858fcd 100644 --- a/oraclecloud-oke-workload-identity/src/main/java/io/micronaut/oraclecloud/oke/workload/identity/OkeWorkloadIdentityFactory.java +++ b/oraclecloud-oke-workload-identity/src/main/java/io/micronaut/oraclecloud/oke/workload/identity/OkeWorkloadIdentityFactory.java @@ -18,12 +18,15 @@ import com.oracle.bmc.auth.AuthenticationDetailsProvider; import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; import com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider; +import com.oracle.bmc.auth.SessionKeySupplier; import com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider; import com.oracle.bmc.auth.okeworkloadidentity.OkeWorkloadIdentityAuthenticationDetailsProvider; import io.micronaut.context.annotation.BootstrapContextCompatible; import io.micronaut.context.annotation.Factory; import io.micronaut.context.annotation.Primary; import io.micronaut.context.annotation.Requires; +import io.micronaut.core.annotation.Nullable; +import jakarta.inject.Inject; import jakarta.inject.Singleton; /** @@ -42,6 +45,9 @@ @Factory @BootstrapContextCompatible public class OkeWorkloadIdentityFactory { + @Inject + @Nullable + SessionKeySupplier sessionKeySupplier; /** * Configures a {@link OkeWorkloadIdentityAuthenticationDetailsProvider} if no other {@link AuthenticationDetailsProvider} is present and @@ -56,7 +62,11 @@ public class OkeWorkloadIdentityFactory { @Primary @BootstrapContextCompatible protected OkeWorkloadIdentityAuthenticationDetailsProvider okeWorkloadIdentityAuthenticationDetailsProvider(OkeWorkloadIdentityConfiguration okeWorkloadIdentityConfiguration) { - return okeWorkloadIdentityConfiguration.getBuilder().build(); + OkeWorkloadIdentityAuthenticationDetailsProvider.OkeWorkloadIdentityAuthenticationDetailsProviderBuilder builder = okeWorkloadIdentityConfiguration.getBuilder(); + if (sessionKeySupplier != null) { + builder.sessionKeySupplier(sessionKeySupplier); + } + return builder.build(); } } From eb0caba5f7222fd0c8a563b1d612e6fc9e14f700 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 09:48:28 +0200 Subject: [PATCH 2/4] fix(deps): update oci to v3.44.1 (#931) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 38d56fa10..c1538526d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ commons-lang3 = '3.14.0' shadow = '8.0.0' groovy = "4.0.21" spock = "2.3-groovy-4.0" -oci = "3.42.0" +oci = "3.44.1" protobuf = '0.9.4' netty-http3 = "0.0.28.Final" From 707967aa2446104c333ba6b1ac8d0cb83597b191 Mon Sep 17 00:00:00 2001 From: micronaut-build <65172877+micronaut-build@users.noreply.github.com> Date: Fri, 5 Jul 2024 09:49:03 +0200 Subject: [PATCH 3/4] [oracle-cloud] Update common files for branch 4.1.x (#932) * fix(deps): update dependency org.apache.groovy:groovy-bom to v4.0.22 * Update common files --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Chaimaa Rouai <161726330+ChaimaaeROUAI@users.noreply.github.com> --- .github/workflows/gradle.yml | 4 ++-- .github/workflows/release.yml | 2 +- gradle/libs.versions.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 33a347c60..d91a8e4fe 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -45,14 +45,14 @@ jobs: fetch-depth: 0 - name: "🔧 Setup GraalVM CE" - uses: graalvm/setup-graalvm@v1.2.1 + uses: graalvm/setup-graalvm@v1.2.2 with: distribution: 'graalvm' java-version: ${{ matrix.java }} github-token: ${{ secrets.GITHUB_TOKEN }} - name: "🔧 Setup Gradle" - uses: gradle/gradle-build-action@v3.3.2 + uses: gradle/gradle-build-action@v3.4.2 - name: "❓ Optional setup step" run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a18844dd..f234f585b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -146,7 +146,7 @@ jobs: if: startsWith(github.ref, 'refs/tags/') steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download artifacts uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c1538526d..1bb0fe145 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ mockito = '5.12.0' slf4j-jcl = '2.0.13' commons-lang3 = '3.14.0' shadow = '8.0.0' -groovy = "4.0.21" +groovy = "4.0.22" spock = "2.3-groovy-4.0" oci = "3.44.1" protobuf = '0.9.4' From 519630ffe54964f7d7a49c4960807b5a8db4faf5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 07:58:37 +0000 Subject: [PATCH 4/4] chore(deps): update actions/github-script action to v7 --- .github/workflows/graalvm-oci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/graalvm-oci.yml b/.github/workflows/graalvm-oci.yml index 794446baf..f249bdc8f 100644 --- a/.github/workflows/graalvm-oci.yml +++ b/.github/workflows/graalvm-oci.yml @@ -96,7 +96,7 @@ jobs: GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} PREDICTIVE_TEST_SELECTION: "${{ github.event_name == 'pull_request' && 'true' || 'false' }}" - name: Add build scan URL as PR comment - uses: actions/github-script@v6 + uses: actions/github-script@v7 if: github.event_name == 'pull_request' && failure() with: github-token: ${{secrets.GITHUB_TOKEN}}