PageRenderTime 38ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/WP7.1/Templates/VB/WPCloud.Mem/WindowsPhoneCloud.Web/Services/SharedAccessSignatureService.vb

#
Visual Basic | 216 lines | 154 code | 38 blank | 24 comment | 3 complexity | a8a23d886e4ce76d38f44139bdff9ed4 MD5 | raw file
  1. ' ----------------------------------------------------------------------------------
  2. ' Microsoft Developer & Platform Evangelism
  3. '
  4. ' Copyright (c) Microsoft Corporation. All rights reserved.
  5. '
  6. ' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  7. ' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
  8. ' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  9. ' ----------------------------------------------------------------------------------
  10. ' The example companies, organizations, products, domain names,
  11. ' e-mail addresses, logos, people, places, and events depicted
  12. ' herein are fictitious. No association with any real company,
  13. ' organization, product, domain name, email address, logo, person,
  14. ' places, or events is intended or should be inferred.
  15. ' ----------------------------------------------------------------------------------
  16. Imports Microsoft.WindowsAzure.StorageClient
  17. Imports Microsoft.WindowsAzure
  18. Imports Microsoft.Samples.WindowsPhoneCloud.Web.UserAccountWrappers
  19. Imports Microsoft.Samples.WindowsPhoneCloud.Web.Infrastructure
  20. Imports System.ServiceModel.Web
  21. Imports System.ServiceModel.Activation
  22. Imports System.ServiceModel
  23. Imports System.Net
  24. Imports System.Globalization
  25. Imports System
  26. #If ACS Then
  27. Imports Microsoft.IdentityModel.Claims
  28. #End If
  29. Namespace Services
  30. <ServiceBehavior(IncludeExceptionDetailInFaults:=False), AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Required)>
  31. Public Class SharedAccessSignatureService
  32. Implements ISharedAccessSignatureService
  33. Private Const ContainerSharedAccessPermissions As SharedAccessPermissions = SharedAccessPermissions.Write Or SharedAccessPermissions.Delete Or SharedAccessPermissions.List
  34. Private ReadOnly cloudBlobClient As CloudBlobClient
  35. Private ReadOnly webOperationContext As WebOperationContext
  36. #If ACS Then
  37. Public Sub New()
  38. Me.New(Nothing, WebOperationContext.Current)
  39. End Sub
  40. <CLSCompliant(False)>
  41. Public Sub New(ByVal cloudBlobClient As CloudBlobClient, ByVal webOperationContext As WebOperationContext)
  42. If (cloudBlobClient Is Nothing) AndAlso (GetStorageAccountFromConfigurationSetting() Is Nothing) Then
  43. Throw New ArgumentNullException("cloudBlobClient", "The Cloud Blob Client cannot be null if no configuration is loaded.")
  44. End If
  45. Me.cloudBlobClient = If(cloudBlobClient, GetStorageAccountFromConfigurationSetting().CreateCloudBlobClient())
  46. Me.webOperationContext = webOperationContext
  47. End Sub
  48. Private ReadOnly Property UserId() As String
  49. Get
  50. Dim identity = TryCast(HttpContext.Current.User.Identity, IClaimsIdentity)
  51. Return identity.Claims.Single(Function(c) c.ClaimType = IdentityModel.Claims.ClaimTypes.NameIdentifier).Value
  52. End Get
  53. End Property
  54. #Else
  55. Private ReadOnly context As HttpContextBase
  56. Private ReadOnly formsAuth As IFormsAuthentication
  57. Private ReadOnly membershipService As IMembershipService
  58. Private ReadOnly userPrivilegesRepository As IUserPrivilegesRepository
  59. Public Sub New()
  60. Me.New(Nothing, New HttpContextWrapper(HttpContext.Current), New UserTablesServiceContext(), New FormsAuthenticationService(), New AccountMembershipService(), webOperationContext.Current)
  61. End Sub
  62. <CLSCompliant(False)>
  63. Public Sub New(ByVal cloudBlobClient As CloudBlobClient, ByVal context As HttpContextBase, ByVal userPrivilegesRepository As IUserPrivilegesRepository, ByVal formsAuth As IFormsAuthentication, ByVal membershipService As IMembershipService, ByVal webOperationContext As WebOperationContext)
  64. If (context Is Nothing) AndAlso (HttpContext.Current Is Nothing) Then
  65. Throw New ArgumentNullException("context", "The context cannot be null if not running on a Web context.")
  66. End If
  67. If (cloudBlobClient Is Nothing) AndAlso (GetStorageAccountFromConfigurationSetting() Is Nothing) Then
  68. Throw New ArgumentNullException("cloudBlobClient", "The Cloud Blob Client cannot be null if no configuration is loaded.")
  69. End If
  70. Me.cloudBlobClient = If(cloudBlobClient, GetStorageAccountFromConfigurationSetting().CreateCloudBlobClient())
  71. Me.context = context
  72. Me.userPrivilegesRepository = userPrivilegesRepository
  73. Me.formsAuth = formsAuth
  74. Me.membershipService = membershipService
  75. Me.webOperationContext = webOperationContext
  76. End Sub
  77. Private ReadOnly Property UserId() As String
  78. Get
  79. Dim ticketValue As String = Nothing
  80. Dim cookie = Me.context.Request.Cookies(Me.formsAuth.FormsCookieName)
  81. If cookie IsNot Nothing Then
  82. ' From cookie.
  83. ticketValue = cookie.Value
  84. ElseIf Me.context.Request.Headers("AuthToken") IsNot Nothing Then
  85. ' From HTTP header.
  86. ticketValue = Me.context.Request.Headers("AuthToken")
  87. End If
  88. If Not String.IsNullOrEmpty(ticketValue) Then
  89. Dim ticket As FormsAuthenticationTicket
  90. Try
  91. ticket = Me.formsAuth.Decrypt(ticketValue)
  92. Catch
  93. Throw New WebFaultException(Of String)("The authorization ticket cannot be decrypted.", HttpStatusCode.Unauthorized)
  94. End Try
  95. If ticket IsNot Nothing Then
  96. ' Authorize blobs usage.
  97. Dim userIdValue = Me.membershipService.GetUser(New FormsIdentity(ticket).Name).ProviderUserKey.ToString()
  98. If Not Me.userPrivilegesRepository.HasUserPrivilege(userIdValue, PrivilegeConstants.BlobsUsagePrivilege) Then
  99. Throw New WebFaultException(Of String)("You have no permission to use blobs.", HttpStatusCode.Unauthorized)
  100. End If
  101. Return userIdValue
  102. Else
  103. Throw New WebFaultException(Of String)("The authorization token is no longer valid.", HttpStatusCode.Unauthorized)
  104. End If
  105. Else
  106. Throw New WebFaultException(Of String)("Resource not found.", HttpStatusCode.NotFound)
  107. End If
  108. End Get
  109. End Property
  110. #End If
  111. Public Function GetContainerSharedAccessSignature() As Uri Implements ISharedAccessSignatureService.GetContainerSharedAccessSignature
  112. ' Authenticate.
  113. Dim userId = Me.UserId
  114. Try
  115. ' Each user has its own container.
  116. Dim container = Me.GetUserContainer(userId)
  117. Dim containerSASExperiationTime = Integer.Parse(ConfigReader.GetConfigValue("ContainerSASExperiationTime"), NumberStyles.Integer, CultureInfo.InvariantCulture)
  118. Dim sas = container.GetSharedAccessSignature(New SharedAccessPolicy() With {.Permissions = ContainerSharedAccessPermissions, .SharedAccessExpiryTime = Date.UtcNow + TimeSpan.FromMinutes(containerSASExperiationTime)})
  119. If Me.webOperationContext IsNot Nothing Then
  120. Me.webOperationContext.OutgoingResponse.Headers.Add("Cache-Control", "no-cache")
  121. End If
  122. Dim uriBuilder = New UriBuilder(container.Uri) With {.Query = sas.TrimStart("?"c)}
  123. Return uriBuilder.Uri
  124. Catch exception As Exception
  125. Throw New WebFaultException(Of String)(exception.Message, HttpStatusCode.InternalServerError)
  126. End Try
  127. End Function
  128. Public Function GetBlobsSharedAccessSignatures(ByVal blobPrefix As String, ByVal useFlatBlobListing As Boolean) As Models.CloudBlobCollection Implements ISharedAccessSignatureService.GetBlobsSharedAccessSignatures
  129. ' Authenticate.
  130. Dim userId = Me.UserId
  131. If Not String.IsNullOrEmpty(blobPrefix) Then
  132. blobPrefix = blobPrefix.TrimStart("/"c, "\"c).Replace("\"c, "/"c)
  133. End If
  134. Try
  135. ' Each user has its own container.
  136. SetReadOnlySharedAccessPolicy(Me.GetUserContainer(userId))
  137. Dim prefix = String.Format(CultureInfo.InvariantCulture, "{0}/{1}", GetUserContainerName(userId), blobPrefix)
  138. Dim blobs = Me.cloudBlobClient.ListBlobsWithPrefix(prefix, New BlobRequestOptions With {.UseFlatBlobListing = useFlatBlobListing})
  139. Dim result = New Models.CloudBlobCollection With {.Blobs = blobs.Where(Function(b) TypeOf b Is CloudBlob).Select(Function(b) b.ToModel(GetUserContainerName(userId), Me.cloudBlobClient.Credentials.AccountName)).ToArray()}
  140. If Me.webOperationContext IsNot Nothing Then
  141. Me.webOperationContext.OutgoingResponse.Headers.Add("Cache-Control", "no-cache")
  142. End If
  143. Return result
  144. Catch exception As Exception
  145. Throw New WebFaultException(Of String)(exception.Message, HttpStatusCode.InternalServerError)
  146. End Try
  147. End Function
  148. Private Shared Sub SetReadOnlySharedAccessPolicy(ByVal container As CloudBlobContainer)
  149. Dim blobSASExperiationTime = Integer.Parse(ConfigReader.GetConfigValue("BlobSASExperiationTime"), NumberStyles.Integer, CultureInfo.InvariantCulture)
  150. Dim permissions = container.GetPermissions()
  151. Dim options = New BlobRequestOptions With {.AccessCondition = AccessCondition.IfMatch(container.Properties.ETag)}
  152. ' Fail if someone else has already changed the container before we do.
  153. Dim sharedAccessPolicy = New SharedAccessPolicy With {.Permissions = SharedAccessPermissions.Read, .SharedAccessExpiryTime = Date.UtcNow + TimeSpan.FromDays(blobSASExperiationTime)}
  154. permissions.SharedAccessPolicies.Remove("readonly")
  155. permissions.SharedAccessPolicies.Add("readonly", sharedAccessPolicy)
  156. container.SetPermissions(permissions, options)
  157. End Sub
  158. Private Shared Function GetStorageAccountFromConfigurationSetting() As CloudStorageAccount
  159. Dim account As CloudStorageAccount = Nothing
  160. Try
  161. account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString")
  162. Catch e1 As InvalidOperationException
  163. account = Nothing
  164. End Try
  165. Return account
  166. End Function
  167. Private Shared Function GetUserContainerName(ByVal userId As String) As String
  168. ' The container name for the user contains a hash of the user Id.
  169. Dim containerName = String.Format(CultureInfo.InvariantCulture, "usercontainer{0}", userId.GetHashCode())
  170. Return containerName.ToLowerInvariant()
  171. End Function
  172. Private Function GetUserContainer(ByVal userId As String) As CloudBlobContainer
  173. Dim container = Me.cloudBlobClient.GetContainerReference(GetUserContainerName(userId))
  174. container.CreateIfNotExist()
  175. Return container
  176. End Function
  177. End Class
  178. End Namespace