// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using EpicGames.Horde.Acls; using EpicGames.Horde.Agents; using HordeServer.Server; using HordeServer.Utilities; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using MongoDB.Driver; namespace HordeServer.Acls { /// /// Wraps functionality for manipulating permissions /// public class AclService : IAclService { private readonly GlobalsService _globalsService; private readonly IOptionsMonitor _globalConfig; /// /// Constructor /// public AclService(GlobalsService globalsService, IOptionsMonitor globalConfig) { _globalsService = globalsService; _globalConfig = globalConfig; } /// /// Issues a bearer token with the given claims /// /// List of claims to include /// Time that the token expires /// Cancellation token for the operation /// JWT security token with a claim for creating new agents public async ValueTask IssueBearerTokenAsync(IEnumerable claims, TimeSpan? expiry, CancellationToken cancellationToken = default) { IGlobals globals = await _globalsService.GetAsync(cancellationToken); SigningCredentials signingCredentials = new(globals.JwtSigningKey, SecurityAlgorithms.HmacSha256); JwtSecurityToken token = new(globals.JwtIssuer, null, claims.DistinctBy(x => (x.Type, x.Value)), null, DateTime.UtcNow + expiry, signingCredentials); return new JwtSecurityTokenHandler().WriteToken(token); } /// /// Gets the agent id associated with a particular user /// /// /// public static AgentId? GetAgentId(ClaimsPrincipal user) { Claim? claim = user.Claims.FirstOrDefault(x => x.Type == HordeClaimTypes.Agent); if (claim == null) { return null; } else { return new AgentId(claim.Value); } } /// public bool TryGetAclScope(AclScopeName scopeName, [NotNullWhen(true)] out AclConfig? scopeConfig) => _globalConfig.CurrentValue.TryGetAclScope(scopeName, out scopeConfig); } }