public async Task CachesExistingTokenWhenPossible() { // Arrange var tokenProvider = new Mock <IAccessTokenProvider>(); tokenProvider.Setup(tp => tp.RequestAccessToken()) .Returns(new ValueTask <AccessTokenResult>(new AccessTokenResult(AccessTokenResultStatus.Success, new AccessToken { Expires = DateTime.Now.AddHours(1), GrantedScopes = new string[] { "All" }, Value = "asdf" }, null, null))); var handler = new AuthorizationMessageHandler(tokenProvider.Object, Mock.Of <NavigationManager>()); handler.ConfigureHandler(new[] { "https://localhost:5001" }); var response = new HttpResponseMessage(HttpStatusCode.OK); handler.InnerHandler = new TestMessageHandler(response); // Act _ = await new HttpClient(handler).GetAsync("https://localhost:5001/weather"); response.RequestMessage = null; _ = await new HttpClient(handler).GetAsync("https://localhost:5001/weather"); // Assert Assert.Single(tokenProvider.Invocations); Assert.Equal("asdf", response.RequestMessage.Headers.Authorization.Parameter); }
public async Task UsesCustomScopesAndReturnUrlWhenProvided() { // Arrange var tokenProvider = new Mock <IAccessTokenProvider>(); tokenProvider.Setup(tp => tp.RequestAccessToken(It.IsAny <AccessTokenRequestOptions>())) .Returns(new ValueTask <AccessTokenResult>(new AccessTokenResult(AccessTokenResultStatus.Success, new AccessToken { Expires = DateTime.Now.AddMinutes(3), GrantedScopes = new string[] { "All" }, Value = "asdf" }, null, null))); var handler = new AuthorizationMessageHandler(tokenProvider.Object, Mock.Of <NavigationManager>()); handler.ConfigureHandler( new[] { "https://localhost:5001" }, scopes: new[] { "example.read", "example.write" }, returnUrl: "https://www.example.com/return"); var response = new HttpResponseMessage(HttpStatusCode.OK); handler.InnerHandler = new TestMessageHandler(response); // Act _ = await new HttpClient(handler).GetAsync("https://localhost:5001/weather"); // Assert Assert.Equal(1, tokenProvider.Invocations.Count); }
public async Task RequestNewTokenWhenCurrentTokenIsAboutToExpire() { // Arrange var tokenProvider = new Mock <IAccessTokenProvider>(); tokenProvider.Setup(tp => tp.RequestAccessToken()) .Returns(new ValueTask <AccessTokenResult>(new AccessTokenResult(AccessTokenResultStatus.Success, new AccessToken { Expires = DateTime.Now.AddMinutes(3), GrantedScopes = new string[] { "All" }, Value = "asdf" }, null, null))); var handler = new AuthorizationMessageHandler(tokenProvider.Object, Mock.Of <NavigationManager>()); handler.ConfigureHandler(new[] { "https://localhost:5001" }); var response = new HttpResponseMessage(HttpStatusCode.OK); handler.InnerHandler = new TestMessageHandler(response); // Act _ = await new HttpClient(handler).GetAsync("https://localhost:5001/weather"); response.RequestMessage = null; _ = await new HttpClient(handler).GetAsync("https://localhost:5001/weather"); // Assert Assert.Equal(2, tokenProvider.Invocations.Count); }
public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add <App>("app"); builder.Services.AddTransient <AuthorizationMessageHandler>(sp => { IAccessTokenProvider provider = sp.GetRequiredService <IAccessTokenProvider>(); NavigationManager naviManager = sp.GetRequiredService <NavigationManager>(); AuthorizationMessageHandler handler = new AuthorizationMessageHandler(provider, naviManager); handler.ConfigureHandler(authorizedUrls: new[] { naviManager.ToAbsoluteUri("api/").AbsoluteUri }); return(handler); }); builder.Services.AddHttpClient("WebUI.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)) .AddHttpMessageHandler <AuthorizationMessageHandler>(); builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddApiAuthorization(); await builder.Build().RunAsync(); }
public async Task Throws_IfTheListOfAllowedUrlsIsNotConfigured() { // Arrange var expectedMessage = "The 'AuthorizationMessageHandler' is not configured. " + "Call 'ConfigureHandler' and provide a list of endpoint urls to attach the token to."; var tokenProvider = new Mock <IAccessTokenProvider>(); var handler = new AuthorizationMessageHandler(tokenProvider.Object, Mock.Of <NavigationManager>()); // Act & Assert var exception = await Assert.ThrowsAsync <InvalidOperationException>( () => new HttpClient(handler).GetAsync("https://www.example.com")); Assert.Equal(expectedMessage, exception.Message); }
public async Task DoesNotAttachTokenToRequest_IfNotPresentInListOfAllowedUrls() { // Arrange var tokenProvider = new Mock <IAccessTokenProvider>(); var handler = new AuthorizationMessageHandler(tokenProvider.Object, Mock.Of <NavigationManager>()); handler.ConfigureHandler(new[] { "https://localhost:5001" }); var response = new HttpResponseMessage(HttpStatusCode.OK); handler.InnerHandler = new TestMessageHandler(response); // Act _ = await new HttpClient(handler).GetAsync("https://www.example.com"); // Assert tokenProvider.VerifyNoOtherCalls(); }
public async Task ThrowsWhenItCanNotProvisionANewToken() { // Arrange var tokenProvider = new Mock <IAccessTokenProvider>(); tokenProvider.Setup(tp => tp.RequestAccessToken()) .Returns(new ValueTask <AccessTokenResult>(new AccessTokenResult(AccessTokenResultStatus.RequiresRedirect, null, "https://www.example.com"))); var handler = new AuthorizationMessageHandler(tokenProvider.Object, Mock.Of <NavigationManager>()); handler.ConfigureHandler(new[] { "https://localhost:5001" }); var response = new HttpResponseMessage(HttpStatusCode.OK); handler.InnerHandler = new TestMessageHandler(response); // Act & assert var exception = await Assert.ThrowsAsync <AccessTokenNotAvailableException>(() => new HttpClient(handler).GetAsync("https://localhost:5001/weather")); }
/// <summary> /// This method gets called by the runtime. /// Use this method to add services to the container. /// </summary> /// /// <param name="builder">The builder.</param> public static void ConfigureBuilder(WebAssemblyHostBuilder builder) { #region [Required: Blazor Components] builder.RootComponents .Add <App>("app"); builder.Services .AddOptions() .AddSharedLocalization <SharedResources>(options => { options.DefaultCulture = "en"; options.SupportedCultures = new[] { "en", "pt" }; }); #endregion #region [Required: Blazor Authentication] builder.Services .AddOidcAuthentication(options => { var settings = new MovieSettings(); builder.Configuration.Bind(settings); // Authority options.ProviderOptions.Authority = settings.IdentityClientOptions.Authority; options.ProviderOptions.ClientId = settings.IdentityClientOptions.ClientId; // Redirection options.ProviderOptions.RedirectUri = settings.IdentityClientOptions.RedirectUri; options.ProviderOptions.PostLogoutRedirectUri = settings.IdentityClientOptions.PostLogoutRedirectUri; // Response options.ProviderOptions.ResponseMode = settings.IdentityClientOptions.ResponseMode; options.ProviderOptions.ResponseType = settings.IdentityClientOptions.ResponseType; // Scopes foreach (var scope in settings.IdentityClientOptions.Scopes) { options.ProviderOptions.DefaultScopes.Add(scope); } }); #endregion #region [Required: AutoMapper] builder.Services .AddAutoMapper(typeof(MovieMapperProfile).Assembly); #endregion #region [Required: Http Clients] builder.Services .AddHttpClient(HttpClientName, client => { client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress); }) .ConfigureHttpMessageHandlerBuilder(options => { var settings = options.Services.GetService <IConfiguration>().Get <MovieSettings>(); // Convert the enumerables to lists var blackListedUris = settings.IdentityClientOptions.BlackListedUris?.ToList() ?? new List <string>(); var whiteListedUris = settings.IdentityClientOptions.WhiteListedUris?.ToList() ?? new List <string>(); // Append the base address to the configured uris blackListedUris = blackListedUris .Select(uri => $"{builder.HostEnvironment.BaseAddress}{uri.ToLowerInvariant()}") .ToList(); whiteListedUris = whiteListedUris .Select(uri => $"{builder.HostEnvironment.BaseAddress}{uri.ToLowerInvariant()}") .ToList(); // Make sure there's at least one white-listed uri if (whiteListedUris.Count == 0) { whiteListedUris.Add(builder.HostEnvironment.BaseAddress); } // Configure the handler var handler = new AuthorizationMessageHandler(options.Services); handler.ConfigureHandler(blackListedUris, whiteListedUris, settings.IdentityClientOptions.Scopes); // Assign the handler options.PrimaryHandler = handler; }); builder.Services .AddTransient(provider => { var factory = provider.GetRequiredService <IHttpClientFactory>(); return(factory.CreateClient(HttpClientName)); }); #endregion #region [Required: Http Services] builder.Services .AddSingleton <IHttpService, HttpService>() .AddSingleton <IGenreService, GenreService>() .AddSingleton <IMovieService, MovieService>() .AddSingleton <IPersonService, PersonService>(); #endregion #region [Required: FileReader] builder.Services .AddFileReaderService(options => { options.InitializeOnFirstCall = true; }); #endregion #region [Required: Toaster] builder.Services .AddToasterService(); #endregion }