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

Language Visual Basic Lines 216
MD5 Hash a8a23d886e4ce76d38f44139bdff9ed4
Repository https://watoolkitwp7.svn.codeplex.com/svn View Raw File
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
' ----------------------------------------------------------------------------------
' 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
Back to Top