diff --git a/NOTICE b/NOTICE index 1f9ce6fe2470be56e94cc556ab69fa1450c402f6..a71aa257107bb02421138312709a9726e98b7b90 100644 --- a/NOTICE +++ b/NOTICE @@ -106,10 +106,8 @@ The following software have components provided under the terms of this license: - Lucene Spatial Extras (from ) - Lucene Suggest (from ) - MapStruct Core (from ) -- Mockito (from http://mockito.org) - Mockito (from http://www.mockito.org) -- MongoDB Java Driver (from http://www.mongodb.org) -- MongoDB Java Driver (from http://www.mongodb.org) +- Mockito (from http://mockito.org) - Netty/Buffer (from http://netty.io/) - Netty/Codec (from ) - Netty/Common (from ) @@ -289,8 +287,6 @@ CC-BY-2.5 The following software have components provided under the terms of this license: - Checker Qual (from https://checkerframework.org) -- MongoDB Java Driver (from http://www.mongodb.org) -- MongoDB Java Driver (from http://www.mongodb.org) ======================================================================== CC-BY-3.0 @@ -507,9 +503,8 @@ The following software have components provided under the terms of this license: - Java JWT (from http://www.jwt.io) - Java JWT (from http://www.jwt.io) - Lucene Core (from ) -- Mockito (from http://mockito.org) - Mockito (from http://www.mockito.org) -- MongoDB Java Driver (from http://www.mongodb.org) +- Mockito (from http://mockito.org) - Netty/Common (from ) - Project Lombok (from https://projectlombok.org) - SLF4J API Module (from http://www.slf4j.org) diff --git a/pom.xml b/pom.xml index 33275c48cbf1acac700b6f41ad2e1a9777bb6625..0f755893b6418314f3b8cbf4e1a9fa28b017c072 100644 --- a/pom.xml +++ b/pom.xml @@ -90,6 +90,7 @@ <modules> <module>register-core</module> <module>provider/register-gcp</module> + <module>provider/register-ibm</module> <module>provider/register-azure</module> </modules> diff --git a/provider/register-ibm/README.md b/provider/register-ibm/README.md new file mode 100644 index 0000000000000000000000000000000000000000..befdcaea1cb3941a7f0a7666954c31b82db090c1 --- /dev/null +++ b/provider/register-ibm/README.md @@ -0,0 +1 @@ +# os-register-ibm \ No newline at end of file diff --git a/provider/register-ibm/pom.xml b/provider/register-ibm/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..949e2b7acf89c5cc2db2abb18c7117d029495f15 --- /dev/null +++ b/provider/register-ibm/pom.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2020 IBM Corp. All Rights Reserved. + 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. +--> + +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.opengroup.osdu</groupId> + <artifactId>register-ibm</artifactId> + <version>1.0.0</version> + <description>Register service</description> + <packaging>jar</packaging> + + <parent> + <groupId>org.opengroup.osdu</groupId> + <artifactId>os-register</artifactId> + <version>1.0.0</version> + <relativePath>../../</relativePath> + </parent> + + <dependencies> + <dependency> + <groupId>org.opengroup.osdu</groupId> + <artifactId>os-core-lib-ibm</artifactId> + <version>0.3.6-SNAPSHOT</version> + </dependency> + + + <dependency> + <groupId>org.opengroup.osdu</groupId> + <artifactId>os-core-common</artifactId> + </dependency> + + <dependency> + <groupId>org.opengroup.osdu</groupId> + <artifactId>register-core</artifactId> + <version>1.0.0</version> + </dependency> + + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-config</artifactId> + </dependency> + + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>2.0.2</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito2</artifactId> + <version>2.0.2</version> + <scope>test</scope> + </dependency> + + </dependencies> + + <repositories> + <repository> + <id>${gitlab-server}</id> + <url>https://community.opengroup.org/api/v4/groups/17/-/packages/maven</url> + </repository> + </repositories> + + <distributionManagement> + <repository> + <id>${gitlab-server}</id> + <url>https://community.opengroup.org/api/v4/projects/157/packages/maven</url> + </repository> + <snapshotRepository> + <id>${gitlab-server}</id> + <url>https://community.opengroup.org/api/v4/projects/157/packages/maven</url> + </snapshotRepository> + </distributionManagement> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + <configuration> + <classifier>spring-boot</classifier> + <mainClass>org.opengroup.osdu.register.provider.ibm.RegisterApplication</mainClass> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/RegisterApplication.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/RegisterApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..a103551ee2ed91de1bdc461c2fa8943fe1b84a62 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/RegisterApplication.java @@ -0,0 +1,41 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; + +import javax.annotation.PostConstruct; + +@SpringBootApplication(exclude = { + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class +}) +@ComponentScan({"org.opengroup.osdu"}) +public class RegisterApplication { + @PostConstruct + void f() { + + } + + public static void main(String[] args) { + SpringApplication.run(RegisterApplication.class, args); + } +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/action/datastore/ActionDoc.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/action/datastore/ActionDoc.java new file mode 100644 index 0000000000000000000000000000000000000000..0e9c14d0dda840d727ac252f3f4c911e1efd94b3 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/action/datastore/ActionDoc.java @@ -0,0 +1,70 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.action.datastore; + +import org.opengroup.osdu.register.action.model.Action; + + +public class ActionDoc extends Action{ + private String _id; + private String _rev; + + public ActionDoc(Action action) { + this._id=action.getId(); + super.setName(action.getName()); + super.setDescription(action.getDescription()); + super.setUrl(action.getUrl()); + super.setImg(action.getImg()); + super.setContactEmail(action.getContactEmail()); + super.setFilter(action.getFilter()); + + } + + public String get_id() { + return _id; + } + + public void set_id(String _id) { + this._id = _id; + } + + public String get_rev() { + return _rev; + } + + public void set_rev(String _rev) { + this._rev = _rev; + } + + public Action getAction() { + Action action=new Action(); + action.setId(this.get_id()); + action.setName(this.getName()); + action.setDescription(this.getDescription()); + action.setUrl(this.getUrl()); + action.setImg(this.getImg()); + action.setContactEmail(this.getContactEmail()); + action.setFilter(this.getFilter()); + return action; + } + + @Override + public String toString() { + return "ActionDoc [_id=" + _id + ", _rev=" + _rev +", "+ getAction()+ "]"; + } + +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/action/datastore/ActionRepository.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/action/datastore/ActionRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..820143adcc1ad9038c9a03f73333cdfca7674b6e --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/action/datastore/ActionRepository.java @@ -0,0 +1,127 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.action.datastore; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.tenant.TenantInfo; +import org.opengroup.osdu.core.common.util.Crc32c; +import org.opengroup.osdu.register.action.model.Action; +import org.opengroup.osdu.register.provider.ibm.ddms.datastore.DatastoreMultiTenantAccess; +import org.opengroup.osdu.register.provider.interfaces.action.IActionRepo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import com.cloudant.client.api.Database; +import com.cloudant.client.org.lightcouch.DocumentConflictException; +import com.google.gson.Gson; + +import lombok.Getter; + +@Repository +public class ActionRepository implements IActionRepo { + + private static final String ACTION_DB_NAME = "action"; + + @Autowired + private JaxRsDpsLog log; + @Autowired + private DatastoreMultiTenantAccess dataStoreTenants; + @Autowired + private TenantInfo tenantInfo; + + @Override + public Action createAction(Action a) { + return createActionInDatastore(a); + } + + @Override + public Action get(String id) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + if(!(db.contains(id))) { + log.error(String.format("Action with id %s does not exist.", id)); + throw new AppException(404, "Not found", String.format("Action with id %s does not exist.", id)); + } + ActionDoc actionDoc = db.find(ActionDoc.class, id); + return actionDoc.getAction(); + } + + @Override + public boolean delete(String id) { + return deleteFromDatastore(id); + } + + private Action createActionInDatastore(Action action) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + ActionDoc actionDoc = new ActionDoc(action); + try { + db.save(actionDoc); + } catch (DocumentConflictException e) { + throwConflict(); + } + return action; + } + + private Action throwConflict() { + throw new AppException(409, "Conflict", "An action already exists with the same message and endpoint combination"); + } + + private boolean deleteFromDatastore(String id) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + boolean output = false; + if(db.contains(id)) { + ActionDoc actionDoc = db.find(ActionDoc.class, id); + db.remove(actionDoc); + output = true; + } + else { + log.error(String.format("deletion failed. Could not find action id : %s", id)); + output=false; + } + return output; + + } + + @Override + public List<Action> getAllActions() { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + List<Action> actionsList=new ArrayList<>(); + try { + List<ActionDoc> actionDocsList = db.getAllDocsRequestBuilder().includeDocs(true).build().getResponse().getDocsAs(ActionDoc.class); + actionsList = actionDocsList.stream().map(i->i.getAction()).collect(Collectors.toList()); + } catch (IOException e) { + log.error("IOException while fetching all actons",e); + e.printStackTrace(); + } + return actionsList; + } + + + /** + * @return + */ + private String getDbNameWithTenant() { + return tenantInfo.getName()+"-"+ACTION_DB_NAME; + } + +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/ddms/datastore/DatastoreDdmsRepository.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/ddms/datastore/DatastoreDdmsRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..2021cb982a3052717fcae6e7152b0c7aa4a1a690 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/ddms/datastore/DatastoreDdmsRepository.java @@ -0,0 +1,130 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.ddms.datastore; + +import static com.cloudant.client.api.query.Expression.eq; +import static com.cloudant.client.api.query.Operation.and; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.tenant.TenantInfo; +import org.opengroup.osdu.register.ddms.model.Ddms; +import org.opengroup.osdu.register.provider.interfaces.ddms.IDdmsRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import com.cloudant.client.api.Database; +import com.cloudant.client.api.query.PredicateExpression; +import com.cloudant.client.api.query.PredicatedOperation.*; +import com.cloudant.client.api.query.QueryBuilder; +import com.cloudant.client.api.query.QueryResult; +import com.cloudant.client.org.lightcouch.DocumentConflictException; +import com.google.gson.Gson; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Repository +public class DatastoreDdmsRepository implements IDdmsRepository { + + private static final String DDMS_DATABASE = "DDMS"; + + @Autowired + private DatastoreMultiTenantAccess dataStoreTenants; + @Autowired + private TenantInfo tenantInfo; + + @Override + public Ddms create(Ddms ddms) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + DdmsDoc ddmsDoc = new DdmsDoc(ddms); + try { + /* + * if(db.contains(ddms.getId())) { log.warn("DDMS already registered"); //throw + * new DocumentConflictException("Document already available"); } + */ + db.save(ddmsDoc); + } catch (DocumentConflictException e) { + log.error("DDMS already registered. A DDMS already exists with the same id : " + ddmsDoc.get_id()); + throw new AppException(409, "Conflict", "DDMS already registered"); + + } catch (Exception e) { + log.error("Error while creating document {} in database {}", ddms.getId(), db.info().getDbName()); + e.printStackTrace(); + } + return ddms; + } + + @Override + public Ddms get(String id) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + if (db.contains(id)) { + DdmsDoc ddmsDoc = db.find(DdmsDoc.class, id); + return ddmsDoc.getDdms(); + } else { + log.error("DDMS with id {} does not exist", id); + throw new AppException(404, "Not found", String.format("DDMS with id %s does not exist.", id)); + } + } + + @Override + public List<Ddms> query(String type) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + String selectorString = "{\"selector\":{\"interfaces\":{\"$elemMatch\":{\"entityType\":\"%s\"}}}}"; + String selector = String.format(selectorString, type); + QueryResult<DdmsDoc> results = db.query(selector, DdmsDoc.class); + if (results.getDocs().isEmpty()) { + throw new AppException(404, "Not found", String.format("DDMS with entity type %s does not exist.", type)); + } + List<DdmsDoc> ddmsDocList = results.getDocs(); + List<Ddms> ddmsList = ddmsDocList.stream().map(i -> i.getDdms()).collect(Collectors.toList()); + return ddmsList; + + } + + @Override + public boolean delete(String id) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + boolean output = false; + try { + if (db.contains(id)) { + DdmsDoc ddmsDoc = db.find(DdmsDoc.class, id); + db.remove(ddmsDoc); + return true; + } else { + log.error("could not found DDMS id : " + id); + return false; + } + } catch (Exception e) { + log.error("failed to delete DDMS : " + id); + e.printStackTrace(); + } + + return output; + } + + /** + * @return + */ + private String getDbNameWithTenant() { + return tenantInfo.getName() + "-" + DDMS_DATABASE; + } +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/ddms/datastore/DatastoreMultiTenantAccess.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/ddms/datastore/DatastoreMultiTenantAccess.java new file mode 100644 index 0000000000000000000000000000000000000000..db1bd0fc824d843954b4194c5e95fb7a318f7202 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/ddms/datastore/DatastoreMultiTenantAccess.java @@ -0,0 +1,101 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.ddms.datastore; + +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.StringUtils; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.opengroup.osdu.core.ibm.auth.ServiceCredentials; +import org.opengroup.osdu.core.ibm.cloudant.IBMCloudantClientFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import com.cloudant.client.api.Database; + +import lombok.extern.slf4j.Slf4j; +@Slf4j +@Component +public class DatastoreMultiTenantAccess { + @Value("${ibm.db.url}") + private String dbUrl; + + @Value("${ibm.env.prefix}") + private String dBEnvPrefix; + + @Value("${ibm.db.user:#{null}}") + private String dbUser; + + @Value("${ibm.db.password:#{null}}") + private String dbPassword; + + //private final IDatastoreFactory factory; + + private IBMCloudantClientFactory cloudantFactory; + + private final Map<String, Database> tenantRepositories = new HashMap<>(); + + /* public DatastoreMultiTenantAccess() { + this(new IBMCloudantClientFactory(new ServiceCredentials(dbUrl, dbUser, dbPassword))); + } + + DatastoreMultiTenantAccess(IBMCloudantClientFactory factory) { + this.cloudantFactory = factory; + }*/ + + @PostConstruct + public void init() { + cloudantFactory = new IBMCloudantClientFactory(new ServiceCredentials(dbUrl, dbUser, dbPassword)); + log.info("IBM Cloudant factory created "); + + } + + public Database get(String tenantName) { + if (StringUtils.isBlank(tenantName)) + throw invalidTenantGivenException(tenantName); + if (!tenantRepositories.containsKey(tenantName)) { + addRepository(tenantName); + } + return tenantRepositories.get(tenantName); + } + + private void addRepository(String tenantName) { + + try { + Database db = cloudantFactory.getDatabase(dBEnvPrefix, tenantName); + if (db == null) + throw invalidTenantGivenException(tenantName); + tenantRepositories.put(tenantName, db); + log.info("Database created and added to tenant repository : "+db.info().getDbName()); + } catch (MalformedURLException e) { + log.error("MalformedURLException while creating Database "); + e.printStackTrace(); + } + + } + + private AppException invalidTenantGivenException(String tenantName) { + return new AppException(403, "Forbidden", String.format("You do not have access to the %s value given %s", + DpsHeaders.DATA_PARTITION_ID, tenantName)); + } +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/ddms/datastore/DdmsDoc.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/ddms/datastore/DdmsDoc.java new file mode 100644 index 0000000000000000000000000000000000000000..39cef79a1b39dc4b8b5c4f836ca0317efa3f22b9 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/ddms/datastore/DdmsDoc.java @@ -0,0 +1,67 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.ddms.datastore; + +import org.opengroup.osdu.register.ddms.model.Ddms; + +public class DdmsDoc extends Ddms { + private String _id; + private String _rev; + + public DdmsDoc(Ddms ddms) { + super(); + + this.set_id(ddms.getId()); + super.setName(ddms.getName()); + super.setDescription(ddms.getDescription()); + super.setContactEmail(ddms.getContactEmail()); + super.setInterfaces(ddms.getInterfaces()); + } + + public String get_id() { + return _id; + } + + public void set_id(String _id) { + this._id = _id; + } + + public String get_rev() { + return _rev; + } + + public void set_rev(String _rev) { + this._rev = _rev; + } + + public Ddms getDdms() { + Ddms ddms = new Ddms(); + ddms.setId(this.get_id()); + ddms.setName(this.getName()); + ddms.setDescription(this.getDescription()); + ddms.setContactEmail(this.getContactEmail()); + ddms.getCreatedDateTimeEpoch(); + ddms.setInterfaces(this.getInterfaces()); + return ddms; + } + + @Override + public String toString() { + return "DdmsDoc [_id=" + _id + ", _rev=" + _rev + ", getDdms()=" + getDdms() + "]"; + } + +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/security/IBMSecurityConfig.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/security/IBMSecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..a1db2e68c989d2105f95a586715d6e92ca88e518 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/security/IBMSecurityConfig.java @@ -0,0 +1,34 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.security; + +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class IBMSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + httpSecurity + .httpBasic().disable() + .csrf().disable(); //disable default authN. AuthN handled by endpoints proxy + } +} \ No newline at end of file diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/DatastoreAccess.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/DatastoreAccess.java new file mode 100644 index 0000000000000000000000000000000000000000..75ccb49bb12460054534b09926747ef8e30d306b --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/DatastoreAccess.java @@ -0,0 +1,212 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.subscriber; + +import static com.cloudant.client.api.query.Expression.eq; +import static java.lang.String.format; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.tenant.TenantInfo; +import org.opengroup.osdu.register.provider.ibm.ddms.datastore.DatastoreMultiTenantAccess; +import org.opengroup.osdu.register.subscriber.model.GsaSecret; +import org.opengroup.osdu.register.subscriber.model.GsaSecretValue; +import org.opengroup.osdu.register.subscriber.model.HmacSecret; +import org.opengroup.osdu.register.subscriber.model.Secret; +import org.opengroup.osdu.register.subscriber.model.Subscription; +import org.opengroup.osdu.register.utils.Constants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import com.cloudant.client.api.Database; +import com.cloudant.client.api.query.QueryBuilder; +import com.cloudant.client.api.query.QueryResult; +import com.cloudant.client.org.lightcouch.DocumentConflictException; +import com.cloudant.client.org.lightcouch.NoDocumentException; +import com.google.cloud.Timestamp; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Repository +public class DatastoreAccess implements IDatastoreAccess { + + private static final String SUBSCRIBER_DB_NAME = "subscription"; + @Autowired + private PushSubscription pushSubscription; + @Autowired + private DatastoreMultiTenantAccess dataStoreTenants; + @Autowired + private TenantInfo tenantInfo; + + @Override + public Subscription create(Subscription s) { + s = createSubscriberInDatastore(s); + try { + // pushSubscription.create(s, tenantInfo, this.config.getGoogleCloudProject(), + // config.getServiceAccountIdentity()); + } catch (Exception e) { + deleteFromDatastore(s.getId(), false); + throw new AppException(500, "Server Error", "Unexpected error creating subscription", e); + } + return s; + } + + @Override + public Subscription get(String id) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + + Subscription subscription = null; + try { + SubscriptionDoc subscriptionDoc = db.find(SubscriptionDoc.class, id); + subscription = convertToSubscription(subscriptionDoc); + } catch (NoDocumentException e) { + throw new AppException(e.getStatusCode(), e.getReason(), + String.format("Subscriber with id %s does not exist.", id)); + } catch (Exception e) { + System.out.println(e.getMessage()); + e.printStackTrace(); + } + return subscription; + + } + + // TODO: Remove this api when switch notification to use cache + @Override + public List<Subscription> query(String notificationId) { + List<Subscription> output = new ArrayList<>(); + Database db = dataStoreTenants.get(getDbNameWithTenant()); + QueryResult<SubscriptionDoc> results = null; + try { + results = db.query(new QueryBuilder(eq("notificationId", notificationId)).build(), SubscriptionDoc.class); + + if (results == null || results.getDocs().isEmpty()) { + throw new AppException(404, "Not Found", + format("Sunscriptio not forund for notification id %s ", notificationId)); + } + } catch (Exception e) { + log.info("Unexpected error querying subscription"); + e.printStackTrace(); + } + output = results.getDocs().stream().map(i -> convertToSubscription(i)).collect(Collectors.toList()); + return output; + } + + @Override + public boolean delete(String id) { + return deleteFromDatastore(id, true); + } + + @Override + public boolean patch(String id, Secret secret) { + return updateInDataStore(id, secret); + } + + @Override + public List<Subscription> getAll() throws Exception { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + List<SubscriptionDoc> subscriptionDocList = db.getAllDocsRequestBuilder().includeDocs(true).build() + .getResponse().getDocsAs(SubscriptionDoc.class); + List<Subscription> subscriptionsList = subscriptionDocList.stream().map(i -> convertToSubscription(i)) + .collect(Collectors.toList()); + return subscriptionsList; + } + + private Subscription createSubscriberInDatastore(Subscription s) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + SubscriptionDoc subscriptionDoc = new SubscriptionDoc(s); + try { + db.save(subscriptionDoc); + } catch (DocumentConflictException e) { + throw new AppException(409, "Conflict", + "A subscriber already exists with the same topic and endpoint combination"); + } catch (Exception e) { + + } + return convertToSubscription(subscriptionDoc); + } + + private boolean deleteFromDatastore(String id, boolean deleteSubscription) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + boolean output = false; + if (!db.contains(id)) { + return output; + } + try { + SubscriptionDoc subscriptionDoc = db.find(SubscriptionDoc.class, id); + /* + * if(deleteSubscription) { // TODO Add flow for deleting the subscription to + * the topic //identify first parameter serviceProjectId + * //pushSubscription.delete(servicesProjectId, + * subscriptionDoc.getNotificationId()); } + */ + db.remove(subscriptionDoc); + output = true; + } catch (NoDocumentException e) { + throw new AppException(e.getStatusCode(), e.getReason(), e.getMessage()); + } catch (DocumentConflictException e) { + throw new AppException(e.getStatusCode(), e.getReason(), e.getMessage()); + } + return output; + } + + private boolean updateInDataStore(String id, Secret secret) { + Database db = dataStoreTenants.get(getDbNameWithTenant()); + boolean output = false; + try { + SubscriptionDoc subscriptionDoc = db.find(SubscriptionDoc.class, id); + subscriptionDoc.setSecretType(secret.getSecretType()); + subscriptionDoc.setSecretValue(secret.toString()); + db.update(subscriptionDoc); + output = true; + } catch (NoDocumentException | DocumentConflictException e) { + throw new AppException(e.getStatusCode(), e.getReason(), e.getMessage()); + } catch (Exception e) { + log.error("Unexpected Error updating subscription " + e); + } + return output; + } + + /** + * @return + */ + private String getDbNameWithTenant() { + return tenantInfo.getName() + "-" + SUBSCRIBER_DB_NAME; + } + + private Subscription convertToSubscription(SubscriptionDoc doc) { + String secretValue = doc.getSecretValue(); + Secret secret; + if (doc.getSecretType().equals(Constants.GSASecret)) { + GsaSecret gsaSecret = new GsaSecret(); + String[] splitSecret = secretValue.split("`"); + gsaSecret.setValue(new GsaSecretValue(splitSecret[0], splitSecret[1])); + secret = gsaSecret; + } else { + HmacSecret hmacSecret = new HmacSecret(); + hmacSecret.setValue(secretValue); + secret = hmacSecret; + } + return new Subscription(doc.get_id(), doc.getName(), doc.getDescription(), doc.getTopic(), + doc.getPushEndpoint(), doc.getCreatedBy(), Timestamp.of(doc.getCreatedOnEpoch()), + doc.getNotificationId(), secret); + } + +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/IDatastoreAccess.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/IDatastoreAccess.java new file mode 100644 index 0000000000000000000000000000000000000000..6ba98f99e93c97e17d37a0d95d21bc2a6bfdfdf3 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/IDatastoreAccess.java @@ -0,0 +1,37 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.subscriber; + + +import org.opengroup.osdu.register.subscriber.model.Secret; +import org.opengroup.osdu.register.subscriber.model.Subscription; + +import java.util.List; + +public interface IDatastoreAccess { + Subscription create(Subscription s); + + Subscription get(String id); + + List<Subscription> query(String notificationId); + + boolean delete(String id); + + boolean patch(String id, Secret secret); + + List<Subscription> getAll() throws Exception; +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/PushSubscription.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/PushSubscription.java new file mode 100644 index 0000000000000000000000000000000000000000..319ca7eea533e53703131fed9c36940ad12bf305 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/PushSubscription.java @@ -0,0 +1,88 @@ +/* + * Copyright 2017-2020, 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.register.provider.ibm.subscriber; + +import com.google.api.gax.rpc.NotFoundException; +import com.google.cloud.pubsub.v1.SubscriptionAdminClient; +import com.google.protobuf.Duration; +import com.google.pubsub.v1.ExpirationPolicy; +import com.google.pubsub.v1.ProjectSubscriptionName; +import com.google.pubsub.v1.ProjectTopicName; +import com.google.pubsub.v1.PushConfig; +import org.opengroup.osdu.core.common.model.tenant.TenantInfo; +import org.opengroup.osdu.register.utils.AppServiceConfig; +import org.opengroup.osdu.register.subscriber.model.Subscription; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +public class PushSubscription { + private static final int ackDeadlineSeconds = 60; + private static final int messageRetentionSeconds = 432000; + private static final int subscriptionExpirationSeconds = 31540000; + + @Autowired + private AppServiceConfig serviceConfig; + + public Subscription create(Subscription subscription, TenantInfo tenant, + String masterGcpId, String serviceIdentityEmail) + throws IOException { + createPushSubscription( + tenant.getProjectId(), + masterGcpId, + subscription.getTopic(), + subscription.getNotificationId(), + serviceConfig.getRecordsChangePubsubEndpoint(), + serviceIdentityEmail); + return subscription; + } + + public void delete(String servicesProjectId, String subscriptionId) throws IOException { + try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) { + try { + ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of(servicesProjectId, subscriptionId); + subscriptionAdminClient.deleteSubscription(subscriptionName); + } catch (NotFoundException e) { + //silently catch + } + } + } + + private com.google.pubsub.v1.Subscription createPushSubscription(String tenantProjectId, String servicesProjectId, String topicId, + String subscriptionId, String url, String serviceIdentityEmail) throws IOException { + try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) { + ProjectTopicName topicName = ProjectTopicName.of(tenantProjectId, topicId); + ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of(servicesProjectId, subscriptionId); + + PushConfig config = PushConfig.newBuilder() + .setPushEndpoint(url) + .setOidcToken(PushConfig.OidcToken.newBuilder().setServiceAccountEmail(serviceIdentityEmail).build()) + .build(); + return subscriptionAdminClient.createSubscription(com.google.pubsub.v1.Subscription.newBuilder() + .setName(subscriptionName.toString()) + .setTopic(topicName.toString()) + .setPushConfig(config) + .setExpirationPolicy(ExpirationPolicy.newBuilder().setTtl( + Duration.newBuilder().setSeconds(subscriptionExpirationSeconds).build()).build()) + .setMessageRetentionDuration(Duration.newBuilder().setSeconds(messageRetentionSeconds).build()) + .setAckDeadlineSeconds(ackDeadlineSeconds) + .build()); + } + } +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/SubscriptionDoc.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/SubscriptionDoc.java new file mode 100644 index 0000000000000000000000000000000000000000..957ab0a14fb06b725107615c3551b12b76079a28 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/SubscriptionDoc.java @@ -0,0 +1,57 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.subscriber; + +import java.sql.Timestamp; + +import org.opengroup.osdu.register.subscriber.model.Subscription; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SubscriptionDoc { + private String _id; + private String _rev; + private String name; + private String description; + private String topic; + private String pushEndpoint; + private String createdBy; + private Timestamp createdOnEpoch; + private String notificationId; + private String secretType; + private String secretValue; + + public SubscriptionDoc(Subscription subscription) { + this._id = subscription.getId(); + this.name = subscription.getName(); + this.description = subscription.getDescription(); + this.topic = subscription.getTopic(); + this.pushEndpoint = subscription.getPushEndpoint(); + this.createdBy = subscription.getCreatedBy(); + this.createdOnEpoch = new Timestamp(System.currentTimeMillis()); + this.notificationId = subscription.getNotificationId(); + this.secretType = subscription.getSecret().getSecretType(); + this.secretValue = subscription.getSecret().toString(); + + } + +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/SubscriptionRepository.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/SubscriptionRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..c2c6a59ede5acb9429d73fd2334091737d600b50 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/subscriber/SubscriptionRepository.java @@ -0,0 +1,71 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.subscriber; + +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.register.subscriber.model.Secret; +import org.opengroup.osdu.register.subscriber.model.Subscription; +import org.opengroup.osdu.register.provider.interfaces.subscriber.ISubscriptionRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class SubscriptionRepository implements ISubscriptionRepository { + + @Autowired + private IDatastoreAccess datastoreAccess; + + @Override + public Subscription create(Subscription input) throws Exception { + int existingSubscriptionsCount = datastoreAccess.getAll().size(); + // Due to the limit of google subscription per project, we are restricting the limit per tenant to 50 + // This already looks a difficult limit to reach, but need to keep a watch on this number. + if (existingSubscriptionsCount == 50) + throw new AppException(429, "Subscription quota reached", + "Number of subscription allowed have already reached to maximum"); + + input = datastoreAccess.create(input); + return input; + } + + @Override + public Subscription get(String id) { + return datastoreAccess.get(id); + } + + @Override + public List<Subscription> query(String notificationId) { + return datastoreAccess.query(notificationId); + } + + @Override + public boolean delete(String id) { + return datastoreAccess.delete(id); + } + + @Override + public boolean patch(Subscription subscription, Secret secret) { + return datastoreAccess.patch(subscription.getId(), secret); + } + + @Override + public List<Subscription> getAll() throws Exception { + return datastoreAccess.getAll(); + } +} diff --git a/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/util/GoogleServiceAccountImpl.java b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/util/GoogleServiceAccountImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..e69f44b4e599b6bd9a2d011dff32ac8239993d53 --- /dev/null +++ b/provider/register-ibm/src/main/java/org/opengroup/osdu/register/provider/ibm/util/GoogleServiceAccountImpl.java @@ -0,0 +1,40 @@ +/** + * Copyright 2020 IBM Corp. All Rights Reserved. + * + * 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.register.provider.ibm.util; + +import lombok.SneakyThrows; +import org.opengroup.osdu.register.utils.IGoogleServiceAccount; +import org.springframework.stereotype.Component; + +@Component +public class GoogleServiceAccountImpl implements IGoogleServiceAccount { + + + @SneakyThrows + @Override + public String getIdToken(String keyString, String audience) { + //TODO Add implementation for generating GSA Tokens + return "token"; + } + + @SneakyThrows + @Override + public String getPrivateKeyId(String keyString) { + //TODO Add implementation for generating GSA Tokens + return "private-key"; + } +} \ No newline at end of file diff --git a/provider/register-ibm/src/main/resources/application.properties b/provider/register-ibm/src/main/resources/application.properties new file mode 100644 index 0000000000000000000000000000000000000000..8dfe64f93bf2c2d5e3bda7eca24a53301d1d9608 --- /dev/null +++ b/provider/register-ibm/src/main/resources/application.properties @@ -0,0 +1,8 @@ +server.servlet.contextPath=/api/register/v1 +logging.level.org.springframework.web=DEBUG +server.port=8080 +LOG_PREFIX=register + +KEY_RING=csqp +KMS_KEY=registerService +SERVICE_IDENTITY=de-notification-service \ No newline at end of file