|
3 | 3 |
|
4 | 4 | using System; |
5 | 5 | using System.Collections.Generic; |
| 6 | +using System.IdentityModel.Tokens.Jwt; |
6 | 7 | using System.Linq; |
7 | 8 | using System.Text; |
| 9 | +using System.Threading; |
8 | 10 | using System.Threading.Tasks; |
| 11 | +using Azure.Core; |
9 | 12 | using Azure.Core.TestFramework; |
| 13 | +using Azure.Storage.Queues.Models; |
10 | 14 | using Azure.Storage.Queues.Specialized; |
11 | 15 | using Azure.Storage.Queues.Tests; |
| 16 | +using Azure.Storage.Sas; |
12 | 17 | using Azure.Storage.Test; |
13 | 18 | using Azure.Storage.Test.Shared; |
14 | 19 | using NUnit.Framework; |
@@ -118,6 +123,132 @@ public async Task AccountSas_ServiceOrder(string services) |
118 | 123 | await InvokeAccountSasTest(services: services); |
119 | 124 | } |
120 | 125 |
|
| 126 | + [RecordedTest] |
| 127 | + [ServiceVersion(Min = QueueClientOptions.ServiceVersion.V2026_02_06)] |
| 128 | + public async Task SendMessageAsync_UserDelegationSAS() |
| 129 | + { |
| 130 | + // Arrange |
| 131 | + string queueName = GetNewQueueName(); |
| 132 | + QueueServiceClient service = GetServiceClient_OAuth(); |
| 133 | + await using DisposingQueue test = await GetTestQueueAsync(service); |
| 134 | + |
| 135 | + Response<UserDelegationKey> userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( |
| 136 | + startsOn: null, |
| 137 | + expiresOn: Recording.UtcNow.AddHours(1)); |
| 138 | + |
| 139 | + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; |
| 140 | + |
| 141 | + Uri queueUri = test.Queue.GenerateUserDelegationSasUri(QueueSasPermissions.All, Recording.UtcNow.AddHours(1), userDelegationKey); |
| 142 | + |
| 143 | + QueueClient queueClient = InstrumentClient(new QueueClient(queueUri, GetOptions())); |
| 144 | + |
| 145 | + // Act |
| 146 | + Response<SendReceipt> response = await queueClient.SendMessageAsync( |
| 147 | + messageText: GetNewString(), |
| 148 | + visibilityTimeout: new TimeSpan(0, 0, 1), |
| 149 | + timeToLive: new TimeSpan(1, 0, 0)); |
| 150 | + |
| 151 | + // Assert |
| 152 | + Assert.NotNull(response.Value); |
| 153 | + } |
| 154 | + |
| 155 | + [RecordedTest] |
| 156 | + [LiveOnly] // Cannot record Entra ID token |
| 157 | + [ServiceVersion(Min = QueueClientOptions.ServiceVersion.V2026_02_06)] |
| 158 | + public async Task SendMessageAsync_UserDelegationSAS_DelegatedObjectId() |
| 159 | + { |
| 160 | + // Arrange |
| 161 | + QueueServiceClient service = GetServiceClient_OAuth(); |
| 162 | + await using DisposingQueue test = await GetTestQueueAsync(service); |
| 163 | + |
| 164 | + Response<UserDelegationKey> userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( |
| 165 | + startsOn: null, |
| 166 | + expiresOn: Recording.UtcNow.AddHours(1)); |
| 167 | + |
| 168 | + // We need to get the object ID from the token credential used to authenticate the request |
| 169 | + TokenCredential tokenCredential = TestEnvironment.Credential; |
| 170 | + AccessToken accessToken = await tokenCredential.GetTokenAsync( |
| 171 | + new TokenRequestContext(Scopes), |
| 172 | + CancellationToken.None); |
| 173 | + |
| 174 | + JwtSecurityToken jwtSecurityToken = new JwtSecurityTokenHandler().ReadJwtToken(accessToken.Token); |
| 175 | + jwtSecurityToken.Payload.TryGetValue(Constants.Sas.ObjectId, out object objectId); |
| 176 | + |
| 177 | + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; |
| 178 | + |
| 179 | + QueueSasBuilder queueSasBuilder = new QueueSasBuilder(QueueSasPermissions.All, Recording.UtcNow.AddHours(1)) |
| 180 | + { |
| 181 | + QueueName = test.Queue.Name, |
| 182 | + DelegatedUserObjectId = objectId?.ToString() |
| 183 | + }; |
| 184 | + |
| 185 | + QueueSasQueryParameters sasQueryParameters = queueSasBuilder.ToSasQueryParameters(userDelegationKey, service.AccountName, out string stringToSign); |
| 186 | + |
| 187 | + QueueUriBuilder uriBuilder = new QueueUriBuilder(test.Queue.Uri) |
| 188 | + { |
| 189 | + Sas = sasQueryParameters |
| 190 | + }; |
| 191 | + |
| 192 | + QueueClient identityQueueClient = InstrumentClient(new QueueClient(uriBuilder.ToUri(), TestEnvironment.Credential, GetOptions())); |
| 193 | + |
| 194 | + // Act |
| 195 | + Response<SendReceipt> response = await identityQueueClient.SendMessageAsync( |
| 196 | + messageText: GetNewString(), |
| 197 | + visibilityTimeout: new TimeSpan(0, 0, 1), |
| 198 | + timeToLive: new TimeSpan(1, 0, 0)); |
| 199 | + |
| 200 | + // Assert |
| 201 | + Assert.NotNull(response.Value); |
| 202 | + } |
| 203 | + |
| 204 | + [RecordedTest] |
| 205 | + [LiveOnly] // Cannot record Entra ID token |
| 206 | + [ServiceVersion(Min = QueueClientOptions.ServiceVersion.V2026_02_06)] |
| 207 | + public async Task SendMessageAsync_UserDelegationSAS_DelegatedObjectId_Fail() |
| 208 | + { |
| 209 | + // Arrange |
| 210 | + QueueServiceClient service = GetServiceClient_OAuth(); |
| 211 | + await using DisposingQueue test = await GetTestQueueAsync(service); |
| 212 | + |
| 213 | + Response<UserDelegationKey> userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( |
| 214 | + startsOn: null, |
| 215 | + expiresOn: Recording.UtcNow.AddHours(1)); |
| 216 | + |
| 217 | + // We need to get the object ID from the token credential used to authenticate the request |
| 218 | + TokenCredential tokenCredential = TestEnvironment.Credential; |
| 219 | + AccessToken accessToken = await tokenCredential.GetTokenAsync( |
| 220 | + new TokenRequestContext(Scopes), |
| 221 | + CancellationToken.None); |
| 222 | + |
| 223 | + JwtSecurityToken jwtSecurityToken = new JwtSecurityTokenHandler().ReadJwtToken(accessToken.Token); |
| 224 | + jwtSecurityToken.Payload.TryGetValue(Constants.Sas.ObjectId, out object objectId); |
| 225 | + |
| 226 | + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; |
| 227 | + |
| 228 | + QueueSasBuilder queueSasBuilder = new QueueSasBuilder(QueueSasPermissions.All, Recording.UtcNow.AddHours(1)) |
| 229 | + { |
| 230 | + QueueName = test.Queue.Name, |
| 231 | + DelegatedUserObjectId = objectId?.ToString() |
| 232 | + }; |
| 233 | + |
| 234 | + QueueSasQueryParameters sasQueryParameters = queueSasBuilder.ToSasQueryParameters(userDelegationKey, service.AccountName, out string stringToSign); |
| 235 | + |
| 236 | + QueueUriBuilder uriBuilder = new QueueUriBuilder(test.Queue.Uri) |
| 237 | + { |
| 238 | + Sas = sasQueryParameters |
| 239 | + }; |
| 240 | + |
| 241 | + QueueClient identityQueueClient = InstrumentClient(new QueueClient(uriBuilder.ToUri(), GetOptions())); |
| 242 | + |
| 243 | + // Act |
| 244 | + await TestHelper.AssertExpectedExceptionAsync<RequestFailedException>( |
| 245 | + identityQueueClient.SendMessageAsync( |
| 246 | + messageText: GetNewString(), |
| 247 | + visibilityTimeout: new TimeSpan(0, 0, 1), |
| 248 | + timeToLive: new TimeSpan(1, 0, 0)), |
| 249 | + e => Assert.AreEqual("AuthenticationFailed", e.ErrorCode)); |
| 250 | + } |
| 251 | + |
121 | 252 | // Creating Client from GetStorageClient |
122 | 253 | #region QueueServiceClient |
123 | 254 | private async Task InvokeAccountServiceToQueueSasTest( |
|
0 commit comments