diff --git a/provider/storage-gcp/pom.xml b/provider/storage-gcp/pom.xml index 02b85ee27969b1a0e47f6f1952f64114fbc73511..81f31bd39dd99cca2eb75b7625c87f9ab3891c3c 100644 --- a/provider/storage-gcp/pom.xml +++ b/provider/storage-gcp/pom.xml @@ -33,6 +33,7 @@ 1.8 1.8 1.8 + 0.9.0-rc17 @@ -46,6 +47,7 @@ org.opengroup.osdu os-core-common + ${os-core-common.version} diff --git a/provider/storage-gcp/src/main/java/org/opengroup/osdu/storage/provider/gcp/util/ServiceAccountJwtClientImpl.java b/provider/storage-gcp/src/main/java/org/opengroup/osdu/storage/provider/gcp/util/ServiceAccountJwtClientImpl.java index ac2c7cdc54e28ea4153c82378337744e962b906d..801f10f1f38a3f5c2e49f822c666509cc87295a9 100644 --- a/provider/storage-gcp/src/main/java/org/opengroup/osdu/storage/provider/gcp/util/ServiceAccountJwtClientImpl.java +++ b/provider/storage-gcp/src/main/java/org/opengroup/osdu/storage/provider/gcp/util/ServiceAccountJwtClientImpl.java @@ -1,172 +1,174 @@ -/* - Copyright 2020 Google LLC - Copyright 2020 EPAM Systems, Inc - - 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.storage.provider.gcp.util; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.http.HttpHeaders; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import com.google.auth.http.HttpCredentialsAdapter; -import com.google.auth.oauth2.GoogleCredentials; -import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; -import com.google.api.client.http.HttpTransport; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.jackson.JacksonFactory; -import com.google.api.services.iam.v1.Iam; -import com.google.api.services.iam.v1.IamScopes; -import com.google.api.services.iam.v1.model.SignJwtRequest; -import com.google.api.services.iam.v1.model.SignJwtResponse; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory; -import org.opengroup.osdu.core.common.model.tenant.TenantInfo; -import org.opengroup.osdu.core.common.model.http.AppException; -import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient; -import org.springframework.web.context.annotation.RequestScope; - -@Component -@RequestScope -public class ServiceAccountJwtClientImpl implements IServiceAccountJwtClient { - - private static final String JWT_AUDIENCE = "https://www.googleapis.com/oauth2/v4/token"; - private static final String SERVICE_ACCOUNT_NAME_FORMAT = "projects/%s/serviceAccounts/%s"; - - private static final JsonFactory JSON_FACTORY = new JacksonFactory(); - - private Iam iam; - - @Autowired - private ITenantFactory tenantStorageFactory; - - @Autowired - private JaxRsDpsLog logger; - - @Value("${STORAGE_HOSTNAME}") - public String storageHostname; - - @Value("${GOOGLE_AUDIENCES}") - public String googleAudiences; - - @Override - public String getIdToken(String tenantName) { - this.logger.info("Tenant name received for auth token is: " + tenantName); - TenantInfo tenantInfo = this.tenantStorageFactory.getTenantInfo(tenantName); - if (tenantInfo == null) { - this.logger.error("Invalid tenant name receiving from pubsub"); - throw new AppException(HttpStatus.SC_BAD_REQUEST, "Invalid tenant Name", "Invalid tenant Name from pubsub"); - } - try { - // 1. get signed JWT - Map signJwtPayload = getJwtCreationPayload(tenantInfo); - - SignJwtRequest signJwtRequest = new SignJwtRequest(); - signJwtRequest.setPayload(JSON_FACTORY.toString(signJwtPayload)); - - String serviceAccountName = String.format(SERVICE_ACCOUNT_NAME_FORMAT, tenantInfo.getProjectId(), - tenantInfo.getServiceAccount()); - - Iam.Projects.ServiceAccounts.SignJwt signJwt = getIam().projects().serviceAccounts() - .signJwt(serviceAccountName, signJwtRequest); - SignJwtResponse signJwtResponse = signJwt.execute(); - String signedJwt = signJwtResponse.getSignedJwt(); - - // 2. get id token - List postParameters = new ArrayList<>(); - postParameters.add(new BasicNameValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")); - postParameters.add(new BasicNameValuePair("assertion", signedJwt)); - - HttpPost post = new HttpPost(JWT_AUDIENCE); - post.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType()); - post.setEntity(new UrlEncodedFormEntity(postParameters, "UTF-8")); - - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - CloseableHttpResponse httpResponse = httpClient.execute(post); - - JsonObject jsonContent = new JsonParser().parse(EntityUtils.toString(httpResponse.getEntity())) - .getAsJsonObject(); - - if (!jsonContent.has("id_token")) { - this.logger.error(String.format("Google IAM response: %s", jsonContent.toString())); - throw new AppException(HttpStatus.SC_FORBIDDEN, "Access denied", - "User is not authorized to perform this operation."); - } - - String token = jsonContent.get("id_token").getAsString(); - - return "Bearer " + token; - } - } catch (AppException e) { - throw e; - } catch (Exception e) { - throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Persistence error", "Error generating token", - e); - } - - } - - Iam getIam() throws GeneralSecurityException, IOException { - if (this.iam == null) { - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - - GoogleCredentials credential = GoogleCredentials.getApplicationDefault(); - if (credential.createScopedRequired()) { - List scopes = new ArrayList<>(); - scopes.add(IamScopes.CLOUD_PLATFORM); - credential = credential.createScoped(scopes); - } - - this.iam = new Iam.Builder(httpTransport, JSON_FACTORY, new HttpCredentialsAdapter(credential)) - .setApplicationName(storageHostname).build(); - } - - return this.iam; - } - - private Map getJwtCreationPayload(TenantInfo tenantInfo) { - String googleAudience = googleAudiences; - if (googleAudience.contains(",")) { - googleAudience = googleAudience.split(",")[0]; - } - Map payload = new HashMap<>(); - payload.put("target_audience", googleAudience); - payload.put("aud", JWT_AUDIENCE); - payload.put("exp", System.currentTimeMillis() / 1000 + 3600); - payload.put("iat", System.currentTimeMillis() / 1000); - payload.put("iss", tenantInfo.getServiceAccount()); - return payload; - } +/* + Copyright 2020 Google LLC + Copyright 2020 EPAM Systems, Inc + + 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.storage.provider.gcp.util; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.http.HttpHeaders; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; + +import com.google.auth.http.HttpCredentialsAdapter; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson.JacksonFactory; +import com.google.api.services.iam.v1.Iam; +import com.google.api.services.iam.v1.IamScopes; +import com.google.api.services.iam.v1.model.SignJwtRequest; +import com.google.api.services.iam.v1.model.SignJwtResponse; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory; +import org.opengroup.osdu.core.common.model.tenant.TenantInfo; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient; +import org.springframework.web.context.annotation.RequestScope; + +@Primary +@Component +@RequestScope +public class ServiceAccountJwtClientImpl implements IServiceAccountJwtClient { + + private static final String JWT_AUDIENCE = "https://www.googleapis.com/oauth2/v4/token"; + private static final String SERVICE_ACCOUNT_NAME_FORMAT = "projects/%s/serviceAccounts/%s"; + + private static final JsonFactory JSON_FACTORY = new JacksonFactory(); + + private Iam iam; + + @Autowired + private ITenantFactory tenantStorageFactory; + + @Autowired + private JaxRsDpsLog logger; + + @Value("${STORAGE_HOSTNAME}") + public String storageHostname; + + @Value("${GOOGLE_AUDIENCES}") + public String googleAudiences; + + @Override + public String getIdToken(String tenantName) { + this.logger.info("Tenant name received for auth token is: " + tenantName); + TenantInfo tenantInfo = this.tenantStorageFactory.getTenantInfo(tenantName); + if (tenantInfo == null) { + this.logger.error("Invalid tenant name receiving from pubsub"); + throw new AppException(HttpStatus.SC_BAD_REQUEST, "Invalid tenant Name", "Invalid tenant Name from pubsub"); + } + try { + // 1. get signed JWT + Map signJwtPayload = getJwtCreationPayload(tenantInfo); + + SignJwtRequest signJwtRequest = new SignJwtRequest(); + signJwtRequest.setPayload(JSON_FACTORY.toString(signJwtPayload)); + + String serviceAccountName = String.format(SERVICE_ACCOUNT_NAME_FORMAT, tenantInfo.getProjectId(), + tenantInfo.getServiceAccount()); + + Iam.Projects.ServiceAccounts.SignJwt signJwt = getIam().projects().serviceAccounts() + .signJwt(serviceAccountName, signJwtRequest); + SignJwtResponse signJwtResponse = signJwt.execute(); + String signedJwt = signJwtResponse.getSignedJwt(); + + // 2. get id token + List postParameters = new ArrayList<>(); + postParameters.add(new BasicNameValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")); + postParameters.add(new BasicNameValuePair("assertion", signedJwt)); + + HttpPost post = new HttpPost(JWT_AUDIENCE); + post.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType()); + post.setEntity(new UrlEncodedFormEntity(postParameters, "UTF-8")); + + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + CloseableHttpResponse httpResponse = httpClient.execute(post); + + JsonObject jsonContent = new JsonParser().parse(EntityUtils.toString(httpResponse.getEntity())) + .getAsJsonObject(); + + if (!jsonContent.has("id_token")) { + this.logger.error(String.format("Google IAM response: %s", jsonContent.toString())); + throw new AppException(HttpStatus.SC_FORBIDDEN, "Access denied", + "User is not authorized to perform this operation."); + } + + String token = jsonContent.get("id_token").getAsString(); + + return "Bearer " + token; + } + } catch (AppException e) { + throw e; + } catch (Exception e) { + throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Persistence error", "Error generating token", + e); + } + + } + + Iam getIam() throws GeneralSecurityException, IOException { + if (this.iam == null) { + HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + + GoogleCredentials credential = GoogleCredentials.getApplicationDefault(); + if (credential.createScopedRequired()) { + List scopes = new ArrayList<>(); + scopes.add(IamScopes.CLOUD_PLATFORM); + credential = credential.createScoped(scopes); + } + + this.iam = new Iam.Builder(httpTransport, JSON_FACTORY, new HttpCredentialsAdapter(credential)) + .setApplicationName(storageHostname).build(); + } + + return this.iam; + } + + private Map getJwtCreationPayload(TenantInfo tenantInfo) { + String googleAudience = googleAudiences; + if (googleAudience.contains(",")) { + googleAudience = googleAudience.split(",")[0]; + } + Map payload = new HashMap<>(); + payload.put("target_audience", googleAudience); + payload.put("aud", JWT_AUDIENCE); + payload.put("exp", System.currentTimeMillis() / 1000 + 3600); + payload.put("iat", System.currentTimeMillis() / 1000); + payload.put("iss", tenantInfo.getServiceAccount()); + return payload; + } } \ No newline at end of file diff --git a/provider/storage-gcp/src/main/java/org/opengroup/osdu/storage/provider/gcp/util/ServiceAccountJwtClientProvider.java b/provider/storage-gcp/src/main/java/org/opengroup/osdu/storage/provider/gcp/util/ServiceAccountJwtClientProvider.java deleted file mode 100644 index 9a7de590fc5e838f39125740bd15a8f5f49620e6..0000000000000000000000000000000000000000 --- a/provider/storage-gcp/src/main/java/org/opengroup/osdu/storage/provider/gcp/util/ServiceAccountJwtClientProvider.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2021 Google LLC - * Copyright 2021 EPAM Systems, Inc - * - * 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 org.opengroup.osdu.storage.provider.gcp.util; - -import lombok.RequiredArgsConstructor; -import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient; -import org.opengroup.osdu.core.gcp.GoogleIdToken.GcpServiceAccountJwtClient; -import org.opengroup.osdu.storage.provider.gcp.config.StorageConfigProperties; -import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; -import org.springframework.web.context.annotation.RequestScope; - -@Primary -@Component -@RequestScope -@RequiredArgsConstructor -public class ServiceAccountJwtClientProvider extends AbstractFactoryBean { - - private final StorageConfigProperties storageConfigProperties; - - @Override - public Class getObjectType() { - return GcpServiceAccountJwtClient.class; - } - - @Override - protected IServiceAccountJwtClient createInstance() { - GcpServiceAccountJwtClient serviceAccountJwtClient = new GcpServiceAccountJwtClient( - storageConfigProperties.getGoogleAudiences()); - return serviceAccountJwtClient; - } -} - diff --git a/provider/storage-gcp/src/main/resources/application.properties b/provider/storage-gcp/src/main/resources/application.properties index e824f6886390a80ea51e15eec1eeee3a13c188e9..ad9e86a53fd2f18fae87727ce1f43ab87f9dfbe6 100644 --- a/provider/storage-gcp/src/main/resources/application.properties +++ b/provider/storage-gcp/src/main/resources/application.properties @@ -3,7 +3,7 @@ LOG_PREFIX=storage osdu.gcp.storage.gcs.enable-impersonalization=false server.servlet.contextPath=/api/storage/v2/ -logging.level.org.springframework.web={LOG_LEVEL:DEBUG} +logging.level.org.springframework.web=${LOG_LEVEL:DEBUG} server.port=8080 JAVA_HEAP_OPTS=-Xms4096M -Xmx4096M JAVA_GC_OPTS=-XX:+UseG1GC -XX:+UseStringDeduplication -XX:InitiatingHeapOccupancyPercent=45