Backend/e-suite.API/eSuite.API/SingleSignOn/CookieManager.cs
2026-01-20 21:50:10 +00:00

199 lines
7.2 KiB
C#

using e_suite.API.Common.exceptions;
using e_suite.API.Common.models;
using e_suite.Database.Audit;
using eSuite.API.Extensions;
using eSuite.API.Middleware;
using eSuite.Core.Miscellaneous;
using IUserManager = e_suite.API.Common.IUserManager;
// ReSharper disable All
namespace eSuite.API.SingleSignOn;
/// <summary>
/// Internal class used to manage cookies
/// </summary>
public class CookieManager : ICookieManager
{
private readonly IUserManager _userManager;
/// <summary>
/// Default constructor
/// </summary>
/// <param name="userManager"></param>
public CookieManager(IUserManager userManager)
{
_userManager = userManager;
}
private const string ssoNewUserLinkCookieName = "eSuiteNewUserLinkCookie";
private const string ssoProfileLinkCookieName = "eSuiteProfileLinkCookie";
private const string ssoIdCookieName = "eSuiteSsoProvider";
/// <summary>
/// Creates the session cookie with appropriate settings
/// </summary>
/// <param name="response"></param>
/// <param name="loginResponse"></param>
/// <returns></returns>
public Task CreateSessionCookie(HttpResponse response, LoginResponse loginResponse)
{
response.Cookies.Append(AuthenticationExtension.SessionCookieName, loginResponse.Token, new CookieOptions
{
HttpOnly = false, //Set False as Javascript (React) needs to read the cookie.
SameSite = SameSiteMode.Strict,
Secure = true,
IsEssential = true,
Expires = null, //Session Cookie
Path = "/"
});
return Task.CompletedTask;
}
/// <summary>
/// Deletes any existing session cookie
/// </summary>
/// <param name="response"></param>
/// <returns></returns>
public Task DeleteSessionCookie(HttpResponse response)
{
response.Cookies.Delete(AuthenticationExtension.SessionCookieName);
return Task.CompletedTask;
}
/// <summary>
/// Creates cookie used with an Sso Identity to a user account
/// </summary>
/// <param name="response"></param>
/// <param name="auditUserDetails"></param>
/// <param name="generalIdRef"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task CreateProfileLinkCookie(HttpResponse response, AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken)
{
var guid = await _userManager.CreateSingleUseGuid(auditUserDetails, generalIdRef, cancellationToken);
response.Cookies.Append(ssoProfileLinkCookieName, guid.ToString(), new CookieOptions
{
HttpOnly = true, //Set True only the server side app needs to know about this
SameSite = SameSiteMode.Lax, //Used when returning from an sso authorisation
Secure = true,
IsEssential = true,
Expires = null, //Session Cookie
Path = "/"
});
}
/// <summary>
/// Creates cookie used with an Sso Identity to a user account
/// </summary>
/// <param name="response"></param>
/// <param name="auditUserDetails"></param>
/// <param name="generalIdRef"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task CreateNewUserLinkCookie(HttpResponse response, AuditUserDetails auditUserDetails, GeneralIdRef generalIdRef, CancellationToken cancellationToken)
{
var guid = await _userManager.CreateSingleUseGuid(auditUserDetails, generalIdRef, cancellationToken);
response.Cookies.Append(ssoNewUserLinkCookieName, guid.ToString(), new CookieOptions
{
HttpOnly = true, //Set True only the server side app needs to know about this
SameSite = SameSiteMode.Lax, //Used when returning from an sso authorisation
Secure = true,
IsEssential = true,
Expires = null, //Session Cookie
Path = "/"
});
}
/// <summary>
/// Used to find a profile link cookie and find the appropriate user account
/// </summary>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <exception cref="NotFoundException"></exception>
public async Task<CookieLink?> GetUserIdFromLinkCookie(HttpRequest request, CancellationToken cancellationToken)
{
var cookieContent = string.Empty;
var cookieLink = new CookieLink()
{
LinkType = LinkType.None
};
if (request.Cookies.ContainsKey(ssoProfileLinkCookieName))
{
cookieContent = request.Cookies[ssoProfileLinkCookieName] ?? throw new NotFoundException();
cookieLink.LinkType = LinkType.Profile;
}
if (request.Cookies.ContainsKey(ssoNewUserLinkCookieName))
{
cookieContent = request.Cookies[ssoNewUserLinkCookieName] ?? throw new NotFoundException();
cookieLink.LinkType = LinkType.NewUser;
}
if (cookieLink.LinkType == LinkType.None)
{
return null;
}
var guid = new Guid(cookieContent);
cookieLink.User = await _userManager.GetUserWithSingleUseGuid(guid, cancellationToken);
return cookieLink;
}
/// <summary>
/// Delete any existing Profile link cookie.
/// </summary>
/// <param name="response"></param>
/// <returns></returns>
public Task DeleteLinkCookie(HttpResponse response)
{
response.Cookies.Delete(ssoProfileLinkCookieName);
response.Cookies.Delete(ssoNewUserLinkCookieName);
return Task.CompletedTask;
}
/// <summary>
/// Find the SsoProvider Id using a cookie to save user input
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public Task<long?> GetSsoIdFromSsoIdCookie(HttpRequest request)
{
return Task.FromResult(request.Cookies.ContainsKey(ssoIdCookieName) ? request.Cookies[ssoIdCookieName].ToLong() : null);
}
/// <summary>
/// Delete the SsoProvider cookie as the user has manually logged out
/// </summary>
/// <param name="response"></param>
/// <returns></returns>
public Task DeleteSsoIdCookie(HttpResponse response)
{
response.Cookies.Delete(ssoIdCookieName);
return Task.CompletedTask;
}
/// <summary>
/// Create the SsoProvider cookie, so that the login provess can be sped up for user convenience
/// </summary>
/// <param name="response"></param>
/// <param name="ssoId"></param>
/// <returns></returns>
public Task CreateSsoIdCookie(HttpResponse response, long ssoId)
{
response.Cookies.Append(ssoIdCookieName, ssoId.ToString(), new CookieOptions()
{
HttpOnly = true,
SameSite = SameSiteMode.Strict,
Secure = true,
IsEssential = true,
Expires = DateTime.UtcNow.AddMonths(1), //cookie will expire after a month.
Path = "/"
});
return Task.CompletedTask;
}
}