// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Hosting;
///
/// A that extracts the session isolation key from a claim
/// in the current user's identity, as provided by ASP.NET Core's .
///
///
///
/// This provider is suitable for ASP.NET Core web applications where session isolation is based on
/// authenticated user identity. It reads a specified claim type (e.g., name, email, or a custom identifier)
/// from the ambient .
///
///
/// If the is unavailable, the user is not authenticated, or the specified claim
/// is missing, the provider returns . The consuming
/// will then enforce strict or pass-through behavior based on its configuration.
///
///
/// This class relies on , which uses
/// to provide access to the current .
///
///
public class ClaimsIdentitySessionIsolationKeyProvider : SessionIsolationKeyProvider
{
private readonly IHttpContextAccessor? _httpContextAccessor;
private readonly string _claimType;
///
/// Initializes a new instance of the class.
///
///
/// The used to retrieve the current HTTP context and user claims.
///
/// The options for configuring the provider. If null, defaults are used.
///
/// is null, empty, or whitespace.
///
public ClaimsIdentitySessionIsolationKeyProvider(
IHttpContextAccessor? httpContextAccessor,
ClaimsIdentitySessionIsolationKeyProviderOptions? options = null)
{
options ??= new ClaimsIdentitySessionIsolationKeyProviderOptions();
this._httpContextAccessor = httpContextAccessor;
this._claimType = Throw.IfNullOrWhitespace(options.ClaimType);
}
///
/// Extracts the session isolation key from the current user's claims.
///
/// The to monitor for cancellation requests.
///
/// A task that represents the asynchronous operation. The task result contains the value of the
/// configured claim type from the current user's identity, or if the claim
/// is not present or the HTTP context is unavailable.
///
///
/// This method retrieves the claim value from HttpContext.User.Claims. If multiple claims
/// of the specified type exist, the first match is returned.
///
public override ValueTask GetSessionIsolationKeyAsync(CancellationToken cancellationToken = default)
{
Claim? claim = this._httpContextAccessor?
.HttpContext?
.User?.Claims.FirstOrDefault(c => c.Type == this._claimType);
return new ValueTask(claim?.Value);
}
}