From d200acf85b62f8027757dc08424699e570f881e9 Mon Sep 17 00:00:00 2001 From: Jan Horvath Date: Thu, 12 Oct 2023 21:04:32 +0200 Subject: [PATCH] Adding action/command for adding DB connection proerties to the OCI Vault --- .../cloud.oracle/external/binaries-list | 22 +- ...se.txt => oci-java-sdk-3.25.3-license.txt} | 4 +- .../cloud.oracle/nbproject/project.properties | 24 +- enterprise/cloud.oracle/nbproject/project.xml | 48 +- .../actions/AddDbConnectionToVault.java | 719 ++++++++++++++++++ .../modules/cloud/oracle/resources/key.svg | 85 +++ .../modules/cloud/oracle/resources/layer.xml | 31 + .../modules/cloud/oracle/resources/secret.svg | 65 ++ .../modules/cloud/oracle/resources/vault.svg | 80 ++ .../modules/cloud/oracle/vault/KeyItem.java | 49 ++ .../modules/cloud/oracle/vault/KeyNode.java | 88 +++ .../cloud/oracle/vault/SecretItem.java | 49 ++ .../cloud/oracle/vault/SecretNode.java | 77 ++ .../modules/cloud/oracle/vault/VaultItem.java | 55 ++ .../modules/cloud/oracle/vault/VaultNode.java | 80 ++ .../actions/AddDbConnectionToVaultTest.java | 70 ++ .../modules/nbcode/integration/layer.xml | 1 + java/java.lsp.server/vscode/package-lock.json | 4 +- java/java.lsp.server/vscode/package.json | 24 + 19 files changed, 1530 insertions(+), 45 deletions(-) rename enterprise/cloud.oracle/external/{oci-java-sdk-3.9.0-license.txt => oci-java-sdk-3.25.3-license.txt} (96%) create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVault.java create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/key.svg create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/secret.svg create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/vault.svg create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/KeyItem.java create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/KeyNode.java create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/SecretItem.java create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/SecretNode.java create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/VaultItem.java create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/VaultNode.java create mode 100644 enterprise/cloud.oracle/test/unit/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVaultTest.java diff --git a/enterprise/cloud.oracle/external/binaries-list b/enterprise/cloud.oracle/external/binaries-list index 622fd1395e84..ecd1327b51b7 100644 --- a/enterprise/cloud.oracle/external/binaries-list +++ b/enterprise/cloud.oracle/external/binaries-list @@ -15,16 +15,18 @@ # specific language governing permissions and limitations # under the License. -F89364D98A616CBA66CA535759EA092C54B4BF75 com.oracle.oci.sdk:oci-java-sdk-common:3.9.0 -7BB77013E6B91FCC7CD72D3338EB9F4019E20EA9 com.oracle.oci.sdk:oci-java-sdk-database:3.9.0 -8AB9B9CA57124F30B6D25CBAC944A7CEE0373068 com.oracle.oci.sdk:oci-java-sdk-identity:3.9.0 -F2071C1D75795350EB4D6807C4327AA333C5930C com.oracle.oci.sdk:oci-java-sdk-circuitbreaker:3.9.0 -10D73A80C8F66F959C84189272A7FC1C0CB1C435 com.oracle.oci.sdk:oci-java-sdk-workrequests:3.9.0 -031597E1BEEED3E48203BE6ECEBBA442E6FE177E com.oracle.oci.sdk:oci-java-sdk-devops:3.9.0 -5E52AF447D216717453E91782FCB965DF5669D5C com.oracle.oci.sdk:oci-java-sdk-adm:3.9.0 -C81CF0C79C300BF0526DF80D7890F688C1E32803 com.oracle.oci.sdk:oci-java-sdk-common-httpclient:3.9.0 -19C42576CC31E6028F29639F442EBA0CD895ADB3 com.oracle.oci.sdk:oci-java-sdk-common-httpclient-jersey:3.9.0 -9499C6360FFDBEBC6F0F1285A20DD91485FEDD46 com.oracle.oci.sdk:oci-java-sdk-addons-apache-configurator-jersey:3.9.0 +01713F2F4C8533893B8BD73C9461698F16F2B091 com.oracle.oci.sdk:oci-java-sdk-common:3.25.3 +5E25BDEF20C9897C16EA939DBF185177F158EC40 com.oracle.oci.sdk:oci-java-sdk-database:3.25.3 +D1015B3664782EABF06354C63748152E6D3BF268 com.oracle.oci.sdk:oci-java-sdk-vault:3.25.3 +0B6A6C71B4880A87B1FB034B3F1AB6E5361FC558 com.oracle.oci.sdk:oci-java-sdk-keymanagement:3.25.3 +E46F0CE2219BBCDA94B87D4CB4EF4166DAF6C925 com.oracle.oci.sdk:oci-java-sdk-identity:3.25.3 +832F50EFBFB3B320CA5CAEC75FE607FB8CEDF40E com.oracle.oci.sdk:oci-java-sdk-circuitbreaker:3.25.3 +78C9D083AD254C858E4A69F51958A9A46D260F97 com.oracle.oci.sdk:oci-java-sdk-workrequests:3.25.3 +9D89873EC1059B5B75058DB5FF1C25D66A9EC859 com.oracle.oci.sdk:oci-java-sdk-devops:3.25.3 +95F57672B60D7A611582262828DCED3F7544BA7C com.oracle.oci.sdk:oci-java-sdk-adm:3.25.3 +A8B7EBCA334E8145469A8FE0365C02A2727218EE com.oracle.oci.sdk:oci-java-sdk-common-httpclient:3.25.3 +AECECCD95E5ED92C73E455B7BA4AC714229041EE com.oracle.oci.sdk:oci-java-sdk-common-httpclient-jersey:3.25.3 +0CEE99CE7AA783353D19C56AC9F1AD72485DDBE8 com.oracle.oci.sdk:oci-java-sdk-addons-apache-configurator-jersey:3.25.3 E5F6CAE5CA7ECAAC1EC2827A9E2D65AE2869CADA org.apache.httpcomponents:httpclient:4.5.13 853B96D3AFBB7BF8CC303FE27EE96836A10C1834 org.apache.httpcomponents:httpcore:4.4.13 diff --git a/enterprise/cloud.oracle/external/oci-java-sdk-3.9.0-license.txt b/enterprise/cloud.oracle/external/oci-java-sdk-3.25.3-license.txt similarity index 96% rename from enterprise/cloud.oracle/external/oci-java-sdk-3.9.0-license.txt rename to enterprise/cloud.oracle/external/oci-java-sdk-3.25.3-license.txt index c7fcf3f3b4df..45069662ffdd 100644 --- a/enterprise/cloud.oracle/external/oci-java-sdk-3.9.0-license.txt +++ b/enterprise/cloud.oracle/external/oci-java-sdk-3.25.3-license.txt @@ -1,9 +1,9 @@ Name: OCI Java SDK Description: Oracle Cloud Infrastructure SDK for Java Origin: https://github.com/oracle/oci-java-sdk -Version: 3.9.0 +Version: 3.25.3 License: UPL-Apache-2.0 -Files: oci-java-sdk-circuitbreaker-3.9.0.jar, oci-java-sdk-common-3.9.0.jar, oci-java-sdk-database-3.9.0.jar, oci-java-sdk-identity-3.9.0.jar, oci-java-sdk-workrequests-3.9.0.jar, oci-java-sdk-adm-3.9.0.jar, oci-java-sdk-devops-3.9.0.jar, oci-java-sdk-addons-apache-configurator-jersey-3.9.0.jar, oci-java-sdk-common-httpclient-3.9.0.jar, oci-java-sdk-common-httpclient-jersey-3.9.0.jar +Files: oci-java-sdk-circuitbreaker-3.25.3.jar, oci-java-sdk-common-3.25.3.jar, oci-java-sdk-database-3.25.3.jar, oci-java-sdk-identity-3.25.3.jar, oci-java-sdk-workrequests-3.25.3.jar, oci-java-sdk-adm-3.25.3.jar, oci-java-sdk-devops-3.25.3.jar, oci-java-sdk-addons-apache-configurator-jersey-3.25.3.jar, oci-java-sdk-common-httpclient-3.25.3.jar, oci-java-sdk-common-httpclient-jersey-3.25.3.jar oci-java-sdk-keymanagement-3.25.3.jar oci-java-sdk-vault-3.25.3.jar Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. diff --git a/enterprise/cloud.oracle/nbproject/project.properties b/enterprise/cloud.oracle/nbproject/project.properties index f69596ddeaa0..28ad8d55af47 100644 --- a/enterprise/cloud.oracle/nbproject/project.properties +++ b/enterprise/cloud.oracle/nbproject/project.properties @@ -15,17 +15,19 @@ # specific language governing permissions and limitations # under the License. -release.external/oci-java-sdk-circuitbreaker-3.9.0.jar=modules/ext/oci-java-sdk-circuitbreaker-3.9.0.jar -release.external/oci-java-sdk-common-3.9.0.jar=modules/ext/oci-java-sdk-common-3.9.0.jar -release.external/oci-java-sdk-devops-3.9.0.jar=modules/ext/oci-java-sdk-devops-3.9.0.jar -release.external/oci-java-sdk-database-3.9.0.jar=modules/ext/oci-java-sdk-database-3.9.0.jar -release.external/oci-java-sdk-identity-3.9.0.jar=modules/ext/oci-java-sdk-identity-3.9.0.jar -release.external/oci-java-sdk-workrequests-3.9.0.jar=modules/ext/oci-java-sdk-workrequests-3.9.0.jar -release.external/oci-java-sdk-devops-3.9.0.jar=modules/ext/oci-java-sdk-devops-3.9.0.jar -release.external/oci-java-sdk-adm-3.9.0.jar=modules/ext/oci-java-sdk-adm-3.9.0.jar -release.external/oci-java-sdk-common-httpclient-3.9.0.jar=modules/ext/oci-java-sdk-common-httpclient-3.9.0.jar -release.external/oci-java-sdk-common-httpclient-jersey-3.9.0.jar=modules/ext/oci-java-sdk-common-httpclient-jersey-3.9.0.jar -release.external/oci-java-sdk-addons-apache-configurator-jersey-3.9.0.jar=modules/ext/oci-java-sdk-addons-apache-configurator-jersey-3.9.0.jar +release.external/oci-java-sdk-circuitbreaker-3.25.3.jar=modules/ext/oci-java-sdk-circuitbreaker-3.25.3.jar +release.external/oci-java-sdk-common-3.25.3.jar=modules/ext/oci-java-sdk-common-3.25.3.jar +release.external/oci-java-sdk-devops-3.25.3.jar=modules/ext/oci-java-sdk-devops-3.25.3.jar +release.external/oci-java-sdk-database-3.25.3.jar=modules/ext/oci-java-sdk-database-3.25.3.jar +release.external/oci-java-sdk-vault-3.25.3.jar=modules/ext/oci-java-sdk-vault-3.25.3.jar +release.external/oci-java-sdk-keymanagement-3.25.3.jar=modules/ext/oci-java-sdk-keymanagement-3.25.3.jar +release.external/oci-java-sdk-identity-3.25.3.jar=modules/ext/oci-java-sdk-identity-3.25.3.jar +release.external/oci-java-sdk-workrequests-3.25.3.jar=modules/ext/oci-java-sdk-workrequests-3.25.3.jar +release.external/oci-java-sdk-devops-3.25.3.jar=modules/ext/oci-java-sdk-devops-3.25.3.jar +release.external/oci-java-sdk-adm-3.25.3.jar=modules/ext/oci-java-sdk-adm-3.25.3.jar +release.external/oci-java-sdk-common-httpclient-3.25.3.jar=modules/ext/oci-java-sdk-common-httpclient-3.25.3.jar +release.external/oci-java-sdk-common-httpclient-jersey-3.25.3.jar=modules/ext/oci-java-sdk-common-httpclient-jersey-3.25.3.jar +release.external/oci-java-sdk-addons-apache-configurator-jersey-3.25.3.jar=modules/ext/oci-java-sdk-addons-apache-configurator-jersey-3.25.3.jar release.external/httpclient-4.5.13.jar=modules/ext/httpclient-4.5.13.jar release.external/httpcore-4.4.13.jar=modules/ext/httpcore-4.4.13.jar release.external/javassist-3.25.0-GA.jar=modules/ext/javassist-3.25.0-GA.jar diff --git a/enterprise/cloud.oracle/nbproject/project.xml b/enterprise/cloud.oracle/nbproject/project.xml index 9cfde3ca2d4b..2aee363fd39a 100644 --- a/enterprise/cloud.oracle/nbproject/project.xml +++ b/enterprise/cloud.oracle/nbproject/project.xml @@ -236,8 +236,8 @@ - ext/oci-java-sdk-identity-3.9.0.jar - external/oci-java-sdk-identity-3.9.0.jar + ext/oci-java-sdk-identity-3.25.3.jar + external/oci-java-sdk-identity-3.25.3.jar ext/resilience4j-circuitbreaker-1.7.1.jar @@ -248,28 +248,28 @@ external/resilience4j-core-1.7.1.jar - ext/oci-java-sdk-common-3.9.0.jar - external/oci-java-sdk-common-3.9.0.jar + ext/oci-java-sdk-common-3.25.3.jar + external/oci-java-sdk-common-3.25.3.jar - ext/oci-java-sdk-devops-3.9.0.jar - external/oci-java-sdk-devops-3.9.0.jar + ext/oci-java-sdk-devops-3.25.3.jar + external/oci-java-sdk-devops-3.25.3.jar - ext/oci-java-sdk-adm-3.9.0.jar - external/oci-java-sdk-adm-3.9.0.jar + ext/oci-java-sdk-adm-3.25.3.jar + external/oci-java-sdk-adm-3.25.3.jar - ext/oci-java-sdk-common-httpclient-3.9.0.jar - external/oci-java-sdk-common-httpclient-3.9.0.jar + ext/oci-java-sdk-common-httpclient-3.25.3.jar + external/oci-java-sdk-common-httpclient-3.25.3.jar - ext/oci-java-sdk-common-httpclient-jersey-3.9.0.jar - external/oci-java-sdk-common-httpclient-jersey-3.9.0.jar + ext/oci-java-sdk-common-httpclient-jersey-3.25.3.jar + external/oci-java-sdk-common-httpclient-jersey-3.25.3.jar - ext/oci-java-sdk-addons-apache-configurator-jersey-3.9.0.jar - external/oci-java-sdk-addons-apache-configurator-jersey-3.9.0.jar + ext/oci-java-sdk-addons-apache-configurator-jersey-3.25.3.jar + external/oci-java-sdk-addons-apache-configurator-jersey-3.25.3.jar ext/httpclient-4.5.13.jar @@ -288,20 +288,28 @@ external/vavr-0.10.2.jar - ext/oci-java-sdk-database-3.9.0.jar - external/oci-java-sdk-database-3.9.0.jar + ext/oci-java-sdk-database-3.25.3.jar + external/oci-java-sdk-database-3.25.3.jar - ext/oci-java-sdk-circuitbreaker-3.9.0.jar - external/oci-java-sdk-circuitbreaker-3.9.0.jar + ext/oci-java-sdk-vault-3.25.3.jar + external/oci-java-sdk-vault-3.25.3.jar + + + ext/oci-java-sdk-keymanagement-3.25.3.jar + external/oci-java-sdk-keymanagement-3.25.3.jar + + + ext/oci-java-sdk-circuitbreaker-3.25.3.jar + external/oci-java-sdk-circuitbreaker-3.25.3.jar ext/vavr-match-0.10.2.jar external/vavr-match-0.10.2.jar - ext/oci-java-sdk-workrequests-3.9.0.jar - external/oci-java-sdk-workrequests-3.9.0.jar + ext/oci-java-sdk-workrequests-3.25.3.jar + external/oci-java-sdk-workrequests-3.25.3.jar diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVault.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVault.java new file mode 100644 index 000000000000..d98e75d9622e --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVault.java @@ -0,0 +1,719 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.netbeans.modules.cloud.oracle.actions; + +import com.oracle.bmc.identity.Identity; +import com.oracle.bmc.identity.IdentityClient; +import com.oracle.bmc.identity.model.Compartment; +import com.oracle.bmc.identity.requests.ListCompartmentsRequest; +import com.oracle.bmc.identity.responses.ListCompartmentsResponse; +import com.oracle.bmc.identity.model.Tenancy; +import org.netbeans.api.db.explorer.DatabaseConnection; +import com.oracle.bmc.model.BmcException; +import com.oracle.bmc.vault.VaultsClient; +import com.oracle.bmc.vault.model.Base64SecretContentDetails; +import com.oracle.bmc.vault.model.CreateSecretDetails; +import com.oracle.bmc.vault.model.SecretContentDetails; +import com.oracle.bmc.vault.model.SecretReuseRule; +import com.oracle.bmc.vault.model.UpdateSecretDetails; +import com.oracle.bmc.vault.requests.CreateSecretRequest; +import com.oracle.bmc.vault.requests.ListSecretsRequest; +import com.oracle.bmc.vault.requests.UpdateSecretRequest; +import com.oracle.bmc.vault.responses.CreateSecretResponse; +import com.oracle.bmc.vault.responses.ListSecretsResponse; +import com.oracle.bmc.vault.responses.UpdateSecretResponse; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.modules.cloud.oracle.OCIManager; +import static org.netbeans.modules.cloud.oracle.OCIManager.getDefault; +import org.netbeans.modules.cloud.oracle.OCIProfile; +import org.netbeans.modules.cloud.oracle.OCISessionInitiator; +import org.netbeans.modules.cloud.oracle.compartment.CompartmentItem; +import org.netbeans.modules.cloud.oracle.items.OCID; +import org.netbeans.modules.cloud.oracle.items.OCIItem; +import org.netbeans.modules.cloud.oracle.items.TenancyItem; +import org.netbeans.modules.cloud.oracle.vault.KeyItem; +import org.netbeans.modules.cloud.oracle.vault.KeyNode; +import org.netbeans.modules.cloud.oracle.vault.SecretItem; +import org.netbeans.modules.cloud.oracle.vault.SecretNode; +import org.netbeans.modules.cloud.oracle.vault.VaultItem; +import org.netbeans.modules.cloud.oracle.vault.VaultNode; +import org.openide.DialogDescriptor; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; +import org.openide.NotifyDescriptor.QuickPick.Item; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionRegistration; +import org.openide.util.NbBundle; +import org.openide.util.Pair; + +/** + * + * @author Jan Horvath + */ +@ActionID( + category = "Tools", + id = "org.netbeans.modules.cloud.oracle.actions.AddDbConnectionToVault" +) +@ActionRegistration( + displayName = "#AddADBToVault", + asynchronous = true +) +@ActionReferences(value = { + @ActionReference(path = "Cloud/Oracle/Databases/Actions", position = 250) +}) +@NbBundle.Messages({ + "AddADBToVault=Add Oracle Autonomous DB details to OCI Vault", + "SelectKey=Select Key", + "SelectVault=Select Vault", + "SecretsCreated=Secrets were created or updated", + "NoKeys=No keys in this Vault. Select another one.", + "DatasourceName=Datasource Name", + "AddVersion=Add new versions", + "Cancel=Cancel", + "SecretExists=Secrets with name {0} already exists", + "NoProfile=There is not any OCI profile in the config", + "NoCompartment=There are no compartments in the Tenancy" +}) +public class AddDbConnectionToVault implements ActionListener { + + private static final Logger LOG = Logger.getLogger(AddDbConnectionToVault.class.getName()); + + private final DatabaseConnection context; + + public AddDbConnectionToVault(DatabaseConnection context) { + this.context = context; + } + + static interface Step { + + Step prepare(T item); + + NotifyDescriptor createInput(); + + boolean onlyOneChoice(); + + Step getNext(); + + void setValue(String selected); + + U getValue(); + } + + class TenancyStep implements Step { + + List profiles = new LinkedList<>(); + private AtomicReference selected = new AtomicReference<>(); + + @Override + public NotifyDescriptor createInput() { + if (onlyOneChoice()) { + throw new IllegalStateException("No data to create input"); // NOI18N + } + String title = Bundle.SelectProfile(); + List items = new ArrayList<>(profiles.size()); + for (OCIProfile p : profiles) { + Tenancy t = p.getTenancyData(); + if (t != null) { + items.add(new NotifyDescriptor.QuickPick.Item(p.getId(), Bundle.SelectProfile_Description(t.getName(), t.getHomeRegionKey()))); + } + } + if (profiles.stream().filter(p -> p.getTenancy().isPresent()).count() == 0) { + title = Bundle.NoProfile(); + } + return new NotifyDescriptor.QuickPick(title, title, items, false); + } + + @Override + public Step getNext() { + return new CompartmentStep().prepare(getValue()); + } + + public Step prepare(Object i) { + ProgressHandle h = ProgressHandle.createHandle(Bundle.MSG_CollectingProfiles()); + h.start(); + h.progress(Bundle.MSG_CollectingProfiles_Text()); + try { + profiles = OCIManager.getDefault().getConnectedProfiles(); + } finally { + h.finish(); + } + return this; + } + + public void setValue(String selected) { + for (OCIProfile profile : profiles) { + if (profile.getId().equals(selected)) { + profile.getTenancy().ifPresent(t -> this.selected.set(t)); + break; + } + } + } + + @Override + public TenancyItem getValue() { + if (onlyOneChoice()) { + return profiles.stream() + .map(p -> p.getTenancy()) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst() + .get(); + } + return selected.get(); + } + + @Override + public boolean onlyOneChoice() { + return profiles.stream().filter(p -> p.getTenancy().isPresent()).count() == 1; + } + } + + static class CompartmentStep implements Step { + + private Map compartments = null; + private CompartmentItem selected; + + public Step prepare(TenancyItem tenancy) { + ProgressHandle h = ProgressHandle.createHandle(Bundle.MSG_CollectingItems()); + h.start(); + h.progress(Bundle.MSG_CollectingItems_Text()); + try { + compartments = getFlatCompartment(tenancy); + } finally { + h.finish(); + } + return this; + } + + @Override + public NotifyDescriptor createInput() { + if (onlyOneChoice()) { + throw new IllegalStateException("Input shouldn't be displayed for one choice"); // NOI18N + } + if (compartments.isEmpty()) { + createQuickPick(compartments, Bundle.NoCompartment()); + } + return createQuickPick(compartments, Bundle.SelectCompartment()); + } + + @Override + public Step getNext() { + return new VaultStep().prepare(getValue()); + } + + @Override + public void setValue(String selected) { + this.selected = (CompartmentItem) compartments.get(selected); + } + + @Override + public CompartmentItem getValue() { + if (onlyOneChoice()) { + return (CompartmentItem) compartments.values().iterator().next(); + } + return selected; + } + + @Override + public boolean onlyOneChoice() { + return compartments.size() == 1; + } + } + + static class VaultStep implements Step { + + private Map vaults = null; + private VaultItem selected; + + public Step prepare(CompartmentItem compartment) { + ProgressHandle h = ProgressHandle.createHandle(Bundle.MSG_CollectingItems()); + h.start(); + h.progress(Bundle.MSG_CollectingItems_Text()); + try { + vaults = getVaults(compartment); + } finally { + h.finish(); + } + return this; + } + + @Override + public NotifyDescriptor createInput() { + return createQuickPick(vaults, Bundle.SelectVault()); + } + + @Override + public Step getNext() { + return new KeyStep().prepare(selected); + } + + @Override + public void setValue(String selected) { + this.selected = vaults.get(selected); + } + + @Override + public VaultItem getValue() { + if (onlyOneChoice()) { + vaults.values().iterator().next(); + } + return selected; + } + + @Override + public boolean onlyOneChoice() { + return vaults.size() == 1; + } + } + + static class KeyStep implements Step> { + + private Map keys = null; + private KeyItem selected; + private VaultItem vault; + + public Step> prepare(VaultItem vault) { + this.vault = vault; + ProgressHandle h = ProgressHandle.createHandle(Bundle.MSG_CollectingItems()); + h.start(); + h.progress(Bundle.MSG_CollectingItems_Text()); + try { + keys = getKeys(vault); + } finally { + h.finish(); + } + return this; + } + + @Override + public boolean onlyOneChoice() { + return keys.size() == 1; + } + + @Override + public NotifyDescriptor createInput() { + if (keys.size() > 1) { + return createQuickPick(keys, Bundle.SelectKey()); + } + if (keys.size() == 0) { + return new NotifyDescriptor.QuickPick("", Bundle.NoKeys(), Collections.emptyList(), false); + } + + throw new IllegalStateException("No data to create input"); // NOI18N + } + + @Override + public Step getNext() { + return new DatasourceNameStep().prepare(getValue()); + } + + @Override + public void setValue(String selected) { + this.selected = keys.get(selected); + } + + @Override + public Pair getValue() { + if (keys.size() == 1) { + return Pair.of(vault, keys.values().iterator().next()); + } + return Pair.of(vault, selected); + } + + } + + static class DatasourceNameStep implements Step, Result> { + + private Result result = new Result(); + + @Override + public Step, Result> prepare(Pair item) { + result.vault = item.first(); + result.key = item.second(); + return this; + } + + @Override + public NotifyDescriptor createInput() { + return new NotifyDescriptor.InputLine("DEFAULT", Bundle.DatasourceName()); //NOI18N + } + + @Override + public Step getNext() { + return new OverwriteStep().prepare(result); + } + + @Override + public void setValue(String selected) { + result.datasourceName = selected; + } + + @Override + public Result getValue() { + return result; + } + + @Override + public boolean onlyOneChoice() { + return false; + } + + } + + static class OverwriteStep implements Step { + + private Result result; + private Set dsNames; + private String choice; + + @Override + public Step prepare(Result result) { + this.result = result; + List secrets = SecretNode.getSecrets().apply(result.vault); + this.dsNames = secrets.stream() + .map(s -> extractDatasourceName(s.getName())) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + return this; + } + + @Override + public NotifyDescriptor createInput() { + List yesNo = new ArrayList(); + yesNo.add(new Item(Bundle.AddVersion(), "")); + yesNo.add(new Item(Bundle.Cancel(), "")); + return new NotifyDescriptor.QuickPick("", Bundle.SecretExists(result.datasourceName), yesNo, false); + } + + @Override + public Step getNext() { + return null; + } + + @Override + public void setValue(String choice) { + this.choice = choice; + } + + @Override + public Result getValue() { + if (Bundle.AddVersion().equals(choice) || onlyOneChoice()) { + result.update = true; + return result; + } + return null; + } + + @Override + public boolean onlyOneChoice() { + return !dsNames.contains(result.datasourceName); + } + + } + + static class Result { + VaultItem vault; + KeyItem key; + String datasourceName; + private boolean update; + } + + static class Multistep { + + private final LinkedList steps = new LinkedList<>(); + + Multistep(Step firstStep) { + steps.add(firstStep); + } + + NotifyDescriptor.ComposedInput.Callback createInput() { + return new NotifyDescriptor.ComposedInput.Callback() { + + private void showInput(Step step, NotifyDescriptor desc) { + String selected = null; + if (!step.onlyOneChoice()) { + if (desc instanceof NotifyDescriptor.QuickPick) { + for (NotifyDescriptor.QuickPick.Item item : ((NotifyDescriptor.QuickPick) desc).getItems()) { + if (item.isSelected()) { + selected = item.getLabel(); + break; + } + } + } else if (desc instanceof NotifyDescriptor.InputLine) { + selected = ((NotifyDescriptor.InputLine) desc).getInputText(); + } + step.setValue(selected); + } + } + + NotifyDescriptor prepareInput(NotifyDescriptor.ComposedInput input, int number) { + if (number == 1) { + steps.get(0).prepare(null); + return steps.get(0).createInput(); + } + if (steps.size() > number) { + steps.removeLast(); + return steps.getLast().createInput(); + } + showInput(steps.getLast(), input.getInputs()[number - 2]); + Step currentStep = steps.getLast().getNext(); + if (currentStep == null) { + return null; + } + + steps.add(currentStep); + if (currentStep.onlyOneChoice()) { + return prepareInput(input, number); + } + return currentStep.createInput(); + } + + @Override + public NotifyDescriptor createInput(NotifyDescriptor.ComposedInput input, int number) { + return prepareInput(input, number); + } + }; + } + + Object getResult() { + return steps.getLast().getValue(); + } + } + + @Override + public void actionPerformed(ActionEvent e) { + + Multistep multistep = new Multistep(new TenancyStep()); + + NotifyDescriptor.ComposedInput ci = new NotifyDescriptor.ComposedInput(Bundle.AddADB(), 3, multistep.createInput()); + if (DialogDescriptor.OK_OPTION == DialogDisplayer.getDefault().notify(ci)) { + if (multistep.getResult() != null) { + Result v = (Result) multistep.getResult(); + addDbConnectionToVault(v.vault, v.key, context, v.datasourceName); + } + } + + } + + private static void addDbConnectionToVault(VaultItem vault, KeyItem key, DatabaseConnection connection, String datasourceName) { + VaultsClient client = VaultsClient.builder().build(getDefault().getActiveProfile().getConfigProvider()); + + ListSecretsRequest listSecretsRequest = ListSecretsRequest.builder() + .compartmentId(vault.getCompartmentId()) + .vaultId(vault.getKey().getValue()) + .limit(88) + .build(); + + ListSecretsResponse secrets = client.listSecrets(listSecretsRequest); + + Map existingSecrets = secrets.getItems().stream() + .collect(Collectors.toMap(s -> s.getSecretName(), s -> s.getId())); + + Map values = new HashMap() { + { + put("Username", connection.getUser()); //NOI18N + put("Password", connection.getPassword()); //NOI18N + put("OCID", (String) connection.getConnectionProperties().get("OCID")); //NOI18N + put("wallet_Password", UUID.randomUUID().toString()); //NOI18N + } + }; + + try { + for (Entry entry : values.entrySet()) { + String secretName = "DATASOURCES_" + datasourceName + "_" + entry.getKey().toUpperCase(); //NOI18N + String base64Content = Base64.getEncoder().encodeToString(entry.getValue().getBytes(StandardCharsets.UTF_8)); + + SecretContentDetails contentDetails = Base64SecretContentDetails.builder() + .content(base64Content) + .stage(SecretContentDetails.Stage.Current).build(); + if (existingSecrets.containsKey(secretName)) { + UpdateSecretDetails updateSecretDetails = UpdateSecretDetails.builder() + .secretContent(contentDetails) + .build(); + UpdateSecretRequest request = UpdateSecretRequest.builder() + .secretId(existingSecrets.get(secretName)) + .updateSecretDetails(updateSecretDetails) + .build(); + UpdateSecretResponse response = client.updateSecret(request); + } else { + CreateSecretDetails createDetails = CreateSecretDetails.builder() + .secretName(secretName) + .secretContent(contentDetails) + .secretRules(new ArrayList<>(Arrays.asList(SecretReuseRule.builder() + .isEnforcedOnDeletedSecretVersions(false).build()))) + .compartmentId(vault.getCompartmentId()) + .vaultId(vault.getKey().getValue()) + .keyId(key.getKey().getValue()) + .build(); + CreateSecretRequest request = CreateSecretRequest + .builder() + .createSecretDetails(createDetails) + .build(); + CreateSecretResponse response = client.createSecret(request); + } + } + + } catch (BmcException e) { + NotifyDescriptor.Message msg = new NotifyDescriptor.Message(e.getMessage()); + DialogDisplayer.getDefault().notify(msg); + throw new RuntimeException(e); + } + NotifyDescriptor.Message msg = new NotifyDescriptor.Message(Bundle.SecretsCreated()); + DialogDisplayer.getDefault().notify(msg); + } + + private static NotifyDescriptor.QuickPick createQuickPick(Map ociItems, String title) { + + List items = ociItems.entrySet().stream() + .map(entry -> new NotifyDescriptor.QuickPick.Item(entry.getKey(), entry.getValue().getDescription())) + .collect(Collectors.toList()); + return new NotifyDescriptor.QuickPick(title, title, items, false); + } + + private static Map getFlatCompartment(TenancyItem tenancy) { + Map compartments = new HashMap<>(); + OCISessionInitiator session = OCIManager.getDefault().getActiveSession(); + Identity identityClient = session.newClient(IdentityClient.class); + String nextPageToken = null; + + do { + ListCompartmentsResponse response + = identityClient.listCompartments( + ListCompartmentsRequest.builder() + .compartmentId(tenancy.getKey().getValue()) + .compartmentIdInSubtree(true) + .lifecycleState(Compartment.LifecycleState.Active) + .accessLevel(ListCompartmentsRequest.AccessLevel.Accessible) + .limit(1000) + .page(nextPageToken) + .build()); + for (Compartment comp : response.getItems()) { + FlatCompartmentItem ci = new FlatCompartmentItem(comp) { + FlatCompartmentItem getItem(OCID compId) { + return compartments.get(compId); + } + }; + compartments.put(ci.getKey(), ci); + } + nextPageToken = response.getOpcNextPage(); + } while (nextPageToken != null); + Map pickItems = computeFlatNames(compartments); + pickItems.put(tenancy.getName() + " (root)", tenancy); // NOI18N + return pickItems; + } + + private static Map computeFlatNames(Map compartments) { + Map pickItems = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + for (FlatCompartmentItem comp : compartments.values()) { + pickItems.put(comp.getName(), comp); + } + return pickItems; + } + + private static abstract class FlatCompartmentItem extends CompartmentItem { + + private final OCID parentId; + private String flatName; + + private FlatCompartmentItem(Compartment ociComp) { + super(OCID.of(ociComp.getId(), "Compartment"), ociComp.getName()); // NOI18N + setDescription(ociComp.getDescription()); + parentId = OCID.of(ociComp.getCompartmentId(), "Compartment"); // NOI18N + } + + public String getName() { + if (parentId.getValue() == null) { + return ""; + } + if (flatName == null) { + String parentFlatName = ""; + FlatCompartmentItem parentComp = getItem(parentId); + if (parentComp != null) { + parentFlatName = parentComp.getName(); + } + flatName = super.getName(); + if (!parentFlatName.isEmpty()) { + flatName = parentFlatName + "/" + flatName; // NOI18N + } + } + return flatName; + } + + abstract FlatCompartmentItem getItem(OCID compId); + } + + protected static Map getVaults(OCIItem parent) { + Map items = new HashMap<>(); + try { + if (parent instanceof CompartmentItem) { + VaultNode.getVaults().apply((CompartmentItem) parent).forEach((db) -> items.put(db.getName(), db)); + } + } catch (BmcException e) { + LOG.log(Level.SEVERE, "Unable to load vault list", e); //NOI18N + } + return items; + } + + protected static Map getKeys(OCIItem parent) { + Map items = new HashMap<>(); + try { + if (parent instanceof VaultItem) { + KeyNode.getKeys().apply((VaultItem) parent).forEach((db) -> items.put(db.getName(), db)); + } + } catch (BmcException e) { + LOG.log(Level.SEVERE, "Unable to load vault list", e); //NOI18N + } + return items; + } + + static Pattern p = Pattern.compile("[A-Z]*_([A-Z]*)_[A-Z]*"); //NOI18N + + protected static String extractDatasourceName(String value) { + Matcher m = p.matcher(value); + if (m.matches()) { + return m.group(1); + } + return null; + } +} diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/key.svg b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/key.svg new file mode 100644 index 000000000000..16e1b4ec3236 --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/key.svg @@ -0,0 +1,85 @@ + + + + + + diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/layer.xml b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/layer.xml index 03c6ebc7865d..63cffaa5b71a 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/layer.xml +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/layer.xml @@ -48,6 +48,9 @@ + + + @@ -162,6 +165,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/secret.svg b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/secret.svg new file mode 100644 index 000000000000..adc4af5e8f03 --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/secret.svg @@ -0,0 +1,65 @@ + + + + + + diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/vault.svg b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/vault.svg new file mode 100644 index 000000000000..13a2c5efb1c9 --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/resources/vault.svg @@ -0,0 +1,80 @@ + + + + + + diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/KeyItem.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/KeyItem.java new file mode 100644 index 000000000000..927b474e4e0d --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/KeyItem.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.netbeans.modules.cloud.oracle.vault; + +import org.netbeans.modules.cloud.oracle.items.OCID; +import org.netbeans.modules.cloud.oracle.items.OCIItem; + +/** + * + * @author Jan Horvath + */ +public class KeyItem extends OCIItem { + String compartmentId; + + public KeyItem(OCID id, String name, String compartmentId) { + super(id, name); + this.compartmentId = compartmentId; + } + + public KeyItem() { + super(); + } + + public String getCompartmentId() { + return compartmentId; + } + + @Override + public int maxInProject() { + return Integer.MAX_VALUE; + } + +} diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/KeyNode.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/KeyNode.java new file mode 100644 index 000000000000..7726949845e2 --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/KeyNode.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.netbeans.modules.cloud.oracle.vault; + +import com.oracle.bmc.keymanagement.KmsManagementClient; +import com.oracle.bmc.keymanagement.model.Vault; +import com.oracle.bmc.keymanagement.requests.ListKeysRequest; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import org.netbeans.modules.cloud.oracle.ChildrenProvider; +import org.netbeans.modules.cloud.oracle.NodeProvider; +import org.netbeans.modules.cloud.oracle.OCIManager; +import org.netbeans.modules.cloud.oracle.OCINode; +import org.netbeans.modules.cloud.oracle.items.OCID; +import org.openide.nodes.Children; +import org.openide.util.NbBundle; + +/** + * + * @author Jan Horvath + */ +@NbBundle.Messages({}) +public class KeyNode extends OCINode { + + private static final String KEY_ICON = "org/netbeans/modules/cloud/oracle/resources/key.svg"; // NOI18N + private static final Logger LOG = Logger.getLogger(KeyNode.class.getName()); + + public KeyNode(KeyItem key) { + super(key, Children.LEAF); + setName(key.getName()); + setDisplayName(key.getName()); + setIconBaseWithExtension(KEY_ICON); + setShortDescription(key.getDescription()); + } + + public static NodeProvider createNode() { + return KeyNode::new; + } + + /** + * Retrieves list of Keys belonging to a given Vault. + * + * @return Returns {@code ChildrenProvider} which fetches List of {@code KeyItem} for given {@code VaultItem} + */ + public static ChildrenProvider getKeys() { + return vault -> { + Vault v = Vault.builder() + .compartmentId(vault.compartmentId) + .id(vault.getKey().getValue()) + .managementEndpoint(vault.managementEndpoint) + .build(); + KmsManagementClient client = KmsManagementClient.builder() + .vault(v) + .build(OCIManager.getDefault().getActiveProfile().getConfigProvider()); + ListKeysRequest listKeysRequest = ListKeysRequest.builder() + .compartmentId(vault.getCompartmentId()) + .limit(88) + .build(); + + return client.listKeys(listKeysRequest) + .getItems() + .stream() + .map(d -> new KeyItem( + OCID.of(d.getId(), "Vault/Key"), //NOI18N + d.getDisplayName(), + d.getCompartmentId()) + ) + .collect(Collectors.toList()); + }; + } + +} diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/SecretItem.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/SecretItem.java new file mode 100644 index 000000000000..74d739089eee --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/SecretItem.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.netbeans.modules.cloud.oracle.vault; + +import org.netbeans.modules.cloud.oracle.items.OCID; +import org.netbeans.modules.cloud.oracle.items.OCIItem; + +/** + * + * @author Jan Horvath + */ +public class SecretItem extends OCIItem { + String compartmentId; + + public SecretItem(OCID id, String name, String compartmentId) { + super(id, name); + this.compartmentId = compartmentId; + } + + public SecretItem() { + super(); + } + + public String getCompartmentId() { + return compartmentId; + } + + @Override + public int maxInProject() { + return Integer.MAX_VALUE; + } + +} diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/SecretNode.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/SecretNode.java new file mode 100644 index 000000000000..e679f385b584 --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/SecretNode.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.netbeans.modules.cloud.oracle.vault; + +import com.oracle.bmc.vault.VaultsClient; +import com.oracle.bmc.vault.requests.ListSecretsRequest; +import java.util.stream.Collectors; +import org.netbeans.modules.cloud.oracle.ChildrenProvider; +import org.netbeans.modules.cloud.oracle.NodeProvider; +import static org.netbeans.modules.cloud.oracle.OCIManager.getDefault; +import org.netbeans.modules.cloud.oracle.OCINode; +import org.netbeans.modules.cloud.oracle.items.OCID; +import org.openide.nodes.Children; + +/** + * + * @author Jan Horvath + */ +public class SecretNode extends OCINode { + private static final String SECRET_ICON = "org/netbeans/modules/cloud/oracle/resources/secret.svg"; // NOI18N + + public SecretNode(SecretItem vault) { + super(vault, Children.LEAF); + setName(vault.getName()); + setDisplayName(vault.getName()); + setIconBaseWithExtension(SECRET_ICON); + setShortDescription(vault.getDescription()); + } + + public static NodeProvider createNode() { + return SecretNode::new; + } + + /** + * Retrieves list of Secrets belonging to a given Vault. + * + * @@return Returns {@code ChildrenProvider} which fetches List of {@code SecretItem} for given {@code VaultItem} + */ + public static ChildrenProvider getSecrets() { + return vault -> { + VaultsClient client = VaultsClient.builder().build(getDefault().getActiveProfile().getConfigProvider()); + + ListSecretsRequest listSecretsRequest = ListSecretsRequest.builder() + .compartmentId(vault.getCompartmentId()) + .vaultId(vault.getKey().getValue()) + .limit(88) + .build(); + + return client.listSecrets(listSecretsRequest) + .getItems() + .stream() + .map(d -> new SecretItem( + OCID.of(d.getId(), "Vault/Secret"), //NOI18N + d.getSecretName(), + d.getCompartmentId()) + ) + .collect(Collectors.toList()); + }; + } + +} diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/VaultItem.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/VaultItem.java new file mode 100644 index 000000000000..caba8cc5cfb3 --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/VaultItem.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.netbeans.modules.cloud.oracle.vault; + +import org.netbeans.modules.cloud.oracle.items.OCID; +import org.netbeans.modules.cloud.oracle.items.OCIItem; + +/** + * + * @author Jan Horvath + */ +public class VaultItem extends OCIItem { + String compartmentId; + String managementEndpoint; + + public VaultItem(OCID id, String name, String compartmentId, String managementEndpoint) { + super(id, name); + this.compartmentId = compartmentId; + this.managementEndpoint = managementEndpoint; + } + + public VaultItem() { + super(); + } + + public String getCompartmentId() { + return compartmentId; + } + + public String getManagementEndpoint() { + return managementEndpoint; + } + + @Override + public int maxInProject() { + return Integer.MAX_VALUE; + } + +} diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/VaultNode.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/VaultNode.java new file mode 100644 index 000000000000..9d26a4e15e72 --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/vault/VaultNode.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.netbeans.modules.cloud.oracle.vault; + +import com.oracle.bmc.keymanagement.KmsVaultClient; +import com.oracle.bmc.keymanagement.requests.ListVaultsRequest; +import java.util.stream.Collectors; +import org.netbeans.modules.cloud.oracle.ChildrenProvider; +import org.netbeans.modules.cloud.oracle.NodeProvider; +import org.netbeans.modules.cloud.oracle.OCIManager; +import org.netbeans.modules.cloud.oracle.OCINode; +import org.netbeans.modules.cloud.oracle.compartment.CompartmentItem; +import org.netbeans.modules.cloud.oracle.items.OCID; +import org.openide.util.NbBundle; + +/** + * + * @author Jan Horvath + */ +@NbBundle.Messages({ +}) +public class VaultNode extends OCINode { + private static final String VAULT_ICON = "org/netbeans/modules/cloud/oracle/resources/vault.svg"; // NOI18N + + public VaultNode(VaultItem vault) { + super(vault); + setName(vault.getName()); + setDisplayName(vault.getName()); + setIconBaseWithExtension(VAULT_ICON); + setShortDescription(vault.getDescription()); + } + + public static NodeProvider createNode() { + return VaultNode::new; + } + + /** + * Retrieves list of Vaults belonging to a given Compartment. + * + * @return Returns {@code ChildrenProvider} which fetches List of {@code VaultItem} for given {@code CompartmentItem} + */ + public static ChildrenProvider getVaults() { + return compartmentId -> { + KmsVaultClient client = KmsVaultClient.builder().build(OCIManager.getDefault().getActiveProfile().getConfigProvider()); + + ListVaultsRequest listVaultsRequest = ListVaultsRequest.builder() + .compartmentId(compartmentId.getKey().getValue()) + .limit(88) + .build(); + + return client.listVaults(listVaultsRequest) + .getItems() + .stream() + .map(d -> new VaultItem( + OCID.of(d.getId(), "Vault"), //NOI18N + d.getDisplayName(), + d.getCompartmentId(), + d.getManagementEndpoint()) + ) + .collect(Collectors.toList()); + }; + } + +} diff --git a/enterprise/cloud.oracle/test/unit/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVaultTest.java b/enterprise/cloud.oracle/test/unit/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVaultTest.java new file mode 100644 index 000000000000..cc9ccd1db440 --- /dev/null +++ b/enterprise/cloud.oracle/test/unit/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVaultTest.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.netbeans.modules.cloud.oracle.actions; + +import java.awt.event.ActionEvent; +import java.util.Map; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; +import org.netbeans.modules.cloud.oracle.items.OCIItem; +import org.netbeans.modules.cloud.oracle.vault.KeyItem; +import org.netbeans.modules.cloud.oracle.vault.VaultItem; + +/** + * + * @author honza + */ +public class AddDbConnectionToVaultTest { + + public AddDbConnectionToVaultTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of actionPerformed method, of class AddDbConnectionToVault. + */ + @Test + public void datasourceName() { + String input = "DATASOURCES_DEFAULT_USERNAME"; + String ds = AddDbConnectionToVault.extractDatasourceName(input); + assertEquals("DEFAULT", ds); + + } + + +} diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml index 8a4529dc402f..225467a72b3b 100644 --- a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml +++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml @@ -52,6 +52,7 @@ + diff --git a/java/java.lsp.server/vscode/package-lock.json b/java/java.lsp.server/vscode/package-lock.json index 7bd0d7017f5a..8243353c8654 100644 --- a/java/java.lsp.server/vscode/package-lock.json +++ b/java/java.lsp.server/vscode/package-lock.json @@ -1,12 +1,12 @@ { "name": "apache-netbeans-java", - "version": "0.1.0", + "version": "19.0.301", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "apache-netbeans-java", - "version": "0.1.0", + "version": "19.0.301", "license": "Apache 2.0", "dependencies": { "@vscode/debugadapter": "1.55.1", diff --git a/java/java.lsp.server/vscode/package.json b/java/java.lsp.server/vscode/package.json index 80841e6d6c44..52534721824f 100644 --- a/java/java.lsp.server/vscode/package.json +++ b/java/java.lsp.server/vscode/package.json @@ -608,6 +608,10 @@ "command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.OpenServiceConsoleAction", "title": "Open Service Console" }, + { + "command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.AddDbConnectionToVault", + "title": "Add to OCI Vault" + }, { "command": "java.select.editor.projects", "title": "Reveal active editor in Projects", @@ -725,6 +729,10 @@ "command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.OpenServiceConsoleAction", "when": "false" }, + { + "command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.AddDbConnectionToVault", + "when": "false" + }, { "command": "java.workspace.configureRunSettings", "when": "false" @@ -843,6 +851,10 @@ "command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.OpenServiceConsoleAction", "when": "viewItem =~ /class:oracle.database.DatabaseItem/" }, + { + "command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.AddDbConnectionToVault", + "when": "viewItem =~ /class:org.netbeans.api.db.explorer.DatabaseConnection/" + }, { "command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.CreateAutonomousDBAction", "when": "viewItem =~ /class:oracle.compartment.CompartmentItem/" @@ -949,6 +961,18 @@ "uriExpression": "nbres:/org/netbeans/modules/cloud/oracle/resources/database.svg", "codeicon": "database" }, + { + "uriExpression": "nbres:/org/netbeans/modules/cloud/oracle/resources/vault.svg", + "codeicon": "lock" + }, + { + "uriExpression": "nbres:/org/netbeans/modules/cloud/oracle/resources/key.svg", + "codeicon": "gist-secret" + }, + { + "uriExpression": "nbres:/org/netbeans/modules/cloud/oracle/resources/secret.svg", + "codeicon": "key" + }, { "uriExpression": "nbres:/org/netbeans/modules/cloud/oracle/resources/devops_project.svg", "codeicon": "project"