server icon indicating copy to clipboard operation
server copied to clipboard

Refactor IWebSocketAuthenticationService

Open Shane32 opened this issue 1 year ago • 6 comments

Suggest changing method AuthenticateAsync to have an AuthenticationRequest class that includes AuthenticationSchemes, as follows:

/// <summary>
/// Authenticates an incoming GraphQL over WebSockets request with the
/// connection initialization message.  A typical implementation will
/// set the <see cref="HttpContext.User"/> property after reading the
/// authorization token.  This service must be registered as a singleton
/// in the dependency injection framework.
/// </summary>
public interface IWebSocketAuthenticationService
{
    /// <summary>
    /// Authenticates an incoming GraphQL over WebSockets request with the connection initialization message.  The implementation should
    /// set the <paramref name="authenticationRequest"/>.<see cref="AuthenticationRequest.Connection">Connection</see>.<see cref="IWebSocketConnection.HttpContext">HttpContext</see>.<see cref="HttpContext.User">User</see>
    /// property after validating the provided credentials.
    /// <br/><br/>
    /// After calling this method to authenticate the request, the infrastructure will authorize the incoming request via the
    /// <see cref="GraphQLHttpMiddlewareOptions.AuthorizationRequired"/>, <see cref="GraphQLHttpMiddlewareOptions.AuthorizedRoles"/> and
    /// <see cref="GraphQLHttpMiddlewareOptions.AuthorizedPolicy"/> properties.
    /// </summary>
    Task AuthenticateAsync(AuthenticationRequest authenticationRequest);
}

/// <summary>
/// Represents an authentication request within the GraphQL ASP.NET Core WebSocket context.
/// </summary>
public class AuthenticationRequest
{
    /// <summary>
    /// Gets the WebSocket connection associated with the authentication request.
    /// </summary>
    /// <value>
    /// An instance of <see cref="IWebSocketConnection"/> representing the active WebSocket connection.
    /// </value>
    public IWebSocketConnection Connection { get; }

    /// <summary>
    /// Gets the subprotocol used for the WebSocket communication.
    /// </summary>
    /// <value>
    /// A <see cref="string"/> specifying the subprotocol negotiated for the WebSocket connection.
    /// </value>
    public string SubProtocol { get; }

    /// <summary>
    /// Gets the operation message containing details of the authentication operation.
    /// </summary>
    /// <value>
    /// An instance of <see cref="OperationMessage"/> that encapsulates the specifics of the authentication request.
    /// </value>
    public OperationMessage OperationMessage { get; }

    /// <summary>
    /// Gets a list of the authentication schemes the authentication requirements are evaluated against.
    /// When no schemes are specified, the default authentication scheme is used.
    /// </summary>
    public IEnumerable<string> AuthenticationSchemes { get; }

    /// <summary>
    /// Initializes a new instance of the <see cref="AuthenticationRequest"/> class.
    /// </summary>
    public AuthenticationRequest(IWebSocketConnection connection, string subProtocol, OperationMessage operationMessage, IEnumerable<string> authenticationSchemes)
    {
        Connection = connection;
        SubProtocol = subProtocol;
        OperationMessage = operationMessage;
        AuthenticationSchemes = authenticationSchemes;
    }
}

This allows for the authentication handler to attempt each scheme specified by the middleware options.

Shane32 avatar Nov 29 '24 08:11 Shane32