diff --git a/client/packages/portal-core/src/framework-configurator/app-configurator.ts b/client/packages/portal-core/src/framework-configurator/app-configurator.ts index 7a6b12b13..e75e58c24 100644 --- a/client/packages/portal-core/src/framework-configurator/app-configurator.ts +++ b/client/packages/portal-core/src/framework-configurator/app-configurator.ts @@ -5,10 +5,10 @@ import { Client } from '@portal/types'; const manifestMapper = (basePath: string) => - + (value: any): AppManifest => { const { appKey, appInformation, isLegacy } = value; - return { ...appInformation, entry: `${basePath}/api/bundles/${appKey}`, isLegacy }; + return { ...appInformation, entry: `${basePath}/bundles/apps/${appKey}`, isLegacy }; }; const manifestMappers = @@ -28,7 +28,7 @@ export const appConfigurator = builder.setAppClient({ getAppManifest: (query) => { return portalClient.json$(`/api/onboarded-apps/${query.appKey}`, { - selector: async (res) => manifestMapper(client.baseUri)(await res.json()), + selector: async (res) => manifestMapper("")(await res.json()), }); }, getAppManifests: () => diff --git a/clientBackend/src/Equinor.ProjectExecutionPortal.ClientBackend/AssetProxy/FusionAppRequestTransformer.cs b/clientBackend/src/Equinor.ProjectExecutionPortal.ClientBackend/AssetProxy/FusionAppRequestTransformer.cs new file mode 100644 index 000000000..8780fbb58 --- /dev/null +++ b/clientBackend/src/Equinor.ProjectExecutionPortal.ClientBackend/AssetProxy/FusionAppRequestTransformer.cs @@ -0,0 +1,60 @@ +using Equinor.ProjectExecutionPortal.ClientBackend.Configurations; +using Fusion; +using Microsoft.Extensions.Options; +using Microsoft.Identity.Web; +using Yarp.ReverseProxy.Forwarder; +using Yarp.ReverseProxy.Transforms; + +namespace Equinor.ProjectExecutionPortal.ClientBackend.AssetProxy +{ + public class FusionAppRequestTransformer : HttpTransformer + { + private readonly ITokenAcquisition _tokenAcquisition; + private readonly FusionProjectPortalApiOptions _options; + + public FusionAppRequestTransformer(ITokenAcquisition tokenAcquisition, IOptions options) + { + _tokenAcquisition = tokenAcquisition; + _options = options.Value; + } + + public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix) + { + var appKey = httpContext.Request.RouteValues["appKey"]; + + // THIS IS FOR POC ONLY! + // We change the scope to use application permissions + var index = _options.Scope.LastIndexOf("/"); + var input = _options.Scope; + if (index >= 0) + { + input = input.Substring(0, index); + } + input = $"{input}/.default"; + + //var token = await tokenProvider.GetAccessTokenForUserAsync(new[] { options.TokenScope! }, user: httpContext.User); + var token = await _tokenAcquisition.GetAccessTokenForAppAsync(input); + + // Copy all request headers + await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix); + + // Customize the query string: + var queryContext = new QueryTransformContext(httpContext.Request); + + // Assign the custom uri. Be careful about extra slashes when concatenating here. RequestUtilities.MakeDestinationAddress is a safe default. + proxyRequest.RequestUri = RequestUtilities.MakeDestinationAddress(_options.BaseAddress!, $"/api/bundles/{appKey}.js", queryContext.QueryString); + + proxyRequest.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + proxyRequest.Headers.Add("X-Fusion-App-Bundle-UniqueId", $"{httpContext.User.GetAzureUniqueId()}"); + + // Suppress the original request header, use the one from the destination Uri. + proxyRequest.Headers.Host = null; + } + + public override ValueTask TransformResponseAsync(HttpContext httpContext, HttpResponseMessage? proxyResponse) + { + // Could remove duplicate headers here + return base.TransformResponseAsync(httpContext, proxyResponse); + } + } +} diff --git a/clientBackend/src/Equinor.ProjectExecutionPortal.ClientBackend/Modules/AssetProxyConfiguration.cs b/clientBackend/src/Equinor.ProjectExecutionPortal.ClientBackend/Modules/AssetProxyConfiguration.cs index 8efa162cb..5f1c487f3 100644 --- a/clientBackend/src/Equinor.ProjectExecutionPortal.ClientBackend/Modules/AssetProxyConfiguration.cs +++ b/clientBackend/src/Equinor.ProjectExecutionPortal.ClientBackend/Modules/AssetProxyConfiguration.cs @@ -14,6 +14,8 @@ public static IServiceCollection AddFusionPortalAssetProxy(this IServiceCollecti services.AddScoped(); services.AddScoped(); + services.AddScoped(); + return services; } @@ -23,6 +25,8 @@ public static IEndpointRouteBuilder MapFusionPortalAssetProxy(this IEndpointRout endpoints.MapGet("/assets/images/profiles/{uniqueId}", AssetProxyHandler.ProxyRequestAsync); endpoints.MapGet("/images/profiles/{uniqueId}", AssetProxyHandler.ProxyRequestAsync); + endpoints.MapGet("/bundles/apps/{appKey}", AssetProxyHandler.ProxyRequestAsync); + return endpoints; } }