diff --git a/provider/indexer-gcp/pom.xml b/provider/indexer-gcp/pom.xml index 7b936e801ba92f6025822260dd7a1a390af76865..09cc7e5240b1cfef8ffab0eb432888c8c8d9e640 100644 --- a/provider/indexer-gcp/pom.xml +++ b/provider/indexer-gcp/pom.xml @@ -43,7 +43,7 @@ <dependency> <groupId>org.opengroup.osdu</groupId> <artifactId>core-lib-gcp</artifactId> - <version>0.1.17</version> + <version>0.3.21</version> </dependency> <dependency> diff --git a/provider/indexer-gcp/src/main/appengine/app.yaml b/provider/indexer-gcp/src/main/appengine/app.yaml index dee4515740c38e195f4afeada8a4b66471a32833..16d9a8ac495f04fa88c5ec438902c621dc08bf96 100644 --- a/provider/indexer-gcp/src/main/appengine/app.yaml +++ b/provider/indexer-gcp/src/main/appengine/app.yaml @@ -39,3 +39,4 @@ env_variables: LEGAL_HOSTNAME: "LEGAL_HOSTNAME_VAR" REGION: "REGION_VAR" SPRING_PROFILES_ACTIVE: 'ENVIRONMENT' + diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/AppengineLogFactory.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/AppengineLogFactory.java deleted file mode 100644 index 66ae62f7a67f9c39327d897e945ef81d4e39e192..0000000000000000000000000000000000000000 --- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/AppengineLogFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.opengroup.osdu.indexer.di; - -import org.opengroup.osdu.core.common.logging.ILogger; -import org.opengroup.osdu.core.gcp.logging.logger.AppEngineLoggingProvider; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Lazy; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; - -@ConditionalOnProperty(name="disable.appengine.log.factory", havingValue = "false", matchIfMissing = true ) -@Component -@Primary -@Lazy -public class AppengineLogFactory implements FactoryBean<ILogger> { - - private AppEngineLoggingProvider appEngineLoggingProvider = new AppEngineLoggingProvider(); - - @Override - public ILogger getObject() throws Exception { - return appEngineLoggingProvider.getLogger(); - } - - @Override - public Class<?> getObjectType() { - return ILogger.class; - } -} \ No newline at end of file diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/DatastoreCredentialsCacheFactory.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/DatastoreCredentialsCacheFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..94e9d343b980c905ff0b72941e5232e40ff42e8d --- /dev/null +++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/DatastoreCredentialsCacheFactory.java @@ -0,0 +1,22 @@ +package org.opengroup.osdu.indexer.di; + +import org.opengroup.osdu.core.common.cache.ICache; +import org.opengroup.osdu.core.common.cache.VmCache; +import org.opengroup.osdu.core.gcp.multitenancy.credentials.DatastoreCredential; +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.springframework.stereotype.Component; + +@Component +public class DatastoreCredentialsCacheFactory extends + AbstractFactoryBean<ICache<String, DatastoreCredential>> { + + @Override + public Class<?> getObjectType() { + return ICache.class; + } + + @Override + protected ICache<String, DatastoreCredential> createInstance() throws Exception { + return new VmCache<>(5 * 60, 20); + } +} diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/kms/KmsClient.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/kms/KmsClient.java deleted file mode 100644 index 020efb85eede96cb8eebd1beec4b23ce2fa42b83..0000000000000000000000000000000000000000 --- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/kms/KmsClient.java +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2017-2019, Schlumberger -// -// 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 org.opengroup.osdu.indexer.kms; - -import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; -import com.google.api.client.http.HttpTransport; -import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.api.services.cloudkms.v1.CloudKMS; -import com.google.api.services.cloudkms.v1.CloudKMSScopes; -import com.google.api.services.cloudkms.v1.model.DecryptRequest; -import com.google.api.services.cloudkms.v1.model.DecryptResponse; -import com.google.api.services.cloudkms.v1.model.EncryptRequest; -import com.google.api.services.cloudkms.v1.model.EncryptResponse; -import org.opengroup.osdu.core.common.provider.interfaces.IKmsClient; -import org.opengroup.osdu.core.common.search.Preconditions; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.springframework.web.context.annotation.RequestScope; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -@Component -@RequestScope -public class KmsClient implements IKmsClient { - - @Value("${GOOGLE_CLOUD_PROJECT}") - private String GOOGLE_CLOUD_PROJECT; - - @Value("${KMS_KEY}") - private String KMS_KEY; - - @Value("${KEY_RING}") - private String KEY_RING; - - private static final String KEY_NAME = "projects/%s/locations/global/keyRings/%s/cryptoKeys/%s"; - - /** - * Encrypts the given plaintext using the specified crypto key. - * Google KMS automatically uses the new primary key version to encrypt data, so this could be directly used for key rotation - */ - public String encryptString(String textToBeEncrypted) throws IOException { - Preconditions.checkNotNullOrEmpty(textToBeEncrypted, "textToBeEncrypted cannot be null"); - - byte[] plaintext = textToBeEncrypted.getBytes(StandardCharsets.UTF_8); - String resourceName = String.format(KEY_NAME, GOOGLE_CLOUD_PROJECT, KEY_RING, KMS_KEY); - CloudKMS kms = createAuthorizedClient(); - EncryptRequest request = new EncryptRequest().encodePlaintext(plaintext); - EncryptResponse response = kms.projects().locations().keyRings().cryptoKeys() - .encrypt(resourceName, request) - .execute(); - return response.getCiphertext(); - } - - /** - * Decrypts the provided ciphertext with the specified crypto key. - * Google KMS automatically uses the correct key version to decrypt data, as long as the key version is not disabled - */ - public String decryptString(String textToBeDecrypted) throws IOException { - Preconditions.checkNotNullOrEmpty(textToBeDecrypted, "textToBeDecrypted cannot be null"); - - CloudKMS kms = createAuthorizedClient(); - String cryptoKeyName = String.format(KEY_NAME, GOOGLE_CLOUD_PROJECT, KEY_RING, KMS_KEY); - DecryptRequest request = new DecryptRequest().setCiphertext(textToBeDecrypted); - DecryptResponse response = kms.projects().locations().keyRings().cryptoKeys() - .decrypt(cryptoKeyName, request) - .execute(); - return new String(response.decodePlaintext(), StandardCharsets.UTF_8).trim(); - } - - /** - * Creates an authorized CloudKMS client service using Application Default Credentials. - * - * @return an authorized CloudKMS client - * @throws IOException if there's an error getting the default credentials. - */ - private CloudKMS createAuthorizedClient() throws IOException { - HttpTransport transport = new NetHttpTransport(); - JsonFactory jsonFactory = new JacksonFactory(); - GoogleCredential credential = GoogleCredential.getApplicationDefault(); - if (credential.createScopedRequired()) { - credential = credential.createScoped(CloudKMSScopes.all()); - } - return new CloudKMS.Builder(transport, jsonFactory, credential) - .setApplicationName("CloudKMS snippets") - .build(); - } -} \ No newline at end of file diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/DatastoreCredential.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/DatastoreCredential.java deleted file mode 100644 index 5bde4448cfd77348818e0d04b312a1ca432f8dde..0000000000000000000000000000000000000000 --- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/DatastoreCredential.java +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2017-2019, Schlumberger -// -// 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 org.opengroup.osdu.indexer.persistence; - -import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; -import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.api.services.iam.v1.Iam; -import com.google.api.services.iam.v1.Iam.Projects.ServiceAccounts.SignJwt; -import com.google.api.services.iam.v1.model.SignJwtRequest; -import com.google.api.services.iam.v1.model.SignJwtResponse; -import com.google.auth.oauth2.AccessToken; -import com.google.auth.oauth2.GoogleCredentials; -import com.google.gson.JsonObject; -import org.apache.commons.lang3.time.DateUtils; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.common.util.Crc32c; -import org.opengroup.osdu.indexer.cache.DatastoreCredentialCache; - -import java.util.Date; - -public class DatastoreCredential extends GoogleCredentials { - - private static final long serialVersionUID = 8344377091688956815L; - private static final JsonFactory JSON_FACTORY = new JacksonFactory(); - private Iam iam; - - private final TenantInfo tenant; - private final DatastoreCredentialCache cache; - - protected DatastoreCredential(TenantInfo tenant, DatastoreCredentialCache cache) { - this.tenant = tenant; - this.cache = cache; - } - - @Override - public AccessToken refreshAccessToken() { - - String cacheKey = this.getCacheKey(); - - AccessToken accessToken = this.cache.get(cacheKey); - - if (accessToken != null) { - return accessToken; - } - - try { - SignJwtRequest signJwtRequest = new SignJwtRequest(); - signJwtRequest.setPayload(this.getPayload()); - - String serviceAccountName = String.format("projects/-/serviceAccounts/%s", this.tenant.getServiceAccount()); - - SignJwt signJwt = this.getIam().projects().serviceAccounts().signJwt(serviceAccountName, signJwtRequest); - - SignJwtResponse signJwtResponse = signJwt.execute(); - String signedJwt = signJwtResponse.getSignedJwt(); - - accessToken = new AccessToken(signedJwt, DateUtils.addSeconds(new Date(), 3600)); - - this.cache.put(cacheKey, accessToken); - - return accessToken; - } catch (Exception e) { - throw new RuntimeException("Error creating datastore credential", e); - } - } - - private String getPayload() { - JsonObject payload = new JsonObject(); - payload.addProperty("iss", this.tenant.getServiceAccount()); - payload.addProperty("sub", this.tenant.getServiceAccount()); - payload.addProperty("aud", "https://datastore.googleapis.com/google.datastore.v1.Datastore"); - payload.addProperty("iat", System.currentTimeMillis() / 1000); - - return payload.toString(); - } - - protected void setIam(Iam iam) { - this.iam = iam; - } - - private Iam getIam() throws Exception { - if (this.iam == null) { - - Iam.Builder builder = new Iam.Builder(GoogleNetHttpTransport.newTrustedTransport(), JSON_FACTORY, - GoogleCredential.getApplicationDefault()).setApplicationName("Search Service"); - - this.iam = builder.build(); - } - return this.iam; - } - - private String getCacheKey() { - return Crc32c.hashToBase64EncodedString(String.format("datastoreCredential:%s", this.tenant.getName())); - } -} \ No newline at end of file diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/DatastoreFactory.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/DatastoreFactory.java deleted file mode 100644 index 1a14870151f97f34e87e4967dd5e496cd3b24b3f..0000000000000000000000000000000000000000 --- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/DatastoreFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2017-2019, Schlumberger -// -// 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 org.opengroup.osdu.indexer.persistence; - -import com.google.api.gax.retrying.RetrySettings; -import com.google.cloud.TransportOptions; -import com.google.cloud.datastore.Datastore; -import com.google.cloud.datastore.DatastoreOptions; -import com.google.cloud.http.HttpTransportOptions; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.indexer.cache.DatastoreCredentialCache; -import org.springframework.stereotype.Component; -import org.threeten.bp.Duration; - -import javax.inject.Inject; -import java.util.HashMap; -import java.util.Map; - -@Component -public class DatastoreFactory { - - @Inject - private DatastoreCredentialCache cache; - - private static Map<String, Datastore> DATASTORE_CLIENTS = new HashMap<>(); - - private static final RetrySettings RETRY_SETTINGS = RetrySettings.newBuilder() - .setMaxAttempts(6) - .setInitialRetryDelay(Duration.ofSeconds(10)) - .setMaxRetryDelay(Duration.ofSeconds(32)) - .setRetryDelayMultiplier(2.0) - .setTotalTimeout(Duration.ofSeconds(50)) - .setInitialRpcTimeout(Duration.ofSeconds(50)) - .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ofSeconds(50)) - .build(); - - private static final TransportOptions TRANSPORT_OPTIONS = HttpTransportOptions.newBuilder() - .setReadTimeout(30000) - .build(); - - public Datastore getDatastoreInstance(TenantInfo tenantInfo) { - if (DATASTORE_CLIENTS.get(tenantInfo.getName()) == null) { - Datastore googleDatastore = DatastoreOptions.newBuilder() - .setCredentials(new DatastoreCredential(tenantInfo, this.cache)) - .setRetrySettings(RETRY_SETTINGS) - .setTransportOptions(TRANSPORT_OPTIONS) - .setNamespace(tenantInfo.getName()) - .setProjectId(tenantInfo.getProjectId()) - .build().getService(); - DATASTORE_CLIENTS.put(tenantInfo.getName(), googleDatastore); - } - return DATASTORE_CLIENTS.get(tenantInfo.getName()); - } -} diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/ElasticRepositoryDatastore.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/ElasticRepositoryDatastore.java index 9c0b6b6eeb8f04001d16886385d6b244dc108fae..3562fff40e6499e282e758bfb976d1f0c424bc4b 100644 --- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/ElasticRepositoryDatastore.java +++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/ElasticRepositoryDatastore.java @@ -26,6 +26,7 @@ import org.opengroup.osdu.core.common.model.http.AppException; import org.opengroup.osdu.core.common.provider.interfaces.IKmsClient; import org.opengroup.osdu.core.common.provider.interfaces.IElasticRepository; import org.opengroup.osdu.core.common.search.Preconditions; +import org.opengroup.osdu.core.gcp.multitenancy.DatastoreFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.inject.Inject; @@ -52,7 +53,7 @@ public class ElasticRepositoryDatastore implements IElasticRepository { @Override public ClusterSettings getElasticClusterSettings(TenantInfo tenantInfo) { - Datastore googleDatastore = this.datastoreFactory.getDatastoreInstance(tenantInfo); + Datastore googleDatastore = this.datastoreFactory.getDatastore(tenantInfo); Key key = googleDatastore.newKeyFactory().setKind(ELASTIC_DATASTORE_KIND).newKey(ELASTIC_DATASTORE_ID); Entity datastoreEntity = googleDatastore.get(key);