/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
- ' ----------------------------------------------------------------------------------
- ' Microsoft Developer & Platform Evangelism
- '
- ' Copyright (c) Microsoft Corporation. All rights reserved.
- '
- ' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
- ' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
- ' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
- ' ----------------------------------------------------------------------------------
- ' The example companies, organizations, products, domain names,
- ' e-mail addresses, logos, people, places, and events depicted
- ' herein are fictitious. No association with any real company,
- ' organization, product, domain name, email address, logo, person,
- ' places, or events is intended or should be inferred.
- ' ----------------------------------------------------------------------------------
-
- Imports Microsoft.WindowsAzure.StorageClient
- Imports Microsoft.WindowsAzure
- Imports Microsoft.Samples.WindowsPhoneCloud.Web.UserAccountWrappers
- Imports Microsoft.Samples.WindowsPhoneCloud.Web.Infrastructure
- Imports System.ServiceModel.Web
- Imports System.ServiceModel.Activation
- Imports System.ServiceModel
- Imports System.Net
- Imports System.Globalization
- Imports System
- #If ACS Then
- Imports Microsoft.IdentityModel.Claims
- #End If
- Namespace Services
-
- <ServiceBehavior(IncludeExceptionDetailInFaults:=False), AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Required)>
- Public Class SharedAccessSignatureService
- Implements ISharedAccessSignatureService
-
- Private Const ContainerSharedAccessPermissions As SharedAccessPermissions = SharedAccessPermissions.Write Or SharedAccessPermissions.Delete Or SharedAccessPermissions.List
-
- Private ReadOnly cloudBlobClient As CloudBlobClient
- Private ReadOnly webOperationContext As WebOperationContext
-
- #If ACS Then
- Public Sub New()
- Me.New(Nothing, WebOperationContext.Current)
- End Sub
-
- <CLSCompliant(False)>
- Public Sub New(ByVal cloudBlobClient As CloudBlobClient, ByVal webOperationContext As WebOperationContext)
- If (cloudBlobClient Is Nothing) AndAlso (GetStorageAccountFromConfigurationSetting() Is Nothing) Then
- Throw New ArgumentNullException("cloudBlobClient", "The Cloud Blob Client cannot be null if no configuration is loaded.")
- End If
-
- Me.cloudBlobClient = If(cloudBlobClient, GetStorageAccountFromConfigurationSetting().CreateCloudBlobClient())
- Me.webOperationContext = webOperationContext
- End Sub
-
- Private ReadOnly Property UserId() As String
- Get
- Dim identity = TryCast(HttpContext.Current.User.Identity, IClaimsIdentity)
- Return identity.Claims.Single(Function(c) c.ClaimType = IdentityModel.Claims.ClaimTypes.NameIdentifier).Value
- End Get
- End Property
- #Else
- Private ReadOnly context As HttpContextBase
- Private ReadOnly formsAuth As IFormsAuthentication
- Private ReadOnly membershipService As IMembershipService
- Private ReadOnly userPrivilegesRepository As IUserPrivilegesRepository
-
- Public Sub New()
- Me.New(Nothing, New HttpContextWrapper(HttpContext.Current), New UserTablesServiceContext(), New FormsAuthenticationService(), New AccountMembershipService(), webOperationContext.Current)
- End Sub
-
- <CLSCompliant(False)>
- 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)
- If (context Is Nothing) AndAlso (HttpContext.Current Is Nothing) Then
- Throw New ArgumentNullException("context", "The context cannot be null if not running on a Web context.")
- End If
-
- If (cloudBlobClient Is Nothing) AndAlso (GetStorageAccountFromConfigurationSetting() Is Nothing) Then
- Throw New ArgumentNullException("cloudBlobClient", "The Cloud Blob Client cannot be null if no configuration is loaded.")
- End If
-
- Me.cloudBlobClient = If(cloudBlobClient, GetStorageAccountFromConfigurationSetting().CreateCloudBlobClient())
- Me.context = context
- Me.userPrivilegesRepository = userPrivilegesRepository
- Me.formsAuth = formsAuth
- Me.membershipService = membershipService
- Me.webOperationContext = webOperationContext
- End Sub
-
- Private ReadOnly Property UserId() As String
- Get
- Dim ticketValue As String = Nothing
-
- Dim cookie = Me.context.Request.Cookies(Me.formsAuth.FormsCookieName)
- If cookie IsNot Nothing Then
- ' From cookie.
- ticketValue = cookie.Value
- ElseIf Me.context.Request.Headers("AuthToken") IsNot Nothing Then
- ' From HTTP header.
- ticketValue = Me.context.Request.Headers("AuthToken")
- End If
-
- If Not String.IsNullOrEmpty(ticketValue) Then
- Dim ticket As FormsAuthenticationTicket
-
- Try
- ticket = Me.formsAuth.Decrypt(ticketValue)
- Catch
- Throw New WebFaultException(Of String)("The authorization ticket cannot be decrypted.", HttpStatusCode.Unauthorized)
- End Try
-
- If ticket IsNot Nothing Then
- ' Authorize blobs usage.
- Dim userIdValue = Me.membershipService.GetUser(New FormsIdentity(ticket).Name).ProviderUserKey.ToString()
- If Not Me.userPrivilegesRepository.HasUserPrivilege(userIdValue, PrivilegeConstants.BlobsUsagePrivilege) Then
- Throw New WebFaultException(Of String)("You have no permission to use blobs.", HttpStatusCode.Unauthorized)
- End If
-
- Return userIdValue
- Else
- Throw New WebFaultException(Of String)("The authorization token is no longer valid.", HttpStatusCode.Unauthorized)
- End If
- Else
- Throw New WebFaultException(Of String)("Resource not found.", HttpStatusCode.NotFound)
- End If
- End Get
- End Property
- #End If
-
- Public Function GetContainerSharedAccessSignature() As Uri Implements ISharedAccessSignatureService.GetContainerSharedAccessSignature
- ' Authenticate.
- Dim userId = Me.UserId
-
- Try
- ' Each user has its own container.
- Dim container = Me.GetUserContainer(userId)
- Dim containerSASExperiationTime = Integer.Parse(ConfigReader.GetConfigValue("ContainerSASExperiationTime"), NumberStyles.Integer, CultureInfo.InvariantCulture)
- Dim sas = container.GetSharedAccessSignature(New SharedAccessPolicy() With {.Permissions = ContainerSharedAccessPermissions, .SharedAccessExpiryTime = Date.UtcNow + TimeSpan.FromMinutes(containerSASExperiationTime)})
-
- If Me.webOperationContext IsNot Nothing Then
- Me.webOperationContext.OutgoingResponse.Headers.Add("Cache-Control", "no-cache")
- End If
-
- Dim uriBuilder = New UriBuilder(container.Uri) With {.Query = sas.TrimStart("?"c)}
- Return uriBuilder.Uri
- Catch exception As Exception
- Throw New WebFaultException(Of String)(exception.Message, HttpStatusCode.InternalServerError)
- End Try
- End Function
-
- Public Function GetBlobsSharedAccessSignatures(ByVal blobPrefix As String, ByVal useFlatBlobListing As Boolean) As Models.CloudBlobCollection Implements ISharedAccessSignatureService.GetBlobsSharedAccessSignatures
- ' Authenticate.
- Dim userId = Me.UserId
-
- If Not String.IsNullOrEmpty(blobPrefix) Then
- blobPrefix = blobPrefix.TrimStart("/"c, "\"c).Replace("\"c, "/"c)
- End If
-
- Try
- ' Each user has its own container.
- SetReadOnlySharedAccessPolicy(Me.GetUserContainer(userId))
- Dim prefix = String.Format(CultureInfo.InvariantCulture, "{0}/{1}", GetUserContainerName(userId), blobPrefix)
-
- Dim blobs = Me.cloudBlobClient.ListBlobsWithPrefix(prefix, New BlobRequestOptions With {.UseFlatBlobListing = useFlatBlobListing})
- 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()}
-
- If Me.webOperationContext IsNot Nothing Then
- Me.webOperationContext.OutgoingResponse.Headers.Add("Cache-Control", "no-cache")
- End If
-
- Return result
- Catch exception As Exception
- Throw New WebFaultException(Of String)(exception.Message, HttpStatusCode.InternalServerError)
- End Try
- End Function
-
- Private Shared Sub SetReadOnlySharedAccessPolicy(ByVal container As CloudBlobContainer)
- Dim blobSASExperiationTime = Integer.Parse(ConfigReader.GetConfigValue("BlobSASExperiationTime"), NumberStyles.Integer, CultureInfo.InvariantCulture)
- Dim permissions = container.GetPermissions()
- Dim options = New BlobRequestOptions With {.AccessCondition = AccessCondition.IfMatch(container.Properties.ETag)}
- ' Fail if someone else has already changed the container before we do.
- Dim sharedAccessPolicy = New SharedAccessPolicy With {.Permissions = SharedAccessPermissions.Read, .SharedAccessExpiryTime = Date.UtcNow + TimeSpan.FromDays(blobSASExperiationTime)}
-
- permissions.SharedAccessPolicies.Remove("readonly")
- permissions.SharedAccessPolicies.Add("readonly", sharedAccessPolicy)
-
- container.SetPermissions(permissions, options)
- End Sub
-
- Private Shared Function GetStorageAccountFromConfigurationSetting() As CloudStorageAccount
- Dim account As CloudStorageAccount = Nothing
-
- Try
- account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString")
- Catch e1 As InvalidOperationException
- account = Nothing
- End Try
-
- Return account
- End Function
-
- Private Shared Function GetUserContainerName(ByVal userId As String) As String
- ' The container name for the user contains a hash of the user Id.
- Dim containerName = String.Format(CultureInfo.InvariantCulture, "usercontainer{0}", userId.GetHashCode())
-
- Return containerName.ToLowerInvariant()
- End Function
-
- Private Function GetUserContainer(ByVal userId As String) As CloudBlobContainer
- Dim container = Me.cloudBlobClient.GetContainerReference(GetUserContainerName(userId))
- container.CreateIfNotExist()
-
- Return container
- End Function
- End Class
- End Namespace