Skip to content

Commit

Permalink
FIx CodeQl issue
Browse files Browse the repository at this point in the history
  • Loading branch information
michelu89 committed Dec 15, 2023
1 parent c4bd46a commit 3870212
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,17 @@ private static Try<Model> loadFromUri( final URI uri ) {
private static Try<Model> loadFromUrl( final URL url ) {
return Try.ofSupplier( () -> TurtleLoader.openUrl( url ) ).flatMap( TurtleLoader::loadTurtle );
}

/**
* Sanitizes the file name to remove any path information and retain only the base file name.
* This method is used to ensure that the file name does not contain any directory path components,
* which helps prevent path traversal attacks. It extracts only the file name portion from a given
* string that may represent a path.
*
* @param fileName The file name string potentially including path information.
* @return The sanitized base file name without any path components.
*/
public static String sanitizeFileInformation( String fileName ) {
return new File( fileName ).getName();

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
This path depends on a user-provided value.
This path depends on a user-provided value.
This path depends on a user-provided value.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

package org.eclipse.esmf.ame.repository.strategy.utils;

import java.io.File;

import javax.annotation.Nonnull;

import org.eclipse.esmf.ame.resolver.strategy.model.FolderStructure;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public FileValidationReport validateAspectModelsForExport( final List<NamespaceF

Map<String, NamespaceFileReport> validFiles =
aspectModelFiles.stream()
.flatMap( data -> data.getFiles().stream().map( fileName -> {
.flatMap( data -> sanitizeIncomingFiles( data.getFiles() ).stream().map( fileName -> {
String aspectModel = strategy.getModelAsString( data.getNamespace(), fileName );
AspectModelToExportCache.put( data.getNamespace() + ":" + fileName, aspectModel );
final FileSystemStrategy fileSystemStrategy = new FileSystemStrategy( aspectModel );
Expand Down Expand Up @@ -184,23 +184,29 @@ private FileValidationReport validateValidFiles( final String modelStoragePath )
public List<String> importAspectModelPackage( final List<NamespaceFileCollection> aspectModelFiles ) {
final ModelResolverStrategy strategy = modelResolverRepository.getStrategy( LocalFolderResolverStrategy.class );

return aspectModelFiles.stream().flatMap( data -> data.getFiles().stream().map( fileName -> {
try {
final FolderStructure folderStructure = LocalFolderResolverUtils.extractFilePath( data.getNamespace() );
folderStructure.setFileName( fileName );
String aspectModel = ResolverUtils.readString(
importFileSystem.getPath( folderStructure.toString() ), StandardCharsets.UTF_8 );
Optional<String> namespaceVersion = Optional.of(
folderStructure.getFileRootPath() + File.separator + folderStructure.getVersion() );

strategy.saveModel( namespaceVersion, Optional.of( fileName ), aspectModel );

return folderStructure.toString();
} catch ( final IOException e ) {
throw new FileNotFoundException(
String.format( "Cannot import Aspect Model with name %s to workspace", fileName ) );
}
} ) ).toList();
return aspectModelFiles.stream().flatMap(
data -> sanitizeIncomingFiles( data.getFiles() ).stream().map( fileName -> {
try {
final FolderStructure folderStructure = LocalFolderResolverUtils.extractFilePath(
data.getNamespace() );
folderStructure.setFileName( fileName );
String aspectModel = ResolverUtils.readString(
importFileSystem.getPath( folderStructure.toString() ), StandardCharsets.UTF_8 );

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
Optional<String> namespaceVersion = Optional.of(
folderStructure.getFileRootPath() + File.separator + folderStructure.getVersion() );

strategy.saveModel( namespaceVersion, Optional.of( fileName ), aspectModel );

return folderStructure.toString();
} catch ( final IOException e ) {
throw new FileNotFoundException(
String.format( "Cannot import Aspect Model with name %s to workspace", fileName ) );
}
} ) ).toList();
}

private List<String> sanitizeIncomingFiles( List<String> incomingFiles ) {
return incomingFiles.stream().map( ModelUtils::sanitizeFileInformation ).toList();
}

private List<ElementMissingReport> getMissingAspectModelFiles( final ViolationReport violationReport,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.eclipse.esmf.ame.exceptions.FileNotFoundException;
import org.eclipse.esmf.ame.services.FileHandlingService;
import org.eclipse.esmf.ame.utils.ModelUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
Expand Down Expand Up @@ -51,7 +52,10 @@ public FileHandlingController( final FileHandlingService fileHandlingService ) {
@GetMapping( "lock" )
public ResponseEntity<String> lockFile( @RequestHeader final Map<String, String> headers )
throws FileNotFoundException {
return processFileOperation( headers, true );
String sanitizedNamespace = ModelUtils.sanitizeFileInformation( headers.get( NAMESPACE ) );
String sanitizedFileName = ModelUtils.sanitizeFileInformation( headers.get( FILE_NAME ) );

return processFileOperation( sanitizedNamespace, sanitizedFileName, true );
}

/**
Expand All @@ -65,30 +69,38 @@ public ResponseEntity<String> lockFile( @RequestHeader final Map<String, String>
@GetMapping( "unlock" )
public ResponseEntity<String> unlockFile( @RequestHeader final Map<String, String> headers )
throws FileNotFoundException {
return processFileOperation( headers, false );
String sanitizedNamespace = ModelUtils.sanitizeFileInformation( headers.get( NAMESPACE ) );
String sanitizedFileName = ModelUtils.sanitizeFileInformation( headers.get( FILE_NAME ) );

return processFileOperation( sanitizedNamespace, sanitizedFileName, false );
}

/**
* Processes file operations (lock/unlock) based on the provided namespace and filename.
* Processes file operations (lock/unlock) based on the provided file namespace and filename.
* This method uses the namespace and filename obtained from HTTP headers to determine
* the specific file for the lock/unlock operation.
*
* @param headers HTTP headers that contain the namespace and filename.
* @param isLocking Boolean flag to determine the operation type (lock/unlock).
* @return ResponseEntity with operation result.
* @param sanitizedNamespace The namespace associated with the file, extracted from HTTP headers.
* @param sanitizedFileName The name of the file, extracted from HTTP headers.
* @param isLocking Boolean flag to determine the operation type (true for lock, false for unlock).
* @return ResponseEntity with the result of the lock/unlock operation.
*
* @throws FileNotFoundException if the filename is not provided.
* @throws FileNotFoundException if the filename is not provided in the headers.
* @throws IllegalArgumentException if either the namespace or filename parameters are invalid.
*/
private ResponseEntity<String> processFileOperation( Map<String, String> headers, boolean isLocking )
private ResponseEntity<String> processFileOperation( String sanitizedNamespace, String sanitizedFileName,
boolean isLocking )
throws FileNotFoundException {
final String namespace = Optional.ofNullable( headers.get( NAMESPACE ) ).orElse( "" );
final String filename = Optional.ofNullable( headers.get( FILE_NAME ) )
final String namespace = Optional.ofNullable( sanitizedNamespace ).orElse( "" );
final String fileName = Optional.ofNullable( sanitizedFileName )
.orElseThrow( () -> new FileNotFoundException( "Please specify a file name" ) );

if ( isValidParam( namespace ) && isValidParam( filename ) ) {
if ( isValidParam( namespace ) && isValidParam( fileName ) ) {
throw new IllegalArgumentException( "Invalid headers parameter" );
}

return ResponseEntity.ok( isLocking ? fileHandlingService.lockFile( namespace, filename )
: fileHandlingService.unlockFile( namespace, filename ) );
return ResponseEntity.ok( isLocking ? fileHandlingService.lockFile( namespace, fileName )
: fileHandlingService.unlockFile( namespace, fileName ) );
}

private boolean isValidParam( String fileName ) {
Expand Down

0 comments on commit 3870212

Please sign in to comment.