// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Agents.AI.Hosting;
///
/// Extension methods for configuring AI hosting services in an .
///
public static class ServiceCollectionExtensions
{
///
/// Registers a that uses claims from the current user's identity
/// to generate session isolation keys.
///
/// The to add services to.
/// Optional configuration for the claims-based session isolation key provider.
/// The so that additional calls can be chained.
///
///
/// This method requires to be registered in the service collection.
/// Ensure that services.AddHttpContextAccessor() has been called before using this method.
///
///
/// When is not supplied, the isolation key is derived from the
/// claim, a stable unique subject identifier. For OpenID
/// Connect tokens (including Microsoft Entra ID), this is typically mapped from the sub claim
/// by the default JWT inbound claim mapping. Authentication schemes that do not project a unique
/// identifier onto (or hosts that require a different claim
/// such as Entra's oid) should override
/// ; otherwise the key may be
/// absent, which causes strict-mode session stores to fail.
///
///
/// Security warning: If you override
/// , the chosen claim must
/// uniquely identify the principal within the served population. Display names, usernames, email
/// aliases, and other mutable or non-unique claims are unsafe isolation keys unless
/// the host can prove their uniqueness across all callers, because distinct principals that share the
/// same claim value would receive the same isolation key and could access one another's sessions.
///
///
public static IServiceCollection UseClaimsBasedSessionIsolation(
this IServiceCollection services,
ClaimsIdentitySessionIsolationKeyProviderOptions? options = null)
{
options ??= new();
ServiceDescriptor descriptor = new(typeof(SessionIsolationKeyProvider), CreateIsolationKeyProvider, ServiceLifetime.Singleton);
services.Add(descriptor);
return services;
object CreateIsolationKeyProvider(IServiceProvider serviceProvider)
{
IHttpContextAccessor contextAccessor = serviceProvider.GetRequiredService();
return new ClaimsIdentitySessionIsolationKeyProvider(contextAccessor, options);
}
}
}