Skip to content

Commit

Permalink
VCST-1985: Use only token authentication for graphql (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
artem-dudarev authored Dec 30, 2024
1 parent d35d32d commit 82be438
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Extensions.Options;
using VirtoCommerce.Xapi.Core.Infrastructure;
using VirtoCommerce.Xapi.Core.Models;
using static VirtoCommerce.Xapi.Core.ModuleConstants;

namespace VirtoCommerce.Xapi.Core.Extensions;

Expand All @@ -20,11 +21,9 @@ public static IApplicationBuilder UseScopedSchema<TMarker>(this IApplicationBuil
public static IApplicationBuilder UseSchemaGraphQL<TSchema>(this IApplicationBuilder builder, bool schemaIntrospectionEnabled = true, string schemaPath = null)
where TSchema : ISchema
{
var graphQlPath = "/graphql";
if (!string.IsNullOrEmpty(schemaPath))
{
graphQlPath = $"{graphQlPath}/{schemaPath}";
}
var graphQlPath = string.IsNullOrEmpty(schemaPath)
? GraphQlPath
: $"{GraphQlPath}/{schemaPath}";

builder.UseGraphQL<TSchema>(path: graphQlPath);
if (schemaIntrospectionEnabled)
Expand Down
8 changes: 8 additions & 0 deletions src/VirtoCommerce.Xapi.Core/Models/GraphQLOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Collections.Generic;

namespace VirtoCommerce.Xapi.Core.Models;

public class GraphQLOptions
{
public IList<string> ForbiddenAuthenticationTypes { get; set; } = [];
}
3 changes: 3 additions & 0 deletions src/VirtoCommerce.Xapi.Core/ModuleConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ namespace VirtoCommerce.Xapi.Core
{
public static class ModuleConstants
{
public static string GraphQlPath => "/graphql";

public static class ConfigKeys
{
public const string GraphQl = "VirtoCommerce:GraphQL";
public const string GraphQlPlayground = "VirtoCommerce:GraphQLPlayground";
public const string GraphQlWebSocket = "VirtoCommerce:GraphQLWebSocket";
public const string Stores = "VirtoCommerce:Stores";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Builder;
using VirtoCommerce.Xapi.Core;
using VirtoCommerce.Xapi.Data.Security;

namespace VirtoCommerce.Xapi.Data.Extensions;
public static class ApplicationBuilderExtensions
{
public static IApplicationBuilder UseAuthenticationFilter(this IApplicationBuilder applicationBuilder)
{
return applicationBuilder.UseWhen(httpContext => httpContext.Request.Path.StartsWithSegments(ModuleConstants.GraphQlPath), builder =>
{
builder.UseMiddleware<AuthenticationFilterMiddleware>();
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
using VirtoCommerce.Xapi.Core;
using VirtoCommerce.Xapi.Core.Extensions;
using VirtoCommerce.Xapi.Core.Infrastructure;
using VirtoCommerce.Xapi.Core.Models;
using VirtoCommerce.Xapi.Core.Services;
using VirtoCommerce.Xapi.Data.Security;
using VirtoCommerce.Xapi.Data.Security.Authorization;
using VirtoCommerce.Xapi.Data.Services;
using static VirtoCommerce.Xapi.Core.ModuleConstants;
using ContactSignInValidator = VirtoCommerce.Xapi.Data.Security.OpenIddict.ContactSignInValidator;
using DynamicPropertyResolverService = VirtoCommerce.Xapi.Data.Services.DynamicPropertyResolverService;
using DynamicPropertyUpdaterService = VirtoCommerce.Xapi.Data.Services.DynamicPropertyUpdaterService;
Expand All @@ -23,6 +26,14 @@ namespace VirtoCommerce.Xapi.Data.Extensions
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddAuthenticationFilter(this IServiceCollection serviceCollection, IConfiguration configuration)
{
serviceCollection.AddOptions<GraphQLOptions>().Bind(configuration.GetSection(ConfigKeys.GraphQl)).ValidateDataAnnotations();
serviceCollection.AddScoped<AuthenticationFilterMiddleware>();

return serviceCollection;
}

public static IServiceCollection AddDistributedLockService(this IServiceCollection services, IConfiguration configuration)
{
var redisConnectionString = configuration.GetConnectionString("RedisConnectionString");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using VirtoCommerce.Xapi.Core.Models;

namespace VirtoCommerce.Xapi.Data.Security;

public class AuthenticationFilterMiddleware : IMiddleware
{
private readonly GraphQLOptions _options;
private readonly ILogger<AuthenticationFilterMiddleware> _logger;

public AuthenticationFilterMiddleware(IOptions<GraphQLOptions> optionsAccessor, ILogger<AuthenticationFilterMiddleware> logger)
{
_logger = logger;
_options = optionsAccessor.Value;
}

public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
_logger.LogDebug("{Method} {Path} {AuthenticationType}",
context.Request.Method, context.Request.Path, string.Join(", ", context.User.Identities.Select(x => x.AuthenticationType + " " + x.Name)));

// Remove identities with forbidden authenticated types
var identities = context.User.Identities
.Where(x => !_options.ForbiddenAuthenticationTypes.Contains(x.AuthenticationType))
.ToList();

if (identities.Count == 0)
{
identities.Add(new ClaimsIdentity());
}

context.User = new ClaimsPrincipal(identities);

return next.Invoke(context);
}
}
4 changes: 4 additions & 0 deletions src/VirtoCommerce.Xapi.Web/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,16 @@ public void Initialize(IServiceCollection serviceCollection)
serviceCollection.Configure<GraphQLPlaygroundOptions>(Configuration.GetSection(ConfigKeys.GraphQlPlayground));
serviceCollection.Configure<GraphQLWebSocketOptions>(Configuration.GetSection(ConfigKeys.GraphQlWebSocket));
serviceCollection.Configure<StoresOptions>(Configuration.GetSection(ConfigKeys.Stores));

serviceCollection.AddAuthenticationFilter(Configuration);
}

public void PostInitialize(IApplicationBuilder appBuilder)
{
var serviceProvider = appBuilder.ApplicationServices;

appBuilder.UseAuthenticationFilter();

// this is required for websockets support
appBuilder.UseWebSockets();

Expand Down

0 comments on commit 82be438

Please sign in to comment.