< Summary

Class:Azure.Security.KeyVault.Keys.Cryptography.KeyResolver
Assembly:Azure.Security.KeyVault.Keys
File(s):C:\Git\azure-sdk-for-net\sdk\keyvault\Azure.Security.KeyVault.Keys\src\Cryptography\KeyResolver.cs
Covered lines:59
Uncovered lines:1
Coverable lines:60
Total lines:194
Line coverage:98.3% (59 of 60)
Covered branches:18
Total branches:18
Branch coverage:100% (18 of 18)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor()-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
Resolve(...)-100%100%
ResolveAsync()-100%100%
Azure.Core.Cryptography.IKeyEncryptionKeyResolver.Resolve(...)-0%100%
Azure-Core-Cryptography-IKeyEncryptionKeyResolver-ResolveAsync()-100%100%
GetKey(...)-100%100%
GetKeyAsync()-100%100%
ParseResponse(...)-100%100%
CreateGetRequest(...)-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\keyvault\Azure.Security.KeyVault.Keys\src\Cryptography\KeyResolver.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Threading;
 6using System.Threading.Tasks;
 7using Azure.Core;
 8using Azure.Core.Cryptography;
 9using Azure.Core.Pipeline;
 10
 11namespace Azure.Security.KeyVault.Keys.Cryptography
 12{
 13    /// <summary>
 14    /// Azure Key Vault KeyResolver. This class resolves Key Vault Key Identifiers and
 15    /// Secret Identifiers to create <see cref="CryptographyClient"/> instances capable of performing
 16    /// cryptographic operations with the key. Secret Identifiers can only be resolved if the Secret is
 17    /// a byte array with a length matching one of the AES key lengths (128, 192, 256) and the
 18    /// content-type of the secret is application/octet-stream.
 19    /// </summary>
 20    public class KeyResolver : IKeyEncryptionKeyResolver
 21    {
 22        private readonly HttpPipeline  _pipeline;
 23        private readonly string _apiVersion;
 24
 25        private ClientDiagnostics _clientDiagnostics;
 26
 27        /// <summary>
 28        /// Initializes a new instance of the <see cref="KeyResolver"/> class for mocking.
 29        /// </summary>
 2830        protected KeyResolver()
 31        {
 2832        }
 33
 34        /// <summary>
 35        /// Initializes a new instance of the <see cref="KeyResolver"/> class.
 36        /// </summary>
 37        /// <param name="credential">A <see cref="TokenCredential"/> used to authenticate requests to the vault, such as
 38        /// <exception cref="ArgumentNullException"><paramref name="credential"/> is null.</exception>
 39        public KeyResolver(TokenCredential credential)
 640            : this(credential, null)
 41        {
 442        }
 43
 44        /// <summary>
 45        /// Initializes a new instance of the <see cref="KeyResolver"/> class.
 46        /// </summary>
 47        /// <param name="credential">A <see cref="TokenCredential"/> used to authenticate requests to the vault, such as
 48        /// <param name="options">Options to configure the management of the requests sent to Key Vault for both the <se
 49        /// <exception cref="ArgumentNullException"><paramref name="credential"/> is null.</exception>
 3450        public KeyResolver(TokenCredential credential, CryptographyClientOptions options)
 51        {
 3452            Argument.AssertNotNull(credential, nameof(credential));
 53
 3254            options ??= new CryptographyClientOptions();
 55
 3256            _apiVersion = options.GetVersionString();
 57
 3258            _pipeline = HttpPipelineBuilder.Build(options,
 3259                    new ChallengeBasedAuthenticationPolicy(credential));
 60
 3261            _clientDiagnostics = new ClientDiagnostics(options);
 3262        }
 63
 64        /// <summary>
 65        /// Retrieves a <see cref="CryptographyClient"/> capable of performing cryptographic operations with the key rep
 66        /// </summary>
 67        /// <param name="keyId">The key identifier of the key used by the created <see cref="CryptographyClient"/>.</par
 68        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
 69        /// <returns>A new <see cref="CryptographyClient"/> capable of performing cryptographic operations with the key 
 70        /// <exception cref="ArgumentNullException"><paramref name="keyId"/> is null.</exception>
 71        public virtual CryptographyClient Resolve(Uri keyId, CancellationToken cancellationToken = default)
 72        {
 1673            Argument.AssertNotNull(keyId, nameof(keyId));
 74
 1475            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(KeyResolver)}.{nameof(Resolve)}");
 1476            scope.AddAttribute("key", keyId);
 1477            scope.Start();
 78
 79            try
 80            {
 1481                Argument.AssertNotNull(keyId, nameof(keyId));
 82
 1483                KeyVaultKey key = GetKey(keyId, cancellationToken);
 84
 885                KeyVaultPipeline pipeline = new KeyVaultPipeline(keyId, _apiVersion, _pipeline, _clientDiagnostics);
 86
 887                return (key != null) ? new CryptographyClient(key, pipeline) : new CryptographyClient(keyId, pipeline);
 88            }
 689            catch (Exception e)
 90            {
 691                scope.Failed(e);
 692                throw;
 93            }
 894        }
 95
 96        /// <summary>
 97        /// Retrieves a <see cref="CryptographyClient"/> capable of performing cryptographic operations with the key rep
 98        /// </summary>
 99        /// <param name="keyId">The key identifier of the key used by the created <see cref="CryptographyClient"/>.</par
 100        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
 101        /// <returns>A new <see cref="CryptographyClient"/> capable of performing cryptographic operations with the key 
 102        /// <exception cref="ArgumentNullException"><paramref name="keyId"/> is null.</exception>
 103        public virtual async Task<CryptographyClient> ResolveAsync(Uri keyId, CancellationToken cancellationToken = defa
 104        {
 16105            Argument.AssertNotNull(keyId, nameof(keyId));
 106
 14107            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(KeyResolver)}.{nameof(Resolve)}");
 14108            scope.AddAttribute("key", keyId);
 14109            scope.Start();
 110
 111            try
 112            {
 14113                Argument.AssertNotNull(keyId, nameof(keyId));
 114
 14115                KeyVaultKey key = await GetKeyAsync(keyId, cancellationToken).ConfigureAwait(false);
 116
 8117                KeyVaultPipeline pipeline = new KeyVaultPipeline(keyId, _apiVersion, _pipeline, _clientDiagnostics);
 118
 8119                return (key != null) ? new CryptographyClient(key, pipeline) : new CryptographyClient(keyId, pipeline);
 120
 121            }
 6122            catch (Exception e)
 123            {
 6124                scope.Failed(e);
 6125                throw;
 126            }
 8127        }
 128
 129        /// <inheritdoc/>
 130        IKeyEncryptionKey IKeyEncryptionKeyResolver.Resolve(string keyId, CancellationToken cancellationToken)
 131        {
 0132            return ((KeyResolver)this).Resolve(new Uri(keyId), cancellationToken);
 133        }
 134
 135        /// <inheritdoc/>
 136        async Task<IKeyEncryptionKey> IKeyEncryptionKeyResolver.ResolveAsync(string keyId, CancellationToken cancellatio
 137        {
 4138            return await ((KeyResolver)this).ResolveAsync(new Uri(keyId), cancellationToken).ConfigureAwait(false);
 4139        }
 140
 141        private KeyVaultKey GetKey(Uri keyId, CancellationToken cancellationToken)
 142        {
 14143            using Request request = CreateGetRequest(keyId);
 144
 14145            Response response = _pipeline.SendRequest(request, cancellationToken);
 146
 14147            return KeyVaultIdentifier.Parse(keyId).Collection == KeyVaultIdentifier.SecretsCollection ? (KeyVaultKey)Par
 8148        }
 149
 150        private async Task<KeyVaultKey> GetKeyAsync(Uri keyId, CancellationToken cancellationToken)
 151        {
 14152            using Request request = CreateGetRequest(keyId);
 153
 14154            Response response = await _pipeline.SendRequestAsync(request, cancellationToken).ConfigureAwait(false);
 155
 14156            return KeyVaultIdentifier.Parse(keyId).Collection == KeyVaultIdentifier.SecretsCollection ? (KeyVaultKey)Par
 8157        }
 158
 159        private Response<T> ParseResponse<T>(Response response, T result)
 160            where T : IJsonDeserializable
 161        {
 28162            switch (response.Status)
 163            {
 164                case 200:
 165                case 201:
 166                case 202:
 167                case 204:
 12168                    result.Deserialize(response.ContentStream);
 12169                    return Response.FromValue(result, response);
 8170                case 403 when !(result is SecretKey):
 171                    // The "get" permission may not be granted on a key, while other key permissions may be granted.
 172                    // To use a key contained within a secret, the "get" permission is required to retrieve the key mate
 4173                    return Response.FromValue<T>(default, response);
 174                default:
 12175                    throw _clientDiagnostics.CreateRequestFailedException(response);
 176            }
 177        }
 178
 179        private Request CreateGetRequest(Uri uri)
 180        {
 28181            Request request = _pipeline.CreateRequest();
 182
 28183            request.Headers.Add(HttpHeader.Common.JsonContentType);
 28184            request.Headers.Add(HttpHeader.Common.JsonAccept);
 28185            request.Method = RequestMethod.Get;
 28186            request.Uri.Reset(uri);
 187
 28188            request.Uri.AppendQuery("api-version", _apiVersion);
 189
 28190            return request;
 191        }
 192
 193    }
 194}