11package cromwell .filesystems .blob
22
3+ import akka .http .scaladsl .model .Uri
34import com .azure .storage .blob .nio .AzureBlobFileAttributes
45import com .google .common .net .UrlEscapers
56import cromwell .core .path .{NioPath , Path , PathBuilder }
@@ -21,6 +22,8 @@ object BlobPathBuilder {
2122 s " Malformed Blob URL for this builder: The endpoint $endpoint doesn't contain the expected host string '{SA}.blob.core.windows.net/' "
2223 def invalidBlobContainerMessage (endpoint : EndpointURL ) =
2324 s " Malformed Blob URL for this builder: Could not parse container "
25+ val externalToken =
26+ " Rejecting pre-signed SAS URL so that filesystem selection falls through to HTTP filesystem"
2427 def parseURI (string : String ): Try [URI ] = Try (URI .create(UrlEscapers .urlFragmentEscaper().escape(string)))
2528 def parseStorageAccount (uri : URI ): Try [StorageAccountName ] = uri.getHost
2629 .split(" \\ ." )
@@ -50,19 +53,34 @@ object BlobPathBuilder {
5053 def validateBlobPath (string : String ): BlobPathValidation = {
5154 val blobValidation = for {
5255 testUri <- parseURI(string)
53- testEndpoint = EndpointURL (testUri.getScheme + " ://" + testUri.getHost() )
54- testStorageAccount <- parseStorageAccount(testUri)
56+ testEndpoint = EndpointURL (testUri.getScheme + " ://" + testUri.getHost)
57+ _ <- parseStorageAccount(testUri)
5558 testContainer = testUri.getPath.split(" /" ).find(_.nonEmpty)
56- isBlobHost = testUri.getHost().contains(blobHostnameSuffix) && testUri.getScheme().contains(" https" )
57- blobPathValidation = (isBlobHost, testContainer) match {
58- case (true , Some (container)) =>
59+ isBlobHost = testUri.getHost.contains(blobHostnameSuffix) && testUri.getScheme.contains(" https" )
60+ hasToken = hasSasToken(string)
61+ blobPathValidation = (isBlobHost, testContainer, hasToken) match {
62+ case (true , Some (container), false ) =>
5963 ValidBlobPath (testUri.getPath.replaceFirst(" /" + container, " " ), BlobContainerName (container), testEndpoint)
60- case (false , _) => UnparsableBlobPath (new MalformedURLException (invalidBlobHostMessage(testEndpoint)))
61- case (true , None ) => UnparsableBlobPath (new MalformedURLException (invalidBlobContainerMessage(testEndpoint)))
64+ case (false , _, false ) =>
65+ UnparsableBlobPath (new MalformedURLException (invalidBlobHostMessage(testEndpoint)))
66+ case (true , None , false ) =>
67+ UnparsableBlobPath (new MalformedURLException (invalidBlobContainerMessage(testEndpoint)))
68+ case (_, _, true ) =>
69+ UnparsableBlobPath (new IllegalArgumentException (externalToken))
6270 }
6371 } yield blobPathValidation
6472 blobValidation recover { case t => UnparsableBlobPath (t) } get
6573 }
74+
75+ private def hasSasToken (uri : Uri ) = {
76+ // These keys are required for all SAS tokens.
77+ // https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas#construct-a-service-sas
78+ val SignedVersionKey = " sv"
79+ val SignatureKey = " sig"
80+
81+ val query = uri.query().toMap
82+ query.isDefinedAt(SignedVersionKey ) && query.isDefinedAt(SignatureKey )
83+ }
6684}
6785
6886class BlobPathBuilder ()(private val fsm : BlobFileSystemManager ) extends PathBuilder {
0 commit comments