diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a2ee41..9720fe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm # Changelog for StorageHub Application Persistence +## [v3.4.0-SNAPSHOT] + +- To ensure persistence of file already stored in the workspace is now used the facility provided by storage-hub #27736 + + ## [v3.3.0] - Added GENERATING_APPLICATION_NAME and GENERATING_APPLICATION_METADATA_VERSION to be used in Metadata diff --git a/pom.xml b/pom.xml index 060cbe7..c5489e0 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ org.gcube.data-publishing storagehub-application-persistence - 3.3.0 + 3.4.0-SNAPSHOT StorageHub Application Persistence This library allows any application to persist in its workspace home any @@ -57,6 +57,10 @@ authorization-utils [2.2.0, 3.0.0-SNAPSHOT) + + org.gcube.core + common-encryption + org.projectlombok lombok diff --git a/src/main/java/org/gcube/storagehub/StorageHubManagement.java b/src/main/java/org/gcube/storagehub/StorageHubManagement.java index f347e7c..9083459 100644 --- a/src/main/java/org/gcube/storagehub/StorageHubManagement.java +++ b/src/main/java/org/gcube/storagehub/StorageHubManagement.java @@ -3,10 +3,12 @@ package org.gcube.storagehub; import java.io.InputStream; import java.io.StringWriter; import java.net.URL; +import java.util.Base64; import java.util.List; import org.gcube.common.authorization.utils.manager.SecretManager; import org.gcube.common.authorization.utils.manager.SecretManagerProvider; +import org.gcube.common.encryption.encrypter.StringEncrypter; import org.gcube.common.scope.impl.ScopeBean; import org.gcube.common.scope.impl.ScopeBean.Type; import org.gcube.common.storagehub.client.dsl.ContainerType; @@ -15,6 +17,7 @@ import org.gcube.common.storagehub.client.dsl.FolderContainer; import org.gcube.common.storagehub.client.dsl.ItemContainer; import org.gcube.common.storagehub.client.dsl.ListResolver; import org.gcube.common.storagehub.client.dsl.ListResolverTyped; +import org.gcube.common.storagehub.client.dsl.OpenResolver; import org.gcube.common.storagehub.client.dsl.StorageHubClient; import org.gcube.common.storagehub.model.Metadata; import org.gcube.common.storagehub.model.exceptions.StorageHubException; @@ -174,6 +177,46 @@ public class StorageHubManagement { recursiveList(folderContainer, 1); } + public static String getPublicLinkID(URL url) { + String path = url.getPath().toString(); + if(path.endsWith("/")) { + path = path.substring(0,path.length()-1); + } + String[] parts = path.split("/"); + String id = parts[parts.length-1]; + return id; + } + + public static final String enchriptedPrefix = "E_"; + + public static String getFileId(URL url) throws Exception { + String encId = getPublicLinkID(url); + encId = encId.replace(enchriptedPrefix, ""); + String decodeURL = new String(Base64.getUrlDecoder().decode(encId)); + String decodedId = StringEncrypter.getEncrypter().decrypt(decodeURL); + return decodedId; + } + + public URL persistFile(URL workspaceFileToCopy, String fileName, String mimeType) + throws Exception { + this.mimeType = mimeType; + FolderContainer destinationFolder = getDestinationFolder(mimeType); + + String id = getFileId(workspaceFileToCopy); + OpenResolver openResolver = storageHubClient.open(id); + FileContainer fileContainer = openResolver.asFile(); + persitedFile = fileContainer.copy(destinationFolder, fileName); + + if(metadataMatcher != null) { + persitedFile.setMetadata(metadataMatcher.getMetadata()); + } + + URL finalURL = persitedFile.getPublicLink(); + logger.debug("File persistence has been ensured. The file is available at {}", finalURL); + return finalURL; + } + + @Deprecated public URL persistFile(InputStream inputStream, String fileName, String mimeType) throws Exception { this.mimeType = mimeType; diff --git a/src/test/java/org/gcube/storagehub/ContextTest.java b/src/test/java/org/gcube/storagehub/ContextTest.java index c8217b2..75f8a44 100644 --- a/src/test/java/org/gcube/storagehub/ContextTest.java +++ b/src/test/java/org/gcube/storagehub/ContextTest.java @@ -13,6 +13,7 @@ import org.gcube.common.authorization.utils.secret.JWTSecret; import org.gcube.common.authorization.utils.secret.Secret; import org.gcube.common.authorization.utils.secret.SecretUtility; import org.gcube.common.keycloak.KeycloakClientFactory; +import org.gcube.common.keycloak.KeycloakClientHelper; import org.gcube.common.keycloak.model.TokenResponse; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -28,17 +29,23 @@ public class ContextTest { protected static final String CONFIG_INI_FILENAME = "config.ini"; + public static final String DEFAULT_TEST_SCOPE; + public static final String GCUBE; public static final String DEVNEXT; public static final String NEXTNEXT; public static final String DEVSEC; public static final String DEVVRE; - public static final String ROOT; + private static final String ROOT_PROD; + private static final String ROOT_PRE; protected static final Properties properties; - protected static final String CLIENT_ID_PROPERTY_KEY = "clientId"; + public static final String TYPE_PROPERTY_KEY = "type"; + public static final String USERNAME_PROPERTY_KEY = "username"; + public static final String PASSWORD_PROPERTY_KEY = "password"; + public static final String CLIENT_ID_PROPERTY_KEY = "clientId"; static { GCUBE = "/gcube"; @@ -47,20 +54,27 @@ public class ContextTest { DEVSEC = GCUBE + "/devsec"; DEVVRE = DEVSEC + "/devVRE"; - ROOT = GCUBE; - + ROOT_PROD = "/d4science.research-infrastructures.eu"; + ROOT_PRE = "/pred4s"; + + DEFAULT_TEST_SCOPE = DEVVRE; + + properties = new Properties(); InputStream input = ContextTest.class.getClassLoader().getResourceAsStream(CONFIG_INI_FILENAME); try { // load the properties file properties.load(input); - } catch (IOException e) { throw new RuntimeException(e); } } + private enum Type{ + USER, CLIENT_ID + }; + public static void set(Secret secret) throws Exception { SecretManagerProvider.instance.reset(); SecretManager secretManager = new SecretManager(); @@ -70,20 +84,56 @@ public class ContextTest { } public static void setContextByName(String fullContextName) throws Exception { + logger.debug("Going to set credentials for context {}", fullContextName); Secret secret = getSecretByContextName(fullContextName); set(secret); } private static TokenResponse getJWTAccessToken(String context) throws Exception { - String clientId = properties.getProperty(CLIENT_ID_PROPERTY_KEY); + Type type = Type.valueOf(properties.get(TYPE_PROPERTY_KEY).toString()); + + TokenResponse tr = null; int index = context.indexOf('/', 1); String root = context.substring(0, index == -1 ? context.length() : index); - String clientSecret = properties.getProperty(root); - TokenResponse tr = KeycloakClientFactory.newInstance().queryUMAToken(context, clientId, clientSecret, context, null); + switch (type) { + case CLIENT_ID: + String clientId = properties.getProperty(CLIENT_ID_PROPERTY_KEY); + String clientSecret = properties.getProperty(root); + + tr = KeycloakClientFactory.newInstance().queryUMAToken(context, clientId, clientSecret, context, null); + break; + + case USER: + default: + String username = properties.getProperty(USERNAME_PROPERTY_KEY); + String password = properties.getProperty(PASSWORD_PROPERTY_KEY); + + switch (root) { + case "/gcube": + default: + clientId = "next.d4science.org"; + break; + + case "/pred4s": + clientId = "pre.d4science.org"; + break; + + case "/d4science.research-infrastructures.eu": + clientId = "services.d4science.org"; + break; + } + clientSecret = null; + + tr = KeycloakClientHelper.getTokenForUser(context, username, password); + break; + + } + return tr; + } public static Secret getSecretByContextName(String context) throws Exception { @@ -101,11 +151,20 @@ public class ContextTest { Secret secret = SecretUtility.getSecretByTokenString(token); return secret; } - + + public static String getUser() { + String user = "UNKNOWN"; + try { + user = SecretManagerProvider.instance.get().getUser().getUsername(); + } catch(Exception e) { + logger.error("Unable to retrieve user. {} will be used", user); + } + return user; + } @BeforeClass public static void beforeClass() throws Exception { - setContextByName(GCUBE); + setContextByName(DEFAULT_TEST_SCOPE); } @AfterClass diff --git a/src/test/java/org/gcube/storagehub/StorageHubManagementTest.java b/src/test/java/org/gcube/storagehub/StorageHubManagementTest.java index f09ef92..f2e6a3d 100644 --- a/src/test/java/org/gcube/storagehub/StorageHubManagementTest.java +++ b/src/test/java/org/gcube/storagehub/StorageHubManagementTest.java @@ -14,7 +14,6 @@ import org.gcube.common.storagehub.client.dsl.OpenResolver; import org.gcube.common.storagehub.model.Metadata; import org.gcube.common.storagehub.model.items.Item; import org.gcube.common.storagehub.model.service.Version; -import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,15 +45,21 @@ public class StorageHubManagementTest extends ContextTest { */ } -// @Ignore + @Test + public void testPublicLink() throws Exception { + String urlString = "https://data.dev.d4science.org/shub/E_WE9XM3Vad1orRGNhZVJJY0NybkFQR1BzRzZKUndPeVdLYTk4b1Y2MmVhVE9oZFYvM2hBb1JKRkluT1JQR1RZdQ=="; + + } + + //@Ignore @Test public void listFolders() throws Exception { + String c = "/pred4s/preprod/GRSF_Pre"; + c = "/gcube"; + c = "/d4science.research-infrastructures.eu/FARM/GRSF_Pre"; + //ContextTest.setContextByName(c); List contexts = new ArrayList<>(); -// contexts.add(GCUBE); -// contexts.add(DEVSEC); - contexts.add(DEVVRE); -// contexts.add(DEVNEXT); -// contexts.add(NEXTNEXT); + contexts.add(c); for(String context : contexts) { ContextTest.setContextByName(context);