From 19a3735c097fe34c181372c1d5c18e435c17c282 Mon Sep 17 00:00:00 2001 From: Nish Anil Date: Tue, 29 Sep 2020 16:36:11 +0530 Subject: [PATCH] Merge dev to feature branch (#1476) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed firewall rules check and improved the script the check shall be like ~ Get-NetFirewallRule -DisplayName eShopOnContainers-* -ErrorAction Stop * #1397: Replaced deprecated docker.for.win.localhost by host.docker.internal in src/.env (#1400) * Updated Readme (#1402) Fixed sentence structure in Readme. Changed "and a several" to "with several." * CatalogService: Fix issue with Status set when items list is empty (#1304) * Fix issue with Status set when items list is empty * Change method Count() call to Count property Co-authored-by: Dmytro Hridin * refactored Equals() method on ValueObject (#1316) * Fix/1403and1404 removed duplicate Key SubscriptionClientName and added app.UseAuthorization() call (#1406) * #1403 removed duplicate Key SubscriptionClientName Removed duplicate key SubscriptionClientName from Tests/Services/Application.FunctionalTests/Services/Marketing/appsettings.json and sorted its content in asc order. * #1404 Added app.UseAuthorization() call Added app.UseAuthorization() call to BasketTestsStartup, LocationsTestsStartup, and MarketingTestsStartup to fix failed unit tests IntegrationEventsScenarios.Post_update_product_price_and_catalog_and_basket_list_modified and MarketingScenarios.Set_new_user_location_and_get_location_campaign_by_user_id (see #1404) * Fix for Campaigns exception and SignalR 401 Unauthorized (#1374) * update API Gateway - /locations-api/ @ webmarketing/envoy.yaml * updated signalr services - envoy: webmarketingapigw - latest client: webmvc - service hub: ordering-signalrhub Co-authored-by: hfz-r * Mis-Spelled 'client' (#1411) * fix parameter error in multiarch job (#1413) * Private readonly string changed to private const string (#1288) * fix disposing of direct instantiated objects in calalog service #1392 (#1395) * Updated version of different packages. (#1420) * for issue #1423: changed literal string "OpenIdConnect" to constant string (#1424) Co-authored-by: Jeremiah Flaga * Updated node-fetch package version. (#1426) * Updated node-fetch package version. * Updated node-forge version. * Fixes #1474: webspa container does not build when running docker-compose up.Updated sha hashes in packages-lock.json (#1475) * Change ReadAllBytes to ReadAllBytesAsync in PicController (#1425) Co-authored-by: edmondshtogu Co-authored-by: InstanceFactory Co-authored-by: Sumit Ghosh Co-authored-by: Yosef Herskovitz <34112131+H3RSKO@users.noreply.github.com> Co-authored-by: Dmytro Hridin Co-authored-by: Dmytro Hridin Co-authored-by: André Silva Co-authored-by: hfz-r <39443205+hfz-r@users.noreply.github.com> Co-authored-by: hfz-r Co-authored-by: Majid Ali Khan Quaid Co-authored-by: Javier Vela Co-authored-by: Facundo La Rocca Co-authored-by: Nabil Sedoud Co-authored-by: jeremiahflaga Co-authored-by: Jeremiah Flaga Co-authored-by: Wojciech Rak Co-authored-by: Zakaria <23211915+zakaria-c@users.noreply.github.com> --- README.md | 2 +- build/azure-devops/multiarch.yaml | 2 +- ...irewall-rules-for-sts-auth-thru-docker.ps1 | 63 ++++-- src/.env | 6 +- .../Envoy/config/webmarketing/envoy.yaml | 13 ++ .../Envoy/config/webshopping/envoy.yaml | 3 + .../EventBusRabbitMQ/EventBusRabbitMQ.cs | 3 +- .../Services/IntegrationEventLogService.cs | 23 ++- .../Catalog.API/Controllers/PicController.cs | 2 +- .../Catalog.API/Grpc/CatalogService.cs | 11 +- .../CatalogIntegrationEventService.cs | 22 +- .../Location/Locations.API/appsettings.json | 4 +- .../AggregatesModel/OrderAggregate/Address.cs | 2 +- .../Ordering.Domain/SeedWork/ValueObject.cs | 23 +-- .../Ordering/Ordering.SignalrHub/Startup.cs | 21 +- .../Domain/SeedWork/ValueObjectTests.cs | 190 ++++++++++++++++++ .../Services/Basket/BasketTestsStartup.cs | 1 + .../Location/LocationsTestsStartup.cs | 1 + .../Marketing/MarketingTestsStartup.cs | 1 + .../Services/Marketing/appsettings.json | 9 +- .../WebMVC/Controllers/AccountController.cs | 5 +- .../WebMVC/Controllers/CampaignsController.cs | 3 +- src/Web/WebMVC/Controllers/CartController.cs | 3 +- src/Web/WebMVC/Controllers/OrderController.cs | 3 +- .../Controllers/OrderManagementController.cs | 3 +- src/Web/WebMVC/Services/LocationService.cs | 2 +- src/Web/WebMVC/libman.json | 2 +- src/Web/WebSPA/package-lock.json | 48 +++-- 28 files changed, 380 insertions(+), 91 deletions(-) create mode 100644 src/Services/Ordering/Ordering.UnitTests/Domain/SeedWork/ValueObjectTests.cs diff --git a/README.md b/README.md index d1a3d2e87..ad35a6d2b 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Do you want to be up-to-date on .NET Architecture guidance and reference apps li ## Updated for .NET Core 3.1 (LTS) -eShopOnContainers is updated to .NET Core 3.1 "wave" of technologies. Not just compilation but also new recommended code in EF Core, ASP.NET Core, and other new related versions and a several significant changes. +eShopOnContainers is updated to .NET Core 3.1 "wave" of technologies. Not just compilation but also new recommended code in EF Core, ASP.NET Core, and other new related versions with several significant changes. **See more details in the [Release notes](https://github.com/dotnet-architecture/eShopOnContainers/wiki/Release-notes) wiki page**. diff --git a/build/azure-devops/multiarch.yaml b/build/azure-devops/multiarch.yaml index 162128d0a..1639fff87 100644 --- a/build/azure-devops/multiarch.yaml +++ b/build/azure-devops/multiarch.yaml @@ -26,7 +26,7 @@ jobs: mkdir -p ~/.docker sed '$ s/.$//' $DOCKER_CONFIG/config.json > ~/.docker/config.json echo ',"experimental": "enabled" }' >> ~/.docker/config.json - docker --config ~/.docker manifest create ${{ parameters.registry }}/${{ parameters.image }}:{{ parameters.branch }} ${{ parameters.registry }}/${{ parameters.image }}:linux-${{ parameters.branch }} + docker --config ~/.docker manifest create ${{ parameters.registry }}/${{ parameters.image }}:${{ parameters.branch }} ${{ parameters.registry }}/${{ parameters.image }}:linux-${{ parameters.branch }} docker --config ~/.docker manifest create ${{ parameters.registry }}/${{ parameters.image }}:latest ${{ parameters.registry }}/${{ parameters.image }}:linux-latest docker --config ~/.docker manifest push ${{ parameters.registry }}/${{ parameters.image }}:${{ parameters.branch }} docker --config ~/.docker manifest push ${{ parameters.registry }}/${{ parameters.image }}:latest diff --git a/deploy/windows/add-firewall-rules-for-sts-auth-thru-docker.ps1 b/deploy/windows/add-firewall-rules-for-sts-auth-thru-docker.ps1 index 271b6a77d..9aad3e45c 100644 --- a/deploy/windows/add-firewall-rules-for-sts-auth-thru-docker.ps1 +++ b/deploy/windows/add-firewall-rules-for-sts-auth-thru-docker.ps1 @@ -1,26 +1,53 @@ -param([switch]$Elevated) +param( + [string]$Name = "eShopOnContainers", + [string]$InboundDisplayName = "eShopOnContainers-Inbound", + [string]$OutboundDisplayName = "eShopOnContainers-Outbound", + [switch]$Elevated + ) + function Check-Admin { -$currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent()) -$currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) + $currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent()) + $currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) } -if ((Check-Admin) -eq $false) { -if ($elevated) -{ -# could not elevate, quit +function Add-InboundRule { + New-NetFirewallRule -DisplayName $InboundDisplayName -Confirm -Description "$Name Inbound Rule for port range 5100-5150" -LocalAddress Any -LocalPort 5100-5150 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Inbound } - -else { - -Start-Process powershell.exe -Verb RunAs -ArgumentList ('-noprofile -noexit -file "{0}" -elevated' -f ($myinvocation.MyCommand.Definition)) +function Add-OutboundRule { + New-NetFirewallRule -DisplayName $OutboundDisplayName -Confirm -Description "$Name Outbound Rule for port range 5100-5150" -LocalAddress Any -LocalPort 5100-5150 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Outbound } -exit + +if ((Check-Admin) -eq $false) { + if ($elevated) + { + # could not elevate, quit + } + else { + Start-Process powershell.exe -Verb RunAs -ArgumentList ('-noprofile -noexit -file "{0}" -elevated' -f ($myinvocation.MyCommand.Definition)) + } + exit } + try { - Get-NetFirewallRule -DisplayName EshopDocker -ErrorAction Stop - Write-Host "Rule found" + $rules = $(Get-NetFirewallRule -DisplayName $Name-* -ErrorAction Stop | Out-String) + if (!$rules.Contains($InboundDisplayName) -and !$rules.Contains($OutboundDisplayName)) + { + Add-InboundRule + Add-OutboundRule + } + elseif (!$rules.Contains($InboundDisplayName)) + { + Add-InboundRule + } + elseif (!$rules.Contains($OutboundDisplayName)) + { + Add-OutboundRule + } + else{ + Write-Host "Rules found!" + } +} +catch [Exception] { + Add-InboundRule + Add-OutboundRule } - catch [Exception] { - New-NetFirewallRule -DisplayName eShopOnContainers-Inbound -Confirm -Description "eShopOnContainers Inbound Rule for port range 5100-5150" -LocalAddress Any -LocalPort 5100-5150 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Inbound - New-NetFirewallRule -DisplayName eShopOnContainers-Outbound -Confirm -Description "eShopOnContainers Outbound Rule for port range 5100-5150" -LocalAddress Any -LocalPort 5100-5150 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Outbound -} \ No newline at end of file diff --git a/src/.env b/src/.env index c802f18eb..96b801650 100644 --- a/src/.env +++ b/src/.env @@ -5,9 +5,9 @@ # The IP below should be swapped to your real IP or DNS name, like 192.168.88.248, etc. if testing from remote browsers or mobile devices # Use this values to run the app locally in Windows -ESHOP_EXTERNAL_DNS_NAME_OR_IP=docker.for.win.localhost -ESHOP_STORAGE_CATALOG_URL=http://docker.for.win.localhost:5202/c/api/v1/catalog/items/[0]/pic/ -ESHOP_STORAGE_MARKETING_URL=http://docker.for.win.localhost:5110/api/v1/campaigns/[0]/pic/ +ESHOP_EXTERNAL_DNS_NAME_OR_IP=host.docker.internal +ESHOP_STORAGE_CATALOG_URL=http://host.docker.internal:5202/c/api/v1/catalog/items/[0]/pic/ +ESHOP_STORAGE_MARKETING_URL=http://host.docker.internal:5110/api/v1/campaigns/[0]/pic/ # Use this values to run the app locally in Mac # ESHOP_EXTERNAL_DNS_NAME_OR_IP=docker.for.mac.localhost diff --git a/src/ApiGateways/Envoy/config/webmarketing/envoy.yaml b/src/ApiGateways/Envoy/config/webmarketing/envoy.yaml index c6f3421de..11ef504da 100644 --- a/src/ApiGateways/Envoy/config/webmarketing/envoy.yaml +++ b/src/ApiGateways/Envoy/config/webmarketing/envoy.yaml @@ -36,6 +36,19 @@ static_resources: route: auto_host_rewrite: true cluster: marketing + - name: "l-short" + match: + prefix: "/l/" + route: + auto_host_rewrite: true + prefix_rewrite: "/locations-api/" + cluster: locations + - name: "l-long" + match: + prefix: "/locations-api/" + route: + auto_host_rewrite: true + cluster: locations http_filters: - name: envoy.router access_log: diff --git a/src/ApiGateways/Envoy/config/webshopping/envoy.yaml b/src/ApiGateways/Envoy/config/webshopping/envoy.yaml index 1ae8c45a1..688fb740c 100644 --- a/src/ApiGateways/Envoy/config/webshopping/envoy.yaml +++ b/src/ApiGateways/Envoy/config/webshopping/envoy.yaml @@ -56,6 +56,9 @@ static_resources: auto_host_rewrite: true cluster: signalr-hub timeout: 300s + upgrade_configs: + upgrade_type: "websocket" + enabled: true - name: "b-short" match: prefix: "/b/" diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs index 5623549d5..6ee3032a8 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs @@ -21,12 +21,12 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ public class EventBusRabbitMQ : IEventBus, IDisposable { const string BROKER_NAME = "eshop_event_bus"; + const string AUTOFAC_SCOPE_NAME = "eshop_event_bus"; private readonly IRabbitMQPersistentConnection _persistentConnection; private readonly ILogger _logger; private readonly IEventBusSubscriptionsManager _subsManager; private readonly ILifetimeScope _autofac; - private readonly string AUTOFAC_SCOPE_NAME = "eshop_event_bus"; private readonly int _retryCount; private IModel _consumerChannel; @@ -86,7 +86,6 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ using (var channel = _persistentConnection.CreateModel()) { - _logger.LogTrace("Declaring RabbitMQ exchange to publish event: {EventId}", @event.Id); channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); diff --git a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs index 800b99a38..22c5e1fba 100644 --- a/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs +++ b/src/BuildingBlocks/EventBus/IntegrationEventLogEF/Services/IntegrationEventLogService.cs @@ -15,11 +15,12 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services { - public class IntegrationEventLogService : IIntegrationEventLogService + public class IntegrationEventLogService : IIntegrationEventLogService,IDisposable { private readonly IntegrationEventLogContext _integrationEventLogContext; private readonly DbConnection _dbConnection; private readonly List _eventTypes; + private volatile bool disposedValue; public IntegrationEventLogService(DbConnection dbConnection) { @@ -89,5 +90,25 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Servi return _integrationEventLogContext.SaveChangesAsync(); } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + _integrationEventLogContext?.Dispose(); + } + + + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } diff --git a/src/Services/Catalog/Catalog.API/Controllers/PicController.cs b/src/Services/Catalog/Catalog.API/Controllers/PicController.cs index 0aa376832..31c93683c 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/PicController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/PicController.cs @@ -46,7 +46,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers string imageFileExtension = Path.GetExtension(item.PictureFileName); string mimetype = GetImageMimeTypeFromImageFileExtension(imageFileExtension); - var buffer = System.IO.File.ReadAllBytes(path); + var buffer = await System.IO.File.ReadAllBytesAsync(path); return File(buffer, mimetype); } diff --git a/src/Services/Catalog/Catalog.API/Grpc/CatalogService.cs b/src/Services/Catalog/Catalog.API/Grpc/CatalogService.cs index 13c7c8d2e..ef22b5be2 100644 --- a/src/Services/Catalog/Catalog.API/Grpc/CatalogService.cs +++ b/src/Services/Catalog/Catalog.API/Grpc/CatalogService.cs @@ -68,11 +68,10 @@ namespace Catalog.API.Grpc { var items = await GetItemsByIdsAsync(request.Ids); - if (!items.Any()) - { - context.Status = new Status(StatusCode.NotFound, $"ids value invalid. Must be comma-separated list of numbers"); - } - context.Status = new Status(StatusCode.OK, string.Empty); + context.Status = !items.Any() ? + new Status(StatusCode.NotFound, $"ids value invalid. Must be comma-separated list of numbers") : + new Status(StatusCode.OK, string.Empty); + return this.MapToResponse(items); } @@ -104,7 +103,7 @@ namespace Catalog.API.Grpc private PaginatedItemsResponse MapToResponse(List items) { - return this.MapToResponse(items, items.Count(), 1, items.Count()); + return this.MapToResponse(items, items.Count, 1, items.Count); } private PaginatedItemsResponse MapToResponse(List items, long count, int pageIndex, int pageSize) diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs index bb3a23d40..3e7ba9868 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs @@ -14,13 +14,14 @@ using System.Threading.Tasks; namespace Catalog.API.IntegrationEvents { - public class CatalogIntegrationEventService : ICatalogIntegrationEventService + public class CatalogIntegrationEventService : ICatalogIntegrationEventService,IDisposable { private readonly Func _integrationEventLogServiceFactory; private readonly IEventBus _eventBus; private readonly CatalogContext _catalogContext; private readonly IIntegrationEventLogService _eventLogService; private readonly ILogger _logger; + private volatile bool disposedValue; public CatalogIntegrationEventService( ILogger logger, @@ -65,5 +66,24 @@ namespace Catalog.API.IntegrationEvents await _eventLogService.SaveEventAsync(evt, _catalogContext.Database.CurrentTransaction); }); } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + (_eventLogService as IDisposable)?.Dispose(); + } + + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } diff --git a/src/Services/Location/Locations.API/appsettings.json b/src/Services/Location/Locations.API/appsettings.json index 7fbe98b3e..3ee24b242 100644 --- a/src/Services/Location/Locations.API/appsettings.json +++ b/src/Services/Location/Locations.API/appsettings.json @@ -23,7 +23,7 @@ "UseVault": false, "Vault": { "Name": "eshop", - "ClientId": "your-clien-id", + "ClientId": "your-client-id", "ClientSecret": "your-client-secret" } -} \ No newline at end of file +} diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Address.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Address.cs index b552f5546..e2c78094d 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Address.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Address.cs @@ -23,7 +23,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O ZipCode = zipcode; } - protected override IEnumerable GetAtomicValues() + protected override IEnumerable GetEqualityComponents() { // Using a yield return statement to return each element one at a time yield return Street; diff --git a/src/Services/Ordering/Ordering.Domain/SeedWork/ValueObject.cs b/src/Services/Ordering/Ordering.Domain/SeedWork/ValueObject.cs index 40fb117e1..5f36900ee 100644 --- a/src/Services/Ordering/Ordering.Domain/SeedWork/ValueObject.cs +++ b/src/Services/Ordering/Ordering.Domain/SeedWork/ValueObject.cs @@ -19,7 +19,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork return !(EqualOperator(left, right)); } - protected abstract IEnumerable GetAtomicValues(); + protected abstract IEnumerable GetEqualityComponents(); public override bool Equals(object obj) { @@ -27,26 +27,15 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork { return false; } - ValueObject other = (ValueObject)obj; - IEnumerator thisValues = GetAtomicValues().GetEnumerator(); - IEnumerator otherValues = other.GetAtomicValues().GetEnumerator(); - while (thisValues.MoveNext() && otherValues.MoveNext()) - { - if (ReferenceEquals(thisValues.Current, null) ^ ReferenceEquals(otherValues.Current, null)) - { - return false; - } - if (thisValues.Current != null && !thisValues.Current.Equals(otherValues.Current)) - { - return false; - } - } - return !thisValues.MoveNext() && !otherValues.MoveNext(); + + var other = (ValueObject)obj; + + return this.GetEqualityComponents().SequenceEqual(other.GetEqualityComponents()); } public override int GetHashCode() { - return GetAtomicValues() + return GetEqualityComponents() .Select(x => x != null ? x.GetHashCode() : 0) .Aggregate((x, y) => x ^ y); } diff --git a/src/Services/Ordering/Ordering.SignalrHub/Startup.cs b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs index a20a1a196..23aaa7c78 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/Startup.cs +++ b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs @@ -19,6 +19,7 @@ using Ordering.SignalrHub.IntegrationEvents.EventHandling; using Ordering.SignalrHub.IntegrationEvents.Events; using RabbitMQ.Client; using System; +using System.Threading.Tasks; using System.IdentityModel.Tokens.Jwt; namespace Ordering.SignalrHub @@ -109,7 +110,7 @@ namespace Ordering.SignalrHub RegisterEventBus(services); services.AddOptions(); - + //configure autofac var container = new ContainerBuilder(); container.RegisterModule(new ApplicationModule()); @@ -133,7 +134,7 @@ namespace Ordering.SignalrHub loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase); app.UsePathBase(pathBase); } - + app.UseRouting(); app.UseCors("CorsPolicy"); app.UseAuthentication(); @@ -150,7 +151,7 @@ namespace Ordering.SignalrHub { Predicate = r => r.Name.Contains("self") }); - endpoints.MapHub("/hub/notificationhub", options => options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransports.All); + endpoints.MapHub("/hub/notificationhub"); }); ConfigureEventBus(app); @@ -185,6 +186,20 @@ namespace Ordering.SignalrHub options.Authority = identityUrl; options.RequireHttpsMetadata = false; options.Audience = "orders.signalrhub"; + options.Events = new JwtBearerEvents + { + OnMessageReceived = context => + { + var accessToken = context.Request.Query["access_token"]; + + var path = context.HttpContext.Request.Path; + if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/hub/notificationhub"))) + { + context.Token = accessToken; + } + return Task.CompletedTask; + } + }; }); } diff --git a/src/Services/Ordering/Ordering.UnitTests/Domain/SeedWork/ValueObjectTests.cs b/src/Services/Ordering/Ordering.UnitTests/Domain/SeedWork/ValueObjectTests.cs new file mode 100644 index 000000000..7eed01fe6 --- /dev/null +++ b/src/Services/Ordering/Ordering.UnitTests/Domain/SeedWork/ValueObjectTests.cs @@ -0,0 +1,190 @@ +using Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Xunit; + +namespace Ordering.UnitTests.Domain.SeedWork +{ + public class ValueObjectTests + { + public ValueObjectTests() + { } + + [Theory] + [MemberData(nameof(EqualValueObjects))] + public void Equals_EqualValueObjects_ReturnsTrue(ValueObject instanceA, ValueObject instanceB, string reason) + { + // Act + var result = EqualityComparer.Default.Equals(instanceA, instanceB); + + // Assert + Assert.True(result, reason); + } + + [Theory] + [MemberData(nameof(NonEqualValueObjects))] + public void Equals_NonEqualValueObjects_ReturnsFalse(ValueObject instanceA, ValueObject instanceB, string reason) + { + // Act + var result = EqualityComparer.Default.Equals(instanceA, instanceB); + + // Assert + Assert.False(result, reason); + } + + private static readonly ValueObject APrettyValueObject = new ValueObjectA(1, "2", Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), new ComplexObject(2, "3")); + + public static readonly TheoryData EqualValueObjects = new TheoryData + { + { + null, + null, + "they should be equal because they are both null" + }, + { + APrettyValueObject, + APrettyValueObject, + "they should be equal because they are the same object" + }, + { + new ValueObjectA(1, "2", Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), new ComplexObject(2, "3")), + new ValueObjectA(1, "2", Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), new ComplexObject(2, "3")), + "they should be equal because they have equal members" + }, + { + new ValueObjectA(1, "2", Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), new ComplexObject(2, "3"), notAnEqualityComponent: "xpto"), + new ValueObjectA(1, "2", Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), new ComplexObject(2, "3"), notAnEqualityComponent: "xpto2"), + "they should be equal because all equality components are equal, even though an additional member was set" + }, + { + new ValueObjectB(1, "2", 1, 2, 3 ), + new ValueObjectB(1, "2", 1, 2, 3 ), + "they should be equal because all equality components are equal, including the 'C' list" + } + }; + + public static readonly TheoryData NonEqualValueObjects = new TheoryData + { + { + new ValueObjectA(a: 1, b: "2", c: Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), d: new ComplexObject(2, "3")), + new ValueObjectA(a: 2, b: "2", c: Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), d: new ComplexObject(2, "3")), + "they should not be equal because the 'A' member on ValueObjectA is different among them" + }, + { + new ValueObjectA(a: 1, b: "2", c: Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), d: new ComplexObject(2, "3")), + new ValueObjectA(a: 1, b: null, c: Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), d: new ComplexObject(2, "3")), + "they should not be equal because the 'B' member on ValueObjectA is different among them" + }, + { + new ValueObjectA(a: 1, b: "2", c: Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), d: new ComplexObject(a: 2, b: "3")), + new ValueObjectA(a: 1, b: "2", c: Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), d: new ComplexObject(a: 3, b: "3")), + "they should not be equal because the 'A' member on ValueObjectA's 'D' member is different among them" + }, + { + new ValueObjectA(a: 1, b: "2", c: Guid.Parse("97ea43f0-6fef-4fb7-8c67-9114a7ff6ec0"), d: new ComplexObject(a: 2, b: "3")), + new ValueObjectB(a: 1, b: "2"), + "they should not be equal because they are not of the same type" + }, + { + new ValueObjectB(1, "2", 1, 2, 3 ), + new ValueObjectB(1, "2", 1, 2, 3, 4 ), + "they should be not be equal because the 'C' list contains one additional value" + }, + { + new ValueObjectB(1, "2", 1, 2, 3, 5 ), + new ValueObjectB(1, "2", 1, 2, 3 ), + "they should be not be equal because the 'C' list contains one additional value" + }, + { + new ValueObjectB(1, "2", 1, 2, 3, 5 ), + new ValueObjectB(1, "2", 1, 2, 3, 4 ), + "they should be not be equal because the 'C' lists are not equal" + } + + }; + + private class ValueObjectA : ValueObject + { + public ValueObjectA(int a, string b, Guid c, ComplexObject d, string notAnEqualityComponent = null) + { + A = a; + B = b; + C = c; + D = d; + NotAnEqualityComponent = notAnEqualityComponent; + } + + public int A { get; } + public string B { get; } + public Guid C { get; } + public ComplexObject D { get; } + public string NotAnEqualityComponent { get; } + + protected override IEnumerable GetEqualityComponents() + { + yield return A; + yield return B; + yield return C; + yield return D; + } + } + + private class ValueObjectB : ValueObject + { + public ValueObjectB(int a, string b, params int[] c) + { + A = a; + B = b; + C = c.ToList(); + } + + public int A { get; } + public string B { get; } + + public List C { get; } + + protected override IEnumerable GetEqualityComponents() + { + yield return A; + yield return B; + + foreach (var c in C) + { + yield return c; + } + } + } + + private class ComplexObject : IEquatable + { + public ComplexObject(int a, string b) + { + A = a; + B = b; + } + + public int A { get; set; } + + public string B { get; set; } + + public override bool Equals(object obj) + { + return Equals(obj as ComplexObject); + } + + public bool Equals(ComplexObject other) + { + return other != null && + A == other.A && + B == other.B; + } + + public override int GetHashCode() + { + return HashCode.Combine(A, B); + } + } + } +} diff --git a/src/Tests/Services/Application.FunctionalTests/Services/Basket/BasketTestsStartup.cs b/src/Tests/Services/Application.FunctionalTests/Services/Basket/BasketTestsStartup.cs index cfb91fd40..6043a7ab3 100644 --- a/src/Tests/Services/Application.FunctionalTests/Services/Basket/BasketTestsStartup.cs +++ b/src/Tests/Services/Application.FunctionalTests/Services/Basket/BasketTestsStartup.cs @@ -16,6 +16,7 @@ namespace FunctionalTests.Services.Basket if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) { app.UseMiddleware(); + app.UseAuthorization(); } else { diff --git a/src/Tests/Services/Application.FunctionalTests/Services/Location/LocationsTestsStartup.cs b/src/Tests/Services/Application.FunctionalTests/Services/Location/LocationsTestsStartup.cs index fce808759..709c4e7eb 100644 --- a/src/Tests/Services/Application.FunctionalTests/Services/Location/LocationsTestsStartup.cs +++ b/src/Tests/Services/Application.FunctionalTests/Services/Location/LocationsTestsStartup.cs @@ -19,6 +19,7 @@ if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) { app.UseMiddleware(); + app.UseAuthorization(); } else { diff --git a/src/Tests/Services/Application.FunctionalTests/Services/Marketing/MarketingTestsStartup.cs b/src/Tests/Services/Application.FunctionalTests/Services/Marketing/MarketingTestsStartup.cs index ae5f4453b..d5d824867 100644 --- a/src/Tests/Services/Application.FunctionalTests/Services/Marketing/MarketingTestsStartup.cs +++ b/src/Tests/Services/Application.FunctionalTests/Services/Marketing/MarketingTestsStartup.cs @@ -16,6 +16,7 @@ if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) { app.UseMiddleware(); + app.UseAuthorization(); } else { diff --git a/src/Tests/Services/Application.FunctionalTests/Services/Marketing/appsettings.json b/src/Tests/Services/Application.FunctionalTests/Services/Marketing/appsettings.json index 2aa46abe6..6d2d7870d 100644 --- a/src/Tests/Services/Application.FunctionalTests/Services/Marketing/appsettings.json +++ b/src/Tests/Services/Application.FunctionalTests/Services/Marketing/appsettings.json @@ -1,12 +1,11 @@ { + "AzureServiceBusEnabled": false, "ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word", - "MongoConnectionString": "mongodb://localhost:27017", - "MongoDatabase": "MarketingDb", + "EventBusConnection": "localhost", "IdentityUrl": "http://localhost:5105", "isTest": "true", - "EventBusConnection": "localhost", - "AzureServiceBusEnabled": false, - "SubscriptionClientName": "Marketing", + "MongoConnectionString": "mongodb://localhost:27017", + "MongoDatabase": "MarketingDb", "PicBaseUrl": "http://localhost:5110/api/v1/campaigns/[0]/pic/", "SubscriptionClientName": "Marketing" } diff --git a/src/Web/WebMVC/Controllers/AccountController.cs b/src/Web/WebMVC/Controllers/AccountController.cs index 8b82498ba..fba04f26d 100644 --- a/src/Web/WebMVC/Controllers/AccountController.cs +++ b/src/Web/WebMVC/Controllers/AccountController.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { - [Authorize(AuthenticationSchemes = "OpenIdConnect")] + [Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] public class AccountController : Controller { private readonly ILogger _logger; @@ -20,7 +20,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - [Authorize(AuthenticationSchemes = "OpenIdConnect")] public async Task SignIn(string returnUrl) + [Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] + public async Task SignIn(string returnUrl) { var user = User as ClaimsPrincipal; var token = await HttpContext.GetTokenAsync("access_token"); diff --git a/src/Web/WebMVC/Controllers/CampaignsController.cs b/src/Web/WebMVC/Controllers/CampaignsController.cs index cf210318b..920269467 100644 --- a/src/Web/WebMVC/Controllers/CampaignsController.cs +++ b/src/Web/WebMVC/Controllers/CampaignsController.cs @@ -11,8 +11,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers using System.Threading.Tasks; using ViewModels; using ViewModels.Pagination; + using Microsoft.AspNetCore.Authentication.OpenIdConnect; - [Authorize(AuthenticationSchemes = "OpenIdConnect")] + [Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] public class CampaignsController : Controller { private readonly ICampaignService _campaignService; diff --git a/src/Web/WebMVC/Controllers/CartController.cs b/src/Web/WebMVC/Controllers/CartController.cs index 78cec5670..d7e577c25 100644 --- a/src/Web/WebMVC/Controllers/CartController.cs +++ b/src/Web/WebMVC/Controllers/CartController.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.WebMVC.Services; @@ -8,7 +9,7 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { - [Authorize(AuthenticationSchemes = "OpenIdConnect")] + [Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] public class CartController : Controller { private readonly IBasketService _basketSvc; diff --git a/src/Web/WebMVC/Controllers/OrderController.cs b/src/Web/WebMVC/Controllers/OrderController.cs index f308d0bdc..d5e98552a 100644 --- a/src/Web/WebMVC/Controllers/OrderController.cs +++ b/src/Web/WebMVC/Controllers/OrderController.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.WebMVC.Services; @@ -7,7 +8,7 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { - [Authorize(AuthenticationSchemes = "OpenIdConnect")] + [Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] public class OrderController : Controller { private IOrderingService _orderSvc; diff --git a/src/Web/WebMVC/Controllers/OrderManagementController.cs b/src/Web/WebMVC/Controllers/OrderManagementController.cs index a488dc4ae..6963c469d 100644 --- a/src/Web/WebMVC/Controllers/OrderManagementController.cs +++ b/src/Web/WebMVC/Controllers/OrderManagementController.cs @@ -7,10 +7,11 @@ using WebMVC.Services.ModelDTOs; using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; namespace WebMVC.Controllers { - [Authorize(AuthenticationSchemes = "OpenIdConnect")] + [Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] public class OrderManagementController : Controller { private IOrderingService _orderSvc; diff --git a/src/Web/WebMVC/Services/LocationService.cs b/src/Web/WebMVC/Services/LocationService.cs index 8d81cbd22..4619cfd6a 100644 --- a/src/Web/WebMVC/Services/LocationService.cs +++ b/src/Web/WebMVC/Services/LocationService.cs @@ -23,7 +23,7 @@ namespace WebMVC.Services _settings = settings; _logger = logger; - _remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/l/locations/"; + _remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/l/api/v1/locations/"; } public async Task CreateOrUpdateUserLocation(LocationDTO location) diff --git a/src/Web/WebMVC/libman.json b/src/Web/WebMVC/libman.json index f7b9d3763..b80fb4ecc 100644 --- a/src/Web/WebMVC/libman.json +++ b/src/Web/WebMVC/libman.json @@ -37,7 +37,7 @@ }, { "provider": "unpkg", - "library": "@microsoft/signalr@3.0.1", + "library": "@microsoft/signalr@latest", "destination": "wwwroot/lib/@microsoft/signalr/", "files": [ "dist/browser/signalr.js", diff --git a/src/Web/WebSPA/package-lock.json b/src/Web/WebSPA/package-lock.json index c3e6ed779..09a5d0707 100644 --- a/src/Web/WebSPA/package-lock.json +++ b/src/Web/WebSPA/package-lock.json @@ -1236,10 +1236,9 @@ "dev": true }, "node-forge": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", - "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", - "dev": true + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" }, "node-libs-browser": { "version": "2.2.1", @@ -1863,8 +1862,8 @@ } }, "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", "dev": true, "requires": { @@ -2943,9 +2942,9 @@ } }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -8541,13 +8540,20 @@ "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==" }, "http-proxy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "requires": { - "eventemitter3": "^3.0.0", + "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" + }, + "dependencies": { + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + } } }, "http-proxy-agent": { @@ -10381,8 +10387,8 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { "encoding": "^0.1.11", @@ -10401,9 +10407,9 @@ } }, "node-forge": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", - "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" }, "node-libs-browser": { "version": "2.2.1", @@ -17255,9 +17261,9 @@ } }, "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "requires": { "camelcase": "^4.1.0" }