diff --git a/Directory.Build.props b/Directory.Build.props index 6d41e536..75dc08ed 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,5 +24,6 @@ 11.0 true + CS8785 diff --git a/Directory.Packages.props b/Directory.Packages.props index a2ed1444..36ac2ed5 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,7 +1,7 @@  - + diff --git a/src/D2L.Security.OAuth2.TestFramework/TestAccessToken.cs b/src/D2L.Security.OAuth2.TestFramework/TestAccessToken.cs index ab2dbb82..3651c1d7 100644 --- a/src/D2L.Security.OAuth2.TestFramework/TestAccessToken.cs +++ b/src/D2L.Security.OAuth2.TestFramework/TestAccessToken.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using D2L.Security.OAuth2.Provisioning; using D2L.Security.OAuth2.Scopes; -using D2L.Services; using IAccessToken = D2L.Security.OAuth2.Provisioning.IAccessToken; namespace D2L.Security.OAuth2.TestFramework { diff --git a/src/D2L.Security.OAuth2/Keys/Default/Data/IJwksProvider.cs b/src/D2L.Security.OAuth2/Keys/Default/Data/IJwksProvider.cs index 8a86dfbe..cb1a5767 100644 --- a/src/D2L.Security.OAuth2/Keys/Default/Data/IJwksProvider.cs +++ b/src/D2L.Security.OAuth2/Keys/Default/Data/IJwksProvider.cs @@ -1,8 +1,11 @@ using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; namespace D2L.Security.OAuth2.Keys.Default.Data { - internal interface IJwksProvider { + internal partial interface IJwksProvider { + [GenerateSync] Task RequestJwksAsync(); + [GenerateSync] Task RequestJwkAsync( string keyId ); string Namespace { get; } } diff --git a/src/D2L.Security.OAuth2/Keys/Default/Data/JwksProvider.cs b/src/D2L.Security.OAuth2/Keys/Default/Data/JwksProvider.cs index bb5e62b2..5fab2a19 100644 --- a/src/D2L.Security.OAuth2/Keys/Default/Data/JwksProvider.cs +++ b/src/D2L.Security.OAuth2/Keys/Default/Data/JwksProvider.cs @@ -3,12 +3,13 @@ using System.Net.Http; using System.Threading.Tasks; using System.Web; +using D2L.CodeStyle.Annotations; +using D2L.Security.OAuth2.Utilities; using D2L.Security.OAuth2.Validation.Exceptions; -using D2L.Services; namespace D2L.Security.OAuth2.Keys.Default.Data { - internal sealed class JwksProvider : IJwksProvider { - private readonly HttpClient m_httpClient; + internal sealed partial class JwksProvider : IJwksProvider { + private readonly ID2LHttpClient m_httpClient; private readonly Uri m_jwksEndpoint; private readonly Uri m_jwkEndpoint; @@ -17,11 +18,12 @@ public JwksProvider( Uri jwksEndpoint, Uri jwkEndpoint ) { - m_httpClient = httpClient; + m_httpClient = new D2LHttpClient( httpClient ); m_jwksEndpoint = jwksEndpoint; m_jwkEndpoint = jwkEndpoint; } + [GenerateSync] async Task IJwksProvider.RequestJwksAsync() { try { using( HttpResponseMessage response = await m_httpClient.GetAsync( m_jwksEndpoint ).ConfigureAwait( false ) ) { @@ -37,6 +39,7 @@ async Task IJwksProvider.RequestJwksAsync() { } } + [GenerateSync] async Task IJwksProvider.RequestJwkAsync( string keyId ) { var url = GetJwkEndpoint( m_jwkEndpoint, keyId ); if( url == null ) { diff --git a/src/D2L.Security.OAuth2/Keys/Default/ExpiringPublicKeyDataProvider.cs b/src/D2L.Security.OAuth2/Keys/Default/ExpiringPublicKeyDataProvider.cs index 40fcf57d..48fe117f 100644 --- a/src/D2L.Security.OAuth2/Keys/Default/ExpiringPublicKeyDataProvider.cs +++ b/src/D2L.Security.OAuth2/Keys/Default/ExpiringPublicKeyDataProvider.cs @@ -2,11 +2,12 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; using D2L.Security.OAuth2.Utilities; using D2L.Services; namespace D2L.Security.OAuth2.Keys.Default { - internal sealed class ExpiringPublicKeyDataProvider : ISanePublicKeyDataProvider { + internal sealed partial class ExpiringPublicKeyDataProvider : ISanePublicKeyDataProvider { private readonly IPublicKeyDataProvider m_inner; private readonly IDateTimeProvider m_dateTimeProvider; @@ -18,6 +19,7 @@ IDateTimeProvider dateTimeProvider m_dateTimeProvider = dateTimeProvider ?? throw new ArgumentException( nameof( dateTimeProvider ) ); } + [GenerateSync] async Task IPublicKeyDataProvider.GetByIdAsync( Guid id ) { // We are intentionally fetching *all* public keys from the database // here. This allows us to clean up all expired public keys even if @@ -44,6 +46,7 @@ async Task IPublicKeyDataProvider.GetByIdAsync( Guid id ) { return key; } + [GenerateSync] async Task> IPublicKeyDataProvider.GetAllAsync() { IEnumerable keys = await m_inner .GetAllAsync() @@ -62,14 +65,17 @@ async Task> IPublicKeyDataProvider.GetAllAsync() { return result; } + [GenerateSync] Task IPublicKeyDataProvider.SaveAsync( Guid id, JsonWebKey key ) { return m_inner.SaveAsync( id, key ); } + [GenerateSync] Task IPublicKeyDataProvider.DeleteAsync( Guid id ) { return m_inner.DeleteAsync( id ); } + [GenerateSync] private async Task KeyExpiryHelperAsync( JsonWebKey key ) { if( key == null ) { return true; diff --git a/src/D2L.Security.OAuth2/Keys/Default/IPublicKeyProvider.cs b/src/D2L.Security.OAuth2/Keys/Default/IPublicKeyProvider.cs index b507be28..ccd81aa7 100644 --- a/src/D2L.Security.OAuth2/Keys/Default/IPublicKeyProvider.cs +++ b/src/D2L.Security.OAuth2/Keys/Default/IPublicKeyProvider.cs @@ -1,23 +1,25 @@ -using System; -using System.Threading.Tasks; +using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; namespace D2L.Security.OAuth2.Keys.Default { /// /// An abstraction for fetching public keys /// - internal interface IPublicKeyProvider { + internal partial interface IPublicKeyProvider { /// /// Gets an individual by its /// /// The key id (kid) /// The or null if the key doesn't exist or has expired + [GenerateSync] Task GetByIdAsync( string id ); /// /// Perform steps to potentially make future key fetches faster. /// + [GenerateSync] Task PrefetchAsync(); } diff --git a/src/D2L.Security.OAuth2/Keys/Default/LocalPublicKeyProvider.cs b/src/D2L.Security.OAuth2/Keys/Default/LocalPublicKeyProvider.cs index 2adecdaa..87c0cdb0 100644 --- a/src/D2L.Security.OAuth2/Keys/Default/LocalPublicKeyProvider.cs +++ b/src/D2L.Security.OAuth2/Keys/Default/LocalPublicKeyProvider.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; using D2L.Security.OAuth2.Keys.Caching; using D2L.Security.OAuth2.Validation.Exceptions; using D2L.Services; namespace D2L.Security.OAuth2.Keys.Default { - internal sealed class LocalPublicKeyProvider : IPublicKeyProvider { + internal sealed partial class LocalPublicKeyProvider : IPublicKeyProvider { private const string PUBLIC_KEY_SOURCE = "Local DB"; @@ -21,6 +22,7 @@ IInMemoryPublicKeyCache cache m_cache = cache ?? throw new ArgumentNullException( nameof( cache ) ); } + [GenerateSync] async Task IPublicKeyProvider.PrefetchAsync() { IEnumerable jwks = await m_publicKeyDataProvider .GetAllAsync() @@ -42,6 +44,7 @@ async Task IPublicKeyProvider.PrefetchAsync() { } } + [GenerateSync] async Task IPublicKeyProvider.GetByIdAsync( string id ) { D2LSecurityToken result = m_cache.Get( PUBLIC_KEY_SOURCE, id ); if( result != null ) { diff --git a/src/D2L.Security.OAuth2/Keys/Default/RemotePublicKeyProvider.cs b/src/D2L.Security.OAuth2/Keys/Default/RemotePublicKeyProvider.cs index fb818ed9..49ee1010 100644 --- a/src/D2L.Security.OAuth2/Keys/Default/RemotePublicKeyProvider.cs +++ b/src/D2L.Security.OAuth2/Keys/Default/RemotePublicKeyProvider.cs @@ -1,12 +1,13 @@ using System; using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; using D2L.Security.OAuth2.Keys.Caching; using D2L.Security.OAuth2.Keys.Default.Data; using D2L.Security.OAuth2.Validation.Exceptions; using D2L.Services; namespace D2L.Security.OAuth2.Keys.Default { - internal sealed class RemotePublicKeyProvider : IPublicKeyProvider { + internal sealed partial class RemotePublicKeyProvider : IPublicKeyProvider { private readonly IJwksProvider m_jwksProvider; private readonly IInMemoryPublicKeyCache m_cache; @@ -18,6 +19,7 @@ IInMemoryPublicKeyCache cache m_cache = cache; } + [GenerateSync] async Task IPublicKeyProvider.GetByIdAsync( string id ) { D2LSecurityToken result = m_cache.Get( m_jwksProvider.Namespace, id ); if( result != null ) { @@ -38,6 +40,7 @@ async Task IPublicKeyProvider.GetByIdAsync( string id ) { throw new PublicKeyNotFoundException( id, jwks.Source.AbsoluteUri ); } + [GenerateSync] async Task IPublicKeyProvider.PrefetchAsync() { JsonWebKeySet jwks = await m_jwksProvider .RequestJwksAsync() diff --git a/src/D2L.Security.OAuth2/Keys/Development/InMemoryPublicKeyDataProvider.cs b/src/D2L.Security.OAuth2/Keys/Development/InMemoryPublicKeyDataProvider.cs index e38cd27d..39c2dce3 100644 --- a/src/D2L.Security.OAuth2/Keys/Development/InMemoryPublicKeyDataProvider.cs +++ b/src/D2L.Security.OAuth2/Keys/Development/InMemoryPublicKeyDataProvider.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; namespace D2L.Security.OAuth2.Keys.Development { @@ -11,9 +12,10 @@ namespace D2L.Security.OAuth2.Keys.Development { /// A simple in-memory key data provider to be used only for testing and prototyping purposes. /// [Obsolete( "Only use this in tests and for prototyping without a db" )] - public sealed class InMemoryPublicKeyDataProvider : IPublicKeyDataProvider { + public sealed partial class InMemoryPublicKeyDataProvider : IPublicKeyDataProvider { private readonly ConcurrentDictionary m_keys = new ConcurrentDictionary(); + [GenerateSync] Task IPublicKeyDataProvider.GetByIdAsync( Guid id ) { if( !m_keys.TryGetValue( id, out JsonWebKey key ) ) { return Task.FromResult( null ); @@ -21,6 +23,7 @@ Task IPublicKeyDataProvider.GetByIdAsync( Guid id ) { return Task.FromResult( key ); } + [GenerateSync] Task> IPublicKeyDataProvider.GetAllAsync() { IEnumerable result = new ReadOnlyCollection( m_keys.Values.ToList() ); @@ -28,6 +31,7 @@ Task> IPublicKeyDataProvider.GetAllAsync() { return Task.FromResult( result ); } + [GenerateSync] Task IPublicKeyDataProvider.SaveAsync( Guid id, JsonWebKey key ) { if( !m_keys.TryAdd( id, key ) ) { throw new InvalidOperationException( "Attempted to add a key twice" ); @@ -35,6 +39,7 @@ Task IPublicKeyDataProvider.SaveAsync( Guid id, JsonWebKey key ) { return Task.CompletedTask; } + [GenerateSync] Task IPublicKeyDataProvider.DeleteAsync( Guid id ) { m_keys.TryRemove( id, out JsonWebKey removedKey ); return Task.CompletedTask; diff --git a/src/D2L.Security.OAuth2/Keys/IPublicKeyDataProvider.cs b/src/D2L.Security.OAuth2/Keys/IPublicKeyDataProvider.cs index 90ea91be..881d8d50 100644 --- a/src/D2L.Security.OAuth2/Keys/IPublicKeyDataProvider.cs +++ b/src/D2L.Security.OAuth2/Keys/IPublicKeyDataProvider.cs @@ -1,25 +1,28 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; namespace D2L.Security.OAuth2.Keys { /// /// Data provider for public keys that belong to this service /// - public interface IPublicKeyDataProvider { + public partial interface IPublicKeyDataProvider { /// /// Gets an individual by its /// /// The key id (kid) /// The or null if the key doesn't exist or has expired + [GenerateSync] Task GetByIdAsync( Guid id ); /// /// Gets all the instances /// /// All keys which haven't expired + [GenerateSync] Task> GetAllAsync(); /// @@ -27,12 +30,14 @@ public interface IPublicKeyDataProvider { /// /// The key id (kid) of the key to save /// The key to save + [GenerateSync] Task SaveAsync( Guid id, JsonWebKey key ); /// /// Deletes a key by key (kid) /// /// The key id (kid) of the key to delete + [GenerateSync] Task DeleteAsync( Guid id ); } diff --git a/src/D2L.Security.OAuth2/Provisioning/Default/AuthServiceClient.cs b/src/D2L.Security.OAuth2/Provisioning/Default/AuthServiceClient.cs index 8cf33be2..c56434d3 100644 --- a/src/D2L.Security.OAuth2/Provisioning/Default/AuthServiceClient.cs +++ b/src/D2L.Security.OAuth2/Provisioning/Default/AuthServiceClient.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using D2L.Security.OAuth2.Scopes; +using D2L.Security.OAuth2.Utilities; using D2L.Services.Core.Exceptions; #if NET6_0 @@ -39,7 +40,7 @@ internal sealed class AuthServiceClient : IAuthServiceClient { SERIALIZATION_ERROR_MESSAGE_PREFIX + "The Auth Service responded with: "; - private readonly HttpClient m_client; + private readonly ID2LHttpClient m_client; private readonly Uri m_tokenProvisioningEndpoint; /// @@ -59,7 +60,7 @@ Uri authEndpoint throw new ArgumentNullException( "authEndpoint" ); } - m_client = httpClient; + m_client = new D2LHttpClient( httpClient ); m_tokenProvisioningEndpoint = authEndpoint.RelativePathAsNonLeaf( TOKEN_PATH ); } diff --git a/src/D2L.Security.OAuth2/Utilities/D2LHttpClient.cs b/src/D2L.Security.OAuth2/Utilities/D2LHttpClient.cs new file mode 100644 index 00000000..d425f171 --- /dev/null +++ b/src/D2L.Security.OAuth2/Utilities/D2LHttpClient.cs @@ -0,0 +1,122 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; + +namespace D2L.Security.OAuth2.Utilities { + /// + /// This class implements sync versions of HTTPClient methods. + /// TODO: Replace the sync methods which are currently using Task.Run(async verison); task.Wait(); + /// With (probably) HttpWebRequest + /// + internal sealed class D2LHttpClient : ID2LHttpClient { + private readonly HttpClient m_httpClient; + + public D2LHttpClient( HttpClient httpClient ) { + m_httpClient = httpClient; + } + + public Task GetAsync( string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken ) + => m_httpClient.GetAsync( requestUri, completionOption, cancellationToken ); + public Task GetAsync( Uri requestUri, CancellationToken cancellationToken ) + => m_httpClient.GetAsync( requestUri, cancellationToken ); + public Task GetAsync( Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken ) + => m_httpClient.GetAsync( requestUri, completionOption, cancellationToken ); + public Task GetAsync( Uri requestUri, HttpCompletionOption completionOption ) + => m_httpClient.GetAsync( requestUri, completionOption ); + public Task GetAsync( string requestUri, HttpCompletionOption completionOption ) + => m_httpClient.GetAsync( requestUri, completionOption ); + public Task GetAsync( Uri requestUri ) + => m_httpClient.GetAsync( requestUri ); + public Task GetAsync( string requestUri ) + => m_httpClient.GetAsync( requestUri ); + public Task GetAsync( string requestUri, CancellationToken cancellationToken ) + => m_httpClient.GetAsync( requestUri, cancellationToken ); + + public Task SendAsync( HttpRequestMessage request ) + => m_httpClient.SendAsync( request ); + public Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken ) + => m_httpClient.SendAsync( request, cancellationToken ); + public Task SendAsync( HttpRequestMessage request, HttpCompletionOption completionOption ) + => m_httpClient.SendAsync( request, completionOption ); + public Task SendAsync( HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken ) + => m_httpClient.SendAsync( request, completionOption, cancellationToken ); + + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Get( string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken ) { + var task = Task.Run( () => m_httpClient.GetAsync( requestUri, completionOption, cancellationToken ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Get( Uri requestUri, CancellationToken cancellationToken ) { + var task = Task.Run( () => m_httpClient.GetAsync( requestUri, cancellationToken ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Get( Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken ) { + var task = Task.Run( () => m_httpClient.GetAsync( requestUri, completionOption, cancellationToken ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Get( Uri requestUri, HttpCompletionOption completionOption ) { + var task = Task.Run( () => m_httpClient.GetAsync( requestUri, completionOption ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Get( string requestUri, HttpCompletionOption completionOption ) { + var task = Task.Run( () => m_httpClient.GetAsync( requestUri, completionOption ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Get( Uri requestUri ) { + var task = Task.Run( () => m_httpClient.GetAsync( requestUri ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Get( string requestUri ) { + var task = Task.Run( () => m_httpClient.GetAsync( requestUri ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Get( string requestUri, CancellationToken cancellationToken ) { + var task = Task.Run( () => m_httpClient.GetAsync( requestUri, cancellationToken ) ); + task.Wait(); + return task.Result; + } + + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Send( HttpRequestMessage request ) { + var task = Task.Run( () => m_httpClient.SendAsync( request ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Send( HttpRequestMessage request, CancellationToken cancellationToken ) { + var task = Task.Run( () => m_httpClient.SendAsync( request, cancellationToken ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Send( HttpRequestMessage request, HttpCompletionOption completionOption ) { + var task = Task.Run( () => m_httpClient.SendAsync( request, completionOption ) ); + task.Wait(); + return task.Result; + } + [DangerousMethodUsage.Audited( typeof( Task ), "Run", "Ana DuCristea", "2023-07-23", "Temporary sync implementation of HttpClient for generated sync methods to be replaced later" )] + public HttpResponseMessage Send( HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken ) { + var task = Task.Run( () => m_httpClient.SendAsync( request, completionOption, cancellationToken ) ); + task.Wait(); + return task.Result; + } + + public void Dispose() { m_httpClient.Dispose(); } + } +} diff --git a/src/D2L.Security.OAuth2/Utilities/ID2LHttpClient.cs b/src/D2L.Security.OAuth2/Utilities/ID2LHttpClient.cs new file mode 100644 index 00000000..29c43762 --- /dev/null +++ b/src/D2L.Security.OAuth2/Utilities/ID2LHttpClient.cs @@ -0,0 +1,40 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace D2L.Security.OAuth2.Utilities { + /// + /// This interface was created to allow the sync generator in D2L.CodeStyle to strip the async suffix from HttpClient calls + /// when it tries to convert async code to sync code. + /// + internal interface ID2LHttpClient : IDisposable { + public Task GetAsync( string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken ); + public Task GetAsync( Uri requestUri, CancellationToken cancellationToken ); + public Task GetAsync( Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken ); + public Task GetAsync( Uri requestUri, HttpCompletionOption completionOption ); + public Task GetAsync( string requestUri, HttpCompletionOption completionOption ); + public Task GetAsync( Uri requestUri ); + public Task GetAsync( string requestUri ); + public Task GetAsync( string requestUri, CancellationToken cancellationToken ); + + public HttpResponseMessage Get( string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken ); + public HttpResponseMessage Get( Uri requestUri, CancellationToken cancellationToken ); + public HttpResponseMessage Get( Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken ); + public HttpResponseMessage Get( Uri requestUri, HttpCompletionOption completionOption ); + public HttpResponseMessage Get( string requestUri, HttpCompletionOption completionOption ); + public HttpResponseMessage Get( Uri requestUri ); + public HttpResponseMessage Get( string requestUri ); + public HttpResponseMessage Get( string requestUri, CancellationToken cancellationToken ); + + public Task SendAsync( HttpRequestMessage request ); + public Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken ); + public Task SendAsync( HttpRequestMessage request, HttpCompletionOption completionOption ); + public Task SendAsync( HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken ); + + public HttpResponseMessage Send( HttpRequestMessage request ); + public HttpResponseMessage Send( HttpRequestMessage request, CancellationToken cancellationToken ); + public HttpResponseMessage Send( HttpRequestMessage request, HttpCompletionOption completionOption ); + public HttpResponseMessage Send( HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken ); + } +} diff --git a/src/D2L.Security.OAuth2/Validation/AccessTokens/AccessTokenValidator.cs b/src/D2L.Security.OAuth2/Validation/AccessTokens/AccessTokenValidator.cs index 22fb5b44..dcdf26f5 100644 --- a/src/D2L.Security.OAuth2/Validation/AccessTokens/AccessTokenValidator.cs +++ b/src/D2L.Security.OAuth2/Validation/AccessTokens/AccessTokenValidator.cs @@ -7,13 +7,14 @@ using D2L.Security.OAuth2.Keys.Default; using D2L.Security.OAuth2.Validation.Exceptions; using D2L.Services; +using D2L.CodeStyle.Annotations; #if DNXCORE50 using System.IdentityModel.Tokens.Jwt; #endif namespace D2L.Security.OAuth2.Validation.AccessTokens { - internal sealed class AccessTokenValidator : IAccessTokenValidator { + internal sealed partial class AccessTokenValidator : IAccessTokenValidator { internal static readonly ImmutableHashSet ALLOWED_SIGNATURE_ALGORITHMS = ImmutableHashSet.Create( SecurityAlgorithms.RsaSha256, SecurityAlgorithms.EcdsaSha256, @@ -33,8 +34,10 @@ IPublicKeyProvider publicKeyProvider m_publicKeyProvider = publicKeyProvider; } + [GenerateSync] Task IAccessTokenValidator.PrefetchAsync() => m_publicKeyProvider.PrefetchAsync(); + [GenerateSync] async Task IAccessTokenValidator.ValidateAsync( string token ) { diff --git a/src/D2L.Security.OAuth2/Validation/AccessTokens/AccessTokenValidatorFactory.cs b/src/D2L.Security.OAuth2/Validation/AccessTokens/AccessTokenValidatorFactory.cs index 221b4b0f..ab51139f 100644 --- a/src/D2L.Security.OAuth2/Validation/AccessTokens/AccessTokenValidatorFactory.cs +++ b/src/D2L.Security.OAuth2/Validation/AccessTokens/AccessTokenValidatorFactory.cs @@ -4,6 +4,7 @@ using D2L.Security.OAuth2.Keys.Caching; using D2L.Security.OAuth2.Keys.Default; using D2L.Security.OAuth2.Keys.Default.Data; +using D2L.Security.OAuth2.Utilities; namespace D2L.Security.OAuth2.Validation.AccessTokens { diff --git a/src/D2L.Security.OAuth2/Validation/AccessTokens/IAccessTokenValidator.cs b/src/D2L.Security.OAuth2/Validation/AccessTokens/IAccessTokenValidator.cs index 3ff20247..7c17e2d2 100644 --- a/src/D2L.Security.OAuth2/Validation/AccessTokens/IAccessTokenValidator.cs +++ b/src/D2L.Security.OAuth2/Validation/AccessTokens/IAccessTokenValidator.cs @@ -1,15 +1,17 @@ using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; namespace D2L.Security.OAuth2.Validation.AccessTokens { /// /// An abstraction for validating access tokens /// - public interface IAccessTokenValidator { + public partial interface IAccessTokenValidator { /// /// Perform steps to potentially make future validations faster. /// + [GenerateSync] Task PrefetchAsync(); /// @@ -18,6 +20,7 @@ public interface IAccessTokenValidator { /// The raw token to validate /// A holding the decoded and validated access token /// Throws on error + [GenerateSync] Task ValidateAsync( string accessToken ); diff --git a/src/D2L.Security.OAuth2/Validation/Request/IRequestAuthenticator.cs b/src/D2L.Security.OAuth2/Validation/Request/IRequestAuthenticator.cs index bfce0d3f..866c292b 100644 --- a/src/D2L.Security.OAuth2/Validation/Request/IRequestAuthenticator.cs +++ b/src/D2L.Security.OAuth2/Validation/Request/IRequestAuthenticator.cs @@ -1,5 +1,6 @@ using System.Net.Http; using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; using D2L.Security.OAuth2.Principal; namespace D2L.Security.OAuth2.Validation.Request { @@ -9,6 +10,7 @@ public partial interface IRequestAuthenticator { /// /// The web request object /// An for an authenticated user. + [GenerateSync] Task AuthenticateAsync( HttpRequestMessage request ); @@ -18,6 +20,7 @@ HttpRequestMessage request /// /// The bearer token. /// An for an authenticated user. + [GenerateSync] Task AuthenticateAsync( string bearerToken ); diff --git a/src/D2L.Security.OAuth2/Validation/Request/RequestAuthenticator.cs b/src/D2L.Security.OAuth2/Validation/Request/RequestAuthenticator.cs index 65676d03..eb66bf91 100644 --- a/src/D2L.Security.OAuth2/Validation/Request/RequestAuthenticator.cs +++ b/src/D2L.Security.OAuth2/Validation/Request/RequestAuthenticator.cs @@ -1,5 +1,6 @@ using System.Net.Http; using System.Threading.Tasks; +using D2L.CodeStyle.Annotations; using D2L.Security.OAuth2.Principal; using D2L.Security.OAuth2.Validation.AccessTokens; @@ -14,6 +15,7 @@ internal RequestAuthenticator( IAccessTokenValidator accessTokenValidator ) { m_accessTokenValidator = accessTokenValidator; } + [GenerateSync] Task IRequestAuthenticator.AuthenticateAsync( HttpRequestMessage request ) { @@ -22,6 +24,7 @@ HttpRequestMessage request return AuthenticateAsync( bearerToken ); } + [GenerateSync] public async Task AuthenticateAsync( string bearerToken ) { diff --git a/test/D2L.Security.OAuth2.Benchmarks/FullStackValidation/FullStackValidationBenchmark.cs b/test/D2L.Security.OAuth2.Benchmarks/FullStackValidation/FullStackValidationBenchmark.cs index 03a128f7..0791d614 100644 --- a/test/D2L.Security.OAuth2.Benchmarks/FullStackValidation/FullStackValidationBenchmark.cs +++ b/test/D2L.Security.OAuth2.Benchmarks/FullStackValidation/FullStackValidationBenchmark.cs @@ -4,6 +4,7 @@ using System.Net.Http; using D2L.Security.OAuth2.Keys; using D2L.Security.OAuth2.Keys.Development; +using D2L.Security.OAuth2.Utilities; using D2L.Security.OAuth2.Validation.AccessTokens; using Newtonsoft.Json; using RichardSzalay.MockHttp;