Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Project Portal appbundle proxy #757

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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: () =>
Expand Down
Original file line number Diff line number Diff line change
@@ -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<FusionProjectPortalApiOptions> 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<bool> TransformResponseAsync(HttpContext httpContext, HttpResponseMessage? proxyResponse)
{
// Could remove duplicate headers here
return base.TransformResponseAsync(httpContext, proxyResponse);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public static IServiceCollection AddFusionPortalAssetProxy(this IServiceCollecti
services.AddScoped<LegacyAppResourcesRequestTransformer>();
services.AddScoped<ProfileImageRequestTransformer>();

services.AddScoped<FusionAppRequestTransformer>();

return services;
}

Expand All @@ -23,6 +25,8 @@ public static IEndpointRouteBuilder MapFusionPortalAssetProxy(this IEndpointRout
endpoints.MapGet("/assets/images/profiles/{uniqueId}", AssetProxyHandler.ProxyRequestAsync<ProfileImageRequestTransformer>);
endpoints.MapGet("/images/profiles/{uniqueId}", AssetProxyHandler.ProxyRequestAsync<ProfileImageRequestTransformer>);

endpoints.MapGet("/bundles/apps/{appKey}", AssetProxyHandler.ProxyRequestAsync<FusionAppRequestTransformer>);

return endpoints;
}
}
Expand Down
Loading