diff --git a/.settings/.gitignore b/.settings/.gitignore new file mode 100644 index 0000000..3b1537c --- /dev/null +++ b/.settings/.gitignore @@ -0,0 +1 @@ +/org.eclipse.jdt.core.prefs diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cdc18b..36faec6 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 org.gcube.spatial.data.ws-thredds +## [v1.0.0-SNAPSHOT] +Integration with new IAM +Security Fixes + + ## [v0.2.5] Fixes #21265 diff --git a/pom.xml b/pom.xml index d0d1c2e..72db0fb 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ org.gcube.spatial.data ws-thredds - 0.2.5 + 1.0.0-SNAPSHOT ws-thredds prototype of WS integration with data-transfer for Thredds pubblication @@ -42,12 +42,6 @@ org.gcube.spatial.data sdi-library [1.0.0-SNAPSHOT,1.3.0-SNAPSHOT) - - - com.fasterxml.jackson.core - jackson-annotations - - @@ -63,17 +57,6 @@ [1.2.0-SNAPSHOT,2.0.0-SNAPSHOT) - - - - - - - - - - - diff --git a/src/main/java/org/gcube/usecases/ws/thredds/TokenSetter.java b/src/main/java/org/gcube/usecases/ws/thredds/TokenSetter.java index 4253f33..78de3c8 100644 --- a/src/main/java/org/gcube/usecases/ws/thredds/TokenSetter.java +++ b/src/main/java/org/gcube/usecases/ws/thredds/TokenSetter.java @@ -21,7 +21,6 @@ public class TokenSetter { public static synchronized void set(String scope){ - try{ if(props==null) { props=new Properties(); try { @@ -30,12 +29,8 @@ public class TokenSetter { throw new RuntimeException("YOU NEED TO SET TOKEN FILE IN CONFIGURATION"); } } - if(!props.containsKey(scope)) throw new Exception("No token found for scope : "+scope); + if(!props.containsKey(scope)) throw new RuntimeException("No token found for scope : "+scope); SecurityTokenProvider.instance.set(props.getProperty(scope)); - }catch(Throwable e){ - log.trace("Unable to set token for scope "+scope,e); - } - ScopeProvider.instance.set(scope); } diff --git a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/Process.java b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/Process.java index d3134d6..c2bba7b 100644 --- a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/Process.java +++ b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/Process.java @@ -59,14 +59,15 @@ public class Process { private CompletionCallback callback=null; public Process(String folderId,CompletionCallback callback) throws WorkspaceInteractionException, InternalException { - log.debug("Created Process with id {} ",processId); + String operator=Security.getToken(); + log.debug("Created Process with id {}, operator {} ",processId,operator); // this.folderId=folderId; manager=new WorkspaceFolderManager(folderId); manager.lock(processId); SynchFolderConfiguration folderConfig=manager.getSynchConfiguration(); - try { - descriptor=new ProcessDescriptor(folderId, manager.getTheFolder().get().getPath(),System.currentTimeMillis(),processId,folderConfig); + try { + descriptor=new ProcessDescriptor(folderId, manager.getTheFolder().get().getPath(),System.currentTimeMillis(),processId,operator,folderConfig); }catch(Exception e) { throw new WorkspaceInteractionException("Unable to read path from folder "+folderId,e); } @@ -225,7 +226,7 @@ public class Process { } String relativePath=toScanFolder.get().getMetadata().getMap().get(Constants.WorkspaceProperties.REMOTE_PATH)+""; - ThreddsController folderController=new ThreddsController(relativePath,config.getTargetToken()); + ThreddsController folderController=new ThreddsController(relativePath,ownerProcess.getDescriptor().getOperator()); RemoteFileDescriptor folderDesc=null; try{ @@ -305,7 +306,7 @@ public class Process { }catch(ItemNotFoundException e) { log.info("Creating folder {} under {} ",item,folderPath); folder=toScanFolder.newFolder(item, "Imported from thredds"); - WorkspaceUtils.initProperties(folder,relativePath+"/"+item , config.getFilter(), config.getTargetToken(),config.getToCreateCatalogName(),config.getValidateMetadata(),config.getRootFolderId()); + WorkspaceUtils.initProperties(folder,relativePath+"/"+item , config.getFilter(), ownerProcess.getDescriptor().getOperator(),config.getToCreateCatalogName(),config.getValidateMetadata(),config.getRootFolderId()); generateRequests(ownerProcess, service, folder); } diff --git a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/ProcessDescriptor.java b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/ProcessDescriptor.java index e7bc75a..d84d293 100644 --- a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/ProcessDescriptor.java +++ b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/ProcessDescriptor.java @@ -14,6 +14,8 @@ public class ProcessDescriptor implements Cloneable{ private long launchTime; private String processId; + private String operator; + private SynchFolderConfiguration synchConfiguration; @Override diff --git a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/Security.java b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/Security.java new file mode 100644 index 0000000..6212533 --- /dev/null +++ b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/Security.java @@ -0,0 +1,57 @@ +package org.gcube.usecases.ws.thredds.engine.impl; + +import static org.gcube.common.authorization.client.Constants.authorizationService; + +import org.gcube.common.authorization.client.exceptions.ObjectNotFound; +import org.gcube.common.authorization.library.AuthorizationEntry; +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; +import org.gcube.common.scope.api.ScopeProvider; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class Security { + + public static String getCurrentScope(){ + try{ + String token=SecurityTokenProvider.instance.get(); + log.debug("Token is : "+token); + if(token==null) throw new Exception("Security Token is null"); + AuthorizationEntry entry = authorizationService().get(token); + return entry.getContext(); + }catch(Exception e ){ + log.debug("Unable to resolve token, checking scope provider..",e); + return ScopeProvider.instance.get(); + } + } + + + public static String getContext(String token) { + try{ + log.debug("Resolving token {} ",token); + AuthorizationEntry entry = authorizationService().get(token); + return entry.getContext(); + }catch(Exception e) { + log.warn("Unable to resolve "+token,e); + return null; + } + } + + public static String getToken() { + return SecurityTokenProvider.instance.get(); + } + + + public static String getCurrentCaller(){ + try{ + String token=SecurityTokenProvider.instance.get(); + log.debug("Token is : "+token); + if(token==null) throw new Exception("Security Token is null"); + AuthorizationEntry entry = authorizationService().get(token); + return entry.getClientInfo().getId(); + }catch(Exception e ){ + log.debug("Unable to resolve token, checking scope provider..",e); + return "Unidentified data-transfer user"; + } + } +} diff --git a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/SynchEngineImpl.java b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/SynchEngineImpl.java index 86d371a..fc5b448 100644 --- a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/SynchEngineImpl.java +++ b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/SynchEngineImpl.java @@ -11,6 +11,7 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.data.transfer.model.plugins.thredds.DataSetScan; import org.gcube.data.transfer.model.plugins.thredds.ThreddsCatalog; import org.gcube.data.transfer.model.plugins.thredds.ThreddsInfo; @@ -138,6 +139,16 @@ public class SynchEngineImpl implements SyncEngine{ if (!manager.isSynched()) throw new WorkspaceNotSynchedException("Folder "+folderId+" is not configured for synchronization."); if(manager.isLocked()) throw new WorkspaceLockedException("Folder "+folderId+"is locked by an external process."); if(!manager.isRoot()) throw new WorkspaceFolderNotRootException("Unable to launch synch operation. Folder "+folderId+" is not root configuration"); + + String callerContext=Security.getCurrentScope(); + log.debug("Checking context. Caller is {} ",callerContext); + + String configurationContext=Security.getContext(manager.getSynchConfiguration().getTargetToken()); + + if(!callerContext.equals(configurationContext)) + throw new WorkspaceInteractionException("Cannot sync folder from context "+callerContext+". Expected context is "+configurationContext); + + Process toLaunch=new Process(folderId,completionCallback); localProcesses.put(folderId, toLaunch); initializationExecutor.submit(new ProcessInitializationThread(toLaunch,synchronizationExecutor)); diff --git a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/WorkspaceFolderManager.java b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/WorkspaceFolderManager.java index dae4da4..80fda61 100644 --- a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/WorkspaceFolderManager.java +++ b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/WorkspaceFolderManager.java @@ -51,9 +51,27 @@ public class WorkspaceFolderManager { private StorageHubClient sc; + + private String operator=null; + + private String getToken() { + if(operator==null) { + log.warn("******************Using config operator**********"); + return config.getTargetToken(); + } + else return operator; + } + + + + public WorkspaceFolderManager(String folderId) throws WorkspaceInteractionException { try{ // ws = HomeLibrary.getHomeManagerFactory().getHomeManager().getHome().getWorkspace(); + String operator=Security.getToken(); + log.debug("Setting operator "+operator); + this.operator=operator; + sc=WorkspaceUtils.getClient(); theFolder=sc.open(folderId).asFolder(); this.folderId=folderId; @@ -70,7 +88,7 @@ public class WorkspaceFolderManager { public ThreddsController getThreddsController() throws WorkspaceNotSynchedException, WorkspaceInteractionException, InternalException { if(threddsController==null) { SynchFolderConfiguration config=getSynchConfiguration(); - threddsController=new ThreddsController(config.getRemotePath(),config.getTargetToken()); + threddsController=new ThreddsController(config.getRemotePath(),getToken()); } return threddsController; } @@ -79,7 +97,7 @@ public class WorkspaceFolderManager { try { FolderContainer root=sc.open(getSynchConfiguration().getRootFolderId()).asFolder(); SynchFolderConfiguration rootConfig=WorkspaceUtils.loadConfiguration(root); - return new ThreddsController(rootConfig.getRemotePath(),rootConfig.getTargetToken()); + return new ThreddsController(rootConfig.getRemotePath(),getToken()); }catch(StorageHubException e) { throw new WorkspaceInteractionException(e); } @@ -116,7 +134,7 @@ public class WorkspaceFolderManager { SynchFolderConfiguration config=getSynchConfiguration(); try{ - checkFolder(theFolder,recursively,config,null,theFolder.getId(),WorkspaceUtils.safelyGetLastUpdate(theFolder.get())); + checkFolder(theFolder,recursively,config,null,theFolder.getId(),WorkspaceUtils.safelyGetLastUpdate(theFolder.get()),getToken()); return new SyncFolderDescriptor(this.folderId,this.theFolder.get().getPath(),config); }catch(StorageHubException e) { throw new WorkspaceInteractionException(e); @@ -151,7 +169,7 @@ public class WorkspaceFolderManager { try { String catalogName=toSet.getToCreateCatalogName(); - ThreddsController controller= new ThreddsController(toSet.getRemotePath(),toSet.getTargetToken()); + ThreddsController controller= new ThreddsController(toSet.getRemotePath(),getToken()); if(!controller.existsThreddsFile(null)) { log.info("Folder not found, creating it.."); controller.createEmptyFolder(null); @@ -241,7 +259,7 @@ public class WorkspaceFolderManager { - private static void checkFolder(FolderContainer folder,boolean recursive, SynchFolderConfiguration rootConfig, String relativePathFromRootFolder, String rootFolderId,Date lastUpdatedRoutine) throws StorageHubException, InternalException { + private static void checkFolder(FolderContainer folder,boolean recursive, SynchFolderConfiguration rootConfig, String relativePathFromRootFolder, String rootFolderId,Date lastUpdatedRoutine, String toUseToken) throws StorageHubException, InternalException { // Check folder configuration log.trace("Checking folder {} ",folder.get().getPath()); log.debug("Configuration is {}, relativePath is {} ",rootConfig,relativePathFromRootFolder); @@ -252,7 +270,7 @@ public class WorkspaceFolderManager { - ThreddsController controller=new ThreddsController(currentRemotePath, rootConfig.getTargetToken()); + ThreddsController controller=new ThreddsController(currentRemotePath, toUseToken); HashSet currentFolderExistingItem=new HashSet(); @@ -269,7 +287,7 @@ public class WorkspaceFolderManager { String itemRemotePath=currentRemotePath+"/"+itemName; if(item.getType().equals(ContainerType.FOLDER)) { if(recursive) - checkFolder((FolderContainer) item,recursive,rootConfig,itemRelativePath,rootFolderId,lastUpdatedRoutine); + checkFolder((FolderContainer) item,recursive,rootConfig,itemRelativePath,rootFolderId,lastUpdatedRoutine,toUseToken); else WorkspaceUtils.initProperties(item, itemRemotePath, rootConfig.getFilter(), rootConfig.getTargetToken(),rootConfig.getToCreateCatalogName(),rootConfig.getValidateMetadata(),rootFolderId); }else if(rootConfig.matchesFilter(itemName)) { if(!WorkspaceUtils.isConfigured(item.get())) diff --git a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/threads/SynchronizationThread.java b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/threads/SynchronizationThread.java index 196591f..b98982a 100644 --- a/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/threads/SynchronizationThread.java +++ b/src/main/java/org/gcube/usecases/ws/thredds/engine/impl/threads/SynchronizationThread.java @@ -73,7 +73,7 @@ public class SynchronizationThread implements Runnable { FolderContainer parentFolder=client.open(parentFolderItem.getId()).asFolder(); checkCancelledProcess(); SynchFolderConfiguration synchConfig=WorkspaceUtils.loadConfiguration(parentFolder); - ThreddsController controller=new ThreddsController(synchConfig.getRemotePath(), synchConfig.getTargetToken()); + ThreddsController controller=new ThreddsController(synchConfig.getRemotePath(), theRequest.getProcess().getDescriptor().getOperator()); if(theRequest instanceof TransferToThreddsRequest) { TransferToThreddsRequest request=(TransferToThreddsRequest) theRequest; diff --git a/src/main/java/org/gcube/usecases/ws/thredds/faults/GenericWebException.java b/src/main/java/org/gcube/usecases/ws/thredds/faults/GenericWebException.java new file mode 100644 index 0000000..33f3c36 --- /dev/null +++ b/src/main/java/org/gcube/usecases/ws/thredds/faults/GenericWebException.java @@ -0,0 +1,49 @@ +package org.gcube.usecases.ws.thredds.faults; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString(callSuper = true) +public class GenericWebException extends Exception{ + + + + /** + * + */ + private static final long serialVersionUID = 5200927893712698886L; + + private String remoteMessage=null; + + private Integer responseHTTPCode=0; + + public GenericWebException() { + super(); + // TODO Auto-generated constructor stub + } + + public GenericWebException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public GenericWebException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public GenericWebException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public GenericWebException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/java/org/gcube/usecases/ws/thredds/DTSynchUseCase.java b/src/test/java/org/gcube/usecases/ws/thredds/DTSynchUseCase.java index 0675951..ac5275b 100644 --- a/src/test/java/org/gcube/usecases/ws/thredds/DTSynchUseCase.java +++ b/src/test/java/org/gcube/usecases/ws/thredds/DTSynchUseCase.java @@ -14,10 +14,13 @@ import org.gcube.usecases.ws.thredds.model.SynchFolderConfiguration; public class DTSynchUseCase { public static void main(String[] args) throws WorkspaceInteractionException, InternalException, ProcessNotFoundException { - TokenSetter.set("/d4science.research-infrastructures.eu"); +// TokenSetter.set("/d4science.research-infrastructures.eu"); +// String folderId="a8cd78d3-69e8-4d02-ac90-681b2d16d84d"; + + TokenSetter.set("/gcube/devsec/devVRE"); + String folderId="8ebe9ffb-e2cf-4b3e-ab91-cc6933d86625"; SyncEngine engine=SyncEngine.get(); - String folderId="a8cd78d3-69e8-4d02-ac90-681b2d16d84d"; // String folderId="8a6f9749-68d7-4a9a-a475-bd645050c3fd"; // sub folder for faster tests diff --git a/src/test/java/org/gcube/usecases/ws/thredds/GetTrhreddsInfoTest.java b/src/test/java/org/gcube/usecases/ws/thredds/GetTrhreddsInfoTest.java new file mode 100644 index 0000000..9a2c3cd --- /dev/null +++ b/src/test/java/org/gcube/usecases/ws/thredds/GetTrhreddsInfoTest.java @@ -0,0 +1,17 @@ +package org.gcube.usecases.ws.thredds; + +import org.gcube.data.transfer.library.utils.ScopeUtils; +import org.gcube.usecases.ws.thredds.faults.InternalException; + +public class GetTrhreddsInfoTest { + + + public static void main(String[] args) throws InternalException { + SyncEngine engine=SyncEngine.get(); + // ROOT + System.out.println(engine.getAvailableCatalogsByToken("***REMOVED***")); + // MEI + System.out.println(engine.getAvailableCatalogsByToken("54f577de-d259-407e-b30d-29bf9e7c0dee-843339462")); + } + +} diff --git a/src/test/java/org/gcube/usecases/ws/thredds/TestCommons.java b/src/test/java/org/gcube/usecases/ws/thredds/TestCommons.java index 3200c5f..464309a 100644 --- a/src/test/java/org/gcube/usecases/ws/thredds/TestCommons.java +++ b/src/test/java/org/gcube/usecases/ws/thredds/TestCommons.java @@ -37,7 +37,7 @@ public class TestCommons { private static Map configs=new HashMap<>(); - private static String toUseConfig="default"; + private static String toUseConfig="simple"; static { @@ -46,7 +46,7 @@ public class TestCommons { // folderName="WS-Tests"; - configs.put("simple", new TestSet("Simple label ","/gcube", "Test1","public/netcdf/simpleFolder","***REMOVED***","simple")); + configs.put("simple", new TestSet("Simple label ","/gcube/devsec/devVRE", "Test1","public/netcdf/simpleFolder","***REMOVED***","simple")); configs.put("cmems", new TestSet("CMEMS","/gcube", "CMEMS","public/netcdf/CMEMS","***REMOVED***","cmems")); configs.put("default", new TestSet("Default Tests","/gcube","Thredds Catalog","public/netcdf","***REMOVED***","main")); diff --git a/src/test/java/org/gcube/usecases/ws/thredds/TokenCheck.java b/src/test/java/org/gcube/usecases/ws/thredds/TokenCheck.java new file mode 100644 index 0000000..6a8e82f --- /dev/null +++ b/src/test/java/org/gcube/usecases/ws/thredds/TokenCheck.java @@ -0,0 +1,11 @@ +package org.gcube.usecases.ws.thredds; + +public class TokenCheck { + +// +// public static void main (String[] args) { +// System.out.println(Security.getContext("8e74a17c-92f1-405a-b591-3a6090066248-98187548")); +// System.out.println(Security.getContext("0e2c7963-8d3e-4ea6-a56d-ffda530dd0fa-98187548")); +// } +// +} diff --git a/src/main/resources/log4j.properties b/src/test/resources/log4j.properties similarity index 80% rename from src/main/resources/log4j.properties rename to src/test/resources/log4j.properties index 38535ae..5d16a34 100644 --- a/src/main/resources/log4j.properties +++ b/src/test/resources/log4j.properties @@ -1,6 +1,6 @@ # Root logger option -#log4j.rootLogger=INFO, SM -log4j.logger.org.gcube.usecases.ws=DEBUG,SM +log4j.rootLogger=DEBUG, SM +#log4j.logger.org.gcube.usecases.ws=DEBUG,SM diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml new file mode 100644 index 0000000..b70dd26 --- /dev/null +++ b/src/test/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file